Locking simplifications

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@39958 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
rfm 2016-07-02 18:56:02 +00:00
parent 1213e12424
commit 6713bb48d6
3 changed files with 29 additions and 40 deletions

View file

@ -1,3 +1,10 @@
2016-07-02 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSKeyValueObserving.m: Remove some unnecessary locking
* Source/NSOperation.m: Simplify handling of finishing of operation
to avoid occasional deadlock if an operation finishes in one thread
while in another thread we are waiting for it.
2016-07-01 Richard Frith-Macdonald <rfm@gnu.org>
* Source/GSICUString.m: For immutable strings, cache the string

View file

@ -1370,7 +1370,7 @@ cifframe_callback(ffi_cif *cif, void *retp, void **args, void *user)
[super dealloc];
}
- (void) observeValueForKeyPath: (NSString *)keyPath
- (void) oberveValueForKeyPath: (NSString *)keyPath
ofObject: (id)anObject
change: (NSDictionary *)change
context: (void *)context
@ -1533,10 +1533,8 @@ cifframe_callback(ffi_cif *cif, void *retp, void **args, void *user)
- (void) removeObserver: (NSObject*)anObserver forKeyPath: (NSString*)aPath
{
GSKVOInfo *info;
id forwarder;
id forwarder;
setup();
[kvoLock lock];
/*
* Get the observation information and remove this observation.
*/
@ -1553,7 +1551,6 @@ cifframe_callback(ffi_cif *cif, void *retp, void **args, void *user)
IF_NO_GC(AUTORELEASE(info);)
[self setObservationInfo: nil];
}
[kvoLock unlock];
if ([aPath rangeOfString:@"."].location != NSNotFound)
[forwarder finalize];
}

View file

@ -201,6 +201,8 @@ static NSArray *empty = nil;
{
NSOperation *op;
[self removeObserver: self
forKeyPath: @"isFinished"];
while ((op = [internal->dependencies lastObject]) != nil)
{
[self removeDependency: op];
@ -239,6 +241,11 @@ static NSArray *empty = nil;
internal->threadPriority = 0.5;
internal->ready = YES;
internal->lock = [NSRecursiveLock new];
internal->cond = [[NSConditionLock alloc] initWithCondition: 0];
[self addObserver: self
forKeyPath: @"isFinished"
options: NSKeyValueObservingOptionNew
context: NULL];
}
return self;
}
@ -280,13 +287,6 @@ static NSArray *empty = nil;
{
[internal->lock lock];
/* We only observe isFinished changes, and we can remove self as an
* observer once we know the operation has finished since it can never
* become unfinished.
*/
[object removeObserver: self
forKeyPath: @"isFinished"];
if (object == self)
{
/* We have finished and need to unlock the condition lock so that
@ -294,8 +294,18 @@ static NSArray *empty = nil;
*/
[internal->cond lock];
[internal->cond unlockWithCondition: 1];
[internal->lock unlock];
return;
}
else if (NO == internal->ready)
/* We only observe isFinished changes, and we can remove self as an
* observer once we know the operation has finished since it can never
* become unfinished.
*/
[object removeObserver: self
forKeyPath: @"isFinished"];
if (NO == internal->ready)
{
NSEnumerator *en;
NSOperation *op;
@ -482,33 +492,8 @@ static NSArray *empty = nil;
- (void) waitUntilFinished
{
if (NO == [self isFinished])
{
[internal->lock lock];
if (nil == internal->cond)
{
/* Set up condition to wait on and observer to unblock.
*/
internal->cond = [[NSConditionLock alloc] initWithCondition: 0];
[self addObserver: self
forKeyPath: @"isFinished"
options: NSKeyValueObservingOptionNew
context: NULL];
/* Some other thread could have marked us as finished while we
* were setting up ... so we can fake the observation if needed.
*/
if (YES == [self isFinished])
{
[self observeValueForKeyPath: @"isFinished"
ofObject: self
change: nil
context: nil];
}
}
[internal->lock unlock];
[internal->cond lockWhenCondition: 1]; // Wait for finish
[internal->cond unlockWithCondition: 1]; // Signal any other watchers
}
[internal->cond lockWhenCondition: 1]; // Wait for finish
[internal->cond unlockWithCondition: 1]; // Signal any other watchers
}
@end