From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/d3dkmt.c | 49 ++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 22 deletions(-)
diff --git a/dlls/win32u/d3dkmt.c b/dlls/win32u/d3dkmt.c index c54145f6090..a8171039d32 100644 --- a/dlls/win32u/d3dkmt.c +++ b/dlls/win32u/d3dkmt.c @@ -42,6 +42,11 @@ struct d3dkmt_object HANDLE handle; /* internal handle of the server object */ };
+struct d3dkmt_mutex +{ + struct d3dkmt_object obj; +}; + struct d3dkmt_resource { struct d3dkmt_object obj; @@ -1237,7 +1242,8 @@ failed: */ NTSTATUS WINAPI NtGdiDdDDIOpenResourceFromNtHandle( D3DKMT_OPENRESOURCEFROMNTHANDLE *params ) { - struct d3dkmt_object *mutex = NULL, *sync = NULL; + struct d3dkmt_object *sync = NULL; + struct d3dkmt_mutex *mutex = NULL; struct d3dkmt_resource *resource = NULL; NTSTATUS status; UINT dummy = 0; @@ -1258,9 +1264,9 @@ NTSTATUS WINAPI NtGdiDdDDIOpenResourceFromNtHandle( D3DKMT_OPENRESOURCEFROMNTHAN ¶ms->PrivateRuntimeDataSize ))) goto failed;
- if (d3dkmt_object_open( mutex, 0, params->hNtHandle, params->pKeyedMutexPrivateRuntimeData, ¶ms->KeyedMutexPrivateRuntimeDataSize )) + if (d3dkmt_object_open( &mutex->obj, 0, params->hNtHandle, params->pKeyedMutexPrivateRuntimeData, ¶ms->KeyedMutexPrivateRuntimeDataSize )) { - d3dkmt_object_free( mutex ); + d3dkmt_object_free( &mutex->obj ); mutex = NULL; }
@@ -1271,7 +1277,7 @@ NTSTATUS WINAPI NtGdiDdDDIOpenResourceFromNtHandle( D3DKMT_OPENRESOURCEFROMNTHAN }
params->hResource = resource->obj.local; - params->hKeyedMutex = mutex ? mutex->local : 0; + params->hKeyedMutex = mutex ? mutex->obj.local : 0; params->hSyncObject = sync ? sync->local : 0; params->TotalPrivateDriverDataBufferSize = 0; params->ResourcePrivateDriverDataSize = 0; @@ -1279,7 +1285,7 @@ NTSTATUS WINAPI NtGdiDdDDIOpenResourceFromNtHandle( D3DKMT_OPENRESOURCEFROMNTHAN
failed: if (sync) d3dkmt_object_free( sync ); - if (mutex) d3dkmt_object_free( mutex ); + if (mutex) d3dkmt_object_free( &mutex->obj ); if (resource) d3dkmt_object_free( &resource->obj ); return status; } @@ -1364,7 +1370,7 @@ NTSTATUS WINAPI NtGdiDdDDIQueryResourceInfoFromNtHandle( D3DKMT_QUERYRESOURCEINF */ NTSTATUS WINAPI NtGdiDdDDICreateKeyedMutex2( D3DKMT_CREATEKEYEDMUTEX2 *params ) { - struct d3dkmt_object *mutex; + struct d3dkmt_mutex *mutex; NTSTATUS status;
FIXME( "params %p semi-stub!\n", params ); @@ -1372,16 +1378,16 @@ NTSTATUS WINAPI NtGdiDdDDICreateKeyedMutex2( D3DKMT_CREATEKEYEDMUTEX2 *params ) if (!params) return STATUS_INVALID_PARAMETER;
if ((status = d3dkmt_object_alloc( sizeof(*mutex), D3DKMT_MUTEX, (void **)&mutex ))) return status; - if ((status = d3dkmt_object_create( mutex, -1, params->Flags.NtSecuritySharing, + if ((status = d3dkmt_object_create( &mutex->obj, -1, params->Flags.NtSecuritySharing, params->pPrivateRuntimeData, params->PrivateRuntimeDataSize ))) goto failed;
- params->hSharedHandle = mutex->shared ? 0 : mutex->global; - params->hKeyedMutex = mutex->local; + params->hSharedHandle = mutex->obj.shared ? 0 : mutex->obj.global; + params->hKeyedMutex = mutex->obj.local; return STATUS_SUCCESS;
failed: - d3dkmt_object_free( mutex ); + d3dkmt_object_free( &mutex->obj ); return status; }
@@ -1409,13 +1415,12 @@ NTSTATUS WINAPI NtGdiDdDDICreateKeyedMutex( D3DKMT_CREATEKEYEDMUTEX *params ) */ NTSTATUS WINAPI NtGdiDdDDIDestroyKeyedMutex( const D3DKMT_DESTROYKEYEDMUTEX *params ) { - struct d3dkmt_object *mutex; + struct d3dkmt_mutex *mutex;
TRACE( "params %p\n", params );
- if (!(mutex = get_d3dkmt_object( params->hKeyedMutex, D3DKMT_MUTEX ))) - return STATUS_INVALID_PARAMETER; - d3dkmt_object_free( mutex ); + if (!(mutex = get_d3dkmt_object( params->hKeyedMutex, D3DKMT_MUTEX ))) return STATUS_INVALID_PARAMETER; + d3dkmt_object_free( &mutex->obj );
return STATUS_SUCCESS; } @@ -1425,7 +1430,7 @@ NTSTATUS WINAPI NtGdiDdDDIDestroyKeyedMutex( const D3DKMT_DESTROYKEYEDMUTEX *par */ NTSTATUS WINAPI NtGdiDdDDIOpenKeyedMutex2( D3DKMT_OPENKEYEDMUTEX2 *params ) { - struct d3dkmt_object *mutex; + struct d3dkmt_mutex *mutex; UINT runtime_size; NTSTATUS status;
@@ -1438,13 +1443,13 @@ NTSTATUS WINAPI NtGdiDdDDIOpenKeyedMutex2( D3DKMT_OPENKEYEDMUTEX2 *params ) if ((status = d3dkmt_object_alloc( sizeof(*mutex), D3DKMT_MUTEX, (void **)&mutex ))) return status;
runtime_size = params->PrivateRuntimeDataSize; - if ((status = d3dkmt_object_open( mutex, params->hSharedHandle, NULL, params->pPrivateRuntimeData, &runtime_size ))) goto failed; + if ((status = d3dkmt_object_open( &mutex->obj, params->hSharedHandle, NULL, params->pPrivateRuntimeData, &runtime_size ))) goto failed;
- params->hKeyedMutex = mutex->local; + params->hKeyedMutex = mutex->obj.local; return STATUS_SUCCESS;
failed: - d3dkmt_object_free( mutex ); + d3dkmt_object_free( &mutex->obj ); return status; }
@@ -1471,21 +1476,21 @@ NTSTATUS WINAPI NtGdiDdDDIOpenKeyedMutex( D3DKMT_OPENKEYEDMUTEX *params ) */ NTSTATUS WINAPI NtGdiDdDDIOpenKeyedMutexFromNtHandle( D3DKMT_OPENKEYEDMUTEXFROMNTHANDLE *params ) { - struct d3dkmt_object *mutex; + struct d3dkmt_mutex *mutex; NTSTATUS status;
FIXME( "params %p semi-stub!\n", params );
if ((status = d3dkmt_object_alloc( sizeof(*mutex), D3DKMT_MUTEX, (void **)&mutex ))) return status; - if ((status = d3dkmt_object_open( mutex, 0, params->hNtHandle, params->pPrivateRuntimeData, + if ((status = d3dkmt_object_open( &mutex->obj, 0, params->hNtHandle, params->pPrivateRuntimeData, ¶ms->PrivateRuntimeDataSize ))) goto failed;
- params->hKeyedMutex = mutex->local; + params->hKeyedMutex = mutex->obj.local; return STATUS_SUCCESS;
failed: - d3dkmt_object_free( mutex ); + d3dkmt_object_free( &mutex->obj ); return status; }
From: Rémi Bernon rbernon@codeweavers.com
--- server/d3dkmt.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-)
diff --git a/server/d3dkmt.c b/server/d3dkmt.c index 4d30ec65966..5b0bd016796 100644 --- a/server/d3dkmt.c +++ b/server/d3dkmt.c @@ -95,6 +95,39 @@ static const struct fd_ops d3dkmt_fd_ops = default_fd_reselect_async /* reselect_async */ };
+struct d3dkmt_mutex +{ + struct d3dkmt_object base; +}; + +static void d3dkmt_mutex_dump( struct object *obj, int verbose ); +static void d3dkmt_mutex_destroy( struct object *obj ); + +static const struct object_ops d3dkmt_mutex_ops = +{ + sizeof(struct d3dkmt_mutex), /* size */ + &no_type, /* type */ + d3dkmt_mutex_dump, /* dump */ + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ + default_get_sync, /* get_sync */ + 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 */ + d3dkmt_mutex_destroy, /* destroy */ +}; + #define DXGK_SHARED_SYNC_QUERY_STATE 0x0001 #define DXGK_SHARED_SYNC_MODIFY_STATE 0x0002 #define DXGK_SHARED_SYNC_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) @@ -370,6 +403,43 @@ static struct d3dkmt_object *d3dkmt_object_create( enum d3dkmt_type type, data_s return object; }
+static void d3dkmt_mutex_dump( struct object *obj, int verbose ) +{ + struct d3dkmt_mutex *mutex = (struct d3dkmt_mutex *)obj; + assert( obj->ops == &d3dkmt_mutex_ops ); + + fprintf( stderr, "d3dkmt mutex global=%#x\n", mutex->base.global ); +} + +static void d3dkmt_mutex_destroy( struct object *obj ) +{ + struct d3dkmt_mutex *mutex = (struct d3dkmt_mutex *)obj; + assert( obj->ops == &d3dkmt_mutex_ops ); + + if (mutex->base.global) free_object_handle( mutex->base.global ); + free( mutex->base.runtime ); +} + +static struct d3dkmt_object *d3dkmt_mutex_create( data_size_t runtime_size, const void *runtime ) +{ + struct d3dkmt_mutex *object; + + if (!(object = alloc_object( &d3dkmt_mutex_ops ))) return NULL; + object->base.type = D3DKMT_MUTEX; + object->base.global = 0; + object->base.runtime_size = runtime_size; + object->base.fd = NULL; + + if (!(object->base.runtime = memdup( runtime, runtime_size )) || + !(object->base.global = alloc_object_handle( &object->base ))) + { + release_object( object ); + return NULL; + } + + return &object->base; +} + /* return a pointer to a d3dkmt object from its global handle */ static void *d3dkmt_object_open( d3dkmt_handle_t global, enum d3dkmt_type type ) { @@ -426,7 +496,16 @@ DECL_HANDLER(d3dkmt_object_create) if (!(fd = create_anonymous_fd( NULL, unix_fd, NULL, 0 ))) return; }
- if (!(object = d3dkmt_object_create( req->type, get_req_data_size(), get_req_data() ))) goto done; + switch (req->type) + { + case D3DKMT_MUTEX: + if (!(object = d3dkmt_mutex_create( get_req_data_size(), get_req_data() ))) goto done; + break; + default: + if (!(object = d3dkmt_object_create( req->type, get_req_data_size(), get_req_data() ))) goto done; + break; + } + if (fd) { set_fd_user( fd, &d3dkmt_fd_ops, &object->obj );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/d3dkmt.c | 14 ++++++++------ server/d3dkmt.c | 6 ++++-- server/protocol.def | 1 + 3 files changed, 13 insertions(+), 8 deletions(-)
diff --git a/dlls/win32u/d3dkmt.c b/dlls/win32u/d3dkmt.c index a8171039d32..f9bcfcfc047 100644 --- a/dlls/win32u/d3dkmt.c +++ b/dlls/win32u/d3dkmt.c @@ -185,7 +185,8 @@ static NTSTATUS d3dkmt_object_alloc( UINT size, enum d3dkmt_type type, void **ob }
/* create a global D3DKMT object, either with a global handle or later shareable */ -static NTSTATUS d3dkmt_object_create( struct d3dkmt_object *object, int fd, BOOL shared, const void *runtime, UINT runtime_size ) +static NTSTATUS d3dkmt_object_create( struct d3dkmt_object *object, int fd, UINT value, BOOL shared, + const void *runtime, UINT runtime_size ) { NTSTATUS status;
@@ -195,6 +196,7 @@ static NTSTATUS d3dkmt_object_create( struct d3dkmt_object *object, int fd, BOOL { req->type = object->type; req->fd = fd; + req->value = value; if (runtime_size) wine_server_add_data( req, runtime, runtime_size ); status = wine_server_call( req ); object->handle = wine_server_ptr_handle( reply->handle ); @@ -1058,7 +1060,7 @@ NTSTATUS WINAPI NtGdiDdDDICreateAllocation2( D3DKMT_CREATEALLOCATION *params ) if ((status = d3dkmt_object_alloc( sizeof(*allocation), D3DKMT_ALLOCATION, (void **)&allocation ))) goto failed;
if (!params->Flags.CreateShared) status = alloc_object_handle( &resource->obj ); - else status = d3dkmt_object_create( &resource->obj, -1, params->Flags.NtSecuritySharing, + else status = d3dkmt_object_create( &resource->obj, -1, 0, params->Flags.NtSecuritySharing, params->pPrivateRuntimeData, params->PrivateRuntimeDataSize ); if (status) goto failed;
@@ -1378,7 +1380,7 @@ NTSTATUS WINAPI NtGdiDdDDICreateKeyedMutex2( D3DKMT_CREATEKEYEDMUTEX2 *params ) if (!params) return STATUS_INVALID_PARAMETER;
if ((status = d3dkmt_object_alloc( sizeof(*mutex), D3DKMT_MUTEX, (void **)&mutex ))) return status; - if ((status = d3dkmt_object_create( &mutex->obj, -1, params->Flags.NtSecuritySharing, + if ((status = d3dkmt_object_create( &mutex->obj, -1, params->InitialValue, params->Flags.NtSecuritySharing, params->pPrivateRuntimeData, params->PrivateRuntimeDataSize ))) goto failed;
@@ -1571,7 +1573,7 @@ NTSTATUS WINAPI NtGdiDdDDICreateSynchronizationObject2( D3DKMT_CREATESYNCHRONIZA
if ((status = d3dkmt_object_alloc( sizeof(*sync), D3DKMT_SYNC, (void **)&sync ))) return status; if (!params->Info.Flags.Shared) status = alloc_object_handle( sync ); - else status = d3dkmt_object_create( sync, -1, params->Info.Flags.NtSecuritySharing, NULL, 0 ); + else status = d3dkmt_object_create( sync, -1, 0, params->Info.Flags.NtSecuritySharing, NULL, 0 ); if (status) goto failed;
if (params->Info.Flags.Shared) params->Info.SharedHandle = sync->shared ? 0 : sync->global; @@ -1758,7 +1760,7 @@ D3DKMT_HANDLE d3dkmt_create_resource( int fd, D3DKMT_HANDLE *global )
if ((status = d3dkmt_object_alloc( sizeof(*resource), D3DKMT_RESOURCE, (void **)&resource ))) goto failed; if ((status = d3dkmt_object_alloc( sizeof(*allocation), D3DKMT_ALLOCATION, (void **)&allocation ))) goto failed; - if ((status = d3dkmt_object_create( &resource->obj, fd, !global, NULL, 0 ))) goto failed; + if ((status = d3dkmt_object_create( &resource->obj, fd, 0, !global, NULL, 0 ))) goto failed;
if ((status = alloc_object_handle( allocation ))) goto failed; resource->allocation = allocation->local; @@ -1823,7 +1825,7 @@ D3DKMT_HANDLE d3dkmt_create_sync( int fd, D3DKMT_HANDLE *global ) TRACE( "global %p\n", global );
if ((status = d3dkmt_object_alloc( sizeof(*sync), D3DKMT_SYNC, (void **)&sync ))) goto failed; - if ((status = d3dkmt_object_create( sync, fd, !global, NULL, 0 ))) goto failed; + if ((status = d3dkmt_object_create( sync, fd, 0, !global, NULL, 0 ))) goto failed; if (global) *global = sync->global; return sync->local;
diff --git a/server/d3dkmt.c b/server/d3dkmt.c index 5b0bd016796..47824a8f1a0 100644 --- a/server/d3dkmt.c +++ b/server/d3dkmt.c @@ -98,6 +98,7 @@ static const struct fd_ops d3dkmt_fd_ops = struct d3dkmt_mutex { struct d3dkmt_object base; + unsigned int key_value; /* last released key value */ };
static void d3dkmt_mutex_dump( struct object *obj, int verbose ); @@ -420,7 +421,7 @@ static void d3dkmt_mutex_destroy( struct object *obj ) free( mutex->base.runtime ); }
-static struct d3dkmt_object *d3dkmt_mutex_create( data_size_t runtime_size, const void *runtime ) +static struct d3dkmt_object *d3dkmt_mutex_create( unsigned int key_value, data_size_t runtime_size, const void *runtime ) { struct d3dkmt_mutex *object;
@@ -429,6 +430,7 @@ static struct d3dkmt_object *d3dkmt_mutex_create( data_size_t runtime_size, cons object->base.global = 0; object->base.runtime_size = runtime_size; object->base.fd = NULL; + object->key_value = key_value;
if (!(object->base.runtime = memdup( runtime, runtime_size )) || !(object->base.global = alloc_object_handle( &object->base ))) @@ -499,7 +501,7 @@ DECL_HANDLER(d3dkmt_object_create) switch (req->type) { case D3DKMT_MUTEX: - if (!(object = d3dkmt_mutex_create( get_req_data_size(), get_req_data() ))) goto done; + if (!(object = d3dkmt_mutex_create( req->value, get_req_data_size(), get_req_data() ))) goto done; break; default: if (!(object = d3dkmt_object_create( req->type, get_req_data_size(), get_req_data() ))) goto done; diff --git a/server/protocol.def b/server/protocol.def index cb46a5ff2dc..ec6738169ed 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -4179,6 +4179,7 @@ enum inproc_sync_type @REQ(d3dkmt_object_create) unsigned int type; /* d3dkmt object type */ int fd; /* host specific fd */ + unsigned int value; /* initial value for keyed mutex */ VARARG(runtime,bytes); /* client runtime data */ @REPLY d3dkmt_handle_t global; /* global d3dkmt handle */
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/d3dkmt.c | 87 +++++++++++++++++++-- dlls/win32u/tests/d3dkmt.c | 42 +++++------ server/d3dkmt.c | 151 +++++++++++++++++++++++++++++++++++++ server/object.h | 1 + server/protocol.def | 25 ++++++ server/thread.c | 1 + server/thread.h | 1 + 7 files changed, 282 insertions(+), 26 deletions(-)
diff --git a/dlls/win32u/d3dkmt.c b/dlls/win32u/d3dkmt.c index f9bcfcfc047..e89127a9103 100644 --- a/dlls/win32u/d3dkmt.c +++ b/dlls/win32u/d3dkmt.c @@ -45,6 +45,7 @@ struct d3dkmt_object struct d3dkmt_mutex { struct d3dkmt_object obj; + BOOL owned; };
struct d3dkmt_resource @@ -1418,12 +1419,28 @@ NTSTATUS WINAPI NtGdiDdDDICreateKeyedMutex( D3DKMT_CREATEKEYEDMUTEX *params ) NTSTATUS WINAPI NtGdiDdDDIDestroyKeyedMutex( const D3DKMT_DESTROYKEYEDMUTEX *params ) { struct d3dkmt_mutex *mutex; + BOOL owned;
TRACE( "params %p\n", params );
if (!(mutex = get_d3dkmt_object( params->hKeyedMutex, D3DKMT_MUTEX ))) return STATUS_INVALID_PARAMETER; - d3dkmt_object_free( &mutex->obj ); + pthread_mutex_lock( &d3dkmt_lock ); + owned = mutex->owned; + mutex->owned = FALSE; + pthread_mutex_unlock( &d3dkmt_lock ); + + if (owned) + { + SERVER_START_REQ( d3dkmt_mutex_release ) + { + req->mutex = mutex->obj.global; + req->abandon = 1; + wine_server_call( req ); + } + SERVER_END_REQ; + }
+ d3dkmt_object_free( &mutex->obj ); return STATUS_SUCCESS; }
@@ -1501,8 +1518,46 @@ failed: */ NTSTATUS WINAPI NtGdiDdDDIAcquireKeyedMutex2( D3DKMT_ACQUIREKEYEDMUTEX2 *params ) { - FIXME( "params %p stub!\n", params ); - return STATUS_NOT_IMPLEMENTED; + NTSTATUS status = STATUS_SUCCESS; + LARGE_INTEGER now, *timeout; + struct d3dkmt_mutex *mutex; + HANDLE wait_handle = NULL; + + TRACE( "params %p\n", params ); + + if ((timeout = params->pTimeout) && timeout->QuadPart < 0) + { + NtQuerySystemTime( &now ); + now.QuadPart -= timeout->QuadPart; + timeout = &now; + } + + if (!(mutex = get_d3dkmt_object( params->hKeyedMutex, D3DKMT_MUTEX ))) return STATUS_INVALID_PARAMETER; + + do + { + if (wait_handle) status = NtWaitForSingleObject( wait_handle, FALSE, timeout ); + SERVER_START_REQ( d3dkmt_mutex_acquire ) + { + req->mutex = mutex->obj.global; + req->key_value = params->Key; + req->wait_handle = wine_server_obj_handle( wait_handle ); + req->wait_status = status; + + status = wine_server_call( req ); + params->FenceValue = reply->fence_value; + wait_handle = wine_server_ptr_handle( reply->wait_handle ); + } + SERVER_END_REQ; + } while (status == STATUS_PENDING); + + if (!status) + { + pthread_mutex_lock( &d3dkmt_lock ); + mutex->owned = TRUE; + pthread_mutex_unlock( &d3dkmt_lock ); + } + return status; }
/****************************************************************************** @@ -1531,8 +1586,30 @@ NTSTATUS WINAPI NtGdiDdDDIAcquireKeyedMutex( D3DKMT_ACQUIREKEYEDMUTEX *params ) */ NTSTATUS WINAPI NtGdiDdDDIReleaseKeyedMutex2( D3DKMT_RELEASEKEYEDMUTEX2 *params ) { - FIXME( "params %p stub!\n", params ); - return STATUS_NOT_IMPLEMENTED; + struct d3dkmt_mutex *mutex; + NTSTATUS status; + + TRACE( "params %p\n", params ); + + if (!(mutex = get_d3dkmt_object( params->hKeyedMutex, D3DKMT_MUTEX ))) return STATUS_INVALID_PARAMETER; + + SERVER_START_REQ( d3dkmt_mutex_release ) + { + req->mutex = mutex->obj.global; + req->key_value = params->Key; + req->fence_value = params->FenceValue; + status = wine_server_call( req ); + } + SERVER_END_REQ; + + if (!status) + { + pthread_mutex_lock( &d3dkmt_lock ); + mutex->owned = FALSE; + pthread_mutex_unlock( &d3dkmt_lock ); + } + + return status; }
/****************************************************************************** diff --git a/dlls/win32u/tests/d3dkmt.c b/dlls/win32u/tests/d3dkmt.c index 4c9e6e5704d..b3a9baf4785 100644 --- a/dlls/win32u/tests/d3dkmt.c +++ b/dlls/win32u/tests/d3dkmt.c @@ -2074,7 +2074,7 @@ static void test_D3DKMTCreateKeyedMutex( void ) static DWORD WINAPI test_acquire_mutex( void *arg ) { NTSTATUS status = D3DKMTAcquireKeyedMutex( arg ); - todo_wine ok_nt( STATUS_ABANDONED, status ); + ok_nt( STATUS_ABANDONED, status ); return 0; }
@@ -2104,7 +2104,7 @@ static void test_D3DKMTAcquireKeyedMutex( void ) acquire.pTimeout = &timeout; acquire.FenceValue = 0xdeadbeef; status = D3DKMTAcquireKeyedMutex( &acquire ); - todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + ok_nt( STATUS_INVALID_PARAMETER, status ); ok_x4( acquire.Key, ==, 0xdeadbeef ); ok_x8( acquire.FenceValue, ==, 0xdeadbeef );
@@ -2112,17 +2112,17 @@ static void test_D3DKMTAcquireKeyedMutex( void ) acquire.Key = 0xdeadbeef; acquire.FenceValue = 0xdeadbeef; status = D3DKMTAcquireKeyedMutex( &acquire ); - todo_wine ok_nt( STATUS_TIMEOUT, status ); + ok_nt( STATUS_TIMEOUT, status ); ok_x4( acquire.Key, ==, 0xdeadbeef ); - todo_wine ok_x8( acquire.FenceValue, ==, 0 ); + ok_x8( acquire.FenceValue, ==, 0 );
acquire.hKeyedMutex = create.hKeyedMutex; acquire.Key = 0; acquire.FenceValue = 0xdeadbeef; status = D3DKMTAcquireKeyedMutex( &acquire ); - todo_wine ok_nt( STATUS_SUCCESS, status ); + ok_nt( STATUS_SUCCESS, status ); ok_x4( acquire.Key, ==, 0 ); - todo_wine ok_x8( acquire.FenceValue, ==, 0 ); + ok_x8( acquire.FenceValue, ==, 0 );
status = D3DKMTReleaseKeyedMutex( NULL ); ok_nt( STATUS_INVALID_PARAMETER, status ); @@ -2130,42 +2130,42 @@ static void test_D3DKMTAcquireKeyedMutex( void ) release.Key = 0xdeadbeef; release.FenceValue = 0xdeadbeef; status = D3DKMTReleaseKeyedMutex( &release ); - todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + ok_nt( STATUS_INVALID_PARAMETER, status ); ok_x4( release.Key, ==, 0xdeadbeef ); ok_x8( release.FenceValue, ==, 0xdeadbeef ); release.hKeyedMutex = create.hKeyedMutex; release.Key = 1; release.FenceValue = 1234; status = D3DKMTReleaseKeyedMutex( &release ); - todo_wine ok_nt( STATUS_SUCCESS, status ); + ok_nt( STATUS_SUCCESS, status ); ok_x4( release.Key, ==, 1 ); ok_x8( release.FenceValue, ==, 1234 ); release.FenceValue = 0xdeadbeef; status = D3DKMTReleaseKeyedMutex( &release ); - todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + ok_nt( STATUS_INVALID_PARAMETER, status ); ok_x4( release.Key, ==, 1 ); ok_x8( release.FenceValue, ==, 0xdeadbeef );
acquire.Key = 0; acquire.FenceValue = 0xdeadbeef; status = D3DKMTAcquireKeyedMutex( &acquire ); - todo_wine ok_nt( STATUS_TIMEOUT, status ); - todo_wine ok_x8( acquire.FenceValue, ==, 0 ); + ok_nt( STATUS_TIMEOUT, status ); + ok_x8( acquire.FenceValue, ==, 0 ); acquire.Key = 1; acquire.FenceValue = 0xdeadbeef; status = D3DKMTAcquireKeyedMutex( &acquire ); - todo_wine ok_nt( STATUS_SUCCESS, status ); - todo_wine ok_x8( acquire.FenceValue, ==, 1234 ); + ok_nt( STATUS_SUCCESS, status ); + ok_x8( acquire.FenceValue, ==, 1234 );
release.Key = 0; release.FenceValue = 0; status = D3DKMTReleaseKeyedMutex( &release ); - todo_wine ok_nt( STATUS_SUCCESS, status ); + ok_nt( STATUS_SUCCESS, status ); acquire.Key = 0; acquire.FenceValue = 0xdeadbeef; status = D3DKMTAcquireKeyedMutex( &acquire ); - todo_wine ok_nt( STATUS_SUCCESS, status ); - todo_wine ok_x8( acquire.FenceValue, ==, 0 ); + ok_nt( STATUS_SUCCESS, status ); + ok_x8( acquire.FenceValue, ==, 0 );
open.hSharedHandle = create.hSharedHandle; open.hKeyedMutex = 0xdeadbeef; @@ -2180,7 +2180,7 @@ static void test_D3DKMTAcquireKeyedMutex( void ) thread = CreateThread( NULL, 0, test_acquire_mutex, &acquire, 0, NULL ); ok_ptr( thread, !=, NULL ); ret = WaitForSingleObject( thread, 100 ); - todo_wine ok_u4( ret, ==, WAIT_TIMEOUT ); + ok_u4( ret, ==, WAIT_TIMEOUT );
destroy.hKeyedMutex = create.hKeyedMutex; status = D3DKMTDestroyKeyedMutex( &destroy ); @@ -2193,11 +2193,11 @@ static void test_D3DKMTAcquireKeyedMutex( void ) acquire.FenceValue = 0xdeadbeef; timeout.QuadPart = 100 * -10000; status = D3DKMTAcquireKeyedMutex( &acquire ); - todo_wine ok_nt( STATUS_ABANDONED, status ); - todo_wine ok_x8( acquire.FenceValue, ==, 0 ); + ok_nt( STATUS_ABANDONED, status ); + ok_x8( acquire.FenceValue, ==, 0 ); status = D3DKMTAcquireKeyedMutex( &acquire ); - todo_wine ok_nt( STATUS_ABANDONED, status ); - todo_wine ok_x8( acquire.FenceValue, ==, 0 ); + ok_nt( STATUS_ABANDONED, status ); + ok_x8( acquire.FenceValue, ==, 0 );
destroy.hKeyedMutex = open.hKeyedMutex; status = D3DKMTDestroyKeyedMutex( &destroy ); diff --git a/server/d3dkmt.c b/server/d3dkmt.c index 47824a8f1a0..6c8c971dc44 100644 --- a/server/d3dkmt.c +++ b/server/d3dkmt.c @@ -95,10 +95,23 @@ static const struct fd_ops d3dkmt_fd_ops = default_fd_reselect_async /* reselect_async */ };
+struct keyed_wait +{ + struct list entry; + int key; + int waiters; + struct object *sync; +}; + struct d3dkmt_mutex { struct d3dkmt_object base; unsigned int key_value; /* last released key value */ + unsigned __int64 fence_value; /* last released fence value */ + bool abandoned; /* mutex has been abandonned */ + struct thread *owner; /* current owner thread */ + struct list waits; /* list of pending keyed_waits */ + struct list entry; /* entry in owner d3dkmt_mutexes */ };
static void d3dkmt_mutex_dump( struct object *obj, int verbose ); @@ -415,8 +428,17 @@ static void d3dkmt_mutex_dump( struct object *obj, int verbose ) static void d3dkmt_mutex_destroy( struct object *obj ) { struct d3dkmt_mutex *mutex = (struct d3dkmt_mutex *)obj; + struct keyed_wait *wait, *next; + assert( obj->ops == &d3dkmt_mutex_ops );
+ LIST_FOR_EACH_ENTRY_SAFE( wait, next, &mutex->waits, struct keyed_wait, entry ) + { + release_object( wait->sync ); + list_remove( &wait->entry ); + free( wait ); + } + if (mutex->base.global) free_object_handle( mutex->base.global ); free( mutex->base.runtime ); } @@ -431,6 +453,10 @@ static struct d3dkmt_object *d3dkmt_mutex_create( unsigned int key_value, data_s object->base.runtime_size = runtime_size; object->base.fd = NULL; object->key_value = key_value; + object->fence_value = 0; + object->abandoned = false; + object->owner = NULL; + list_init( &object->waits );
if (!(object->base.runtime = memdup( runtime, runtime_size )) || !(object->base.global = alloc_object_handle( &object->base ))) @@ -442,6 +468,80 @@ static struct d3dkmt_object *d3dkmt_mutex_create( unsigned int key_value, data_s return &object->base; }
+static struct object *keyed_wait_grab( struct d3dkmt_mutex *mutex, int key ) +{ + struct keyed_wait *wait; + + LIST_FOR_EACH_ENTRY( wait, &mutex->waits, struct keyed_wait, entry ) + { + if (wait->key != key) continue; + wait->waiters++; + return grab_object( wait->sync ); + } + + if (!(wait = mem_alloc( sizeof(*wait) ))) return NULL; + wait->key = key; + wait->waiters = 1; + if (!(wait->sync = create_internal_sync( 0, 0 ))) + { + free( wait ); + return NULL; + } + + list_add_tail( &mutex->waits, &wait->entry ); + return grab_object( wait->sync ); +} + +static void keyed_wait_release( struct d3dkmt_mutex *mutex, int key ) +{ + struct keyed_wait *wait; + + LIST_FOR_EACH_ENTRY( wait, &mutex->waits, struct keyed_wait, entry ) + { + if (wait->key == key && !--wait->waiters) + { + release_object( wait->sync ); + list_remove( &wait->entry ); + free( wait ); + break; + } + } +} + +static void mutex_grab( struct d3dkmt_mutex *mutex ) +{ + grab_object( mutex ); + list_add_tail( ¤t->d3dkmt_mutexes, &mutex->entry ); + mutex->owner = current; +} + +static void mutex_release( struct d3dkmt_mutex *mutex, bool abandon ) +{ + struct keyed_wait *wait; + + LIST_FOR_EACH_ENTRY( wait, &mutex->waits, struct keyed_wait, entry ) + { + if (abandon || wait->key == mutex->key_value) + { + signal_sync( wait->sync ); + if (!abandon) break; + } + } + if (abandon) mutex->abandoned = true; + + mutex->owner = NULL; + list_remove( &mutex->entry ); + release_object( mutex ); +} + +void abandon_d3dkmt_mutexes( struct thread *thread ) +{ + struct d3dkmt_mutex *mutex, *next; + + LIST_FOR_EACH_ENTRY_SAFE( mutex, next, &thread->d3dkmt_mutexes, struct d3dkmt_mutex, entry ) + mutex_release( mutex, true ); +} + /* return a pointer to a d3dkmt object from its global handle */ static void *d3dkmt_object_open( d3dkmt_handle_t global, enum d3dkmt_type type ) { @@ -646,3 +746,54 @@ DECL_HANDLER(d3dkmt_object_open_name) break; } } + +/* Acquire a global d3dkmt keyed mutex */ +DECL_HANDLER(d3dkmt_mutex_acquire) +{ + struct d3dkmt_mutex *mutex; + struct object *sync; + + if (!(mutex = d3dkmt_object_open( req->mutex, D3DKMT_MUTEX ))) goto done; + + if (req->wait_status) set_error( req->wait_status ); + else if (mutex->abandoned) set_error( STATUS_ABANDONED ); + else if (mutex->key_value == req->key_value && !mutex->owner) + { + reply->fence_value = mutex->fence_value; + mutex_grab( mutex ); + } + else if ((reply->wait_handle = req->wait_handle)) set_error( STATUS_PENDING ); + else if ((sync = keyed_wait_grab( mutex, req->key_value ))) + { + if ((reply->wait_handle = alloc_handle( current->process, sync, SYNCHRONIZE, 0 ))) set_error( STATUS_PENDING ); + release_object( sync ); + } + + release_object( mutex ); + +done: + if (get_error() != STATUS_PENDING && req->wait_handle) + { + close_handle( current->process, req->wait_handle ); + if (mutex) keyed_wait_release( mutex, req->key_value ); + } +} + +/* Release a global d3dkmt keyed mutex */ +DECL_HANDLER(d3dkmt_mutex_release) +{ + struct d3dkmt_mutex *mutex; + + if (!(mutex = d3dkmt_object_open( req->mutex, D3DKMT_MUTEX ))) return; + + if (mutex->abandoned) set_error( STATUS_ABANDONED ); + else if (mutex->owner != current) set_error( STATUS_INVALID_PARAMETER ); + else + { + mutex->key_value = req->key_value; + mutex->fence_value = req->fence_value; + mutex_release( mutex, req->abandon ); + } + + release_object( mutex ); +} diff --git a/server/object.h b/server/object.h index 2a0ecfc2cf2..cab8ad25a59 100644 --- a/server/object.h +++ b/server/object.h @@ -240,6 +240,7 @@ extern void reset_event( struct event *event ); /* mutex functions */
extern void abandon_mutexes( struct thread *thread ); +extern void abandon_d3dkmt_mutexes( struct thread *thread );
/* in-process synchronization functions */
diff --git a/server/protocol.def b/server/protocol.def index ec6738169ed..93e574b61a3 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -4240,3 +4240,28 @@ enum inproc_sync_type @REPLY obj_handle_t handle; /* shared object handle */ @END + + +/* Acquire a global d3dkmt keyed mutex */ +@REQ(d3dkmt_mutex_acquire) + d3dkmt_handle_t mutex; /* mutex global handle */ + unsigned int key_value; /* the key to acquire/wait for */ + obj_handle_t wait_handle; /* previously returned wait handle */ + unsigned int wait_status; /* status returned from previous wait */ +@REPLY + unsigned __int64 fence_value; /* semaphore fence value */ + data_size_t runtime_size; /* size of client runtime data */ + obj_handle_t wait_handle; /* wait handle for pending acquire */ + VARARG(runtime,bytes); /* client runtime data */ +@END + + +/* Release a global d3dkmt keyed mutex */ +@REQ(d3dkmt_mutex_release) + d3dkmt_handle_t mutex; /* mutex global handle */ + int abandon; /* mutex is being abandonned */ + unsigned int key_value; /* the key to release */ + unsigned __int64 fence_value; /* semaphore fence value */ + data_size_t runtime_size; /* size of client runtime data */ + VARARG(runtime,bytes); /* client runtime data */ +@END diff --git a/server/thread.c b/server/thread.c index 6a1b1f8c559..3aed496450a 100644 --- a/server/thread.c +++ b/server/thread.c @@ -434,6 +434,7 @@ static inline void init_thread_structure( struct thread *thread ) thread->completion_wait = NULL;
list_init( &thread->mutex_list ); + list_init( &thread->d3dkmt_mutexes ); list_init( &thread->system_apc ); list_init( &thread->user_apc ); list_init( &thread->kernel_object ); diff --git a/server/thread.h b/server/thread.h index fb77901ba7c..77ea355483d 100644 --- a/server/thread.h +++ b/server/thread.h @@ -58,6 +58,7 @@ struct thread struct process *process; thread_id_t id; /* thread id */ struct list mutex_list; /* list of currently owned mutexes */ + struct list d3dkmt_mutexes;/* list of currently owned d3dkmt mutexes */ unsigned int system_regs; /* which system regs have been set */ struct msg_queue *queue; /* message queue */ struct thread_wait *wait; /* current wait condition if sleeping */