server: Make it possible for WaitCommEvent to detect recursive requests.

This commit is contained in:
Dmitry Timoshkov 2013-10-31 16:58:19 +09:00 committed by Alexandre Julliard
parent 318931bd46
commit a890d0f030
5 changed files with 54 additions and 7 deletions

View File

@ -966,7 +966,6 @@ static void test_waittxempty(void)
SetLastError(0xdeadbeef);
res = WaitCommEvent(hcom, &evtmask, &ovl_wait2);
ok(!res, "WaitCommEvent should fail if there is a pending wait\n");
todo_wine
ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
CloseHandle(ovl_wait2.hEvent);

View File

@ -381,7 +381,21 @@ static NTSTATUS get_timeouts(HANDLE handle, SERIAL_TIMEOUTS* st)
return status;
}
static NTSTATUS get_wait_mask(HANDLE hDevice, DWORD *mask, DWORD *cookie, DWORD *pending_write)
static void stop_waiting( HANDLE handle )
{
NTSTATUS status;
SERVER_START_REQ( set_serial_info )
{
req->handle = wine_server_obj_handle( handle );
req->flags = SERIALINFO_PENDING_WAIT;
if ((status = wine_server_call( req )))
ERR("failed to clear waiting state: %#x\n", status);
}
SERVER_END_REQ;
}
static NTSTATUS get_wait_mask(HANDLE hDevice, DWORD *mask, DWORD *cookie, DWORD *pending_write, BOOL start_wait)
{
NTSTATUS status;
@ -389,6 +403,7 @@ static NTSTATUS get_wait_mask(HANDLE hDevice, DWORD *mask, DWORD *cookie, DWORD
{
req->handle = wine_server_obj_handle( hDevice );
req->flags = pending_write ? SERIALINFO_PENDING_WRITE : 0;
if (start_wait) req->flags |= SERIALINFO_PENDING_WAIT;
if (!(status = wine_server_call( req )))
{
*mask = reply->eventmask;
@ -940,7 +955,7 @@ static DWORD CALLBACK wait_for_event(LPVOID arg)
&new_irq_info, &commio->irq_info,
new_mstat, commio->mstat, commio->pending_write);
if (*commio->events) break;
get_wait_mask(commio->hDevice, &dummy, &cookie, (commio->evtmask & EV_TXEMPTY) ? &commio->pending_write : NULL);
get_wait_mask(commio->hDevice, &dummy, &cookie, (commio->evtmask & EV_TXEMPTY) ? &commio->pending_write : NULL, FALSE);
if (commio->cookie != cookie)
{
*commio->events = 0;
@ -959,6 +974,7 @@ static DWORD CALLBACK wait_for_event(LPVOID arg)
else
commio->iosb->u.Status = STATUS_CANCELLED;
}
stop_waiting(commio->hDevice);
if (commio->hEvent) NtSetEvent(commio->hEvent, NULL);
RtlFreeHeap(GetProcessHeap(), 0, commio);
return 0;
@ -980,7 +996,12 @@ static NTSTATUS wait_on(HANDLE hDevice, int fd, HANDLE hEvent, PIO_STATUS_BLOCK
commio->iosb = piosb;
commio->hEvent = hEvent;
commio->pending_write = 0;
get_wait_mask(commio->hDevice, &commio->evtmask, &commio->cookie, (commio->evtmask & EV_TXEMPTY) ? &commio->pending_write : NULL);
status = get_wait_mask(commio->hDevice, &commio->evtmask, &commio->cookie, (commio->evtmask & EV_TXEMPTY) ? &commio->pending_write : NULL, TRUE);
if (status)
{
RtlFreeHeap(GetProcessHeap(), 0, commio);
return status;
}
/* We may never return, if some capabilities miss
* Return error in that case
@ -1045,6 +1066,7 @@ error_caps:
status = STATUS_INVALID_PARAMETER;
#endif
out_now:
stop_waiting(commio->hDevice);
RtlFreeHeap(GetProcessHeap(), 0, commio);
return status;
}
@ -1175,7 +1197,7 @@ static inline NTSTATUS io_control(HANDLE hDevice,
case IOCTL_SERIAL_GET_WAIT_MASK:
if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
{
if (!(status = get_wait_mask(hDevice, lpOutBuffer, NULL, NULL)))
if (!(status = get_wait_mask(hDevice, lpOutBuffer, NULL, NULL, FALSE)))
sz = sizeof(DWORD);
}
else

View File

@ -3083,6 +3083,7 @@ struct set_serial_info_reply
#define SERIALINFO_SET_TIMEOUTS 0x01
#define SERIALINFO_SET_MASK 0x02
#define SERIALINFO_PENDING_WRITE 0x04
#define SERIALINFO_PENDING_WAIT 0x08
@ -5845,6 +5846,6 @@ union generic_reply
struct set_suspend_context_reply set_suspend_context_reply;
};
#define SERVER_PROTOCOL_VERSION 451
#define SERVER_PROTOCOL_VERSION 452
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */

View File

@ -2239,6 +2239,7 @@ enum message_type
#define SERIALINFO_SET_TIMEOUTS 0x01
#define SERIALINFO_SET_MASK 0x02
#define SERIALINFO_PENDING_WRITE 0x04
#define SERIALINFO_PENDING_WAIT 0x08
/* Create an async I/O */

View File

@ -77,7 +77,8 @@ struct serial
unsigned int eventmask;
unsigned int generation; /* event mask change counter */
unsigned int pending_write;
unsigned int pending_write : 1;
unsigned int pending_wait : 1;
struct termios original;
@ -139,6 +140,7 @@ struct object *create_serial( struct fd *fd )
serial->eventmask = 0;
serial->generation = 0;
serial->pending_write = 0;
serial->pending_wait = 0;
serial->fd = (struct fd *)grab_object( fd );
set_fd_user( fd, &serial_fd_ops, &serial->obj );
return &serial->obj;
@ -205,6 +207,17 @@ DECL_HANDLER(get_serial_info)
if ((serial = get_serial_obj( current->process, req->handle, 0 )))
{
if (req->flags & SERIALINFO_PENDING_WAIT)
{
if (serial->pending_wait)
{
release_object( serial );
set_error( STATUS_INVALID_PARAMETER );
return;
}
serial->pending_wait = 1;
}
/* timeouts */
reply->readinterval = serial->readinterval;
reply->readconst = serial->readconst;
@ -231,6 +244,17 @@ DECL_HANDLER(set_serial_info)
if ((serial = get_serial_obj( current->process, req->handle, 0 )))
{
if (req->flags & SERIALINFO_PENDING_WAIT)
{
if (!serial->pending_wait)
{
release_object( serial );
set_error( STATUS_INVALID_PARAMETER );
return;
}
serial->pending_wait = 0;
}
/* timeouts */
if (req->flags & SERIALINFO_SET_TIMEOUTS)
{