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( ¤t->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