{
CRITICAL_SECTION writer_lock;
gboolean ever_shared; /* protected by writer_lock */
+ gboolean writer_locked; /* protected by writer_lock */
/* below is only ever touched if ever_shared becomes true */
CRITICAL_SECTION atomicity;
g_thread_abort (errno, "malloc");
InitializeCriticalSection (&result->writer_lock);
+ result->writer_locked = FALSE;
result->ever_shared = FALSE;
*lock = result;
EnterCriticalSection (&lock->writer_lock);
+ /* CRITICAL_SECTION is reentrant, but SRWLock is not.
+ * Detect the deadlock that would occur on later Windows version.
+ */
+ g_assert (!lock->writer_locked);
+ lock->writer_locked = TRUE;
+
if (lock->ever_shared)
{
GThreadXpWaiter *waiter = NULL;
if (!TryEnterCriticalSection (&lock->writer_lock))
return FALSE;
+ /* CRITICAL_SECTION is reentrant, but SRWLock is not.
+ * Ensure that this properly returns FALSE (as SRWLock would).
+ */
+ if G_UNLIKELY (lock->writer_locked)
+ {
+ LeaveCriticalSection (&lock->writer_lock);
+ return FALSE;
+ }
+
+ lock->writer_locked = TRUE;
+
if (lock->ever_shared)
{
gboolean available;
{
GThreadSRWLock *lock = *(GThreadSRWLock * volatile *) mutex;
+ lock->writer_locked = FALSE;
+
/* We need this until we fix some weird parts of GLib that try to
* unlock freshly-allocated mutexes.
*/
EnterCriticalSection (&lock->writer_lock);
+ /* See g_thread_xp_AcquireSRWLockExclusive */
+ g_assert (!lock->writer_locked);
+
g_thread_xp_srwlock_become_reader (lock);
LeaveCriticalSection (&lock->writer_lock);
if (!TryEnterCriticalSection (&lock->writer_lock))
return FALSE;
+ /* See g_thread_xp_AcquireSRWLockExclusive */
+ if G_UNLIKELY (lock->writer_locked)
+ {
+ LeaveCriticalSection (&lock->writer_lock);
+ return FALSE;
+ }
+
g_thread_xp_srwlock_become_reader (lock);
LeaveCriticalSection (&lock->writer_lock);