Module: wine Branch: master Commit: a890d0f030a864d893646bd0c29dd761781bcdd0 URL: http://source.winehq.org/git/wine.git/?a=commit;h=a890d0f030a864d893646bd0c2...
Author: Dmitry Timoshkov dmitry@baikal.ru Date: Thu Oct 31 16:58:19 2013 +0900
server: Make it possible for WaitCommEvent to detect recursive requests.
---
dlls/kernel32/tests/comm.c | 1 - dlls/ntdll/serial.c | 30 ++++++++++++++++++++++++++---- include/wine/server_protocol.h | 3 ++- server/protocol.def | 1 + server/serial.c | 26 +++++++++++++++++++++++++- 5 files changed, 54 insertions(+), 7 deletions(-)
diff --git a/dlls/kernel32/tests/comm.c b/dlls/kernel32/tests/comm.c index 1f88707..cbd276b 100644 --- a/dlls/kernel32/tests/comm.c +++ b/dlls/kernel32/tests/comm.c @@ -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);
diff --git a/dlls/ntdll/serial.c b/dlls/ntdll/serial.c index 04aacf0..b03ac61 100644 --- a/dlls/ntdll/serial.c +++ b/dlls/ntdll/serial.c @@ -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 diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 604affd..dc83806 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -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 */ diff --git a/server/protocol.def b/server/protocol.def index 31b85f8..3c3b0b5 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -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 */ diff --git a/server/serial.c b/server/serial.c index 25587a7..880f5e3 100644 --- a/server/serial.c +++ b/server/serial.c @@ -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) {