ICU-3786 detect deadlock on WIN32
X-SVN-Rev: 15709
This commit is contained in:
parent
6d43abc307
commit
3c07c3f00c
@ -91,6 +91,34 @@ static UMTX gIncDecMutex = NULL;
|
|||||||
static UBool gMutexPoolInitialized = FALSE;
|
static UBool gMutexPoolInitialized = FALSE;
|
||||||
static char gMutexesInUse[MAX_MUTEXES];
|
static char gMutexesInUse[MAX_MUTEXES];
|
||||||
|
|
||||||
|
/* ICU_WIN32_DETECT_MUTEX_DEADLOCK
|
||||||
|
*
|
||||||
|
* On WIN32 mutexes are reentrant. This makes it difficult to debug
|
||||||
|
* deadlocking problems that show up on POSIXy platforms, where
|
||||||
|
* mutexes deadlock upon reentry. To enable checking code for all
|
||||||
|
* mutexes that duplicates the recursion checking that is always done
|
||||||
|
* for the global mutex (using gRecursionCount), define this symbol.
|
||||||
|
*
|
||||||
|
* This is for debugging purposes.
|
||||||
|
*
|
||||||
|
* This has no effect on non-WIN32 platforms, non-DEBUG builds, and
|
||||||
|
* non-ICU_USE_THREADS builds.
|
||||||
|
*
|
||||||
|
* Note: The CRITICAL_SECTION structure already has a RecursionCount
|
||||||
|
* member that can be used for this purpose, but portability to
|
||||||
|
* Win98/NT/2K needs to be tested before use. Works fine on XP.
|
||||||
|
* After portability is confirmed, the built-in RecursionCount can be
|
||||||
|
* used, and the gRecursionCountPool can be removed.
|
||||||
|
*
|
||||||
|
* Note: The checking only happens if there is no custom pMutexLockFn
|
||||||
|
* defined. Use one function, not two (don't use pMutexLockFn and
|
||||||
|
* pMutexUnlockFn) so the increment and decrement of the recursion
|
||||||
|
* count don't get out of sync. Users might set just one function,
|
||||||
|
* e.g., to perform a custom action, followed by a standard call
|
||||||
|
* to EnterCriticalSection.
|
||||||
|
*/
|
||||||
|
#define ICU_WIN32_DETECT_MUTEX_DEADLOCK
|
||||||
|
|
||||||
#if defined(WIN32)
|
#if defined(WIN32)
|
||||||
/*-------------------------------------------------------------
|
/*-------------------------------------------------------------
|
||||||
*
|
*
|
||||||
@ -100,9 +128,12 @@ static char gMutexesInUse[MAX_MUTEXES];
|
|||||||
static CRITICAL_SECTION gMutexes[MAX_MUTEXES];
|
static CRITICAL_SECTION gMutexes[MAX_MUTEXES];
|
||||||
static CRITICAL_SECTION gGlobalWinMutex;
|
static CRITICAL_SECTION gGlobalWinMutex;
|
||||||
|
|
||||||
/* Detect Recursive locking of the global mutex. For debugging only. */
|
/* Detect recursive locking on WIN32. For debugging only. */
|
||||||
#if defined(_DEBUG) && (ICU_USE_THREADS==1)
|
#if defined(_DEBUG) && (ICU_USE_THREADS==1)
|
||||||
static int32_t gRecursionCount = 0;
|
#ifdef ICU_WIN32_DETECT_MUTEX_DEADLOCK
|
||||||
|
static int32_t gRecursionCountPool[MAX_MUTEXES]; /* see comments above */
|
||||||
|
#endif
|
||||||
|
static int32_t gRecursionCount = 0; /* detect global mutex locking */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -195,6 +226,23 @@ umtx_lock(UMTX *mutex)
|
|||||||
gRecursionCount++; /* Recursion causes deadlocks on Unixes. */
|
gRecursionCount++; /* Recursion causes deadlocks on Unixes. */
|
||||||
U_ASSERT(gRecursionCount == 1); /* Detection works on Windows. Debug problems there. */
|
U_ASSERT(gRecursionCount == 1); /* Detection works on Windows. Debug problems there. */
|
||||||
}
|
}
|
||||||
|
#ifdef ICU_WIN32_DETECT_MUTEX_DEADLOCK
|
||||||
|
/* This handles gGlobalMutex too, but only if there is no pMutexLockFn */
|
||||||
|
else if (pMutexLockFn == NULL) { /* see comments above */
|
||||||
|
int i = ((CRITICAL_SECTION*)*mutex) - &gMutexes[0];
|
||||||
|
U_ASSERT(i >= 0 && i < MAX_MUTEXES);
|
||||||
|
++gRecursionCountPool[i];
|
||||||
|
|
||||||
|
U_ASSERT(gRecursionCountPool[i] == 1); /* !Detect Deadlock! */
|
||||||
|
|
||||||
|
/* This works and is fast, but needs testing on Win98/NT/2K.
|
||||||
|
See comments above. [alan]
|
||||||
|
U_ASSERT((CRITICAL_SECTION*)*mutex >= &gMutexes[0] &&
|
||||||
|
(CRITICAL_SECTION*)*mutex <= &gMutexes[MAX_MUTEXES]);
|
||||||
|
U_ASSERT(((CRITICAL_SECTION*)*mutex)->RecursionCount == 1);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#endif /*_DEBUG*/
|
#endif /*_DEBUG*/
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,6 +268,24 @@ umtx_unlock(UMTX* mutex)
|
|||||||
gRecursionCount--;
|
gRecursionCount--;
|
||||||
U_ASSERT(gRecursionCount == 0); /* Detect unlock of an already unlocked mutex */
|
U_ASSERT(gRecursionCount == 0); /* Detect unlock of an already unlocked mutex */
|
||||||
}
|
}
|
||||||
|
#ifdef ICU_WIN32_DETECT_MUTEX_DEADLOCK
|
||||||
|
/* This handles gGlobalMutex too, but only if there is no pMutexLockFn */
|
||||||
|
else if (pMutexLockFn == NULL) { /* see comments above */
|
||||||
|
int i = ((CRITICAL_SECTION*)*mutex) - &gMutexes[0];
|
||||||
|
U_ASSERT(i >= 0 && i < MAX_MUTEXES);
|
||||||
|
--gRecursionCountPool[i];
|
||||||
|
|
||||||
|
U_ASSERT(gRecursionCountPool[i] == 0); /* !Detect Deadlock! */
|
||||||
|
|
||||||
|
/* This works and is fast, but needs testing on Win98/NT/2K.
|
||||||
|
Note that RecursionCount will be 1, not 0, since we haven't
|
||||||
|
left the CRITICAL_SECTION yet. See comments above. [alan]
|
||||||
|
U_ASSERT((CRITICAL_SECTION*)*mutex >= &gMutexes[0] &&
|
||||||
|
(CRITICAL_SECTION*)*mutex <= &gMutexes[MAX_MUTEXES]);
|
||||||
|
U_ASSERT(((CRITICAL_SECTION*)*mutex)->RecursionCount == 1);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (pMutexUnlockFn) {
|
if (pMutexUnlockFn) {
|
||||||
@ -274,6 +340,9 @@ static void initGlobalMutex() {
|
|||||||
int i;
|
int i;
|
||||||
for (i=0; i<MAX_MUTEXES; i++) {
|
for (i=0; i<MAX_MUTEXES; i++) {
|
||||||
InitializeCriticalSection(&gMutexes[i]);
|
InitializeCriticalSection(&gMutexes[i]);
|
||||||
|
#ifdef ICU_WIN32_DETECT_MUTEX_DEADLOCK
|
||||||
|
gRecursionCountPool[i] = 0; /* see comments above */
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
gMutexPoolInitialized = TRUE;
|
gMutexPoolInitialized = TRUE;
|
||||||
}
|
}
|
||||||
@ -383,6 +452,7 @@ umtx_destroy(UMTX *mutex) {
|
|||||||
/* Return this mutex to the pool of available mutexes, if it came from the
|
/* Return this mutex to the pool of available mutexes, if it came from the
|
||||||
* pool in the first place.
|
* pool in the first place.
|
||||||
*/
|
*/
|
||||||
|
/* TODO use pointer math here, instead of iterating! */
|
||||||
int i;
|
int i;
|
||||||
for (i=0; i<MAX_MUTEXES; i++) {
|
for (i=0; i<MAX_MUTEXES; i++) {
|
||||||
if (*mutex == &gMutexes[i]) {
|
if (*mutex == &gMutexes[i]) {
|
||||||
|
Loading…
Reference in New Issue
Block a user