mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
Small bugfixes and OSX compatibility tweak.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@28616 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
d626a852e5
commit
6b1b12123a
2 changed files with 223 additions and 145 deletions
10
ChangeLog
10
ChangeLog
|
@ -1,3 +1,13 @@
|
|||
2009-09-06 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Source/NSLock.m: Fix the ([-tryLock]) and [(-lockBeforeDate:])
|
||||
implementations for NSLock and NSCondictionLock to return NO for
|
||||
recursive locking. Fix to only initialise mutex attributes once
|
||||
(to avoid leaking a set of attributes with every lock created on
|
||||
platforms where attributes need to be destroyed when no longer used).
|
||||
Reorganise to make it easy to replace method implementations.
|
||||
Fix for bug #25444 ... OSX compatibility change.
|
||||
|
||||
2009-09-06 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Source/NSRunLoop.m: Fix for rare problem if someone changes the
|
||||
|
|
358
Source/NSLock.m
358
Source/NSLock.m
|
@ -45,7 +45,39 @@
|
|||
* is probably better behaviour, because it encourages developer to fix their
|
||||
* code.
|
||||
*/
|
||||
#define NSLOCKING_METHODS \
|
||||
|
||||
#define MDEALLOC \
|
||||
- (void) dealloc\
|
||||
{\
|
||||
[self finalize];\
|
||||
[_name release];\
|
||||
[super dealloc];\
|
||||
}
|
||||
#define MDESCRIPTION \
|
||||
- (NSString*) description\
|
||||
{\
|
||||
if (_name == nil)\
|
||||
{\
|
||||
return [super description];\
|
||||
}\
|
||||
return [NSString stringWithFormat: @"%@ '%@'",\
|
||||
[super description], _name];\
|
||||
}
|
||||
#define MFINALIZE \
|
||||
- (void) finalize\
|
||||
{\
|
||||
pthread_mutex_destroy(&_mutex);\
|
||||
}
|
||||
#define MNAME \
|
||||
- (void) setName: (NSString*)newName\
|
||||
{\
|
||||
ASSIGNCOPY(_name, newName);\
|
||||
}\
|
||||
- (NSString*) name\
|
||||
{\
|
||||
return _name;\
|
||||
}
|
||||
#define MLOCK \
|
||||
- (void) lock\
|
||||
{\
|
||||
int err = pthread_mutex_lock(&_mutex);\
|
||||
|
@ -54,48 +86,17 @@
|
|||
[NSException raise: NSLockException\
|
||||
format: @"failed to lock mutex"];\
|
||||
}\
|
||||
if (EDEADLK == err)\
|
||||
{\
|
||||
_NSLockError(self, _cmd);\
|
||||
}\
|
||||
}\
|
||||
- (void) unlock\
|
||||
{\
|
||||
if (0 != pthread_mutex_unlock(&_mutex))\
|
||||
{\
|
||||
[NSException raise: NSLockException\
|
||||
format: @"failed to unlock mutex"];\
|
||||
}\
|
||||
}\
|
||||
- (NSString*) description\
|
||||
{\
|
||||
if (_name == nil)\
|
||||
{\
|
||||
return [super description];\
|
||||
}\
|
||||
return [NSString stringWithFormat: @"%@ '%@'",\
|
||||
[super description], _name];\
|
||||
}\
|
||||
- (BOOL) tryLock\
|
||||
{\
|
||||
int err = pthread_mutex_trylock(&_mutex);\
|
||||
if (EDEADLK == err)\
|
||||
{\
|
||||
_NSLockError(self, _cmd);\
|
||||
return YES;\
|
||||
}\
|
||||
return (0 == err);\
|
||||
}\
|
||||
}
|
||||
#define MLOCKBEFOREDATE \
|
||||
- (BOOL) lockBeforeDate: (NSDate*)limit\
|
||||
{\
|
||||
do\
|
||||
{\
|
||||
int err = pthread_mutex_trylock(&_mutex);\
|
||||
if (EDEADLK == err)\
|
||||
{\
|
||||
_NSLockError(self, _cmd);\
|
||||
return YES;\
|
||||
}\
|
||||
if (0 == err)\
|
||||
{\
|
||||
return YES;\
|
||||
|
@ -103,86 +104,162 @@
|
|||
sched_yield();\
|
||||
} while([limit timeIntervalSinceNow] < 0);\
|
||||
return NO;\
|
||||
}\
|
||||
NAME_METHODS
|
||||
|
||||
#define NAME_METHODS \
|
||||
- (void) setName: (NSString*)newName\
|
||||
{\
|
||||
ASSIGNCOPY(_name, newName);\
|
||||
}\
|
||||
- (NSString*) name\
|
||||
{\
|
||||
return _name;\
|
||||
}
|
||||
#define MTRYLOCK \
|
||||
- (BOOL) tryLock\
|
||||
{\
|
||||
int err = pthread_mutex_trylock(&_mutex);\
|
||||
return (0 == err) ? YES : NO;\
|
||||
}
|
||||
#define MUNLOCK \
|
||||
- (void) unlock\
|
||||
{\
|
||||
if (0 != pthread_mutex_unlock(&_mutex))\
|
||||
{\
|
||||
[NSException raise: NSLockException\
|
||||
format: @"failed to unlock mutex"];\
|
||||
}\
|
||||
}
|
||||
|
||||
static pthread_mutex_t deadlock;
|
||||
static pthread_mutexattr_t attr_normal;
|
||||
static pthread_mutexattr_t attr_reporting;
|
||||
static pthread_mutexattr_t attr_recursive;
|
||||
|
||||
/**
|
||||
* OS X 10.5 compatibility function to allow debugging deadlock conditions.
|
||||
*
|
||||
* On OS X, this really deadlocks. For now, we just continue, while logging
|
||||
* the 'you are a numpty' warning.
|
||||
*/
|
||||
void _NSLockError(id obj, SEL _cmd)
|
||||
{
|
||||
NSLog(@"*** -[%@ %@]: deadlock (%@)", [obj class],
|
||||
NSStringFromSelector(_cmd), obj);
|
||||
NSStringFromSelector(_cmd), obj);
|
||||
NSLog(@"*** Break on _NSLockError() to debug.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Init method for an NSLock / NSRecursive lock. Creates a mutex of the
|
||||
* specified type. Also adds the corresponding -finalize and -dealloc methods.
|
||||
*/
|
||||
#define INIT_LOCK_WITH_TYPE(lock_type) \
|
||||
- (id) init\
|
||||
{\
|
||||
pthread_mutexattr_t attr;\
|
||||
if (nil == (self = [super init]))\
|
||||
{\
|
||||
return nil;\
|
||||
}\
|
||||
pthread_mutexattr_init(&attr);\
|
||||
pthread_mutexattr_settype(&attr, lock_type);\
|
||||
if (0 != pthread_mutex_init(&_mutex, &attr))\
|
||||
{\
|
||||
[self release];\
|
||||
return nil;\
|
||||
}\
|
||||
return self;\
|
||||
}\
|
||||
- (void) finalize\
|
||||
{\
|
||||
pthread_mutex_destroy(&_mutex);\
|
||||
}\
|
||||
- (void) dealloc\
|
||||
{\
|
||||
[self finalize];\
|
||||
[_name release];\
|
||||
[super dealloc];\
|
||||
pthread_mutex_lock(&deadlock);
|
||||
}
|
||||
|
||||
// Exceptions
|
||||
|
||||
NSString *NSLockException = @"NSLockException";
|
||||
|
||||
|
||||
@implementation NSLock
|
||||
// Use an error-checking lock. This is marginally slower, but lets us throw
|
||||
// exceptions when incorrect locking occurs.
|
||||
INIT_LOCK_WITH_TYPE(PTHREAD_MUTEX_ERRORCHECK)
|
||||
NSLOCKING_METHODS
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
static BOOL beenHere = NO;
|
||||
|
||||
if (beenHere == NO)
|
||||
{
|
||||
beenHere = YES;
|
||||
|
||||
/* Initialise attributes for the different types of mutex.
|
||||
* We do it once, since attributes can be shared between multiple
|
||||
* mutexes.
|
||||
* If we had a pthread_mutexattr_t instance for each mutex, we would
|
||||
* either have to store it as an ivar of our NSLock (or similar), or
|
||||
* we would potentially leak instances as we couldn't destroy them
|
||||
* when destroying the NSLock. I don't know if any implementation
|
||||
* of pthreads actually allocates memory when you call the
|
||||
* pthread_mutexattr_init function, but they are allowed to do so
|
||||
* (and deallocate the memory in pthread_mutexattr_destroy).
|
||||
*/
|
||||
pthread_mutexattr_init(&attr_normal);
|
||||
pthread_mutexattr_settype(&attr_normal, PTHREAD_MUTEX_NORMAL);
|
||||
pthread_mutexattr_init(&attr_reporting);
|
||||
pthread_mutexattr_settype(&attr_reporting, PTHREAD_MUTEX_ERRORCHECK);
|
||||
pthread_mutexattr_init(&attr_recursive);
|
||||
pthread_mutexattr_settype(&attr_recursive, PTHREAD_MUTEX_RECURSIVE);
|
||||
|
||||
/* To emulate OSX behavior, we need to be able both to detect deadlocks
|
||||
* (so we can log them), and also hang the thread when one occurs.
|
||||
* the simple way to do that is to set up a locked mutex we can
|
||||
* force a deadlock on.
|
||||
*/
|
||||
pthread_mutex_init(&deadlock, &attr_normal);
|
||||
pthread_mutex_lock(&deadlock);
|
||||
}
|
||||
}
|
||||
|
||||
MDEALLOC
|
||||
MDESCRIPTION
|
||||
MFINALIZE
|
||||
|
||||
/* Use an error-checking lock. This is marginally slower, but lets us throw
|
||||
* exceptions when incorrect locking occurs.
|
||||
*/
|
||||
- (id) init
|
||||
{
|
||||
if (nil != (self = [super init]))
|
||||
{
|
||||
if (0 != pthread_mutex_init(&_mutex, &attr_reporting))
|
||||
{
|
||||
[self release];
|
||||
self = nil;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
MLOCK
|
||||
MLOCKBEFOREDATE
|
||||
MNAME
|
||||
MTRYLOCK
|
||||
MUNLOCK
|
||||
@end
|
||||
|
||||
@implementation NSRecursiveLock
|
||||
INIT_LOCK_WITH_TYPE(PTHREAD_MUTEX_RECURSIVE);
|
||||
NSLOCKING_METHODS
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
[NSLock class]; // Ensure mutex attributes are set up.
|
||||
}
|
||||
|
||||
MDEALLOC
|
||||
MDESCRIPTION
|
||||
MFINALIZE
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if (nil != (self = [super init]))
|
||||
{
|
||||
if (0 != pthread_mutex_init(&_mutex, &attr_recursive))
|
||||
{
|
||||
[self release];
|
||||
self = nil;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
MLOCK
|
||||
MLOCKBEFOREDATE
|
||||
MNAME
|
||||
MTRYLOCK
|
||||
MUNLOCK
|
||||
@end
|
||||
|
||||
@implementation NSCondition
|
||||
- (id)init
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
[NSLock class]; // Ensure mutex attributes are set up.
|
||||
}
|
||||
|
||||
- (void) broadcast
|
||||
{
|
||||
pthread_cond_broadcast(&_condition);
|
||||
}
|
||||
|
||||
MDEALLOC
|
||||
MDESCRIPTION
|
||||
|
||||
- (void) finalize
|
||||
{
|
||||
pthread_cond_destroy(&_condition);
|
||||
pthread_mutex_destroy(&_mutex);
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if (nil == (self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
|
@ -192,9 +269,7 @@ NSLOCKING_METHODS
|
|||
[self release];
|
||||
return nil;
|
||||
}
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
if (0 != pthread_mutex_init(&_mutex, &attr))
|
||||
if (0 != pthread_mutex_init(&_mutex, &attr_reporting))
|
||||
{
|
||||
pthread_cond_destroy(&_condition);
|
||||
[self release];
|
||||
|
@ -203,18 +278,17 @@ NSLOCKING_METHODS
|
|||
return self;
|
||||
}
|
||||
|
||||
- (void) finalize
|
||||
MLOCK
|
||||
MLOCKBEFOREDATE
|
||||
MNAME
|
||||
|
||||
- (void) signal
|
||||
{
|
||||
pthread_cond_destroy(&_condition);
|
||||
pthread_mutex_destroy(&_mutex);
|
||||
pthread_cond_signal(&_condition);
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[self finalize];
|
||||
[_name release];
|
||||
[super dealloc];
|
||||
}
|
||||
MTRYLOCK
|
||||
MUNLOCK
|
||||
|
||||
- (void) wait
|
||||
{
|
||||
|
@ -235,20 +309,27 @@ NSLOCKING_METHODS
|
|||
return (0 == pthread_cond_timedwait(&_condition, &_mutex, &timeout));
|
||||
}
|
||||
|
||||
- (void) signal
|
||||
{
|
||||
pthread_cond_signal(&_condition);
|
||||
}
|
||||
|
||||
- (void) broadcast
|
||||
{
|
||||
pthread_cond_broadcast(&_condition);
|
||||
}
|
||||
|
||||
NSLOCKING_METHODS
|
||||
@end
|
||||
|
||||
@implementation NSConditionLock
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
[NSLock class]; // Ensure mutex attributes are set up.
|
||||
}
|
||||
|
||||
- (NSInteger) condition
|
||||
{
|
||||
return _condition_value;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[_name release];
|
||||
[_condition release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
return [self initWithCondition: 0];
|
||||
|
@ -269,16 +350,14 @@ NSLOCKING_METHODS
|
|||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
- (void) lock
|
||||
{
|
||||
[_name release];
|
||||
[_condition release];
|
||||
[super dealloc];
|
||||
[_condition lock];
|
||||
}
|
||||
|
||||
- (NSInteger) condition
|
||||
- (BOOL) lockBeforeDate: (NSDate*)limit
|
||||
{
|
||||
return _condition_value;
|
||||
return [_condition lockBeforeDate: limit];
|
||||
}
|
||||
|
||||
- (void) lockWhenCondition: (NSInteger)value
|
||||
|
@ -290,24 +369,6 @@ NSLOCKING_METHODS
|
|||
}
|
||||
}
|
||||
|
||||
- (void) unlockWithCondition: (NSInteger)value
|
||||
{
|
||||
_condition_value = value;
|
||||
[_condition broadcast];
|
||||
[_condition unlock];
|
||||
}
|
||||
|
||||
- (BOOL) tryLockWhenCondition: (NSInteger)value
|
||||
{
|
||||
return [self lockWhenCondition: value
|
||||
beforeDate: [NSDate date]];
|
||||
}
|
||||
|
||||
- (BOOL) lockBeforeDate: (NSDate*)limit
|
||||
{
|
||||
return [_condition lockBeforeDate: limit];
|
||||
}
|
||||
|
||||
- (BOOL) lockWhenCondition: (NSInteger)condition_to_meet
|
||||
beforeDate: (NSDate*)limitDate
|
||||
{
|
||||
|
@ -324,11 +385,17 @@ NSLOCKING_METHODS
|
|||
return NO;
|
||||
}
|
||||
|
||||
// NSLocking methods. These aren't instantiated with the macro as they are
|
||||
// delegated to the NSCondition.
|
||||
- (void) lock
|
||||
MNAME
|
||||
|
||||
- (BOOL) tryLock
|
||||
{
|
||||
[_condition lock];
|
||||
return [_condition tryLock];
|
||||
}
|
||||
|
||||
- (BOOL) tryLockWhenCondition: (NSInteger)value
|
||||
{
|
||||
return [self lockWhenCondition: value
|
||||
beforeDate: [NSDate date]];
|
||||
}
|
||||
|
||||
- (void) unlock
|
||||
|
@ -336,10 +403,11 @@ NSLOCKING_METHODS
|
|||
[_condition unlock];
|
||||
}
|
||||
|
||||
- (BOOL) tryLock
|
||||
- (void) unlockWithCondition: (NSInteger)value
|
||||
{
|
||||
return [_condition tryLock];
|
||||
_condition_value = value;
|
||||
[_condition broadcast];
|
||||
[_condition unlock];
|
||||
}
|
||||
|
||||
NAME_METHODS
|
||||
@end
|
||||
|
|
Loading…
Reference in a new issue