mirror of
https://gitlab.winehq.org/wine/wine.git
synced 2024-11-21 17:09:06 -07:00
ntdll: Introduce a separate per-thread object for internal completion waits.
This commit is contained in:
parent
18844cef20
commit
e01b70851f
Notes:
Alexandre Julliard
2024-10-23 23:32:39 +02:00
Approved-by: Elizabeth Figura (@zfigura) Approved-by: Alexandre Julliard (@julliard) Merge-Request: https://gitlab.winehq.org/wine/wine/merge_requests/6630
9 changed files with 133 additions and 5 deletions
|
@ -1999,6 +1999,7 @@ NTSTATUS WINAPI NtSetIoCompletion( HANDLE handle, ULONG_PTR key, ULONG_PTR value
|
|||
NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE handle, ULONG_PTR *key, ULONG_PTR *value,
|
||||
IO_STATUS_BLOCK *io, LARGE_INTEGER *timeout )
|
||||
{
|
||||
HANDLE wait_handle = NULL;
|
||||
unsigned int status;
|
||||
|
||||
TRACE( "(%p, %p, %p, %p, %p)\n", handle, key, value, io, timeout );
|
||||
|
@ -2015,10 +2016,11 @@ NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE handle, ULONG_PTR *key, ULONG_PTR *
|
|||
io->Information = reply->information;
|
||||
io->Status = reply->status;
|
||||
}
|
||||
else wait_handle = wine_server_ptr_handle( reply->wait_handle );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
if (status != STATUS_PENDING) return status;
|
||||
status = NtWaitForSingleObject( handle, FALSE, timeout );
|
||||
status = NtWaitForSingleObject( wait_handle, FALSE, timeout );
|
||||
if (status != WAIT_OBJECT_0) return status;
|
||||
}
|
||||
}
|
||||
|
@ -2030,6 +2032,7 @@ NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE handle, ULONG_PTR *key, ULONG_PTR *
|
|||
NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE handle, FILE_IO_COMPLETION_INFORMATION *info, ULONG count,
|
||||
ULONG *written, LARGE_INTEGER *timeout, BOOLEAN alertable )
|
||||
{
|
||||
HANDLE wait_handle = NULL;
|
||||
unsigned int status;
|
||||
ULONG i = 0;
|
||||
|
||||
|
@ -2049,6 +2052,7 @@ NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE handle, FILE_IO_COMPLETION_INFORM
|
|||
info[i].IoStatusBlock.Information = reply->information;
|
||||
info[i].IoStatusBlock.Status = reply->status;
|
||||
}
|
||||
else wait_handle = wine_server_ptr_handle( reply->wait_handle );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
if (status != STATUS_SUCCESS) break;
|
||||
|
@ -2059,7 +2063,7 @@ NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE handle, FILE_IO_COMPLETION_INFORM
|
|||
if (status == STATUS_PENDING) status = STATUS_SUCCESS;
|
||||
break;
|
||||
}
|
||||
status = NtWaitForSingleObject( handle, alertable, timeout );
|
||||
status = NtWaitForSingleObject( wait_handle, alertable, timeout );
|
||||
if (status != WAIT_OBJECT_0) break;
|
||||
}
|
||||
*written = i ? i : 1;
|
||||
|
|
|
@ -5410,7 +5410,7 @@ struct remove_completion_reply
|
|||
apc_param_t cvalue;
|
||||
apc_param_t information;
|
||||
unsigned int status;
|
||||
char __pad_36[4];
|
||||
obj_handle_t wait_handle;
|
||||
};
|
||||
|
||||
|
||||
|
@ -6711,7 +6711,7 @@ union generic_reply
|
|||
|
||||
/* ### protocol_version begin ### */
|
||||
|
||||
#define SERVER_PROTOCOL_VERSION 843
|
||||
#define SERVER_PROTOCOL_VERSION 844
|
||||
|
||||
/* ### protocol_version end ### */
|
||||
|
||||
|
|
|
@ -56,13 +56,71 @@ struct type_descr completion_type =
|
|||
},
|
||||
};
|
||||
|
||||
struct completion_wait
|
||||
{
|
||||
struct object obj;
|
||||
obj_handle_t handle;
|
||||
struct completion *completion;
|
||||
struct thread *thread;
|
||||
struct list wait_queue_entry;
|
||||
};
|
||||
|
||||
struct completion
|
||||
{
|
||||
struct object obj;
|
||||
struct list queue;
|
||||
struct list wait_queue;
|
||||
unsigned int depth;
|
||||
};
|
||||
|
||||
static void completion_wait_dump( struct object*, int );
|
||||
static int completion_wait_signaled( struct object *obj, struct wait_queue_entry *entry );
|
||||
static void completion_wait_destroy( struct object * );
|
||||
|
||||
static const struct object_ops completion_wait_ops =
|
||||
{
|
||||
sizeof(struct completion_wait), /* size */
|
||||
&no_type, /* type */
|
||||
completion_wait_dump, /* dump */
|
||||
add_queue, /* add_queue */
|
||||
remove_queue, /* remove_queue */
|
||||
completion_wait_signaled, /* signaled */
|
||||
no_satisfied, /* satisfied */
|
||||
no_signal, /* signal */
|
||||
no_get_fd, /* get_fd */
|
||||
default_map_access, /* map_access */
|
||||
default_get_sd, /* get_sd */
|
||||
default_set_sd, /* set_sd */
|
||||
no_get_full_name, /* get_full_name */
|
||||
no_lookup_name, /* lookup_name */
|
||||
no_link_name, /* link_name */
|
||||
NULL, /* unlink_name */
|
||||
no_open_file, /* open_file */
|
||||
no_kernel_obj_list, /* get_kernel_obj_list */
|
||||
no_close_handle, /* close_handle */
|
||||
completion_wait_destroy /* destroy */
|
||||
};
|
||||
|
||||
static void completion_wait_destroy( struct object *obj )
|
||||
{
|
||||
}
|
||||
|
||||
static void completion_wait_dump( struct object *obj, int verbose )
|
||||
{
|
||||
struct completion_wait *wait = (struct completion_wait *)obj;
|
||||
|
||||
assert( obj->ops == &completion_wait_ops );
|
||||
fprintf( stderr, "Completion wait completion=%p\n", wait->completion );
|
||||
}
|
||||
|
||||
static int completion_wait_signaled( struct object *obj, struct wait_queue_entry *entry )
|
||||
{
|
||||
struct completion_wait *wait = (struct completion_wait *)obj;
|
||||
|
||||
assert( obj->ops == &completion_wait_ops );
|
||||
return wait->completion->depth;
|
||||
}
|
||||
|
||||
static void completion_dump( struct object*, int );
|
||||
static int completion_signaled( struct object *obj, struct wait_queue_entry *entry );
|
||||
static void completion_destroy( struct object * );
|
||||
|
@ -103,12 +161,19 @@ struct comp_msg
|
|||
static void completion_destroy( struct object *obj)
|
||||
{
|
||||
struct completion *completion = (struct completion *) obj;
|
||||
struct completion_wait *wait, *wait_next;
|
||||
struct comp_msg *tmp, *next;
|
||||
|
||||
LIST_FOR_EACH_ENTRY_SAFE( tmp, next, &completion->queue, struct comp_msg, queue_entry )
|
||||
{
|
||||
free( tmp );
|
||||
}
|
||||
|
||||
LIST_FOR_EACH_ENTRY_SAFE( wait, wait_next, &completion->wait_queue, struct completion_wait, wait_queue_entry )
|
||||
{
|
||||
assert( wait->completion );
|
||||
cleanup_thread_completion( wait->thread );
|
||||
}
|
||||
}
|
||||
|
||||
static void completion_dump( struct object *obj, int verbose )
|
||||
|
@ -126,6 +191,35 @@ static int completion_signaled( struct object *obj, struct wait_queue_entry *ent
|
|||
return !list_empty( &completion->queue );
|
||||
}
|
||||
|
||||
void cleanup_thread_completion( struct thread *thread )
|
||||
{
|
||||
if (!thread->completion_wait) return;
|
||||
|
||||
if (thread->completion_wait->handle)
|
||||
{
|
||||
close_handle( thread->process, thread->completion_wait->handle );
|
||||
thread->completion_wait->handle = 0;
|
||||
}
|
||||
list_remove( &thread->completion_wait->wait_queue_entry );
|
||||
release_object( &thread->completion_wait->obj );
|
||||
thread->completion_wait = NULL;
|
||||
}
|
||||
|
||||
static struct completion_wait *create_completion_wait( struct thread *thread )
|
||||
{
|
||||
struct completion_wait *wait;
|
||||
|
||||
if (!(wait = alloc_object( &completion_wait_ops ))) return NULL;
|
||||
wait->completion = NULL;
|
||||
wait->thread = thread;
|
||||
if (!(wait->handle = alloc_handle( current->process, wait, SYNCHRONIZE, 0 )))
|
||||
{
|
||||
release_object( &wait->obj );
|
||||
return NULL;
|
||||
}
|
||||
return wait;
|
||||
}
|
||||
|
||||
static struct completion *create_completion( struct object *root, const struct unicode_str *name,
|
||||
unsigned int attr, unsigned int concurrent,
|
||||
const struct security_descriptor *sd )
|
||||
|
@ -137,6 +231,7 @@ static struct completion *create_completion( struct object *root, const struct u
|
|||
if (get_error() != STATUS_OBJECT_NAME_EXISTS)
|
||||
{
|
||||
list_init( &completion->queue );
|
||||
list_init( &completion->wait_queue );
|
||||
completion->depth = 0;
|
||||
}
|
||||
}
|
||||
|
@ -153,6 +248,7 @@ void add_completion( struct completion *completion, apc_param_t ckey, apc_param_
|
|||
unsigned int status, apc_param_t information )
|
||||
{
|
||||
struct comp_msg *msg = mem_alloc( sizeof( *msg ) );
|
||||
struct completion_wait *wait;
|
||||
|
||||
if (!msg)
|
||||
return;
|
||||
|
@ -164,7 +260,12 @@ void add_completion( struct completion *completion, apc_param_t ckey, apc_param_
|
|||
|
||||
list_add_tail( &completion->queue, &msg->queue_entry );
|
||||
completion->depth++;
|
||||
wake_up( &completion->obj, 1 );
|
||||
LIST_FOR_EACH_ENTRY( wait, &completion->wait_queue, struct completion_wait, wait_queue_entry )
|
||||
{
|
||||
wake_up( &wait->obj, 1 );
|
||||
if (list_empty( &completion->queue )) return;
|
||||
}
|
||||
if (!list_empty( &completion->queue )) wake_up( &completion->obj, 0 );
|
||||
}
|
||||
|
||||
/* create a completion */
|
||||
|
@ -219,8 +320,22 @@ DECL_HANDLER(remove_completion)
|
|||
if (!completion) return;
|
||||
|
||||
entry = list_head( &completion->queue );
|
||||
if (current->completion_wait)
|
||||
{
|
||||
list_remove( ¤t->completion_wait->wait_queue_entry );
|
||||
}
|
||||
else if (!(current->completion_wait = create_completion_wait( current )))
|
||||
{
|
||||
release_object( completion );
|
||||
return;
|
||||
}
|
||||
current->completion_wait->completion = completion;
|
||||
list_add_head( &completion->wait_queue, ¤t->completion_wait->wait_queue_entry );
|
||||
if (!entry)
|
||||
{
|
||||
reply->wait_handle = current->completion_wait->handle;
|
||||
set_error( STATUS_PENDING );
|
||||
}
|
||||
else
|
||||
{
|
||||
list_remove( entry );
|
||||
|
@ -231,6 +346,7 @@ DECL_HANDLER(remove_completion)
|
|||
reply->status = msg->status;
|
||||
reply->information = msg->information;
|
||||
free( msg );
|
||||
reply->wait_handle = 0;
|
||||
}
|
||||
|
||||
release_object( completion );
|
||||
|
|
|
@ -238,6 +238,7 @@ extern struct dir *get_dir_obj( struct process *process, obj_handle_t handle, un
|
|||
extern struct completion *get_completion_obj( struct process *process, obj_handle_t handle, unsigned int access );
|
||||
extern void add_completion( struct completion *completion, apc_param_t ckey, apc_param_t cvalue,
|
||||
unsigned int status, apc_param_t information );
|
||||
extern void cleanup_thread_completion( struct thread *thread );
|
||||
|
||||
/* serial port functions */
|
||||
|
||||
|
|
|
@ -3798,6 +3798,7 @@ typedef union
|
|||
apc_param_t cvalue; /* completion value */
|
||||
apc_param_t information; /* IO_STATUS_BLOCK Information */
|
||||
unsigned int status; /* completion result */
|
||||
obj_handle_t wait_handle; /* handle to completion wait internal object */
|
||||
@END
|
||||
|
||||
|
||||
|
|
|
@ -2240,6 +2240,7 @@ C_ASSERT( FIELD_OFFSET(struct remove_completion_reply, ckey) == 8 );
|
|||
C_ASSERT( FIELD_OFFSET(struct remove_completion_reply, cvalue) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct remove_completion_reply, information) == 24 );
|
||||
C_ASSERT( FIELD_OFFSET(struct remove_completion_reply, status) == 32 );
|
||||
C_ASSERT( FIELD_OFFSET(struct remove_completion_reply, wait_handle) == 36 );
|
||||
C_ASSERT( sizeof(struct remove_completion_reply) == 40 );
|
||||
C_ASSERT( FIELD_OFFSET(struct query_completion_request, handle) == 12 );
|
||||
C_ASSERT( sizeof(struct query_completion_request) == 16 );
|
||||
|
|
|
@ -249,6 +249,7 @@ static inline void init_thread_structure( struct thread *thread )
|
|||
|
||||
thread->creation_time = current_time;
|
||||
thread->exit_time = 0;
|
||||
thread->completion_wait = NULL;
|
||||
|
||||
list_init( &thread->mutex_list );
|
||||
list_init( &thread->system_apc );
|
||||
|
@ -402,6 +403,7 @@ static void cleanup_thread( struct thread *thread )
|
|||
{
|
||||
int i;
|
||||
|
||||
cleanup_thread_completion( thread );
|
||||
if (thread->context)
|
||||
{
|
||||
thread->context->status = STATUS_ACCESS_DENIED;
|
||||
|
|
|
@ -31,6 +31,7 @@ struct thread_apc;
|
|||
struct debug_obj;
|
||||
struct debug_event;
|
||||
struct msg_queue;
|
||||
struct completion_wait;
|
||||
|
||||
enum run_state
|
||||
{
|
||||
|
@ -91,6 +92,7 @@ struct thread
|
|||
struct list kernel_object; /* list of kernel object pointers */
|
||||
data_size_t desc_len; /* thread description length in bytes */
|
||||
WCHAR *desc; /* thread description string */
|
||||
struct completion_wait *completion_wait; /* completion port wait object the thread is associated with */
|
||||
};
|
||||
|
||||
extern struct thread *current;
|
||||
|
|
|
@ -4527,6 +4527,7 @@ static void dump_remove_completion_reply( const struct remove_completion_reply *
|
|||
dump_uint64( ", cvalue=", &req->cvalue );
|
||||
dump_uint64( ", information=", &req->information );
|
||||
fprintf( stderr, ", status=%08x", req->status );
|
||||
fprintf( stderr, ", wait_handle=%04x", req->wait_handle );
|
||||
}
|
||||
|
||||
static void dump_query_completion_request( const struct query_completion_request *req )
|
||||
|
|
Loading…
Reference in a new issue