From 4a65b59dc6903758da2c3000b5bd23af67550116 Mon Sep 17 00:00:00 2001 From: rfm Date: Mon, 18 Feb 2008 12:31:23 +0000 Subject: [PATCH] Lock names directory. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@26088 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 4 +- Source/NSMessagePortNameServer.m | 121 ++++++++++++++++++++++++------- Tools/gdnc.m | 2 + 3 files changed, 99 insertions(+), 28 deletions(-) diff --git a/ChangeLog b/ChangeLog index 04d1888b5..da7f8f851 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,11 +1,13 @@ 2008-02-17 Richard Frith-Macdonald * Source/NSDistributedNotificationCenter.m: Remove delay and change - code to immediately release resources used while trying to conneect + code to immediately release resources used while trying to connect to server. * Source/NSConnection.m: When creating a connection and getting its proxy, release the connection immediately if the proxy is nil, so that repeated calls don't use more resources. + * Source/NSMessagePortNameServer.m: Implement distributed locking + of names directory. * Source/NSNSAutoreleasePool.m: When emptying pool, add diagnostic message and exceptions where an object we are releasing is bad in some way. diff --git a/Source/NSMessagePortNameServer.m b/Source/NSMessagePortNameServer.m index 4bd47b759..daeb57423 100644 --- a/Source/NSMessagePortNameServer.m +++ b/Source/NSMessagePortNameServer.m @@ -29,6 +29,7 @@ #include "Foundation/NSDebug.h" #include "Foundation/NSException.h" #include "Foundation/NSLock.h" +#include "Foundation/NSDistributedLock.h" #include "Foundation/NSMapTable.h" #include "Foundation/NSPathUtilities.h" #include "Foundation/NSPort.h" @@ -77,16 +78,17 @@ static NSMapTable portToNamesMap; @interface NSMessagePortNameServer (private) -+(NSString *) _pathForName: (NSString *)name; ++ (NSDistributedLock*) _fileLock; ++ (NSString *) _pathForName: (NSString *)name; @end static void clean_up_names(void) { - NSMapEnumerator mEnum; - NSMessagePort *port; - NSString *name; - BOOL unknownThread = GSRegisterCurrentThread(); + NSMapEnumerator mEnum; + NSMessagePort *port; + NSString *name; + BOOL unknownThread = GSRegisterCurrentThread(); CREATE_AUTORELEASE_POOL(arp); mEnum = NSEnumerateMapTable(portToNamesMap); @@ -139,21 +141,56 @@ static void clean_up_names(void) return defaultServer; } ++ (NSDistributedLock*) _fileLock +{ + NSDistributedLock *dl; + dl = [NSDistributedLock lockWithPath: [self _pathForName: nil]]; + if ([dl tryLock] == NO) + { + NSDate *limit = [NSDate dateWithTimeIntervalSinceNow: 2.0]; + + while ([dl tryLock] == NO) + { + if ([limit timeIntervalSinceNow] > 0.0) + { + [NSThread sleepForTimeInterval: 0.1]; + } + else + { + NSLog(@"Failed to lock names for NSMessagePortNameServer"); + return nil; + } + } + } + return dl; +} + +/* Return the full path for the supplied port name or, if it's nil, + * the path for the distributed lock protecting all names. + */ + (NSString *) _pathForName: (NSString *)name { static NSString *base_path = nil; NSString *path; NSData *data; - /* - * Make sure name is representable as a filename ... assume base64 encoded - * strings are valid on all filesystems. - */ - data = [name dataUsingEncoding: NSUTF8StringEncoding]; - data = [GSMimeDocument encodeBase64: data]; - name = [[NSString alloc] initWithData: data encoding: NSASCIIStringEncoding]; - AUTORELEASE(name); + if (name == nil) + { + name = @"lock"; + } + else + { + /* + * Make sure name is representable as a filename ... assume base64 encoded + * strings are valid on all filesystems. + */ + data = [name dataUsingEncoding: NSUTF8StringEncoding]; + data = [GSMimeDocument encodeBase64: data]; + name = [[NSString alloc] initWithData: data + encoding: NSASCIIStringEncoding]; + AUTORELEASE(name); + } [serverLock lock]; if (!base_path) { @@ -260,9 +297,10 @@ static void clean_up_names(void) - (NSPort*) portForName: (NSString *)name onHost: (NSString *)host { - NSString *path; - FILE *f; - char socket_path[512]; + NSDistributedLock *dl; + NSString *path; + FILE *f; + char socket_path[512]; NSDebugLLog(@"NSMessagePort", @"portForName: %@ host: %@", name, host); @@ -278,8 +316,14 @@ static void clean_up_names(void) } path = [[self class] _pathForName: name]; + if ((dl = [[self class] _fileLock]) == nil) + { + [NSException raise: NSGenericException + format: @"Failed to lock names for NSMessagePortNameServer"]; + } if (![[self class] _livePort: path]) { + [dl unlock]; NSDebugLLog(@"NSMessagePort", @"not a live port"); return nil; } @@ -287,6 +331,7 @@ static void clean_up_names(void) f = fopen([path fileSystemRepresentation], "rt"); if (!f) { + [dl unlock]; NSDebugLLog(@"NSMessagePort", @"can't open file (%m)"); return nil; } @@ -296,6 +341,7 @@ static void clean_up_names(void) fclose(f); NSDebugLLog(@"NSMessagePort", @"got %s", socket_path); + [dl unlock]; return [NSMessagePort _portWithName: (unsigned char*)socket_path listener: NO]; @@ -306,6 +352,7 @@ static void clean_up_names(void) { int fd; unsigned char buf[32]; + NSDistributedLock *dl; NSString *path; const unsigned char *socket_name; NSMutableArray *a; @@ -316,13 +363,17 @@ static void clean_up_names(void) [NSException raise: NSInvalidArgumentException format: @"Attempted to register a non-NSMessagePort (%@)", port]; - return NO; } path = [[self class] _pathForName: name]; - + if ((dl = [[self class] _fileLock]) == nil) + { + [NSException raise: NSGenericException + format: @"Failed to lock names for NSMessagePortNameServer"]; + } if ([[self class] _livePort: path]) { + [dl unlock]; NSDebugLLog(@"NSMessagePort", @"fail, is a live port (%@)", name); return NO; } @@ -330,6 +381,7 @@ static void clean_up_names(void) fd = open([path fileSystemRepresentation], O_CREAT|O_EXCL|O_WRONLY, 0600); if (fd < 0) { + [dl unlock]; NSDebugLLog(@"NSMessagePort", @"fail, can't open file (%@) for %@", path, name); return NO; @@ -355,17 +407,25 @@ static void clean_up_names(void) [a addObject: [name copy]]; [serverLock unlock]; + [dl unlock]; return YES; } - (BOOL) removePortForName: (NSString *)name { - NSString *path; + NSDistributedLock *dl; + NSString *path; NSDebugLLog(@"NSMessagePort", @"removePortForName: %@", name); path = [[self class] _pathForName: name]; + if ((dl = [[self class] _fileLock]) == nil) + { + [NSException raise: NSGenericException + format: @"Failed to lock names for NSMessagePortNameServer"]; + } unlink([path fileSystemRepresentation]); + [dl unlock]; return YES; } @@ -405,29 +465,36 @@ static void clean_up_names(void) { FILE *f; char socket_path[512]; + NSDistributedLock *dl; NSString *path; const unsigned char *port_path; NSDebugLLog(@"NSMessagePort", @"removePort: %@ forName: %@", port, name); path = [[self class] _pathForName: name]; - + if ((dl = [[self class] _fileLock]) == nil) + { + [NSException raise: NSGenericException + format: @"Failed to lock names for NSMessagePortNameServer"]; + } f = fopen([path fileSystemRepresentation], "rt"); if (!f) - return YES; - + { + [dl unlock]; + return YES; + } fgets(socket_path, sizeof(socket_path), f); - if (strlen(socket_path) > 0) socket_path[strlen(socket_path) - 1] = 0; - + if (strlen(socket_path) > 0) + { + socket_path[strlen(socket_path) - 1] = 0; + } fclose(f); - port_path = [(NSMessagePort *)port _name]; - if (!strcmp((char*)socket_path, (char*)port_path)) { unlink([path fileSystemRepresentation]); } - + [dl unlock]; return YES; } diff --git a/Tools/gdnc.m b/Tools/gdnc.m index 4ddd96843..4cd5fcc36 100644 --- a/Tools/gdnc.m +++ b/Tools/gdnc.m @@ -472,6 +472,7 @@ ihandler(int sig) name = [service stringByAppendingFormat: @"-%@", name]; if ([ns registerPort: port forName: name] == NO) { + NSLog(@"gdnc - failed to register as %@", name); } } a = [host addresses]; @@ -483,6 +484,7 @@ ihandler(int sig) name = [service stringByAppendingFormat: @"-%@", name]; if ([ns registerPort: port forName: name] == NO) { + NSLog(@"gdnc - failed to register as %@", name); } } }