mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-30 16:30:41 +00:00
* Source/NSUserDefaults.m: Changes to bulletproof NSUserDefaults from
deadlocks when it is accessed by more than one thread. Patch applied by: Gregory Casamento <greg.casamento@gmail.com> git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@28500 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
da568f9a9b
commit
04bd61ab32
2 changed files with 796 additions and 569 deletions
|
@ -1,3 +1,9 @@
|
|||
2009-08-21 Doug Simons <dpsimons@testplant.com>
|
||||
|
||||
* Source/NSUserDefaults.m: Changes to bulletproof NSUserDefaults from
|
||||
deadlocks when it is accessed by more than one thread.
|
||||
Patch applied by: Gregory Casamento <greg.casamento@gmail.com>
|
||||
|
||||
2009-08-19 Eric Wasylishen <ewasylishen@gmail.com>
|
||||
|
||||
* Source/Additions/GSObjCRuntime.m:
|
||||
|
|
|
@ -305,6 +305,8 @@ static BOOL setSharedDefaults = NO; /* Flag to prevent infinite recursion */
|
|||
+ (void) resetStandardUserDefaults
|
||||
{
|
||||
[classLock lock];
|
||||
NS_DURING
|
||||
{
|
||||
if (sharedDefaults != nil)
|
||||
{
|
||||
NSDictionary *regDefs;
|
||||
|
@ -338,6 +340,13 @@ static BOOL setSharedDefaults = NO; /* Flag to prevent infinite recursion */
|
|||
}
|
||||
[classLock unlock];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[classLock unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
}
|
||||
|
||||
/* Create a locale dictionary when we have absolutely no information
|
||||
about the locale. This method should go away, since it will never
|
||||
|
@ -492,6 +501,8 @@ static BOOL setSharedDefaults = NO; /* Flag to prevent infinite recursion */
|
|||
}
|
||||
setSharedDefaults = YES;
|
||||
|
||||
NS_DURING
|
||||
{
|
||||
// Create new sharedDefaults (NOTE: Not added to the autorelease pool!)
|
||||
#if defined(__MINGW32__)
|
||||
{
|
||||
|
@ -514,7 +525,7 @@ static BOOL setSharedDefaults = NO; /* Flag to prevent infinite recursion */
|
|||
{
|
||||
NSLog(@"WARNING - unable to create shared user defaults!\n");
|
||||
[classLock unlock];
|
||||
return nil;
|
||||
NS_VALRETURN(nil);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -668,12 +679,19 @@ static BOOL setSharedDefaults = NO; /* Flag to prevent infinite recursion */
|
|||
IF_NO_GC([sharedDefaults retain];)
|
||||
updateCache(sharedDefaults);
|
||||
[classLock unlock];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[classLock unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
return AUTORELEASE(sharedDefaults);
|
||||
}
|
||||
|
||||
+ (NSArray*) userLanguages
|
||||
{
|
||||
NSArray *result;
|
||||
NSArray *result = nil;
|
||||
|
||||
/*
|
||||
* Calling +standardUserDefaults and +userLanguages is horribly interrelated.
|
||||
|
@ -701,6 +719,8 @@ static BOOL setSharedDefaults = NO; /* Flag to prevent infinite recursion */
|
|||
*/
|
||||
|
||||
[classLock lock];
|
||||
NS_DURING
|
||||
{
|
||||
if (invalidatedLanguages == YES)
|
||||
{
|
||||
invalidatedLanguages = NO;
|
||||
|
@ -779,6 +799,13 @@ static BOOL setSharedDefaults = NO; /* Flag to prevent infinite recursion */
|
|||
}
|
||||
result = RETAIN(userLanguages);
|
||||
[classLock unlock];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[classLock unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
return AUTORELEASE(result);
|
||||
}
|
||||
|
||||
|
@ -937,14 +964,23 @@ static BOOL setSharedDefaults = NO; /* Flag to prevent infinite recursion */
|
|||
|
||||
- (NSString*) description
|
||||
{
|
||||
NSMutableString *desc;
|
||||
NSMutableString *desc = nil;
|
||||
|
||||
[_lock lock];
|
||||
NS_DURING
|
||||
{
|
||||
desc = [NSMutableString stringWithFormat: @"%@", [super description]];
|
||||
[desc appendFormat: @" SearchList: %@", _searchList];
|
||||
[desc appendFormat: @" Persistant: %@", _persDomains];
|
||||
[desc appendFormat: @" Temporary: %@", _tempDomains];
|
||||
[_lock unlock];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[_lock unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
return desc;
|
||||
}
|
||||
|
||||
|
@ -958,6 +994,8 @@ static BOOL setSharedDefaults = NO; /* Flag to prevent infinite recursion */
|
|||
format: @"attempt to add suite with nil name"];
|
||||
}
|
||||
[_lock lock];
|
||||
NS_DURING
|
||||
{
|
||||
DESTROY(_dictionaryRep);
|
||||
if (self == sharedDefaults) invalidatedLanguages = YES;
|
||||
[_searchList removeObject: aName];
|
||||
|
@ -966,6 +1004,13 @@ static BOOL setSharedDefaults = NO; /* Flag to prevent infinite recursion */
|
|||
aName = [aName copy];
|
||||
[_searchList insertObject: aName atIndex: index];
|
||||
[_lock unlock];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[_lock unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
RELEASE(aName);
|
||||
}
|
||||
|
||||
|
@ -1038,12 +1083,14 @@ static BOOL setSharedDefaults = NO; /* Flag to prevent infinite recursion */
|
|||
{
|
||||
NSEnumerator *enumerator;
|
||||
IMP nImp;
|
||||
id object;
|
||||
id object = nil;
|
||||
id dN;
|
||||
IMP pImp;
|
||||
IMP tImp;
|
||||
|
||||
[_lock lock];
|
||||
NS_DURING
|
||||
{
|
||||
enumerator = [_searchList objectEnumerator];
|
||||
nImp = [enumerator methodForSelector: nextObjectSel];
|
||||
object = nil;
|
||||
|
@ -1063,6 +1110,13 @@ static BOOL setSharedDefaults = NO; /* Flag to prevent infinite recursion */
|
|||
}
|
||||
IF_NO_GC([object retain];)
|
||||
[_lock unlock];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[_lock unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
return AUTORELEASE(object);
|
||||
}
|
||||
|
||||
|
@ -1071,6 +1125,8 @@ static BOOL setSharedDefaults = NO; /* Flag to prevent infinite recursion */
|
|||
id obj;
|
||||
|
||||
[_lock lock];
|
||||
NS_DURING
|
||||
{
|
||||
obj = [_persDomains objectForKey: processName];
|
||||
obj = [(NSDictionary*)obj objectForKey: defaultName];
|
||||
if (obj != nil)
|
||||
|
@ -1092,6 +1148,13 @@ static BOOL setSharedDefaults = NO; /* Flag to prevent infinite recursion */
|
|||
}
|
||||
[_lock unlock];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[_lock unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
}
|
||||
|
||||
- (void) setBool: (BOOL)value forKey: (NSString*)defaultName
|
||||
{
|
||||
|
@ -1197,6 +1260,8 @@ static BOOL isPlistObject(id o)
|
|||
|
||||
value = [value copy];
|
||||
[_lock lock];
|
||||
NS_DURING
|
||||
{
|
||||
obj = [_persDomains objectForKey: processName];
|
||||
if ([obj isKindOfClass: NSMutableDictionaryClass] == YES)
|
||||
{
|
||||
|
@ -1211,6 +1276,13 @@ static BOOL isPlistObject(id o)
|
|||
[dict setObject: value forKey: defaultName];
|
||||
[self __changePersistentDomain: processName];
|
||||
[_lock unlock];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[_lock unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
RELEASE(value);
|
||||
}
|
||||
|
||||
|
@ -1251,47 +1323,85 @@ static BOOL isPlistObject(id o)
|
|||
|
||||
- (NSArray*) searchList
|
||||
{
|
||||
NSArray *copy;
|
||||
NSArray *copy = nil;
|
||||
|
||||
[_lock lock];
|
||||
NS_DURING
|
||||
{
|
||||
copy = [_searchList copy];
|
||||
[_lock unlock];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[_lock unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
return AUTORELEASE(copy);
|
||||
}
|
||||
|
||||
- (void) setSearchList: (NSArray*)newList
|
||||
{
|
||||
[_lock lock];
|
||||
NS_DURING
|
||||
{
|
||||
DESTROY(_dictionaryRep);
|
||||
if (self == sharedDefaults) invalidatedLanguages = YES;
|
||||
RELEASE(_searchList);
|
||||
_searchList = [newList mutableCopy];
|
||||
[_lock unlock];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[_lock unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
}
|
||||
|
||||
- (NSDictionary*) persistentDomainForName: (NSString*)domainName
|
||||
{
|
||||
NSDictionary *copy;
|
||||
NSDictionary *copy = nil;
|
||||
|
||||
[_lock lock];
|
||||
NS_DURING
|
||||
{
|
||||
copy = [[_persDomains objectForKey: domainName] copy];
|
||||
[_lock unlock];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[_lock unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
return AUTORELEASE(copy);
|
||||
}
|
||||
|
||||
- (NSArray*) persistentDomainNames
|
||||
{
|
||||
NSArray *keys;
|
||||
NSArray *keys = nil;
|
||||
|
||||
[_lock lock];
|
||||
NS_DURING
|
||||
{
|
||||
keys = [_persDomains allKeys];
|
||||
[_lock unlock];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[_lock unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
return keys;
|
||||
}
|
||||
|
||||
- (void) removePersistentDomainForName: (NSString*)domainName
|
||||
{
|
||||
[_lock lock];
|
||||
NS_DURING
|
||||
{
|
||||
if ([_persDomains objectForKey: domainName])
|
||||
{
|
||||
[_persDomains removeObjectForKey: domainName];
|
||||
|
@ -1299,6 +1409,13 @@ static BOOL isPlistObject(id o)
|
|||
}
|
||||
[_lock unlock];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[_lock unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
}
|
||||
|
||||
- (void) setPersistentDomain: (NSDictionary*)domain
|
||||
forName: (NSString*)domainName
|
||||
|
@ -1306,10 +1423,11 @@ static BOOL isPlistObject(id o)
|
|||
NSDictionary *dict;
|
||||
|
||||
[_lock lock];
|
||||
NS_DURING
|
||||
{
|
||||
dict = [_tempDomains objectForKey: domainName];
|
||||
if (dict != nil)
|
||||
{
|
||||
[_lock unlock];
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"a volatile domain called %@ exists", domainName];
|
||||
}
|
||||
|
@ -1319,6 +1437,13 @@ static BOOL isPlistObject(id o)
|
|||
[self __changePersistentDomain: domainName];
|
||||
[_lock unlock];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[_lock unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
}
|
||||
|
||||
- (id) valueForKey: (NSString*)aKey
|
||||
{
|
||||
|
@ -1571,7 +1696,8 @@ NSLog(@"Creating empty user defaults database");
|
|||
BOOL wasLocked;
|
||||
|
||||
[_lock lock];
|
||||
|
||||
NS_DURING
|
||||
{
|
||||
/*
|
||||
* If we haven't changed anything, we only need to synchronise if
|
||||
* the on-disk database has been changed by someone else.
|
||||
|
@ -1582,7 +1708,7 @@ NSLog(@"Creating empty user defaults database");
|
|||
if ([self wantToReadDefaultsSince: _lastSync] == NO)
|
||||
{
|
||||
[_lock unlock];
|
||||
return YES;
|
||||
NS_VALRETURN(YES);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1595,7 +1721,7 @@ NSLog(@"Creating empty user defaults database");
|
|||
if ([self lockDefaultsFile: &wasLocked] == NO)
|
||||
{
|
||||
[_lock unlock];
|
||||
return NO;
|
||||
NS_VALRETURN(NO);
|
||||
}
|
||||
|
||||
newDict = [self readDefaults];
|
||||
|
@ -1607,7 +1733,7 @@ NSLog(@"Creating empty user defaults database");
|
|||
[self unlockDefaultsFile];
|
||||
}
|
||||
[_lock unlock];
|
||||
return NO;
|
||||
NS_VALRETURN(NO);
|
||||
}
|
||||
|
||||
if (_changedDomains != nil)
|
||||
|
@ -1638,7 +1764,7 @@ NSLog(@"Creating empty user defaults database");
|
|||
[self unlockDefaultsFile];
|
||||
}
|
||||
[_lock unlock];
|
||||
return NO;
|
||||
NS_VALRETURN(NO);
|
||||
}
|
||||
ASSIGN(_lastSync, [NSDateClass date]);
|
||||
}
|
||||
|
@ -1660,6 +1786,13 @@ NSLog(@"Creating empty user defaults database");
|
|||
[self unlockDefaultsFile];
|
||||
}
|
||||
[_lock unlock];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[_lock unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
@ -1667,11 +1800,20 @@ NSLog(@"Creating empty user defaults database");
|
|||
- (void) removeVolatileDomainForName: (NSString*)domainName
|
||||
{
|
||||
[_lock lock];
|
||||
NS_DURING
|
||||
{
|
||||
DESTROY(_dictionaryRep);
|
||||
if (self == sharedDefaults) invalidatedLanguages = YES;
|
||||
[_tempDomains removeObjectForKey: domainName];
|
||||
[_lock unlock];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[_lock unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
}
|
||||
|
||||
- (void) setVolatileDomain: (NSDictionary*)domain
|
||||
forName: (NSString*)domainName
|
||||
|
@ -1679,17 +1821,17 @@ NSLog(@"Creating empty user defaults database");
|
|||
id dict;
|
||||
|
||||
[_lock lock];
|
||||
NS_DURING
|
||||
{
|
||||
dict = [_persDomains objectForKey: domainName];
|
||||
if (dict != nil)
|
||||
{
|
||||
[_lock unlock];
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"a persistent domain called %@ exists", domainName];
|
||||
}
|
||||
dict = [_tempDomains objectForKey: domainName];
|
||||
if (dict != nil)
|
||||
{
|
||||
[_lock unlock];
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"the volatile domain %@ already exists", domainName];
|
||||
}
|
||||
|
@ -1701,32 +1843,59 @@ NSLog(@"Creating empty user defaults database");
|
|||
RELEASE(domain);
|
||||
[_lock unlock];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[_lock unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
}
|
||||
|
||||
- (NSDictionary*) volatileDomainForName: (NSString*)domainName
|
||||
{
|
||||
NSDictionary *copy;
|
||||
NSDictionary *copy = nil;
|
||||
|
||||
[_lock lock];
|
||||
NS_DURING
|
||||
{
|
||||
copy = [[_tempDomains objectForKey: domainName] copy];
|
||||
[_lock unlock];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[_lock unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
return AUTORELEASE(copy);
|
||||
}
|
||||
|
||||
- (NSArray*) volatileDomainNames
|
||||
{
|
||||
NSArray *keys;
|
||||
NSArray *keys = nil;
|
||||
|
||||
[_lock lock];
|
||||
NS_DURING
|
||||
{
|
||||
keys = [_tempDomains allKeys];
|
||||
[_lock unlock];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[_lock unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
return keys;
|
||||
}
|
||||
|
||||
- (NSDictionary*) dictionaryRepresentation
|
||||
{
|
||||
NSDictionary *rep;
|
||||
NSDictionary *rep = nil;
|
||||
|
||||
[_lock lock];
|
||||
NS_DURING
|
||||
{
|
||||
if (_dictionaryRep == nil)
|
||||
{
|
||||
NSEnumerator *enumerator;
|
||||
|
@ -1760,6 +1929,13 @@ NSLog(@"Creating empty user defaults database");
|
|||
}
|
||||
rep = RETAIN(_dictionaryRep);
|
||||
[_lock unlock];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[_lock unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
return AUTORELEASE(rep);
|
||||
}
|
||||
|
||||
|
@ -1768,6 +1944,8 @@ NSLog(@"Creating empty user defaults database");
|
|||
NSMutableDictionary *regDefs;
|
||||
|
||||
[_lock lock];
|
||||
NS_DURING
|
||||
{
|
||||
regDefs = [_tempDomains objectForKey: NSRegistrationDomain];
|
||||
if (regDefs == nil)
|
||||
{
|
||||
|
@ -1780,6 +1958,13 @@ NSLog(@"Creating empty user defaults database");
|
|||
[regDefs addEntriesFromDictionary: newVals];
|
||||
[_lock unlock];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[_lock unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
}
|
||||
|
||||
- (void) removeSuiteNamed: (NSString*)aName
|
||||
{
|
||||
|
@ -1789,11 +1974,20 @@ NSLog(@"Creating empty user defaults database");
|
|||
format: @"attempt to remove suite with nil name"];
|
||||
}
|
||||
[_lock lock];
|
||||
NS_DURING
|
||||
{
|
||||
DESTROY(_dictionaryRep);
|
||||
if (self == sharedDefaults) invalidatedLanguages = YES;
|
||||
[_searchList removeObject: aName];
|
||||
[_lock unlock];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[_lock unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
*** Accessing the User Defaults database
|
||||
|
@ -1803,11 +1997,13 @@ NSLog(@"Creating empty user defaults database");
|
|||
{
|
||||
NSArray *args;
|
||||
NSEnumerator *enumerator;
|
||||
NSMutableDictionary *argDict;
|
||||
NSMutableDictionary *argDict = nil;
|
||||
BOOL done;
|
||||
id key, val;
|
||||
|
||||
[_lock lock];
|
||||
NS_DURING
|
||||
{
|
||||
args = [[NSProcessInfo processInfo] arguments];
|
||||
enumerator = [args objectEnumerator];
|
||||
argDict = [NSMutableDictionaryClass dictionaryWithCapacity: 2];
|
||||
|
@ -1885,12 +2081,21 @@ NSLog(@"Creating empty user defaults database");
|
|||
done = ((key = [enumerator nextObject]) == nil);
|
||||
}
|
||||
[_lock unlock];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[_lock unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
return argDict;
|
||||
}
|
||||
|
||||
- (void) __changePersistentDomain: (NSString*)domainName
|
||||
{
|
||||
[_lock lock];
|
||||
NS_DURING
|
||||
{
|
||||
DESTROY(_dictionaryRep);
|
||||
if (self == sharedDefaults) invalidatedLanguages = YES;
|
||||
if (_changedDomains == nil)
|
||||
|
@ -1908,6 +2113,13 @@ NSLog(@"Creating empty user defaults database");
|
|||
}
|
||||
[_lock unlock];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[_lock unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
}
|
||||
@end
|
||||
|
||||
BOOL
|
||||
|
@ -1928,20 +2140,29 @@ GSPrivateDefaultsFlag(GSUserDefaultFlagType type)
|
|||
*/
|
||||
NSDictionary *GSPrivateDefaultLocale()
|
||||
{
|
||||
NSDictionary *locale;
|
||||
NSUserDefaults *defs;
|
||||
NSDictionary *locale = nil;
|
||||
NSUserDefaults *defs = nil;
|
||||
|
||||
if (classLock == nil)
|
||||
{
|
||||
[NSUserDefaults standardUserDefaults];
|
||||
}
|
||||
[classLock lock];
|
||||
NS_DURING
|
||||
{
|
||||
if (sharedDefaults == nil)
|
||||
{
|
||||
[NSUserDefaults standardUserDefaults];
|
||||
}
|
||||
defs = [sharedDefaults retain];
|
||||
[classLock unlock];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[classLock unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
locale = [defs dictionaryRepresentation];
|
||||
[defs release];
|
||||
return locale;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue