* 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:
gcasa 2009-08-21 10:30:15 +00:00
parent da568f9a9b
commit 04bd61ab32
2 changed files with 796 additions and 569 deletions

View file

@ -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:

View file

@ -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;