indicate trace by use of subclass rather than flag

This commit is contained in:
Richard Frith-Macdonald 2018-04-04 12:58:06 +01:00
parent efb4ec5f22
commit 603c3b1103
4 changed files with 417 additions and 226 deletions

View file

@ -64,18 +64,49 @@ static inline void GSPThreadInitRecursiveMutex(pthread_mutex_t *x)
NSArray *addresses;
@public
NSUInteger recursion; // Recursion count for lock trace
void **returns; // The return addresses on the stack
NSUInteger *returns; // The return addresses on the stack
int numReturns; // Number of return addresses
}
- (NSArray*) addresses;
- (NSArray*) symbols;
- (NSArray*) addresses; // Return addresses from last trace
- (NSArray*) symbols; // Return symbols from last trace
- (void) trace; // Populate with new stack trace
@end
/* Versions of the lock classes where the locking is never traced
*/
@interface GSUntracedCondition : NSCondition
@end
@interface GSUntracedConditionLock : NSConditionLock
@end
@interface GSUntracedLock : NSLock
@end
@interface GSUntracedRecursiveLock : NSRecursiveLock
@end
/* Versions of the lock classes where the locking is traced
*/
@interface GSTracedCondition : NSCondition
{
GSStackTrace *stack;
}
- (GSStackTrace*) stack;
@end
@interface GSTracedConditionLock : NSConditionLock
@end
@interface GSTracedLock : NSLock
{
GSStackTrace *stack;
}
- (GSStackTrace*) stack;
@end
@interface GSTracedRecursiveLock : NSRecursiveLock
{
GSStackTrace *stack;
}
- (GSStackTrace*) stack;
@end
#endif // _GSPThread_h_

View file

@ -842,91 +842,19 @@ NSReturnAddress(NSUInteger offset)
return env->addr;
}
@implementation GSStackTrace : NSObject
/** Offset from the top of the stack (when we generate a trace) to the
* first frame likely to be of interest for debugging.
*/
#define FrameOffset 4
+ (void) initialize
{
#if defined(_WIN32) && !defined(USE_BFD)
GS_INIT_RECURSIVE_MUTEX(traceLock);
#endif
}
- (NSArray*) addresses
{
if (nil == addresses && numReturns > FrameOffset)
{
CREATE_AUTORELEASE_POOL(pool);
NSInteger count = numReturns - FrameOffset;
NSValue *objects[count];
NSUInteger index;
const void **ptrs = (const void **)returns;
for (index = 0; index < count; index++)
{
objects[index] = [NSValue valueWithPointer: ptrs[FrameOffset+index]];
}
addresses = [[NSArray alloc] initWithObjects: objects count: count];
DESTROY(pool);
}
return addresses;
}
- (oneway void) dealloc
{
DESTROY(addresses);
DESTROY(symbols);
if (returns != NULL)
{
free(returns);
returns = NULL;
}
[super dealloc];
}
- (NSString*) description
{
NSMutableString *result;
NSArray *s;
int i;
int n;
result = [NSMutableString string];
s = [self symbols];
n = [s count];
for (i = 0; i < n; i++)
{
NSString *line = [s objectAtIndex: i];
[result appendFormat: @"%3d: %@\n", i, line];
}
return result;
}
- (id) init
{
return [self initWithOffset: 3];
}
// grab the current stack
- (id) initWithOffset: (unsigned)o
unsigned
GSPrivateReturnAddresses(NSUInteger **returns)
{
unsigned numReturns;
#if HAVE_BACKTRACE
void *addr[MAXFRAMES*sizeof(void*)];
void *addr[MAXFRAMES*sizeof(void*)];
numReturns = backtrace(addr, MAXFRAMES);
if (numReturns > 0)
{
returns = malloc(numReturns * sizeof(void*));
memcpy(returns, addr, numReturns * sizeof(void*));
}
*returns = malloc(numReturns * sizeof(void*));
memcpy(*returns, addr, numReturns * sizeof(void*));
}
#elif defined(_WIN32) && !defined(USE_BFD)
NSUInteger addr[MAXFRAMES];
@ -945,7 +873,7 @@ NSReturnAddress(NSUInteger offset)
fprintf(stderr, "Failed to load kernel32.dll with error: %d\n",
(int)GetLastError());
(void)pthread_mutex_unlock(&traceLock);
return self;
return 0;
}
capture = (CaptureStackBackTraceType)GetProcAddress(
hModule, "RtlCaptureStackBackTrace");
@ -954,7 +882,7 @@ NSReturnAddress(NSUInteger offset)
fprintf(stderr, "Failed to find RtlCaptureStackBackTrace: %d\n",
(int)GetLastError());
(void)pthread_mutex_unlock(&traceLock);
return self;
return 0;
}
hModule = LoadLibrary("dbghelp.dll");
if (0 == hModule)
@ -962,7 +890,7 @@ NSReturnAddress(NSUInteger offset)
fprintf(stderr, "Failed to load dbghelp.dll with error: %d\n",
(int)GetLastError());
(void)pthread_mutex_unlock(&traceLock);
return self;
return 0;
}
optSym = (SymSetOptionsType)GetProcAddress(
hModule, "SymSetOptions");
@ -971,7 +899,7 @@ NSReturnAddress(NSUInteger offset)
fprintf(stderr, "Failed to find SymSetOptions: %d\n",
(int)GetLastError());
(void)pthread_mutex_unlock(&traceLock);
return self;
return 0;
}
initSym = (SymInitializeType)GetProcAddress(
hModule, "SymInitialize");
@ -980,7 +908,7 @@ NSReturnAddress(NSUInteger offset)
fprintf(stderr, "Failed to find SymInitialize: %d\n",
(int)GetLastError());
(void)pthread_mutex_unlock(&traceLock);
return self;
return 0;
}
fromSym = (SymFromAddrType)GetProcAddress(
hModule, "SymFromAddr");
@ -989,7 +917,7 @@ NSReturnAddress(NSUInteger offset)
fprintf(stderr, "Failed to find SymFromAddr: %d\n",
(int)GetLastError());
(void)pthread_mutex_unlock(&traceLock);
return self;
return 0;
}
}
@ -1001,20 +929,20 @@ NSReturnAddress(NSUInteger offset)
(int)GetLastError());
fromSym = 0;
(void)pthread_mutex_unlock(&traceLock);
return self;
return 0;
}
}
if (0 == capture)
{
(void)pthread_mutex_unlock(&traceLock);
return self;
return 0;
}
numReturns = (capture)(0, MAXFRAMES, (void**)addr, NULL);
if (numReturns > 0)
{
returns = malloc(numReturns * sizeof(void*));
memcpy(returns, addr, numReturns * sizeof(void*));
*returns = malloc(numReturns * sizeof(void*));
memcpy(*returns, addr, numReturns * sizeof(void*));
}
(void)pthread_mutex_unlock(&traceLock);
@ -1092,7 +1020,7 @@ NSReturnAddress(NSUInteger offset)
{
break;
}
memcpy(&returns[i], env->addr, sizeof(void*));
memcpy(&(*returns)[i], env->addr, sizeof(void*));
}
signal(SIGSEGV, env->segv);
signal(SIGBUS, env->bus);
@ -1105,6 +1033,80 @@ NSReturnAddress(NSUInteger offset)
}
}
#endif
return numReturns;
}
@implementation GSStackTrace : NSObject
/** Offset from the top of the stack (when we generate a trace) to the
* first frame likely to be of interest for debugging.
*/
#define FrameOffset 4
+ (void) initialize
{
#if defined(_WIN32) && !defined(USE_BFD)
GS_INIT_RECURSIVE_MUTEX(traceLock);
#endif
#if defined(USE_BFD)
GS_INIT_RECURSIVE_MUTEX(modLock);
#endif
}
- (NSArray*) addresses
{
if (nil == addresses && numReturns > FrameOffset)
{
CREATE_AUTORELEASE_POOL(pool);
NSInteger count = numReturns - FrameOffset;
NSValue *objects[count];
NSUInteger index;
const void **ptrs = (const void **)returns;
for (index = 0; index < count; index++)
{
objects[index] = [NSValue valueWithPointer: ptrs[FrameOffset+index]];
}
addresses = [[NSArray alloc] initWithObjects: objects count: count];
DESTROY(pool);
}
return addresses;
}
- (oneway void) dealloc
{
DESTROY(addresses);
DESTROY(symbols);
if (returns != NULL)
{
free(returns);
returns = NULL;
}
[super dealloc];
}
- (NSString*) description
{
NSMutableString *result;
NSArray *s;
int i;
int n;
result = [NSMutableString string];
s = [self symbols];
n = [s count];
for (i = 0; i < n; i++)
{
NSString *line = [s objectAtIndex: i];
[result appendFormat: @"%3d: %@\n", i, line];
}
return result;
}
- (id) init
{
return self;
}
@ -1235,6 +1237,18 @@ NSReturnAddress(NSUInteger offset)
return symbols;
}
- (void) trace
{
DESTROY(addresses);
DESTROY(symbols);
if (returns != NULL)
{
free(returns);
returns = NULL;
}
numReturns = GSPrivateReturnAddresses(&returns);
}
@end
@ -1327,9 +1341,6 @@ callUncaughtHandler(id value)
{
if (self == [NSException class])
{
#if defined(USE_BFD)
GS_INIT_RECURSIVE_MUTEX(modLock);
#endif /* USE_BFD */
#if defined(_NATIVE_OBJC_EXCEPTIONS)
# ifdef HAVE_SET_UNCAUGHT_EXCEPTION_HANDLER
objc_setUncaughtExceptionHandler(callUncaughtHandler);
@ -1487,6 +1498,7 @@ callUncaughtHandler(id value)
{
// Only set the stack when first raised
_e_stack = [GSStackTrace new];
[_e_stack trace];
}
#if defined(_NATIVE_OBJC_EXCEPTIONS)
@ -1635,9 +1647,9 @@ callUncaughtHandler(id value)
+ (NSArray *) callStackSymbols
{
GSStackTrace *stackTrace = [[[GSStackTrace alloc] init] autorelease];
NSArray *symbols = [stackTrace symbols];
return symbols;
GSStackTrace *stackTrace = AUTORELEASE([GSStackTrace new]);
[stackTrace trace];
return [stackTrace symbols];
}
@end

View file

@ -43,6 +43,21 @@
#import "GSPThread.h"
static Class baseConditionClass = Nil;
static Class baseConditionLockClass = Nil;
static Class baseLockClass = Nil;
static Class baseRecursiveLockClass = Nil;
static Class tracedConditionClass = Nil;
static Class tracedConditionLockClass = Nil;
static Class tracedLockClass = Nil;
static Class tracedRecursiveLockClass = Nil;
static Class untracedConditionClass = Nil;
static Class untracedConditionLockClass = Nil;
static Class untracedLockClass = Nil;
static Class untracedRecursiveLockClass = Nil;
static BOOL traceLocks = NO;
void
@ -51,17 +66,11 @@ GSPrivateTraceLocks(BOOL aFlag)
traceLocks = (aFlag ? YES : NO);
}
#define CHKT(T,X) \
if (traceLocks) { \
NSString *msg = [T mutex ## X: self]; \
if (nil != msg) \
{ \
(*_NSLock_error_handler)(self, _cmd, YES, msg); \
} \
};
#define CHK(X) CHKT(GSCurrentThread(), X)
/* In untraced operations these macros do nothing.
* When tracing they are defined to perform the trace methods of the thread.
*/
#define CHKT(T,X)
#define CHK(X)
/*
* Methods shared between NSLock, NSRecursiveLock, and NSCondition
@ -144,56 +153,18 @@ if (traceLocks) { \
pthread_mutex_destroy(&_mutex);\
}
#define MNAME \
- (void) setName: (NSString*)newName\
{\
ASSIGNCOPY(_name, newName);\
}\
- (NSString*) name\
{\
return _name;\
}
#define MLOCK_TRACED \
{ \
NSThread *t = GSCurrentThread(); \
CHKT(t,Wait) \
int err = pthread_mutex_lock(&_mutex);\
if (EDEADLK == err)\
{\
CHKT(t,Drop) \
(*_NSLock_error_handler)(self, _cmd, YES, @"deadlock");\
}\
else if (err != 0)\
{\
CHKT(t,Drop) \
[NSException raise: NSLockException\
format: @"failed to lock mutex"];\
}\
CHKT(t,Hold) \
}
#define MLOCK_UNTRACED \
{ \
int err = pthread_mutex_lock(&_mutex);\
if (EDEADLK == err)\
{\
(*_NSLock_error_handler)(self, _cmd, YES, @"deadlock");\
}\
else if (err != 0)\
{\
[NSException raise: NSLockException\
format: @"failed to lock mutex"];\
}\
}
#define MLOCK \
- (void) lock\
{\
if (traceLocks) \
MLOCK_TRACED \
else \
MLOCK_UNTRACED \
int err = pthread_mutex_lock(&_mutex);\
if (EDEADLK == err)\
{\
(*_NSLock_error_handler)(self, _cmd, YES, @"deadlock");\
}\
else if (err != 0)\
{\
[NSException raise: NSLockException format: @"failed to lock mutex"];\
}\
}
#define MLOCKBEFOREDATE \
@ -212,6 +183,22 @@ if (traceLocks) { \
return NO;\
}
#define MNAME \
- (void) setName: (NSString*)newName\
{\
ASSIGNCOPY(_name, newName);\
}\
- (NSString*) name\
{\
return _name;\
}
#define MSTACK \
- (GSStackTrace*) stack \
{ \
return nil; \
}
#define MTRYLOCK \
- (BOOL) tryLock\
{\
@ -263,6 +250,15 @@ NSString *NSLockException = @"NSLockException";
@implementation NSLock
+ (id) allocWithZone: (NSZone*)z
{
if (self == baseLockClass && YES == traceLocks)
{
return class_createInstance(tracedLockClass, 0);
}
return class_createInstance(self, 0);
}
+ (void) initialize
{
static BOOL beenHere = NO;
@ -296,6 +292,21 @@ NSString *NSLockException = @"NSLockException";
*/
pthread_mutex_init(&deadlock, &attr_normal);
pthread_mutex_lock(&deadlock);
baseConditionClass = [NSCondition class];
baseConditionLockClass = [NSConditionLock class];
baseLockClass = [NSLock class];
baseRecursiveLockClass = [NSRecursiveLock class];
tracedConditionClass = [GSTracedCondition class];
tracedConditionLockClass = [GSTracedConditionLock class];
tracedLockClass = [GSTracedLock class];
tracedRecursiveLockClass = [GSTracedRecursiveLock class];
untracedConditionClass = [GSUntracedCondition class];
untracedConditionLockClass = [GSUntracedConditionLock class];
untracedLockClass = [GSUntracedLock class];
untracedRecursiveLockClass = [GSUntracedRecursiveLock class];
}
}
@ -328,7 +339,7 @@ MLOCK
int err = pthread_mutex_trylock(&_mutex);
if (0 == err)
{
if (traceLocks) CHK(Hold)
CHK(Hold)
return YES;
}
if (EDEADLK == err)
@ -341,12 +352,23 @@ MLOCK
}
MNAME
MSTACK
MTRYLOCK
MUNLOCK
@end
@implementation NSRecursiveLock
+ (id) allocWithZone: (NSZone*)z
{
if (self == baseRecursiveLockClass && YES == traceLocks)
{
return class_createInstance(tracedRecursiveLockClass, 0);
}
return class_createInstance(self, 0);
}
+ (void) initialize
{
[NSLock class]; // Ensure mutex attributes are set up.
@ -372,12 +394,22 @@ MISLOCKED
MLOCK
MLOCKBEFOREDATE
MNAME
MSTACK
MTRYLOCK
MUNLOCK
@end
@implementation NSCondition
+ (id) allocWithZone: (NSZone*)z
{
if (self == baseConditionClass && YES == traceLocks)
{
return class_createInstance(tracedConditionClass, 0);
}
return class_createInstance(self, 0);
}
+ (void) initialize
{
[NSLock class]; // Ensure mutex attributes are set up.
@ -424,23 +456,13 @@ MNAME
pthread_cond_signal(&_condition);
}
MSTACK
MTRYLOCK
MUNLOCK
- (void) wait
{
if (traceLocks)
{
NSThread *t = GSCurrentThread();
CHKT(t,Drop)
CHKT(t,Wait)
pthread_cond_wait(&_condition, &_mutex);
CHKT(t,Hold)
}
else
{
pthread_cond_wait(&_condition, &_mutex);
}
pthread_cond_wait(&_condition, &_mutex);
}
- (BOOL) waitUntilDate: (NSDate*)limit
@ -459,36 +481,15 @@ MUNLOCK
/* NB. On timeout the lock is still held even through condition is not met
*/
if (traceLocks)
retVal = pthread_cond_timedwait(&_condition, &_mutex, &timeout);
if (retVal == 0)
{
NSThread *t = GSCurrentThread();
CHKT(t,Drop)
retVal = pthread_cond_timedwait(&_condition, &_mutex, &timeout);
if (retVal == 0)
{
CHKT(t,Hold)
return YES;
}
if (retVal == ETIMEDOUT)
{
CHKT(t,Hold)
return NO;
}
return YES;
}
else
if (retVal == ETIMEDOUT)
{
retVal = pthread_cond_timedwait(&_condition, &_mutex, &timeout);
if (retVal == 0)
{
return YES;
}
if (retVal == ETIMEDOUT)
{
return NO;
}
return NO;
}
if (retVal == EINVAL)
{
NSLog(@"Invalid arguments to pthread_cond_timedwait");
@ -500,6 +501,15 @@ MUNLOCK
@implementation NSConditionLock
+ (id) allocWithZone: (NSZone*)z
{
if (self == baseConditionLockClass && YES == traceLocks)
{
return class_createInstance(tracedConditionLockClass, 0);
}
return class_createInstance(self, 0);
}
+ (void) initialize
{
[NSLock class]; // Ensure mutex attributes are set up.
@ -587,6 +597,7 @@ MUNLOCK
}
MNAME
MSTACK
- (BOOL) tryLock
{
@ -627,10 +638,6 @@ MNAME
/* Versions of the lock classes where the locking is unconditionally traced
*/
@interface GSTracedRecursiveLock : NSRecursiveLock
@end
@interface GSTracedLock : NSLock
@end
#undef CHKT
#define CHKT(T,X) \
@ -641,20 +648,151 @@ MNAME
(*_NSLock_error_handler)(self, _cmd, YES, msg); \
} \
}
#undef CHK
#define CHK(X) CHKT(GSCurrentThread(), X)
#undef MDEALLOC
#define MDEALLOC \
- (void) dealloc \
{ \
DESTROY(stack); \
[super dealloc]; \
}
#undef MLOCK
#define MLOCK \
- (void) lock\
MLOCK_TRACED
{ \
NSThread *t = GSCurrentThread(); \
CHKT(t,Wait) \
int err = pthread_mutex_lock(&_mutex);\
if (EDEADLK == err)\
{\
CHKT(t,Drop) \
(*_NSLock_error_handler)(self, _cmd, YES, @"deadlock");\
}\
else if (err != 0)\
{\
CHKT(t,Drop) \
[NSException raise: NSLockException format: @"failed to lock mutex"];\
}\
CHKT(t,Hold) \
}
@implementation GSTracedLock
#undef MSTACK
#define MSTACK \
- (GSStackTrace*) stack \
{ \
if (nil == stack) \
{ \
stack = [GSStackTrace new]; \
} \
return stack; \
}
@implementation GSTracedCondition
+ (id) allocWithZone: (NSZone*)z
{
return class_createInstance(tracedConditionClass, 0);
}
MDEALLOC
MLOCK
MLOCKBEFOREDATE
MSTACK
MTRYLOCK
- (void) wait
{
NSThread *t = GSCurrentThread();
CHKT(t,Drop)
CHKT(t,Wait)
pthread_cond_wait(&_condition, &_mutex);
CHKT(t,Hold)
}
- (BOOL) waitUntilDate: (NSDate*)limit
{
NSTimeInterval ti = [limit timeIntervalSince1970];
NSThread *t = GSCurrentThread();
double secs, subsecs;
struct timespec timeout;
int retVal = 0;
// Split the float into seconds and fractions of a second
subsecs = modf(ti, &secs);
timeout.tv_sec = secs;
// Convert fractions of a second to nanoseconds
timeout.tv_nsec = subsecs * 1e9;
/* NB. On timeout the lock is still held even through condition is not met
*/
CHKT(t,Drop)
retVal = pthread_cond_timedwait(&_condition, &_mutex, &timeout);
if (retVal == 0)
{
CHKT(t,Hold)
return YES;
}
if (retVal == ETIMEDOUT)
{
CHKT(t,Hold)
return NO;
}
if (retVal == EINVAL)
{
NSLog(@"Invalid arguments to pthread_cond_timedwait");
}
return NO;
}
MUNLOCK
@end
@implementation GSTracedConditionLock
+ (id) allocWithZone: (NSZone*)z
{
return class_createInstance(tracedConditionLockClass, 0);
}
- (id) initWithCondition: (NSInteger)value
{
if (nil != (self = [super init]))
{
if (nil == (_condition = [GSTracedCondition new]))
{
DESTROY(self);
}
else
{
_condition_value = value;
[_condition setName:
[NSString stringWithFormat: @"condition-for-lock-%p", self]];
}
}
return self;
}
@end
@implementation GSTracedLock
+ (id) allocWithZone: (NSZone*)z
{
return class_createInstance(tracedLockClass, 0);
}
MDEALLOC
MLOCK
MLOCKBEFOREDATE
MSTACK
MTRYLOCK
MUNLOCK
@end
@implementation GSTracedRecursiveLock
+ (id) allocWithZone: (NSZone*)z
{
return class_createInstance(tracedRecursiveLockClass, 0);
}
MDEALLOC
MLOCK
MLOCKBEFOREDATE
MSTACK
MTRYLOCK
MUNLOCK
@end
@ -662,22 +800,28 @@ MUNLOCK
/* Versions of the lock classes where the locking is never traced
*/
#undef CHKT
#define CHKT(T,X)
#undef MLOCK
#define MLOCK \
- (void) lock\
MLOCK_UNTRACED
@implementation GSUntracedCondition
+ (id) allocWithZone: (NSZone*)z
{
return class_createInstance(baseConditionClass, 0);
}
@end
@implementation GSUntracedConditionLock
+ (id) allocWithZone: (NSZone*)z
{
return class_createInstance(baseConditionLockClass, 0);
}
@end
@implementation GSUntracedLock
MLOCK
MLOCKBEFOREDATE
MTRYLOCK
MUNLOCK
+ (id) allocWithZone: (NSZone*)z
{
return class_createInstance(baseRecursiveLockClass, 0);
}
@end
@implementation GSUntracedRecursiveLock
MLOCK
MLOCKBEFOREDATE
MTRYLOCK
MUNLOCK
+ (id) allocWithZone: (NSZone*)z
{
return class_createInstance(baseRecursiveLockClass, 0);
}
@end

View file

@ -1363,12 +1363,13 @@ lockInfoErr(NSString *str)
- (NSString *) mutexDrop: (id)mutex
{
if (GS_EXISTS_INTERNAL && traceLocks)
if (GS_EXISTS_INTERNAL)
{
GSLockInfo *li = &lockInfo;
GSStackTrace *stck;
int err;
if (NO == traceLocks) return nil;
err = pthread_spin_lock(&li->spin);
if (EDEADLK == err) return lockInfoErr(@"thread spin lock deadlocked");
if (EINVAL == err) return lockInfoErr(@"thread spin lock invalid");
@ -1387,16 +1388,16 @@ lockInfoErr(NSString *str)
if (stck->recursion-- == 0)
{
NSMapRemove(li->held, (void*)mutex);
//fprintf(stderr, "%lu: Drop %p (final) %lu\n", (unsigned long)_threadID, mutex, [li->held count]);
fprintf(stderr, "%lu: Drop %p (final) %lu\n", (unsigned long)_threadID, mutex, [li->held count]);
}
else
{
//fprintf(stderr, "%lu: Drop %p (%lu) %lu\n", (unsigned long)threadID, mutex, (unsigned long)stck->recursion, [li->held count]);
fprintf(stderr, "%lu: Drop %p (%lu) %lu\n", (unsigned long)threadID, mutex, (unsigned long)stck->recursion, [li->held count]);
}
}
else
{
//fprintf(stderr, "%lu: Drop %p (bad) %lu\n", (unsigned long)threadID, mutex, [li->held count]);
fprintf(stderr, "%lu: Drop %p (bad) %lu\n", (unsigned long)threadID, mutex, [li->held count]);
pthread_spin_unlock(&li->spin);
return lockInfoErr(
@"attempt to unlock mutex not locked by this thread");
@ -1409,12 +1410,13 @@ lockInfoErr(NSString *str)
- (NSString *) mutexHold: (id)mutex
{
if (GS_EXISTS_INTERNAL && traceLocks)
if (GS_EXISTS_INTERNAL)
{
GSLockInfo *li = &lockInfo;
GSStackTrace *stck;
int err;
if (NO == traceLocks) return nil;
err = pthread_spin_lock(&li->spin);
if (EDEADLK == err) return lockInfoErr(@"thread spin lock deadlocked");
if (EINVAL == err) return lockInfoErr(@"thread spin lock invalid");
@ -1435,15 +1437,15 @@ lockInfoErr(NSString *str)
stck = NSMapGet(li->held, (void*)mutex);
if (nil == stck)
{
stck = [GSStackTrace new];
stck = [GSStackTrace new]; [stck trace];
NSMapInsert(li->held, (void*)mutex, (void*)stck);
RELEASE(stck);
//fprintf(stderr, "%lu: Hold %p (initial) %lu\n", (unsigned long)threadID, mutex, [li->held count]);
fprintf(stderr, "%lu: Hold %p (initial) %lu\n", (unsigned long)threadID, mutex, [li->held count]);
}
else
{
stck->recursion++;
//fprintf(stderr, "%lu: Hold %p (%lu) %lu\n", (unsigned long)threadID, mutex, (unsigned long)stck->recursion, [li->held count]);
fprintf(stderr, "%lu: Hold %p (%lu) %lu\n", (unsigned long)threadID, mutex, (unsigned long)stck->recursion, [li->held count]);
}
li->wait = nil;
pthread_spin_unlock(&li->spin);
@ -1454,12 +1456,13 @@ lockInfoErr(NSString *str)
- (NSString *) mutexWait: (id)mutex
{
if (GS_EXISTS_INTERNAL && traceLocks)
if (GS_EXISTS_INTERNAL)
{
GSLockInfo *li = &lockInfo;
BOOL owned = NO;
int err;
if (NO == traceLocks) return nil;
err = pthread_spin_lock(&li->spin);
if (EDEADLK == err) return lockInfoErr(@"thread spin lock deadlocked");
if (EINVAL == err) return lockInfoErr(@"thread spin lock invalid");
@ -1477,6 +1480,7 @@ lockInfoErr(NSString *str)
owned = YES;
}
pthread_spin_unlock(&li->spin);
fprintf(stderr, "%lu: Wait %p\n", (unsigned long)_threadID, mutex);
if (YES == owned && [mutex isKindOfClass: [NSRecursiveLock class]])
{
return nil; // We can't deadlock on a recursive lock we own
@ -1625,7 +1629,7 @@ lockInfoErr(NSString *str)
if (nil != dependencies)
{
GSStackTrace *stack = [GSStackTrace new];
GSStackTrace *stack = [GSStackTrace new]; [stack trace];
NSUInteger count;
NSUInteger index = 0;
NSMutableString *m;