server: Make it possible for WaitCommEvent to detect recursive requests.
Dmitry Timoshkov
dmitry at baikal.ru
Thu Oct 31 02:58:19 CDT 2013
---
dlls/kernel32/tests/comm.c | 1 -
dlls/ntdll/serial.c | 30 ++++++++++++++++++++++++++----
server/protocol.def | 1 +
server/serial.c | 26 +++++++++++++++++++++++++-
4 files changed, 52 insertions(+), 6 deletions(-)
diff --git a/dlls/kernel32/tests/comm.c b/dlls/kernel32/tests/comm.c
index 455ee89..5059fc9 100644
--- a/dlls/kernel32/tests/comm.c
+++ b/dlls/kernel32/tests/comm.c
@@ -964,7 +964,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/server/protocol.def b/server/protocol.def
index 95d7994..57163c2 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)
{
--
1.8.4.1
More information about the wine-patches
mailing list