Skip to content

Commit

Permalink
Don't call NtReleaseKeyedEvent() if RtlDllShutdownInProgress() re…
Browse files Browse the repository at this point in the history
…turns `true` as it causes deadlocks. See issue #21. (#22)

Close #21.
  • Loading branch information
lhmouse authored Mar 27, 2017
1 parent 2f9ed46 commit b4115eb
Show file tree
Hide file tree
Showing 15 changed files with 28 additions and 10 deletions.
Binary file modified debug/mingw32/bin/mcfgthread-10.dll
Binary file not shown.
Binary file modified debug/mingw32/lib/libmcfgthread.a
Binary file not shown.
Binary file modified debug/mingw32/lib/libmcfgthread.dll.a
Binary file not shown.
Binary file modified debug/mingw64/bin/mcfgthread-10.dll
Binary file not shown.
Binary file modified debug/mingw64/lib/libmcfgthread.a
Binary file not shown.
Binary file modified debug/mingw64/lib/libmcfgthread.dll.a
Binary file not shown.
Binary file modified release/mingw32/bin/mcfgthread-10.dll
Binary file not shown.
Binary file modified release/mingw32/lib/libmcfgthread.a
Binary file not shown.
Binary file modified release/mingw32/lib/libmcfgthread.dll.a
Binary file not shown.
Binary file modified release/mingw64/bin/mcfgthread-10.dll
Binary file not shown.
Binary file modified release/mingw64/lib/libmcfgthread.a
Binary file not shown.
Binary file modified release/mingw64/lib/libmcfgthread.dll.a
Binary file not shown.
15 changes: 11 additions & 4 deletions src/env/condition_variable.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ extern NTSTATUS NtWaitForKeyedEvent(HANDLE hKeyedEvent, void *pKey, BOOLEAN bAle
__attribute__((__dllimport__, __stdcall__))
extern NTSTATUS NtReleaseKeyedEvent(HANDLE hKeyedEvent, void *pKey, BOOLEAN bAlertable, const LARGE_INTEGER *pliTimeout);

__attribute__((__dllimport__, __stdcall__, __const__))
extern BOOLEAN RtlDllShutdownInProgress(void);

#define MASK_WAITING ((uintptr_t) 0x0001)
#define MASK_THREADS_SPINNING ((uintptr_t) 0x000C)
#define MASK_THREADS_TRAPPED ((uintptr_t)~0x000F)
Expand Down Expand Up @@ -138,10 +141,14 @@ static inline size_t ReallySignalConditionVariable(volatile uintptr_t *puControl
uNew -= uCountToSignal * THREADS_TRAPPED_ONE;
} while(_MCFCRT_EXPECT_NOT(!__atomic_compare_exchange_n(puControl, &uOld, uNew, false, __ATOMIC_RELAXED, __ATOMIC_RELAXED)));
}
for(size_t i = 0; i < uCountToSignal; ++i){
NTSTATUS lStatus = NtReleaseKeyedEvent(_MCFCRT_NULLPTR, (void *)puControl, false, _MCFCRT_NULLPTR);
_MCFCRT_ASSERT_MSG(NT_SUCCESS(lStatus), L"NtReleaseKeyedEvent() failed.");
_MCFCRT_ASSERT(lStatus != STATUS_TIMEOUT);
// If `RtlDllShutdownInProgress()` is `true`, other threads will have been terminated.
// Calling `NtReleaseKeyedEvent()` when no thread is waiting results in deadlocks. Don't do that.
if((uCountToSignal > 0) && !RtlDllShutdownInProgress()){
for(size_t i = 0; i < uCountToSignal; ++i){
NTSTATUS lStatus = NtReleaseKeyedEvent(_MCFCRT_NULLPTR, (void *)puControl, false, _MCFCRT_NULLPTR);
_MCFCRT_ASSERT_MSG(NT_SUCCESS(lStatus), L"NtReleaseKeyedEvent() failed.");
_MCFCRT_ASSERT(lStatus != STATUS_TIMEOUT);
}
}
return uCountToSignal;
}
Expand Down
8 changes: 6 additions & 2 deletions src/env/mutex.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
#include "_nt_timeout.h"
#include "../ext/assert.h"
#include "../ext/expect.h"
#include <limits.h>
#include <winternl.h>
#include <ntstatus.h>

Expand All @@ -16,6 +15,9 @@ extern NTSTATUS NtWaitForKeyedEvent(HANDLE hKeyedEvent, void *pKey, BOOLEAN bAle
__attribute__((__dllimport__, __stdcall__))
extern NTSTATUS NtReleaseKeyedEvent(HANDLE hKeyedEvent, void *pKey, BOOLEAN bAlertable, const LARGE_INTEGER *pliTimeout);

__attribute__((__dllimport__, __stdcall__, __const__))
extern BOOLEAN RtlDllShutdownInProgress(void);

#define MASK_LOCKED ((uintptr_t) 0x0001)
#define MASK_THREADS_SPINNING ((uintptr_t) 0x000C)
#define MASK_THREADS_TRAPPED ((uintptr_t)~0x000F)
Expand Down Expand Up @@ -134,7 +136,9 @@ static inline void ReallySignalMutex(volatile uintptr_t *puControl){
uNew -= bSignalOne * THREADS_TRAPPED_ONE;
} while(_MCFCRT_EXPECT_NOT(!__atomic_compare_exchange_n(puControl, &uOld, uNew, false, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)));
}
if(bSignalOne){
// If `RtlDllShutdownInProgress()` is `true`, other threads will have been terminated.
// Calling `NtReleaseKeyedEvent()` when no thread is waiting results in deadlocks. Don't do that.
if(bSignalOne && !RtlDllShutdownInProgress()){
NTSTATUS lStatus = NtReleaseKeyedEvent(_MCFCRT_NULLPTR, (void *)puControl, false, _MCFCRT_NULLPTR);
_MCFCRT_ASSERT_MSG(NT_SUCCESS(lStatus), L"NtReleaseKeyedEvent() failed.");
_MCFCRT_ASSERT(lStatus != STATUS_TIMEOUT);
Expand Down
15 changes: 11 additions & 4 deletions src/env/once_flag.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ extern NTSTATUS NtWaitForKeyedEvent(HANDLE hKeyedEvent, void *pKey, BOOLEAN bAle
__attribute__((__dllimport__, __stdcall__))
extern NTSTATUS NtReleaseKeyedEvent(HANDLE hKeyedEvent, void *pKey, BOOLEAN bAlertable, const LARGE_INTEGER *pliTimeout);

__attribute__((__dllimport__, __stdcall__, __const__))
extern BOOLEAN RtlDllShutdownInProgress(void);

// The first byte is reserved by Itanium ABI to indicate whether the initialization has succeeded.
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define BSUSR(v_) ((uintptr_t)((uintptr_t)(v_) << CHAR_BIT))
Expand Down Expand Up @@ -124,10 +127,14 @@ static inline void RealSetAndSignalOnceFlag(volatile uintptr_t *puControl, bool
uNew -= uCountToSignal * THREADS_TRAPPED_ONE;
} while(_MCFCRT_EXPECT_NOT(!__atomic_compare_exchange_n(puControl, &uOld, uNew, false, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)));
}
for(size_t i = 0; i < uCountToSignal; ++i){
NTSTATUS lStatus = NtReleaseKeyedEvent(_MCFCRT_NULLPTR, (void *)puControl, false, _MCFCRT_NULLPTR);
_MCFCRT_ASSERT_MSG(NT_SUCCESS(lStatus), L"NtReleaseKeyedEvent() failed.");
_MCFCRT_ASSERT(lStatus != STATUS_TIMEOUT);
// If `RtlDllShutdownInProgress()` is `true`, other threads will have been terminated.
// Calling `NtReleaseKeyedEvent()` when no thread is waiting results in deadlocks. Don't do that.
if((uCountToSignal > 0) && !RtlDllShutdownInProgress()){
for(size_t i = 0; i < uCountToSignal; ++i){
NTSTATUS lStatus = NtReleaseKeyedEvent(_MCFCRT_NULLPTR, (void *)puControl, false, _MCFCRT_NULLPTR);
_MCFCRT_ASSERT_MSG(NT_SUCCESS(lStatus), L"NtReleaseKeyedEvent() failed.");
_MCFCRT_ASSERT(lStatus != STATUS_TIMEOUT);
}
}
}

Expand Down

0 comments on commit b4115eb

Please sign in to comment.