NTDLL: implement NtSignalAndWaitForSingleObject

Mike McCormack mike at codeweavers.com
Mon Apr 18 11:29:02 CDT 2005


ChangeLog:
* implement NtSignalAndWaitForSingleObject
-------------- next part --------------
Index: server/event.c
===================================================================
RCS file: /home/wine/wine/server/event.c,v
retrieving revision 1.29
diff -u -p -r1.29 event.c
--- server/event.c	2 Dec 2004 18:05:37 -0000	1.29
+++ server/event.c	18 Apr 2005 16:28:01 -0000
@@ -123,6 +123,29 @@ static int event_satisfied( struct objec
     return 0;  /* Not abandoned */
 }
 
+void event_operation( obj_handle_t handle, int op )
+{
+    struct event *event;
+
+    if (!(event = get_event_obj( current->process, handle, EVENT_MODIFY_STATE )))
+        return;
+    switch(op)
+    {
+    case PULSE_EVENT:
+        pulse_event( event );
+        break;
+    case SET_EVENT:
+        set_event( event );
+        break;
+    case RESET_EVENT:
+        reset_event( event );
+        break;
+    default:
+        fatal_protocol_error( current, "event_op: invalid operation %d\n", op );
+    }
+    release_object( event );
+}
+
 /* create an event */
 DECL_HANDLER(create_event)
 {
@@ -147,22 +170,5 @@ DECL_HANDLER(open_event)
 /* do an event operation */
 DECL_HANDLER(event_op)
 {
-    struct event *event;
-
-    if (!(event = get_event_obj( current->process, req->handle, EVENT_MODIFY_STATE ))) return;
-    switch(req->op)
-    {
-    case PULSE_EVENT:
-        pulse_event( event );
-        break;
-    case SET_EVENT:
-        set_event( event );
-        break;
-    case RESET_EVENT:
-        reset_event( event );
-        break;
-    default:
-        fatal_protocol_error( current, "event_op: invalid operation %d\n", req->op );
-    }
-    release_object( event );
+    event_operation( req->handle, req->op );
 }
Index: server/mutex.c
===================================================================
RCS file: /home/wine/wine/server/mutex.c,v
retrieving revision 1.27
diff -u -p -r1.27 mutex.c
--- server/mutex.c	25 Feb 2005 16:58:43 -0000	1.27
+++ server/mutex.c	18 Apr 2005 16:28:01 -0000
@@ -143,6 +143,24 @@ static void mutex_destroy( struct object
     do_release( mutex );
 }
 
+void release_mutex( obj_handle_t handle, unsigned int *prev )
+{
+    struct mutex *mutex;
+
+    if ((mutex = (struct mutex *)get_handle_obj( current->process, handle,
+                                                 MUTEX_MODIFY_STATE, &mutex_ops )))
+    {
+        if (!mutex->count || (mutex->owner != current)) set_error( STATUS_MUTANT_NOT_OWNED );
+        else
+        {
+            if (prev)
+                *prev = mutex->count;
+            if (!--mutex->count) do_release( mutex );
+        }
+        release_object( mutex );
+    }
+}
+
 /* create a mutex */
 DECL_HANDLER(create_mutex)
 {
@@ -166,17 +184,5 @@ DECL_HANDLER(open_mutex)
 /* release a mutex */
 DECL_HANDLER(release_mutex)
 {
-    struct mutex *mutex;
-
-    if ((mutex = (struct mutex *)get_handle_obj( current->process, req->handle,
-                                                 MUTEX_MODIFY_STATE, &mutex_ops )))
-    {
-        if (!mutex->count || (mutex->owner != current)) set_error( STATUS_MUTANT_NOT_OWNED );
-        else
-        {
-            reply->prev_count = mutex->count;
-            if (!--mutex->count) do_release( mutex );
-        }
-        release_object( mutex );
-    }
+    release_mutex( req->handle, &reply->prev_count );
 }
Index: server/object.h
===================================================================
RCS file: /home/wine/wine/server/object.h,v
retrieving revision 1.57
diff -u -p -r1.57 object.h
--- server/object.h	1 Mar 2005 11:49:58 -0000	1.57
+++ server/object.h	18 Apr 2005 16:28:01 -0000
@@ -113,10 +113,15 @@ extern struct event *get_event_obj( stru
 extern void pulse_event( struct event *event );
 extern void set_event( struct event *event );
 extern void reset_event( struct event *event );
+extern void event_operation( obj_handle_t handle, int op );
+
+/* semaphore functions */
+extern void release_semaphore( obj_handle_t handle, unsigned int count, unsigned int *prev );
 
 /* mutex functions */
 
 extern void abandon_mutexes( struct thread *thread );
+extern void release_mutex( obj_handle_t handle, unsigned int *prev );
 
 /* serial functions */
 
Index: server/protocol.def
===================================================================
RCS file: /home/wine/wine/server/protocol.def,v
retrieving revision 1.129
diff -u -p -r1.129 protocol.def
--- server/protocol.def	18 Apr 2005 15:38:44 -0000	1.129
+++ server/protocol.def	18 Apr 2005 16:28:02 -0000
@@ -489,6 +489,15 @@ enum apc_type { APC_NONE, APC_USER, APC_
 #define SELECT_TIMEOUT       8
 
 
+ at REQ(signal_and_wait)
+    obj_handle_t   hsignal;      /* handle to signal */
+    obj_handle_t   hwait;        /* handle to wait on */
+    int            flags;        /* wait flags (see above) */
+    void*          cookie;       /* magic cookie to return to client */
+    abs_time_t     timeout;      /* absolute timeout */
+ at END
+
+
 /* Create an event */
 @REQ(create_event)
     unsigned int access;        /* wanted access rights */
Index: server/semaphore.c
===================================================================
RCS file: /home/wine/wine/server/semaphore.c,v
retrieving revision 1.27
diff -u -p -r1.27 semaphore.c
--- server/semaphore.c	2 Dec 2004 18:05:37 -0000	1.27
+++ server/semaphore.c	18 Apr 2005 16:28:02 -0000
@@ -77,15 +77,15 @@ static struct semaphore *create_semaphor
     return sem;
 }
 
-static unsigned int release_semaphore( obj_handle_t handle, unsigned int count )
+void release_semaphore( obj_handle_t handle, unsigned int count, unsigned int *prev )
 {
     struct semaphore *sem;
-    unsigned int prev = 0;
 
     if ((sem = (struct semaphore *)get_handle_obj( current->process, handle,
                                                    SEMAPHORE_MODIFY_STATE, &semaphore_ops )))
     {
-        prev = sem->count;
+        if (prev)
+            *prev = sem->count;
         if (sem->count + count < sem->count || sem->count + count > sem->max)
         {
             set_error( STATUS_SEMAPHORE_LIMIT_EXCEEDED );
@@ -102,7 +102,6 @@ static unsigned int release_semaphore( o
         }
         release_object( sem );
     }
-    return prev;
 }
 
 static void semaphore_dump( struct object *obj, int verbose )
@@ -154,5 +153,5 @@ DECL_HANDLER(open_semaphore)
 /* release a semaphore */
 DECL_HANDLER(release_semaphore)
 {
-    reply->prev_count = release_semaphore( req->handle, req->count );
+    release_semaphore( req->handle, req->count, &reply->prev_count );
 }
Index: server/thread.c
===================================================================
RCS file: /home/wine/wine/server/thread.c,v
retrieving revision 1.110
diff -u -p -r1.110 thread.c
--- server/thread.c	4 Mar 2005 12:38:36 -0000	1.110
+++ server/thread.c	18 Apr 2005 16:28:02 -0000
@@ -577,6 +577,73 @@ void wake_up( struct object *obj, int ma
     }
 }
 
+/* 
+ * signal_object
+ *
+ * Try signaling an event flag, a semaphore or a mutex.
+ * FIXME: find out which operation to do by checking the type of object
+ */
+static void signal_object( obj_handle_t handle )
+{
+    /* is it an event flag? */
+    set_error( STATUS_SUCCESS );
+    event_operation( handle, SET_EVENT );
+    if (get_error() != STATUS_OBJECT_TYPE_MISMATCH)
+        return;
+
+    /* is it a semaphore? */
+    set_error( STATUS_SUCCESS );
+    release_semaphore( handle, 1, NULL );
+    if (get_error() != STATUS_OBJECT_TYPE_MISMATCH)
+        return;
+
+    /* is it a mutex? */
+    set_error( STATUS_SUCCESS );
+    release_mutex( handle, NULL );
+    if (get_error() != STATUS_OBJECT_TYPE_MISMATCH)
+        return;
+
+    set_error( STATUS_INVALID_HANDLE );
+}
+
+static void signal_and_wait( obj_handle_t hsignal, struct object *wait,
+                            int flags, const abs_time_t *timeout )
+{
+    int r;
+
+    if (!wait_on( 1, &wait, flags, timeout ))
+        return;
+
+    /* signal the object */
+    signal_object( hsignal );
+    if (get_error())
+    {
+        end_wait( current );
+        return;
+    }
+
+    /* check if we woke ourselves up */
+    if (!current->wait)
+        return;
+
+    r = check_wait( current );
+    if (r != -1)
+    {
+        end_wait( current );
+        set_error( r );
+        return;
+    }
+
+    /* check if we need to wait */
+    if (!(flags & SELECT_TIMEOUT))
+        return;
+
+    current->wait->user = add_timeout_user( &current->wait->timeout,
+                                            thread_timeout, current->wait );
+    if (!current->wait->user)
+        end_wait( current );
+}
+
 /* queue an async procedure call */
 int thread_queue_apc( struct thread *thread, struct object *owner, void *func,
                       enum apc_type type, int system, void *arg1, void *arg2, void *arg3 )
@@ -954,6 +1021,18 @@ DECL_HANDLER(select)
 {
     int count = get_req_data_size() / sizeof(int);
     select_on( count, req->cookie, get_req_data(), req->flags, &req->timeout );
+}
+
+DECL_HANDLER(signal_and_wait)
+{   
+    struct object *wait;
+
+    wait = get_handle_obj( current->process, req->hwait, SYNCHRONIZE, NULL );
+    if (wait)
+    {
+        signal_and_wait( req->hsignal, wait, req->flags, &req->timeout );
+        release_object( wait );
+    }
 }
 
 /* queue an APC for a thread */
Index: dlls/ntdll/sync.c
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/sync.c,v
retrieving revision 1.45
diff -u -p -r1.45 sync.c
--- dlls/ntdll/sync.c	18 Apr 2005 15:38:44 -0000	1.45
+++ dlls/ntdll/sync.c	18 Apr 2005 16:28:02 -0000
@@ -827,6 +827,35 @@ NTSTATUS WINAPI NtDelayExecution( BOOLEA
 NTSTATUS WINAPI NtSignalAndWaitForSingleObject( HANDLE hSignalObject, HANDLE hWaitObject,
                                                 BOOLEAN bAlertable, PLARGE_INTEGER Timeout )
 {
-    FIXME("%p %p %d %p\n", hSignalObject, hWaitObject, bAlertable, Timeout);
-    return STATUS_SUCCESS;
+    int cookie, flags = SELECT_INTERRUPTIBLE;
+    NTSTATUS ret;
+
+    TRACE("%p %p %d %p\n", hSignalObject, hWaitObject, bAlertable, Timeout);
+
+    if (Timeout) flags |= SELECT_TIMEOUT;
+    if (bAlertable) flags |= SELECT_ALERTABLE;
+    for (;;)
+    {
+        SERVER_START_REQ( signal_and_wait )
+        {
+            req->hsignal = hSignalObject;
+            req->hwait   = hWaitObject;
+            req->flags   = flags;
+            req->cookie  = &cookie;
+            NTDLL_get_server_timeout( &req->timeout, Timeout );
+            ret = wine_server_call( req );
+        }
+        SERVER_END_REQ;
+        if (ret == STATUS_PENDING) ret = wait_reply( &cookie );
+        if (ret != STATUS_USER_APC) break;
+        call_apcs( (flags & SELECT_ALERTABLE) != 0 );
+        if (flags & SELECT_ALERTABLE) break;
+    }
+
+    /* A test on Windows 2000 shows that Windows always yields during
+       a wait, but a wait that is hit by an event gets a priority
+       boost as well.  This seems to model that behavior the closest.  */
+    if (ret == WAIT_TIMEOUT) NtYieldExecution();
+
+    return ret;
 }


More information about the wine-patches mailing list