mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-30 08:21:25 +00:00
indicate trace by use of subclass rather than flag
This commit is contained in:
parent
efb4ec5f22
commit
603c3b1103
4 changed files with 417 additions and 226 deletions
378
Source/NSLock.m
378
Source/NSLock.m
|
@ -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
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue