mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-30 00:11:26 +00:00
locking updates (fine grained locking rather than global lock)
This commit is contained in:
parent
430629b097
commit
241e2a47ca
24 changed files with 176 additions and 732 deletions
|
@ -39,7 +39,6 @@ Additions_OBJC_FILES =\
|
|||
GCObject.m \
|
||||
GCArray.m \
|
||||
GCDictionary.m \
|
||||
GSLock.m \
|
||||
GSMime.m \
|
||||
GSXML.m \
|
||||
GSFunctions.m \
|
||||
|
@ -53,7 +52,6 @@ Additions_OBJC_FILES =\
|
|||
NSError+GNUstepBase.m \
|
||||
NSHashTable+GNUstepBase.m \
|
||||
NSFileHandle+GNUstepBase.m \
|
||||
NSLock+GNUstepBase.m \
|
||||
NSMutableString+GNUstepBase.m \
|
||||
NSNumber+GNUstepBase.m \
|
||||
NSObject+GNUstepBase.m \
|
||||
|
|
|
@ -1,305 +0,0 @@
|
|||
/** Implementation for GSLock
|
||||
|
||||
Copyright (C) 2003 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Richard Frith-Macdonald <rfm@gnu.org>
|
||||
Date: October 2003
|
||||
|
||||
This file is part of the GNUstep Base Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02111 USA.
|
||||
*/
|
||||
|
||||
#import "common.h"
|
||||
#define EXPOSE_GSLock_IVARS 1
|
||||
#import "Foundation/NSException.h"
|
||||
#import "Foundation/NSLock.h"
|
||||
#import "Foundation/NSNotification.h"
|
||||
#import "Foundation/NSThread.h"
|
||||
#import "GNUstepBase/GSLock.h"
|
||||
|
||||
/**
|
||||
* This implements a class which, when used in single-threaded mode,
|
||||
* acts like a lock while avoiding the overheads of actually using
|
||||
* a real lock. However, when the programm in which the class is
|
||||
* used becomes multi-threaded, all instances of this class transform
|
||||
* themselves into real locks in the correct state (locked/unlocked)
|
||||
* corresponding to whether the lazy lock was locked or not at the
|
||||
* point where the program became multi threadeed.<br />
|
||||
* Use of this class allows you to write thread-safe code which avoids
|
||||
* locking inefficiencies when used in a single threaded application,
|
||||
* without having to worry about dealing with the issue yourself.
|
||||
*/
|
||||
@implementation GSLazyLock
|
||||
|
||||
/**
|
||||
* Do not use this method ... it is used internally to handle the transition
|
||||
* from a single threaded system to a multi threaded one.
|
||||
*/
|
||||
- (void) _becomeThreaded: (NSNotification*)n
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver: self];
|
||||
object_setClass(self, [NSLock class]);
|
||||
if (locked == YES)
|
||||
{
|
||||
if ([self tryLock] == NO)
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"Failed to lock mutex"];
|
||||
}
|
||||
}
|
||||
/*
|
||||
* While we have changed 'isa', it's possible someone might have
|
||||
* cached our old method implementations, so we set the 'locked'
|
||||
* ivar to a value to tell the old method implementations to use
|
||||
* the superclass implementatins.
|
||||
*/
|
||||
locked = -1;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver: self];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if ([NSThread isMultiThreaded] == YES)
|
||||
{
|
||||
DESTROY(self);
|
||||
return (GSLazyLock*)[NSLock new];
|
||||
}
|
||||
else if (self != nil)
|
||||
{
|
||||
locked = NO;
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver: self
|
||||
selector: @selector(_becomeThreaded:)
|
||||
name: NSWillBecomeMultiThreadedNotification
|
||||
object: nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) lock
|
||||
{
|
||||
if (locked == NO)
|
||||
{
|
||||
locked = YES;
|
||||
}
|
||||
else if (locked == YES)
|
||||
{
|
||||
[NSException raise: NSGenericException
|
||||
format: @"lock: when already locked"];
|
||||
}
|
||||
else
|
||||
{
|
||||
[super lock];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL) lockBeforeDate: (NSDate*)limit
|
||||
{
|
||||
BOOL result;
|
||||
|
||||
if (locked == NO)
|
||||
{
|
||||
result = YES;
|
||||
}
|
||||
else if (locked == YES)
|
||||
{
|
||||
result = NO;
|
||||
[NSException raise: NSGenericException
|
||||
format: @"lock: when already locked"];
|
||||
}
|
||||
else
|
||||
{
|
||||
result = [super lockBeforeDate: limit];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
- (BOOL) tryLock
|
||||
{
|
||||
if (locked == NO)
|
||||
{
|
||||
locked = YES;
|
||||
return YES;
|
||||
}
|
||||
else if (locked == YES)
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
return [super tryLock];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) unlock
|
||||
{
|
||||
if (locked == YES)
|
||||
{
|
||||
locked = NO;
|
||||
}
|
||||
else if (locked == NO)
|
||||
{
|
||||
[NSException raise: NSGenericException
|
||||
format: @"unlock: when already unlocked"];
|
||||
}
|
||||
else
|
||||
{
|
||||
[super unlock];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This implements a class which, when used in single-threaded mode,
|
||||
* acts like a recursive lock while avoiding the overheads of using
|
||||
* a real lock. However, when the programm in which the class is
|
||||
* used becomes multi-threaded, all instances of this class transform
|
||||
* themselves into real locks in the correct state (locked/unlocked)
|
||||
* corresponding to whether the lazy recursive lock was locked or not
|
||||
* at the point where the program became multi threadeed.<br />
|
||||
* Use of this class allows you to write thread-safe code which avoids
|
||||
* locking inefficiencies when used in a single threaded application,
|
||||
* without having to worry about dealing with the issue yourself.
|
||||
*/
|
||||
@implementation GSLazyRecursiveLock
|
||||
|
||||
/**
|
||||
* Do not use this method ... it is used internally to handle the transition
|
||||
* from a single threaded system to a multi threaded one.
|
||||
*/
|
||||
- (void) _becomeThreaded: (NSNotification*)n
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver: self];
|
||||
object_setClass(self, [NSRecursiveLock class]);
|
||||
while (counter-- > 0)
|
||||
{
|
||||
if ([self tryLock] == NO)
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"Failed to lock mutex"];
|
||||
}
|
||||
}
|
||||
/*
|
||||
* While we have changed 'isa', it's possible someone might have
|
||||
* cached our old method implementations, so we set the 'locked'
|
||||
* ivar to a value to tell the old method implementations to use
|
||||
* the superclass implementatins.
|
||||
*/
|
||||
counter = -1;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver: self];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if ([NSThread isMultiThreaded] == YES)
|
||||
{
|
||||
DESTROY(self);
|
||||
return (GSLazyRecursiveLock*)[NSRecursiveLock new];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (self != nil)
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver: self
|
||||
selector: @selector(_becomeThreaded:)
|
||||
name: NSWillBecomeMultiThreadedNotification
|
||||
object: nil];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) lock
|
||||
{
|
||||
if (counter >= 0)
|
||||
{
|
||||
counter++;
|
||||
}
|
||||
else
|
||||
{
|
||||
[super lock];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL) lockBeforeDate: (NSDate*)limit
|
||||
{
|
||||
if (counter >= 0)
|
||||
{
|
||||
counter++;
|
||||
return YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
return [super lockBeforeDate: limit];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL) tryLock
|
||||
{
|
||||
if (counter >= 0)
|
||||
{
|
||||
counter++;
|
||||
return YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
return [super tryLock];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) unlock
|
||||
{
|
||||
if (counter > 0)
|
||||
{
|
||||
counter--;
|
||||
}
|
||||
else if (counter == 0)
|
||||
{
|
||||
[NSException raise: NSGenericException
|
||||
format: @"unlock: failed to unlock mutex"];
|
||||
}
|
||||
else
|
||||
{
|
||||
[super unlock];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/* Global lock to be used by classes when operating on any global
|
||||
data that invoke other methods which also access global; thus,
|
||||
creating the potential for deadlock. */
|
||||
NSRecursiveLock *gnustep_global_lock = nil;
|
||||
|
|
@ -48,7 +48,7 @@ strerror_r(int eno, char *buf, int len)
|
|||
const char *ptr;
|
||||
int result;
|
||||
|
||||
[gnustep_global_lock lock];
|
||||
[GSPrivateGlobalLock() lock];
|
||||
ptr = strerror(eno);
|
||||
if (ptr == 0)
|
||||
{
|
||||
|
@ -61,7 +61,7 @@ strerror_r(int eno, char *buf, int len)
|
|||
result = 0;
|
||||
}
|
||||
buf[len - 1] = '\0';
|
||||
[gnustep_global_lock unlock];
|
||||
[GSPrivateGlobalLock() unlock];
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
|
|
|
@ -1,100 +0,0 @@
|
|||
/* Implementation of extension methods to base additions
|
||||
|
||||
Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
This file is part of the GNUstep Base Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02111 USA.
|
||||
|
||||
*/
|
||||
#import "common.h"
|
||||
#import "Foundation/NSException.h"
|
||||
#import "GNUstepBase/NSLock+GNUstepBase.h"
|
||||
#import "GNUstepBase/GSLock.h"
|
||||
|
||||
/**
|
||||
* GNUstep specific (non-standard) additions to the NSLock class.
|
||||
*/
|
||||
|
||||
static GSLazyRecursiveLock *local_lock = nil;
|
||||
|
||||
/* This class only exists to provide a thread safe mechanism to
|
||||
initialize local_lock as +initialize is called under a lock in ObjC
|
||||
runtimes. User code should resort to GS_INITIALIZED_LOCK(), which
|
||||
uses the +newLockAt: extension. */
|
||||
|
||||
@interface _GSLockInitializer : NSObject
|
||||
@end
|
||||
@implementation _GSLockInitializer
|
||||
+ (void) initialize
|
||||
{
|
||||
if (local_lock == nil)
|
||||
{
|
||||
/* As we do not know whether creating custom locks may
|
||||
implicitly create other locks, we use a recursive lock. */
|
||||
local_lock = [GSLazyRecursiveLock new];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
static inline id
|
||||
newLockAt(Class self, SEL _cmd, id *location)
|
||||
{
|
||||
if (location == 0)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"'%@' called with nil location",
|
||||
NSStringFromSelector(_cmd)];
|
||||
}
|
||||
|
||||
if (*location == nil)
|
||||
{
|
||||
if (local_lock == nil)
|
||||
{
|
||||
[_GSLockInitializer class];
|
||||
}
|
||||
|
||||
[local_lock lock];
|
||||
|
||||
if (*location == nil)
|
||||
{
|
||||
*location = [[(id)self alloc] init];
|
||||
}
|
||||
|
||||
[local_lock unlock];
|
||||
}
|
||||
|
||||
return *location;
|
||||
}
|
||||
|
||||
|
||||
@implementation NSLock (GNUstepBase)
|
||||
+ (id) newLockAt: (id *)location
|
||||
{
|
||||
return newLockAt(self, _cmd, location);
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation NSRecursiveLock (GNUstepBase)
|
||||
+ (id) newLockAt: (id *)location
|
||||
{
|
||||
return newLockAt(self, _cmd, location);
|
||||
}
|
||||
@end
|
||||
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
*/
|
||||
#import "common.h"
|
||||
#import "GSPThread.h"
|
||||
#import "Foundation/NSArray.h"
|
||||
#import "Foundation/NSException.h"
|
||||
#import "Foundation/NSHashTable.h"
|
||||
|
@ -162,12 +163,14 @@ static inline void setup()
|
|||
{
|
||||
if (nil == exitLock)
|
||||
{
|
||||
[gnustep_global_lock lock];
|
||||
static gs_mutex_t setupLock = GS_MUTEX_INIT_STATIC;
|
||||
|
||||
GS_MUTEX_LOCK(setupLock);
|
||||
if (nil == exitLock)
|
||||
{
|
||||
exitLock = [NSLock new];
|
||||
}
|
||||
[gnustep_global_lock unlock];
|
||||
GS_MUTEX_UNLOCK(setupLock);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3100,7 +3100,7 @@ GSPrivateNativeCStringEncoding()
|
|||
char *old;
|
||||
|
||||
/* Take it from the system locale information. */
|
||||
[gnustep_global_lock lock];
|
||||
[GSPrivateGlobalLock() lock];
|
||||
/* Initialise locale system by setting current locale from
|
||||
* environment and then resetting it. Must be done before
|
||||
* any call to nl_langinfo()
|
||||
|
@ -3111,7 +3111,7 @@ GSPrivateNativeCStringEncoding()
|
|||
}
|
||||
strncpy(encbuf, nl_langinfo(CODESET), sizeof(encbuf)-1);
|
||||
encbuf[sizeof(encbuf)-1] = '\0';
|
||||
[gnustep_global_lock unlock];
|
||||
[GSPrivateGlobalLock() unlock];
|
||||
#else
|
||||
encbuf[0] = '\0';
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue