server: Allow kernel to keep reference to server objects by client pointer.
Signed-off-by: Jacek Caban <jacek@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
134e264ae5
commit
94c1ef0ee1
|
@ -290,6 +290,14 @@ void *alloc_kernel_object( POBJECT_TYPE type, HANDLE handle, SIZE_T size, LONG r
|
|||
return header + 1;
|
||||
}
|
||||
|
||||
static CRITICAL_SECTION obref_cs;
|
||||
static CRITICAL_SECTION_DEBUG obref_critsect_debug =
|
||||
{
|
||||
0, 0, &obref_cs,
|
||||
{ &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
|
||||
0, 0, { (DWORD_PTR)(__FILE__ ": obref_cs") }
|
||||
};
|
||||
static CRITICAL_SECTION obref_cs = { &obref_critsect_debug, -1, 0, 0, 0, 0 };
|
||||
|
||||
/***********************************************************************
|
||||
* ObDereferenceObject (NTOSKRNL.EXE.@)
|
||||
|
@ -305,13 +313,29 @@ void WINAPI ObDereferenceObject( void *obj )
|
|||
return;
|
||||
}
|
||||
|
||||
ref = InterlockedDecrement( &header->ref );
|
||||
EnterCriticalSection( &obref_cs );
|
||||
|
||||
ref = --header->ref;
|
||||
TRACE( "(%p) ref=%u\n", obj, ref );
|
||||
if (!ref)
|
||||
{
|
||||
if (header->type->release) header->type->release( obj );
|
||||
else FIXME( "no destructor\n" );
|
||||
if (header->type->release)
|
||||
{
|
||||
header->type->release( obj );
|
||||
}
|
||||
else
|
||||
{
|
||||
SERVER_START_REQ( release_kernel_object )
|
||||
{
|
||||
req->manager = wine_server_obj_handle( get_device_manager() );
|
||||
req->user_ptr = wine_server_client_ptr( obj );
|
||||
if (wine_server_call( req )) FIXME( "failed to release %p\n", obj );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection( &obref_cs );
|
||||
}
|
||||
|
||||
static void ObReferenceObject( void *obj )
|
||||
|
@ -325,8 +349,22 @@ static void ObReferenceObject( void *obj )
|
|||
return;
|
||||
}
|
||||
|
||||
ref = InterlockedIncrement( &header->ref );
|
||||
EnterCriticalSection( &obref_cs );
|
||||
|
||||
ref = ++header->ref;
|
||||
TRACE( "(%p) ref=%u\n", obj, ref );
|
||||
if (ref == 1)
|
||||
{
|
||||
SERVER_START_REQ( grab_kernel_object )
|
||||
{
|
||||
req->manager = wine_server_obj_handle( get_device_manager() );
|
||||
req->user_ptr = wine_server_client_ptr( obj );
|
||||
if (wine_server_call( req )) FIXME( "failed to grab %p reference\n", obj );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
}
|
||||
|
||||
LeaveCriticalSection( &obref_cs );
|
||||
}
|
||||
|
||||
static const POBJECT_TYPE *known_types[] =
|
||||
|
|
|
@ -5277,6 +5277,32 @@ struct set_kernel_object_ptr_reply
|
|||
|
||||
|
||||
|
||||
struct grab_kernel_object_request
|
||||
{
|
||||
struct request_header __header;
|
||||
obj_handle_t manager;
|
||||
client_ptr_t user_ptr;
|
||||
};
|
||||
struct grab_kernel_object_reply
|
||||
{
|
||||
struct reply_header __header;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct release_kernel_object_request
|
||||
{
|
||||
struct request_header __header;
|
||||
obj_handle_t manager;
|
||||
client_ptr_t user_ptr;
|
||||
};
|
||||
struct release_kernel_object_reply
|
||||
{
|
||||
struct reply_header __header;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct make_process_system_request
|
||||
{
|
||||
struct request_header __header;
|
||||
|
@ -5965,6 +5991,8 @@ enum request
|
|||
REQ_get_next_device_request,
|
||||
REQ_get_kernel_object_ptr,
|
||||
REQ_set_kernel_object_ptr,
|
||||
REQ_grab_kernel_object,
|
||||
REQ_release_kernel_object,
|
||||
REQ_make_process_system,
|
||||
REQ_get_token_statistics,
|
||||
REQ_create_completion,
|
||||
|
@ -6265,6 +6293,8 @@ union generic_request
|
|||
struct get_next_device_request_request get_next_device_request_request;
|
||||
struct get_kernel_object_ptr_request get_kernel_object_ptr_request;
|
||||
struct set_kernel_object_ptr_request set_kernel_object_ptr_request;
|
||||
struct grab_kernel_object_request grab_kernel_object_request;
|
||||
struct release_kernel_object_request release_kernel_object_request;
|
||||
struct make_process_system_request make_process_system_request;
|
||||
struct get_token_statistics_request get_token_statistics_request;
|
||||
struct create_completion_request create_completion_request;
|
||||
|
@ -6563,6 +6593,8 @@ union generic_reply
|
|||
struct get_next_device_request_reply get_next_device_request_reply;
|
||||
struct get_kernel_object_ptr_reply get_kernel_object_ptr_reply;
|
||||
struct set_kernel_object_ptr_reply set_kernel_object_ptr_reply;
|
||||
struct grab_kernel_object_reply grab_kernel_object_reply;
|
||||
struct release_kernel_object_reply release_kernel_object_reply;
|
||||
struct make_process_system_reply make_process_system_reply;
|
||||
struct get_token_statistics_reply get_token_statistics_reply;
|
||||
struct create_completion_reply create_completion_reply;
|
||||
|
@ -6592,6 +6624,6 @@ union generic_reply
|
|||
struct terminate_job_reply terminate_job_reply;
|
||||
};
|
||||
|
||||
#define SERVER_PROTOCOL_VERSION 574
|
||||
#define SERVER_PROTOCOL_VERSION 575
|
||||
|
||||
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
||||
|
|
|
@ -233,6 +233,7 @@ struct kernel_object
|
|||
struct device_manager *manager;
|
||||
client_ptr_t user_ptr;
|
||||
struct object *object;
|
||||
int owned;
|
||||
struct list list_entry;
|
||||
struct wine_rb_entry rb_entry;
|
||||
};
|
||||
|
@ -274,6 +275,7 @@ static struct kernel_object *set_kernel_object( struct device_manager *manager,
|
|||
kernel_object->manager = manager;
|
||||
kernel_object->user_ptr = user_ptr;
|
||||
kernel_object->object = obj;
|
||||
kernel_object->owned = 0;
|
||||
|
||||
if (wine_rb_put( &manager->kernel_objects, &user_ptr, &kernel_object->rb_entry ))
|
||||
{
|
||||
|
@ -286,6 +288,21 @@ static struct kernel_object *set_kernel_object( struct device_manager *manager,
|
|||
return kernel_object;
|
||||
}
|
||||
|
||||
static struct kernel_object *kernel_object_from_ptr( struct device_manager *manager, client_ptr_t client_ptr )
|
||||
{
|
||||
struct wine_rb_entry *entry = wine_rb_get( &manager->kernel_objects, &client_ptr );
|
||||
return entry ? WINE_RB_ENTRY_VALUE( entry, struct kernel_object, rb_entry ) : NULL;
|
||||
}
|
||||
|
||||
static void grab_kernel_object( struct kernel_object *ptr )
|
||||
{
|
||||
if (!ptr->owned)
|
||||
{
|
||||
grab_object( ptr->object );
|
||||
ptr->owned = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void irp_call_dump( struct object *obj, int verbose )
|
||||
{
|
||||
struct irp_call *irp = (struct irp_call *)obj;
|
||||
|
@ -685,6 +702,7 @@ static void device_manager_destroy( struct object *obj )
|
|||
kernel_object = WINE_RB_ENTRY_VALUE( manager->kernel_objects.root, struct kernel_object, rb_entry );
|
||||
wine_rb_remove( &manager->kernel_objects, &kernel_object->rb_entry );
|
||||
list_remove( &kernel_object->list_entry );
|
||||
if (kernel_object->owned) release_object( kernel_object->object );
|
||||
free( kernel_object );
|
||||
}
|
||||
|
||||
|
@ -717,6 +735,7 @@ void free_kernel_objects( struct object *obj )
|
|||
while ((ptr = list_head( list )))
|
||||
{
|
||||
struct kernel_object *kernel_object = LIST_ENTRY( ptr, struct kernel_object, list_entry );
|
||||
assert( !kernel_object->owned );
|
||||
list_remove( &kernel_object->list_entry );
|
||||
wine_rb_remove( &kernel_object->manager->kernel_objects, &kernel_object->rb_entry );
|
||||
free( kernel_object );
|
||||
|
@ -890,3 +909,43 @@ DECL_HANDLER(set_kernel_object_ptr)
|
|||
release_object( object );
|
||||
release_object( manager );
|
||||
}
|
||||
|
||||
|
||||
/* grab server object reference from kernel object pointer */
|
||||
DECL_HANDLER(grab_kernel_object)
|
||||
{
|
||||
struct device_manager *manager;
|
||||
struct kernel_object *ref;
|
||||
|
||||
if (!(manager = (struct device_manager *)get_handle_obj( current->process, req->manager,
|
||||
0, &device_manager_ops )))
|
||||
return;
|
||||
|
||||
if ((ref = kernel_object_from_ptr( manager, req->user_ptr )) && !ref->owned)
|
||||
grab_kernel_object( ref );
|
||||
else
|
||||
set_error( STATUS_INVALID_HANDLE );
|
||||
|
||||
release_object( manager );
|
||||
}
|
||||
|
||||
|
||||
/* release server object reference from kernel object pointer */
|
||||
DECL_HANDLER(release_kernel_object)
|
||||
{
|
||||
struct device_manager *manager;
|
||||
struct kernel_object *ref;
|
||||
|
||||
if (!(manager = (struct device_manager *)get_handle_obj( current->process, req->manager,
|
||||
0, &device_manager_ops )))
|
||||
return;
|
||||
|
||||
if ((ref = kernel_object_from_ptr( manager, req->user_ptr )) && ref->owned)
|
||||
{
|
||||
ref->owned = 0;
|
||||
release_object( ref->object );
|
||||
}
|
||||
else set_error( STATUS_INVALID_HANDLE );
|
||||
|
||||
release_object( manager );
|
||||
}
|
||||
|
|
|
@ -3640,6 +3640,20 @@ struct handle_info
|
|||
@END
|
||||
|
||||
|
||||
/* Grab server object reference from kernel object pointer */
|
||||
@REQ(grab_kernel_object)
|
||||
obj_handle_t manager; /* handle to the device manager */
|
||||
client_ptr_t user_ptr; /* kernel object pointer */
|
||||
@END
|
||||
|
||||
|
||||
/* Release server object reference from kernel object pointer */
|
||||
@REQ(release_kernel_object)
|
||||
obj_handle_t manager; /* handle to the device manager */
|
||||
client_ptr_t user_ptr; /* kernel object pointer */
|
||||
@END
|
||||
|
||||
|
||||
/* Make the current process a system process */
|
||||
@REQ(make_process_system)
|
||||
@REPLY
|
||||
|
|
|
@ -378,6 +378,8 @@ DECL_HANDLER(delete_device);
|
|||
DECL_HANDLER(get_next_device_request);
|
||||
DECL_HANDLER(get_kernel_object_ptr);
|
||||
DECL_HANDLER(set_kernel_object_ptr);
|
||||
DECL_HANDLER(grab_kernel_object);
|
||||
DECL_HANDLER(release_kernel_object);
|
||||
DECL_HANDLER(make_process_system);
|
||||
DECL_HANDLER(get_token_statistics);
|
||||
DECL_HANDLER(create_completion);
|
||||
|
@ -677,6 +679,8 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
|
|||
(req_handler)req_get_next_device_request,
|
||||
(req_handler)req_get_kernel_object_ptr,
|
||||
(req_handler)req_set_kernel_object_ptr,
|
||||
(req_handler)req_grab_kernel_object,
|
||||
(req_handler)req_release_kernel_object,
|
||||
(req_handler)req_make_process_system,
|
||||
(req_handler)req_get_token_statistics,
|
||||
(req_handler)req_create_completion,
|
||||
|
@ -2298,6 +2302,12 @@ C_ASSERT( FIELD_OFFSET(struct set_kernel_object_ptr_request, manager) == 12 );
|
|||
C_ASSERT( FIELD_OFFSET(struct set_kernel_object_ptr_request, handle) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct set_kernel_object_ptr_request, user_ptr) == 24 );
|
||||
C_ASSERT( sizeof(struct set_kernel_object_ptr_request) == 32 );
|
||||
C_ASSERT( FIELD_OFFSET(struct grab_kernel_object_request, manager) == 12 );
|
||||
C_ASSERT( FIELD_OFFSET(struct grab_kernel_object_request, user_ptr) == 16 );
|
||||
C_ASSERT( sizeof(struct grab_kernel_object_request) == 24 );
|
||||
C_ASSERT( FIELD_OFFSET(struct release_kernel_object_request, manager) == 12 );
|
||||
C_ASSERT( FIELD_OFFSET(struct release_kernel_object_request, user_ptr) == 16 );
|
||||
C_ASSERT( sizeof(struct release_kernel_object_request) == 24 );
|
||||
C_ASSERT( sizeof(struct make_process_system_request) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct make_process_system_reply, event) == 8 );
|
||||
C_ASSERT( sizeof(struct make_process_system_reply) == 16 );
|
||||
|
|
|
@ -4316,6 +4316,18 @@ static void dump_set_kernel_object_ptr_request( const struct set_kernel_object_p
|
|||
dump_uint64( ", user_ptr=", &req->user_ptr );
|
||||
}
|
||||
|
||||
static void dump_grab_kernel_object_request( const struct grab_kernel_object_request *req )
|
||||
{
|
||||
fprintf( stderr, " manager=%04x", req->manager );
|
||||
dump_uint64( ", user_ptr=", &req->user_ptr );
|
||||
}
|
||||
|
||||
static void dump_release_kernel_object_request( const struct release_kernel_object_request *req )
|
||||
{
|
||||
fprintf( stderr, " manager=%04x", req->manager );
|
||||
dump_uint64( ", user_ptr=", &req->user_ptr );
|
||||
}
|
||||
|
||||
static void dump_make_process_system_request( const struct make_process_system_request *req )
|
||||
{
|
||||
}
|
||||
|
@ -4831,6 +4843,8 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
|||
(dump_func)dump_get_next_device_request_request,
|
||||
(dump_func)dump_get_kernel_object_ptr_request,
|
||||
(dump_func)dump_set_kernel_object_ptr_request,
|
||||
(dump_func)dump_grab_kernel_object_request,
|
||||
(dump_func)dump_release_kernel_object_request,
|
||||
(dump_func)dump_make_process_system_request,
|
||||
(dump_func)dump_get_token_statistics_request,
|
||||
(dump_func)dump_create_completion_request,
|
||||
|
@ -5127,6 +5141,8 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
|||
(dump_func)dump_get_next_device_request_reply,
|
||||
(dump_func)dump_get_kernel_object_ptr_reply,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(dump_func)dump_make_process_system_reply,
|
||||
(dump_func)dump_get_token_statistics_reply,
|
||||
(dump_func)dump_create_completion_reply,
|
||||
|
@ -5423,6 +5439,8 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
|
|||
"get_next_device_request",
|
||||
"get_kernel_object_ptr",
|
||||
"set_kernel_object_ptr",
|
||||
"grab_kernel_object",
|
||||
"release_kernel_object",
|
||||
"make_process_system",
|
||||
"get_token_statistics",
|
||||
"create_completion",
|
||||
|
|
Loading…
Reference in New Issue