summaryrefslogtreecommitdiffstats
path: root/src/gallium/state_trackers/nine/iunknown.c
diff options
context:
space:
mode:
authorAxel Davy <[email protected]>2017-01-05 23:04:09 +0100
committerAxel Davy <[email protected]>2017-01-12 20:33:11 +0100
commit970556292b37fb9f7a64460a964e7a88503dcab6 (patch)
treee5d998d46f2ac87b49dc76638f578ef5fa173099 /src/gallium/state_trackers/nine/iunknown.c
parent5f4359ea0ed54b06d443e0ba040eb73406fc3e34 (diff)
st/nine: Protect dtors with mutex
When the flag D3DCREATE_MULTITHREAD is set, a global mutex is used to protect nine calls. However for performance reasons, AddRef and Release didn't hold the mutex, and instead used atomics. Unfortunately at item release, the item can be destroyed, and that destruction path should be protected by a mutex (at least for some objects). Without this patch, it is possible an app thread is in a dtor while another thread is making gallium nine calls. It is possible that two threads are using the same gallium pipe, which is forbiden. The problem has been made worse with csmt, because it can cause hang, since nine_csmt_process is not threadsafe. Fixes Hitman hang, and possibly others. Signed-off-by: Axel Davy <[email protected]>
Diffstat (limited to 'src/gallium/state_trackers/nine/iunknown.c')
-rw-r--r--src/gallium/state_trackers/nine/iunknown.c26
1 files changed, 26 insertions, 0 deletions
diff --git a/src/gallium/state_trackers/nine/iunknown.c b/src/gallium/state_trackers/nine/iunknown.c
index eae4997aa1c..d76d6447896 100644
--- a/src/gallium/state_trackers/nine/iunknown.c
+++ b/src/gallium/state_trackers/nine/iunknown.c
@@ -26,6 +26,7 @@
#include "nine_helpers.h"
#include "nine_pdata.h"
+#include "nine_lock.h"
#define DBG_CHANNEL DBG_UNKNOWN
@@ -135,6 +136,31 @@ NineUnknown_Release( struct NineUnknown *This )
return r;
}
+/* No need to lock the mutex protecting nine (when D3DCREATE_MULTITHREADED)
+ * for AddRef and Release, except for dtor as some of the dtors require it. */
+ULONG NINE_WINAPI
+NineUnknown_ReleaseWithDtorLock( struct NineUnknown *This )
+{
+ if (This->forward)
+ return NineUnknown_ReleaseWithDtorLock(This->container);
+
+ ULONG r = p_atomic_dec_return(&This->refs);
+
+ if (r == 0) {
+ if (This->device) {
+ if (NineUnknown_ReleaseWithDtorLock(NineUnknown(This->device)) == 0)
+ return r; /* everything's gone */
+ }
+ /* Containers (here with !forward) take care of item destruction */
+ if (!This->container && This->bind == 0) {
+ NineLockGlobalMutex();
+ This->dtor(This);
+ NineUnlockGlobalMutex();
+ }
+ }
+ return r;
+}
+
HRESULT NINE_WINAPI
NineUnknown_GetDevice( struct NineUnknown *This,
IDirect3DDevice9 **ppDevice )