From 72efdaa9a10dba5518c9b8537d029400abed3e1c Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 12 Dec 2008 18:55:12 +0000 Subject: [PATCH] Monotone-Parent: ff27cb5c0c118c485e7cf9d8e62d4428edafdb32 Monotone-Revision: 8373ee4a182606382fcb3aea7864b142db4aaa95 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2008-12-12T18:55:12 Monotone-Branch: ca.inverse.sogo --- SOPE/GDLContentStore/GCSChannelManager.m | 39 ++++++++++++ SOPE/GDLContentStore/GCSFolderManager.m | 77 ++++++++++++++++-------- SoObjects/SOGo/LDAPUserManager.m | 71 ++++++++++++++++------ SoObjects/SOGo/SOGoCache.m | 77 +++++++++++++++++++++--- configure | 18 ++++++ 5 files changed, 231 insertions(+), 51 deletions(-) diff --git a/SOPE/GDLContentStore/GCSChannelManager.m b/SOPE/GDLContentStore/GCSChannelManager.m index 13159677c..17d796bbb 100644 --- a/SOPE/GDLContentStore/GCSChannelManager.m +++ b/SOPE/GDLContentStore/GCSChannelManager.m @@ -23,6 +23,7 @@ #import #import #import +#import #import #import @@ -44,6 +45,10 @@ (eg missing release due to an exception) */ +#if defined(THREADSAFE) +static NSLock *lock; +#endif + @interface GCSChannelHandle : NSObject { @public @@ -82,6 +87,10 @@ static NSTimeInterval ChannelCollectionTimer = 5 * 60; [[ud objectForKey: @"GCSChannelCollectionTimer"] intValue]; if (ChannelCollectionTimer < 1) ChannelCollectionTimer = 5*60; + +#if defined(THREADSAFE) + lock = [NSLock new]; +#endif } + (NSString *) adaptorNameForURLScheme: (NSString *) _scheme @@ -94,8 +103,14 @@ static NSTimeInterval ChannelCollectionTimer = 5 * 60; { static GCSChannelManager *cm = nil; +#if defined(THREADSAFE) + [lock lock]; +#endif if (!cm) cm = [self new]; +#if defined(THREADSAFE) + [lock unlock]; +#endif return cm; } @@ -184,6 +199,9 @@ static NSTimeInterval ChannelCollectionTimer = 5 * 60; { if ((key = [self databaseKeyForURL: _url])) { +#if defined(THREADSAFE) + [lock lock]; +#endif adaptor = [urlToAdaptor objectForKey: key]; if (adaptor) [self debugWithFormat: @"using cached adaptor: %@", adaptor]; @@ -215,6 +233,9 @@ static NSTimeInterval ChannelCollectionTimer = 5 * 60; [urlToAdaptor setObject: adaptor forKey: key]; } +#if defined(THREADSAFE) + [lock unlock]; +#endif } } @@ -295,6 +316,9 @@ static NSTimeInterval ChannelCollectionTimer = 5 * 60; /* look for cached handles */ +#if defined(THREADSAFE) + [lock lock]; +#endif handle = [self findAvailChannelHandleForURL: _url]; if (handle) { @@ -339,6 +363,9 @@ static NSTimeInterval ChannelCollectionTimer = 5 * 60; channel, [_url absoluteString]]; } } +#if defined(THREADSAFE) + [lock unlock]; +#endif return channel; } @@ -347,6 +374,9 @@ static NSTimeInterval ChannelCollectionTimer = 5 * 60; { GCSChannelHandle *handle; +#if defined(THREADSAFE) + [lock lock]; +#endif handle = [self findBusyChannelHandleForChannel: _channel]; if (handle) { @@ -380,6 +410,9 @@ static NSTimeInterval ChannelCollectionTimer = 5 * 60; [_channel release]; } +#if defined(THREADSAFE) + [lock unlock]; +#endif } /* checking for tables */ @@ -428,6 +461,9 @@ static NSTimeInterval ChannelCollectionTimer = 5 * 60; unsigned i, count; GCSChannelHandle *handle; +#if defined(THREADSAFE) + [lock lock]; +#endif count = [availableChannels count]; if (count) { @@ -462,6 +498,9 @@ static NSTimeInterval ChannelCollectionTimer = 5 * 60; [handlesToRemove release]; } +#if defined(THREADSAFE) + [lock unlock]; +#endif } /* debugging */ diff --git a/SOPE/GDLContentStore/GCSFolderManager.m b/SOPE/GDLContentStore/GCSFolderManager.m index 27794a511..ab8f9b52a 100644 --- a/SOPE/GDLContentStore/GCSFolderManager.m +++ b/SOPE/GDLContentStore/GCSFolderManager.m @@ -19,7 +19,23 @@ 02111-1307, USA. */ +#import +#import +#import +#import +#import #import +#import +#import +#import + +#import +#import + +#import +#import +#import +#import #import "GCSFolderManager.h" #import "GCSChannelManager.h" @@ -27,11 +43,6 @@ #import "GCSFolder.h" #import "NSURL+GCS.h" #import "EOAdaptorChannel+GCS.h" -#import "common.h" -#import -#import -#import -#import /* Required database schema: @@ -64,6 +75,10 @@ static NSString *GCSGenericFolderTypeName = @"Container"; static const char *GCSPathColumnPattern = "c_path%i"; static NSCharacterSet *asciiAlphaNumericCS = nil; +#if defined(THREADSAFE) +static NSLock *lock; +#endif + + (void) initialize { NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; @@ -76,6 +91,9 @@ static NSCharacterSet *asciiAlphaNumericCS = nil; debugOn = [ud boolForKey: @"GCSFolderManagerDebugEnabled"]; debugSQLGen = [ud boolForKey: @"GCSFolderManagerSQLDebugEnabled"]; emptyArray = [[NSArray alloc] init]; +#if defined(THREADSAFE) + lock = [NSLock new]; +#endif if (!asciiAlphaNumericCS) { asciiAlphaNumericCS @@ -90,26 +108,34 @@ static NSCharacterSet *asciiAlphaNumericCS = nil; + (id)defaultFolderManager { NSString *s; NSURL *url; - if (fm) return fm; - - s = [[NSUserDefaults standardUserDefaults] stringForKey:@"OCSFolderInfoURL"]; - if ([s length] == 0) { - NSLog(@"ERROR(%s): default 'OCSFolderInfoURL' is not configured.", - __PRETTY_FUNCTION__); - return nil; - } - if ((url = [NSURL URLWithString:s]) == nil) { - NSLog(@"ERROR(%s): default 'OCSFolderInfoURL' is not a valid URL: '%@'", - __PRETTY_FUNCTION__, s); - return nil; - } - if ((fm = [[self alloc] initWithFolderInfoLocation:url]) == nil) { - NSLog(@"ERROR(%s): could not create folder manager with URL: '%@'", - __PRETTY_FUNCTION__, [url absoluteString]); - return nil; - } - - NSLog(@"Note: setup default manager at: %@", url); + +#if defined(THREADSAFE) + [lock lock]; +#endif + if (!fm) + { + s = [[NSUserDefaults standardUserDefaults] stringForKey:@"OCSFolderInfoURL"]; + if ([s length] == 0) { + NSLog(@"ERROR(%s): default 'OCSFolderInfoURL' is not configured.", + __PRETTY_FUNCTION__); + return nil; + } + if ((url = [NSURL URLWithString:s]) == nil) { + NSLog(@"ERROR(%s): default 'OCSFolderInfoURL' is not a valid URL: '%@'", + __PRETTY_FUNCTION__, s); + return nil; + } + if ((fm = [[self alloc] initWithFolderInfoLocation:url]) == nil) { + NSLog(@"ERROR(%s): could not create folder manager with URL: '%@'", + __PRETTY_FUNCTION__, [url absoluteString]); + return nil; + } + NSLog(@"Note: setup default manager at: %@", url); + } +#if defined(THREADSAFE) + [lock unlock]; +#endif + return fm; } @@ -199,6 +225,7 @@ static NSCharacterSet *asciiAlphaNumericCS = nil; ch = [[self channelManager] acquireOpenChannelForURL: [self folderInfoLocation]]; + return ch; } - (void)releaseChannel:(EOAdaptorChannel *)_channel { diff --git a/SoObjects/SOGo/LDAPUserManager.m b/SoObjects/SOGo/LDAPUserManager.m index 7bc07bf8a..bf5ff00ba 100644 --- a/SoObjects/SOGo/LDAPUserManager.m +++ b/SoObjects/SOGo/LDAPUserManager.m @@ -23,6 +23,7 @@ #import #import #import +#import #import #import #import @@ -38,6 +39,10 @@ static NSString *LDAPContactInfoAttribute = nil; static BOOL defaultMailDomainIsConfigured = NO; static BOOL forceImapLoginWithEmail = NO; +#if defined(THREADSAFE) +static NSLock *lock; +#endif + @implementation LDAPUserManager + (void) initialize @@ -64,6 +69,9 @@ static BOOL forceImapLoginWithEmail = NO; } if (!forceImapLoginWithEmail) forceImapLoginWithEmail = [ud boolForKey: @"SOGoForceIMAPLoginWithEmail"]; +#if defined(THREADSAFE) + lock = [NSLock new]; +#endif } + (BOOL) defaultMailDomainIsConfigured @@ -75,8 +83,14 @@ static BOOL forceImapLoginWithEmail = NO; { static id sharedUserManager = nil; +#if defined(THREADSAFE) + [lock lock]; +#endif if (!sharedUserManager) sharedUserManager = [self new]; +#if defined(THREADSAFE) + [lock unlock]; +#endif return sharedUserManager; } @@ -149,16 +163,18 @@ static BOOL forceImapLoginWithEmail = NO; cleanupInterval = 0.0; if (cleanupInterval > 0.0) { - cleanupTimer = [NSTimer scheduledTimerWithTimeInterval: cleanupInterval - target: self - selector: @selector (_cleanupSources) - userInfo: nil - repeats: YES]; + cleanupTimer + = [NSTimer scheduledTimerWithTimeInterval: cleanupInterval + target: self + selector: @selector (_cleanupSources) + userInfo: nil + repeats: YES]; [self logWithFormat: @"cleanup interval set every %f seconds", cleanupInterval]; } else - [self logWithFormat: @"no cleanup interval set: memory usage will grow"]; + [self + logWithFormat: @"no cleanup interval set: memory usage will grow"]; [self _prepareLDAPSourcesWithDefaults: ud]; } @@ -300,6 +316,10 @@ static BOOL forceImapLoginWithEmail = NO; NSMutableDictionary *currentUser; NSString *dictPassword; +#if defined(THREADSAFE) + [lock lock]; +#endif + currentUser = [users objectForKey: login]; dictPassword = [currentUser objectForKey: @"password"]; if (currentUser && dictPassword) @@ -323,6 +343,10 @@ static BOOL forceImapLoginWithEmail = NO; [currentUser setObject: cleanupDate forKey: @"cleanupDate"]; } +#if defined(THREADSAFE) + [lock unlock]; +#endif + return checkOK; } @@ -402,12 +426,18 @@ static BOOL forceImapLoginWithEmail = NO; NSString *key; NSEnumerator *emails; +#if defined(THREADSAFE) + [lock lock]; +#endif key = [newUser objectForKey: @"c_uid"]; if (key) [users setObject: newUser forKey: key]; emails = [[newUser objectForKey: @"emails"] objectEnumerator]; while ((key = [emails nextObject])) [users setObject: newUser forKey: key]; +#if defined(THREADSAFE) + [lock unlock]; +#endif } - (NSDictionary *) contactInfosForUserWithUIDorEmail: (NSString *) uid @@ -420,6 +450,9 @@ static BOOL forceImapLoginWithEmail = NO; { contactInfos = [NSMutableDictionary dictionary]; currentUser = [users objectForKey: uid]; +#if defined(THREADSAFE) + [lock lock]; +#endif if (!([currentUser objectForKey: @"emails"] && [currentUser objectForKey: @"cn"])) { @@ -446,6 +479,9 @@ static BOOL forceImapLoginWithEmail = NO; cleanupDate = [[NSDate date] addTimeInterval: cleanupInterval]; [currentUser setObject: cleanupDate forKey: @"cleanupDate"]; } +#if defined(THREADSAFE) + [lock unlock]; +#endif } else currentUser = nil; @@ -453,18 +489,6 @@ static BOOL forceImapLoginWithEmail = NO; return currentUser; } -- (void) _fillContactsMailRecords: (NSEnumerator *) contacts -{ - NSMutableDictionary *currentContact; - - currentContact = [contacts nextObject]; - while (currentContact) - { - [self _fillContactMailRecords: currentContact]; - currentContact = [contacts nextObject]; - } -} - - (NSArray *) _compactAndCompleteContacts: (NSEnumerator *) contacts { NSMutableDictionary *compactContacts, *returnContact; @@ -517,10 +541,11 @@ static BOOL forceImapLoginWithEmail = NO; [returnContact setObject: infoAttribute forKey: LDAPContactInfoAttribute]; } + [self _fillContactMailRecords: returnContact]; } } + newContacts = [compactContacts allValues]; - [self _fillContactsMailRecords: [newContacts objectEnumerator]]; return newContacts; } @@ -565,6 +590,10 @@ static BOOL forceImapLoginWithEmail = NO; NSDate *now; unsigned int count; +#if defined(THREADSAFE) + [lock lock]; +#endif + now = [NSDate date]; count = 0; @@ -583,6 +612,10 @@ static BOOL forceImapLoginWithEmail = NO; if (count) [self logWithFormat: @"cleaned %d users records from cache", count]; + +#if defined(THREADSAFE) + [lock unlock]; +#endif } @end diff --git a/SoObjects/SOGo/SOGoCache.m b/SoObjects/SOGo/SOGoCache.m index ed9f65611..bbc940c87 100644 --- a/SoObjects/SOGo/SOGoCache.m +++ b/SoObjects/SOGo/SOGoCache.m @@ -25,6 +25,7 @@ #import #import #import +#import #import #import #import @@ -51,8 +52,19 @@ static NSMutableDictionary *s_userSettings = nil; static SOGoCache *sharedCache = nil; +#if defined(THREADSAFE) +static NSLock *lock; +#endif + @implementation SOGoCache +#if defined(THREADSAFE) ++ (void) initialize +{ + lock = [NSLock new]; +} +#endif + + (NSTimeInterval) cleanupInterval { return cleanupInterval; @@ -60,16 +72,28 @@ static SOGoCache *sharedCache = nil; + (SOGoCache *) sharedCache { +#if defined(THREADSAFE) + [lock lock]; +#endif if (!sharedCache) sharedCache = [self new]; +#if defined(THREADSAFE) + [lock unlock]; +#endif return sharedCache; } + (void) killCache { +#if defined(THREADSAFE) + [lock lock]; +#endif [cache removeAllObjects]; [users removeAllObjects]; +#if defined(THREADSAFE) + [lock unlock]; +#endif } - (id) init @@ -134,7 +158,7 @@ static SOGoCache *sharedCache = nil; } - (NSString *) _pathFromObject: (SOGoObject *) container - withName: (NSString *) name +withName: (NSString *) name { NSString *fullPath, *nameInContainer; NSMutableArray *names; @@ -169,13 +193,19 @@ static SOGoCache *sharedCache = nil; inContainer: [container container]]; fullPath = [self _pathFromObject: container withName: name]; +#if defined(THREADSAFE) + [lock lock]; +#endif if (![cache objectForKey: fullPath]) { -// NSLog (@"registering '%@'", fullPath); + // NSLog (@"registering '%@'", fullPath); [cache setObject: object forKey: fullPath]; } -// else -// NSLog (@"'%@' already registered", fullPath); +#if defined(THREADSAFE) + [lock unlock]; +#endif + // else + // NSLog (@"'%@' already registered", fullPath); } } @@ -188,14 +218,20 @@ static SOGoCache *sharedCache = nil; withName: name]; return [cache objectForKey: fullPath]; -// if (object) -// NSLog (@"found cached object '%@'", fullPath); + // if (object) + // NSLog (@"found cached object '%@'", fullPath); } - (void) registerUser: (SOGoUser *) user { +#if defined(THREADSAFE) + [lock lock]; +#endif [users setObject: user forKey: [user login]]; +#if defined(THREADSAFE) + [lock unlock]; +#endif } - (id) userNamed: (NSString *) name @@ -214,11 +250,17 @@ static SOGoCache *sharedCache = nil; { NSDate *cleanupDate; +#if defined(THREADSAFE) + [lock lock]; +#endif cleanupDate = [[NSDate date] addTimeInterval: [SOGoCache cleanupInterval]]; [s_userDefaults setObject: [NSDictionary dictionaryWithObjectsAndKeys: theDefaults, @"dictionary", cleanupDate, @"cleanupDate", nil] forKey: login]; +#if defined(THREADSAFE) + [lock unlock]; +#endif } + (NSDictionary *) cachedUserSettings @@ -231,11 +273,17 @@ static SOGoCache *sharedCache = nil; { NSDate *cleanupDate; +#if defined(THREADSAFE) + [lock lock]; +#endif cleanupDate = [[NSDate date] addTimeInterval: [SOGoCache cleanupInterval]]; [s_userSettings setObject: [NSDictionary dictionaryWithObjectsAndKeys: theSettings, @"dictionary", cleanupDate, @"cleanupDate", nil] forKey: login]; +#if defined(THREADSAFE) + [lock unlock]; +#endif } - (void) _userDefaultsHaveChanged: (NSNotification *) theNotification @@ -245,6 +293,9 @@ static SOGoCache *sharedCache = nil; uid = [[theNotification userInfo] objectForKey: @"uid"]; +#if defined(THREADSAFE) + [lock lock]; +#endif if ((user = [users objectForKey: uid])) { [[user userDefaults] setValues: [[theNotification userInfo] objectForKey: @"values"]]; @@ -254,6 +305,9 @@ static SOGoCache *sharedCache = nil; { [s_userDefaults removeObjectForKey: uid]; } +#if defined(THREADSAFE) + [lock unlock]; +#endif } - (void) _userSettingsHaveChanged: (NSNotification *) theNotification @@ -283,6 +337,10 @@ static SOGoCache *sharedCache = nil; unsigned int count; +#if defined(THREADSAFE) + [lock lock]; +#endif + now = [NSDate date]; // We cleanup the user defaults @@ -317,7 +375,12 @@ static SOGoCache *sharedCache = nil; } if (count) - [self logWithFormat: @"cleaned %d users records from user settings cache", count]; + [self logWithFormat: @"cleaned %d users records from user settings cache", + count]; + +#if defined(THREADSAFE) + [lock unlock]; +#endif } @end diff --git a/configure b/configure index fa5539262..6ef244abf 100755 --- a/configure +++ b/configure @@ -18,6 +18,7 @@ ARG_GSMAKE=`gnustep-config --variable=GNUSTEP_MAKEFILES 2>/dev/null` ARG_CFGMAKE="$PWD/config.make" ARG_WITH_DEBUG=1 ARG_WITH_STRIP=0 +ARG_WITH_THREADS=0 ARG_WITH_LDAP_CONFIG=0 GNUSTEP_INSTALLATION_DOMAIN="LOCAL" @@ -58,6 +59,7 @@ Installation directories: --configmake=PATH path to the config file being created --enable-debug turn on debugging and compile time warnings --enable-strip turn on stripping of debug symbols + --enable-thread-safety turn on thread-safety --enable-ldap-config enable LDAP based configuration of SOGo @@ -83,6 +85,11 @@ printParas() { else echo " strip: no"; fi + if test $ARG_WITH_THREADS = 1; then + echo " thread-safe: yes"; + else + echo " thread-safe: no"; + fi if test $ARG_WITH_LDAP_CONFIG = 1; then echo " ldap-based configuration: yes"; else @@ -261,6 +268,11 @@ genConfigMake() { fi cfgwrite "" + if test $ARG_WITH_THREADS = 1; then + cfgwrite "# configured to produce thread-safe code"; + cfgwrite "ADDITIONAL_CPPFLAGS += -DTHREADSAFE=1" + fi + cfgwrite "# enforce shared libraries"; cfgwrite "shared:=yes" cfgwrite "" @@ -393,6 +405,12 @@ processOption() { "x--disable-strip") ARG_WITH_STRIP=0 ;; + "x--enable-thread-safety") + ARG_WITH_THREADS=1 + ;; + "x--disable-thread-safety") + ARG_WITH_THREADS=0 + ;; "x--enable-ldap-config") ARG_WITH_LDAP_CONFIG=1