server: Make signal and wait a separate select operation.
This commit is contained in:
parent
042e0046d4
commit
947e337480
|
@ -235,7 +235,7 @@ static inline NTSTATUS wait_semaphore( RTL_CRITICAL_SECTION *crit, int timeout )
|
|||
time.QuadPart = timeout * (LONGLONG)-10000000;
|
||||
select_op.wait.op = SELECT_WAIT;
|
||||
select_op.wait.handles[0] = wine_server_obj_handle( sem );
|
||||
ret = NTDLL_wait_for_multiple_objects( &select_op, offsetof( select_op_t, wait.handles[1] ), 0, &time, 0 );
|
||||
ret = NTDLL_wait_for_multiple_objects( &select_op, offsetof( select_op_t, wait.handles[1] ), 0, &time );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ void wait_suspend( CONTEXT *context )
|
|||
|
||||
/* wait with 0 timeout, will only return once the thread is no longer suspended */
|
||||
timeout.QuadPart = 0;
|
||||
NTDLL_wait_for_multiple_objects( NULL, 0, SELECT_INTERRUPTIBLE, &timeout, 0 );
|
||||
NTDLL_wait_for_multiple_objects( NULL, 0, SELECT_INTERRUPTIBLE, &timeout );
|
||||
|
||||
/* retrieve the new context */
|
||||
SERVER_START_REQ( get_suspend_context )
|
||||
|
@ -134,7 +134,7 @@ NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *con
|
|||
|
||||
select_op.wait.op = SELECT_WAIT;
|
||||
select_op.wait.handles[0] = handle;
|
||||
NTDLL_wait_for_multiple_objects( &select_op, offsetof( select_op_t, wait.handles[1] ), SELECT_INTERRUPTIBLE, NULL, 0 );
|
||||
NTDLL_wait_for_multiple_objects( &select_op, offsetof( select_op_t, wait.handles[1] ), SELECT_INTERRUPTIBLE, NULL );
|
||||
|
||||
SERVER_START_REQ( get_exception_status )
|
||||
{
|
||||
|
|
|
@ -63,8 +63,8 @@ extern LPCSTR debugstr_us( const UNICODE_STRING *str ) DECLSPEC_HIDDEN;
|
|||
extern LPCSTR debugstr_ObjectAttributes(const OBJECT_ATTRIBUTES *oa) DECLSPEC_HIDDEN;
|
||||
|
||||
extern NTSTATUS NTDLL_queue_process_apc( HANDLE process, const apc_call_t *call, apc_result_t *result ) DECLSPEC_HIDDEN;
|
||||
extern NTSTATUS NTDLL_wait_for_multiple_objects( const select_op_t *select_op, data_size_t size, UINT flags,
|
||||
const LARGE_INTEGER *timeout, HANDLE signal_object ) DECLSPEC_HIDDEN;
|
||||
extern NTSTATUS NTDLL_wait_for_multiple_objects( const select_op_t *select_op, data_size_t size,
|
||||
UINT flags, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN;
|
||||
|
||||
/* init routines */
|
||||
extern NTSTATUS signal_alloc_thread( TEB **teb ) DECLSPEC_HIDDEN;
|
||||
|
|
|
@ -1107,7 +1107,7 @@ NTSTATUS NTDLL_queue_process_apc( HANDLE process, const apc_call_t *call, apc_re
|
|||
* Implementation of NtWaitForMultipleObjects
|
||||
*/
|
||||
NTSTATUS NTDLL_wait_for_multiple_objects( const select_op_t *select_op, data_size_t size, UINT flags,
|
||||
const LARGE_INTEGER *timeout, HANDLE signal_object )
|
||||
const LARGE_INTEGER *timeout )
|
||||
{
|
||||
NTSTATUS ret;
|
||||
int cookie;
|
||||
|
@ -1125,7 +1125,6 @@ NTSTATUS NTDLL_wait_for_multiple_objects( const select_op_t *select_op, data_siz
|
|||
{
|
||||
req->flags = flags;
|
||||
req->cookie = wine_server_client_ptr( &cookie );
|
||||
req->signal = wine_server_obj_handle( signal_object );
|
||||
req->prev_apc = apc_handle;
|
||||
req->timeout = abs_timeout;
|
||||
wine_server_add_data( req, &result, sizeof(result) );
|
||||
|
@ -1145,7 +1144,10 @@ NTSTATUS NTDLL_wait_for_multiple_objects( const select_op_t *select_op, data_siz
|
|||
abs_timeout = 0;
|
||||
user_apc = TRUE;
|
||||
}
|
||||
signal_object = 0; /* don't signal it multiple times */
|
||||
|
||||
/* don't signal multiple times */
|
||||
if (size >= sizeof(select_op->signal_and_wait) && select_op->op == SELECT_SIGNAL_AND_WAIT)
|
||||
size = offsetof( select_op_t, signal_and_wait.signal );
|
||||
}
|
||||
|
||||
if (ret == STATUS_TIMEOUT && user_apc) ret = STATUS_USER_APC;
|
||||
|
@ -1176,7 +1178,7 @@ NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles,
|
|||
if (alertable) flags |= SELECT_ALERTABLE;
|
||||
select_op.wait.op = wait_all ? SELECT_WAIT_ALL : SELECT_WAIT;
|
||||
for (i = 0; i < count; i++) select_op.wait.handles[i] = wine_server_obj_handle( handles[i] );
|
||||
return NTDLL_wait_for_multiple_objects( &select_op, offsetof( select_op_t, wait.handles[count] ), flags, timeout, 0 );
|
||||
return NTDLL_wait_for_multiple_objects( &select_op, offsetof( select_op_t, wait.handles[count] ), flags, timeout );
|
||||
}
|
||||
|
||||
|
||||
|
@ -1199,10 +1201,12 @@ NTSTATUS WINAPI NtSignalAndWaitForSingleObject( HANDLE hSignalObject, HANDLE hWa
|
|||
UINT flags = SELECT_INTERRUPTIBLE;
|
||||
|
||||
if (!hSignalObject) return STATUS_INVALID_HANDLE;
|
||||
|
||||
if (alertable) flags |= SELECT_ALERTABLE;
|
||||
select_op.wait.op = SELECT_WAIT;
|
||||
select_op.wait.handles[0] = wine_server_obj_handle( hWaitObject );
|
||||
return NTDLL_wait_for_multiple_objects( &select_op, offsetof( select_op_t, wait.handles[1] ), flags, timeout, hSignalObject );
|
||||
select_op.signal_and_wait.op = SELECT_SIGNAL_AND_WAIT;
|
||||
select_op.signal_and_wait.wait = wine_server_obj_handle( hWaitObject );
|
||||
select_op.signal_and_wait.signal = wine_server_obj_handle( hSignalObject );
|
||||
return NTDLL_wait_for_multiple_objects( &select_op, sizeof(select_op.signal_and_wait), flags, timeout );
|
||||
}
|
||||
|
||||
|
||||
|
@ -1228,7 +1232,7 @@ NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeou
|
|||
/* if alertable, we need to query the server */
|
||||
if (alertable)
|
||||
return NTDLL_wait_for_multiple_objects( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE,
|
||||
timeout, 0 );
|
||||
timeout );
|
||||
|
||||
if (!timeout || timeout->QuadPart == TIMEOUT_INFINITE) /* sleep forever */
|
||||
{
|
||||
|
|
|
@ -408,7 +408,8 @@ enum select_op
|
|||
{
|
||||
SELECT_NONE,
|
||||
SELECT_WAIT,
|
||||
SELECT_WAIT_ALL
|
||||
SELECT_WAIT_ALL,
|
||||
SELECT_SIGNAL_AND_WAIT
|
||||
};
|
||||
|
||||
typedef union
|
||||
|
@ -419,6 +420,12 @@ typedef union
|
|||
enum select_op op;
|
||||
obj_handle_t handles[MAXIMUM_WAIT_OBJECTS];
|
||||
} wait;
|
||||
struct
|
||||
{
|
||||
enum select_op op;
|
||||
obj_handle_t wait;
|
||||
obj_handle_t signal;
|
||||
} signal_and_wait;
|
||||
} select_op_t;
|
||||
|
||||
enum apc_type
|
||||
|
@ -1069,11 +1076,11 @@ struct select_request
|
|||
struct request_header __header;
|
||||
int flags;
|
||||
client_ptr_t cookie;
|
||||
obj_handle_t signal;
|
||||
obj_handle_t prev_apc;
|
||||
timeout_t timeout;
|
||||
obj_handle_t prev_apc;
|
||||
/* VARARG(result,apc_result); */
|
||||
/* VARARG(data,select_op); */
|
||||
char __pad_36[4];
|
||||
};
|
||||
struct select_reply
|
||||
{
|
||||
|
@ -5787,6 +5794,6 @@ union generic_reply
|
|||
struct set_suspend_context_reply set_suspend_context_reply;
|
||||
};
|
||||
|
||||
#define SERVER_PROTOCOL_VERSION 445
|
||||
#define SERVER_PROTOCOL_VERSION 446
|
||||
|
||||
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
||||
|
|
|
@ -424,7 +424,8 @@ enum select_op
|
|||
{
|
||||
SELECT_NONE,
|
||||
SELECT_WAIT,
|
||||
SELECT_WAIT_ALL
|
||||
SELECT_WAIT_ALL,
|
||||
SELECT_SIGNAL_AND_WAIT
|
||||
};
|
||||
|
||||
typedef union
|
||||
|
@ -435,6 +436,12 @@ typedef union
|
|||
enum select_op op; /* SELECT_WAIT or SELECT_WAIT_ALL */
|
||||
obj_handle_t handles[MAXIMUM_WAIT_OBJECTS];
|
||||
} wait;
|
||||
struct
|
||||
{
|
||||
enum select_op op; /* SELECT_SIGNAL_AND_WAIT */
|
||||
obj_handle_t wait;
|
||||
obj_handle_t signal; /* must be last in the structure so we can remove it on retries */
|
||||
} signal_and_wait;
|
||||
} select_op_t;
|
||||
|
||||
enum apc_type
|
||||
|
@ -937,9 +944,8 @@ struct rawinput_device
|
|||
@REQ(select)
|
||||
int flags; /* wait flags (see below) */
|
||||
client_ptr_t cookie; /* magic cookie to return to client */
|
||||
obj_handle_t signal; /* object to signal (0 if none) */
|
||||
obj_handle_t prev_apc; /* handle to previous APC */
|
||||
timeout_t timeout; /* timeout */
|
||||
obj_handle_t prev_apc; /* handle to previous APC */
|
||||
VARARG(result,apc_result); /* result of previous APC */
|
||||
VARARG(data,select_op); /* operation-specific data */
|
||||
@REPLY
|
||||
|
|
|
@ -816,9 +816,8 @@ C_ASSERT( FIELD_OFFSET(struct open_thread_reply, handle) == 8 );
|
|||
C_ASSERT( sizeof(struct open_thread_reply) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct select_request, flags) == 12 );
|
||||
C_ASSERT( FIELD_OFFSET(struct select_request, cookie) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct select_request, signal) == 24 );
|
||||
C_ASSERT( FIELD_OFFSET(struct select_request, prev_apc) == 28 );
|
||||
C_ASSERT( FIELD_OFFSET(struct select_request, timeout) == 32 );
|
||||
C_ASSERT( FIELD_OFFSET(struct select_request, timeout) == 24 );
|
||||
C_ASSERT( FIELD_OFFSET(struct select_request, prev_apc) == 32 );
|
||||
C_ASSERT( sizeof(struct select_request) == 40 );
|
||||
C_ASSERT( FIELD_OFFSET(struct select_reply, timeout) == 8 );
|
||||
C_ASSERT( FIELD_OFFSET(struct select_reply, call) == 16 );
|
||||
|
|
|
@ -590,6 +590,25 @@ static int wait_on( const select_op_t *select_op, unsigned int count, struct obj
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int wait_on_handles( const select_op_t *select_op, unsigned int count, const obj_handle_t *handles,
|
||||
int flags, timeout_t timeout )
|
||||
{
|
||||
struct object *objects[MAXIMUM_WAIT_OBJECTS];
|
||||
unsigned int i;
|
||||
int ret = 0;
|
||||
|
||||
assert( count <= MAXIMUM_WAIT_OBJECTS );
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
if (!(objects[i] = get_handle_obj( current->process, handles[i], SYNCHRONIZE, NULL )))
|
||||
break;
|
||||
|
||||
if (i == count) ret = wait_on( select_op, count, objects, flags, timeout );
|
||||
|
||||
while (i > 0) release_object( objects[--i] );
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* check if the thread waiting condition is satisfied */
|
||||
static int check_wait( struct thread *thread )
|
||||
{
|
||||
|
@ -714,18 +733,17 @@ static int signal_object( obj_handle_t handle )
|
|||
|
||||
/* select on a list of handles */
|
||||
static timeout_t select_on( const select_op_t *select_op, data_size_t op_size, client_ptr_t cookie,
|
||||
int flags, timeout_t timeout, obj_handle_t signal_obj )
|
||||
int flags, timeout_t timeout )
|
||||
{
|
||||
int ret;
|
||||
unsigned int i, count;
|
||||
struct object *objects[MAXIMUM_WAIT_OBJECTS];
|
||||
unsigned int count;
|
||||
|
||||
if (timeout <= 0) timeout = current_time - timeout;
|
||||
|
||||
switch (select_op->op)
|
||||
{
|
||||
case SELECT_NONE:
|
||||
count = 0;
|
||||
if (!wait_on( select_op, 0, NULL, flags, timeout )) return timeout;
|
||||
break;
|
||||
|
||||
case SELECT_WAIT:
|
||||
|
@ -736,6 +754,23 @@ static timeout_t select_on( const select_op_t *select_op, data_size_t op_size, c
|
|||
set_error( STATUS_INVALID_PARAMETER );
|
||||
return 0;
|
||||
}
|
||||
if (!wait_on_handles( select_op, count, select_op->wait.handles, flags, timeout ))
|
||||
return timeout;
|
||||
break;
|
||||
|
||||
case SELECT_SIGNAL_AND_WAIT:
|
||||
if (!wait_on_handles( select_op, 1, &select_op->signal_and_wait.wait, flags, timeout ))
|
||||
return timeout;
|
||||
if (select_op->signal_and_wait.signal)
|
||||
{
|
||||
if (!signal_object( select_op->signal_and_wait.signal ))
|
||||
{
|
||||
end_wait( current );
|
||||
return timeout;
|
||||
}
|
||||
/* check if we woke ourselves up */
|
||||
if (!current->wait) return timeout;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -743,34 +778,12 @@ static timeout_t select_on( const select_op_t *select_op, data_size_t op_size, c
|
|||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (!(objects[i] = get_handle_obj( current->process, select_op->wait.handles[i],
|
||||
SYNCHRONIZE, NULL )))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < count) goto done;
|
||||
if (!wait_on( select_op, count, objects, flags, timeout )) goto done;
|
||||
|
||||
/* signal the object */
|
||||
if (signal_obj)
|
||||
{
|
||||
if (!signal_object( signal_obj ))
|
||||
{
|
||||
end_wait( current );
|
||||
goto done;
|
||||
}
|
||||
/* check if we woke ourselves up */
|
||||
if (!current->wait) goto done;
|
||||
}
|
||||
|
||||
if ((ret = check_wait( current )) != -1)
|
||||
{
|
||||
/* condition is already satisfied */
|
||||
end_wait( current );
|
||||
set_error( ret );
|
||||
goto done;
|
||||
return timeout;
|
||||
}
|
||||
|
||||
/* now we need to wait */
|
||||
|
@ -780,14 +793,11 @@ static timeout_t select_on( const select_op_t *select_op, data_size_t op_size, c
|
|||
thread_timeout, current->wait )))
|
||||
{
|
||||
end_wait( current );
|
||||
goto done;
|
||||
return timeout;
|
||||
}
|
||||
}
|
||||
current->wait->cookie = cookie;
|
||||
set_error( STATUS_PENDING );
|
||||
|
||||
done:
|
||||
while (i > 0) release_object( objects[--i] );
|
||||
return timeout;
|
||||
}
|
||||
|
||||
|
@ -1370,7 +1380,7 @@ DECL_HANDLER(select)
|
|||
release_object( apc );
|
||||
}
|
||||
|
||||
reply->timeout = select_on( &select_op, op_size, req->cookie, req->flags, req->timeout, req->signal );
|
||||
reply->timeout = select_on( &select_op, op_size, req->cookie, req->flags, req->timeout );
|
||||
|
||||
if (get_error() == STATUS_USER_APC)
|
||||
{
|
||||
|
|
|
@ -405,6 +405,10 @@ static void dump_varargs_select_op( const char *prefix, data_size_t size )
|
|||
dump_handles( ",handles=", data.wait.handles,
|
||||
min( size, sizeof(data.wait) ) - offsetof( select_op_t, wait.handles ));
|
||||
break;
|
||||
case SELECT_SIGNAL_AND_WAIT:
|
||||
fprintf( stderr, "SIGNAL_AND_WAIT,signal=%04x,wait=%04x",
|
||||
data.signal_and_wait.signal, data.signal_and_wait.wait );
|
||||
break;
|
||||
default:
|
||||
fprintf( stderr, "op=%u", data.op );
|
||||
break;
|
||||
|
@ -1388,9 +1392,8 @@ static void dump_select_request( const struct select_request *req )
|
|||
{
|
||||
fprintf( stderr, " flags=%d", req->flags );
|
||||
dump_uint64( ", cookie=", &req->cookie );
|
||||
fprintf( stderr, ", signal=%04x", req->signal );
|
||||
fprintf( stderr, ", prev_apc=%04x", req->prev_apc );
|
||||
dump_timeout( ", timeout=", &req->timeout );
|
||||
fprintf( stderr, ", prev_apc=%04x", req->prev_apc );
|
||||
dump_varargs_apc_result( ", result=", cur_size );
|
||||
dump_varargs_select_op( ", data=", cur_size );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue