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