Some tidyup and improvements of new DO performance etc.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@6866 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
richard 2000-07-04 09:44:05 +00:00
parent a8432b33bc
commit 5fa248bac4
10 changed files with 503 additions and 202 deletions

View file

@ -1,3 +1,15 @@
2000-07-04 Richard Frith-Macdonald <rfm@gnu.org>
* Source/GSConnection.m: Improved coder caching and added code for
multiple thread support.
* Source/GSPortCoder.m: Improved performance of class version
lookup and tidied.
* Source/GSTcpPort.m: Ensure we don't remain in the run loop any
longer than necessary.
* Source/NSArchiver.m: minor tidyup
* Source/NSDistantObject.m: minor performance tweak
* Source/NSUnarchiver.m: minor tidyup.
2000-07-03 Richard Frith-Macdonald <rfm@gnu.org>
* Source/GSConnection.m: Cache coders fro performance.

View file

@ -63,6 +63,7 @@ GS_EXPORT NSString *NSConnectionProxyCount; /* Objects received */
BOOL _independentQueueing;
BOOL _authenticateIn;
BOOL _authenticateOut;
BOOL _multipleThreads;
NSPort *_receivePort;
NSPort *_sendPort;
unsigned _requestDepth;
@ -82,8 +83,8 @@ GS_EXPORT NSString *NSConnectionProxyCount; /* Objects received */
NSMutableArray *_requestQueue;
id _delegate;
NSRecursiveLock *_refGate;
NSPortCoder *_cachedDecoder;
NSPortCoder *_cachedEncoder;
NSMutableArray *_cachedDecoders;
NSMutableArray *_cachedEncoders;
}
+ (NSArray*) allConnections;
@ -142,6 +143,9 @@ GS_EXPORT NSString *NSConnectionProxyCount; /* Objects received */
*/
@interface NSConnection (GNUstepExtensions) <GCFinalization>
+ (NSConnection*) newRegisteringAtName: (NSString*)n
withRootObject: (id)anObject;
- (void) gcFinalize;
- (retval_t) forwardForProxy: (NSDistantObject*)object

View file

@ -72,7 +72,7 @@
#ifndef _IN_PORT_CODER_M
#undef GSIArray
#endif
NSMutableArray *_cInfo; /* Class version information. */
NSMutableDictionary *_cInfo; /* Class version information. */
unsigned _cursor; /* Position in data buffer. */
unsigned _version; /* Version of archiver used. */
NSZone *_zone; /* Zone for allocating objs. */

View file

@ -30,6 +30,7 @@
@interface NSArchiver : NSCoder
{
@private
NSMutableData *_data; /* Data to write into. */
id _dst; /* Serialization destination. */
IMP _serImp; /* Method to serialize with. */
@ -137,6 +138,7 @@
@interface NSUnarchiver : NSCoder
{
@private
NSData *data; /* Data to write into. */
Class dataClass; /* What sort of data is it? */
id src; /* Deserialization source. */

View file

@ -56,6 +56,12 @@
#define M_LOCK(X) {NSDebugMLLog(@"GSConnection",@"Lock %@",X);[X lock];}
#define M_UNLOCK(X) {NSDebugMLLog(@"GSConnection",@"Unlock %@",X);[X unlock];}
static Class connectionClass;
static Class dateClass;
static Class distantObjectClass;
static Class portCoderClass;
static Class runLoopClass;
static NSString*
stringFromMsgType(int type)
{
@ -121,14 +127,14 @@ stringFromMsgType(int type)
unsigned target;
id object;
}
+ (GSLocalCounter*) newWithObject: (id)ob;
+ (id) newWithObject: (id)ob;
@end
@implementation GSLocalCounter
static unsigned local_object_counter = 0;
+ (GSLocalCounter*) newWithObject: (id)obj
+ (id) newWithObject: (id)obj
{
GSLocalCounter *counter;
@ -141,7 +147,7 @@ static unsigned local_object_counter = 0;
- (void) dealloc
{
RELEASE(object);
[super dealloc];
NSDeallocateObject(self);
}
@end
@ -161,24 +167,25 @@ static unsigned local_object_counter = 0;
}
- (BOOL)countdown;
- (id) obj;
+ (CachedLocalObject*) itemWithObject: (id)o time: (int)t;
+ (id) newWithObject: (id)o time: (int)t;
@end
@implementation CachedLocalObject
+ (CachedLocalObject*) itemWithObject: (id)o time: (int)t
+ (id) newWithObject: (id)o time: (int)t
{
CachedLocalObject *item = [[self alloc] init];
CachedLocalObject *item;
item = (CachedLocalObject*)NSAllocateObject(self, 0, NSDefaultMallocZone());
item->obj = RETAIN(o);
item->time = t;
return AUTORELEASE(item);
return item;
}
- (void) dealloc
{
RELEASE(obj);
[super dealloc];
NSDeallocateObject(self);
}
- (BOOL) countdown
@ -198,11 +205,12 @@ static unsigned local_object_counter = 0;
@interface NSConnection (Private)
+ (void) setDebug: (int)val;
- (void) handlePortMessage: (NSPortMessage*)msg;
- (void) _runInNewThread;
+ (void) setDebug: (int)val;
- _getReplyRmc: (int)n;
- (void) _doneInRmc: (NSPortCoder*)c;
- (NSPortCoder*) _getReplyRmc: (int)sn;
- (NSPortCoder*) _makeInRmc: (NSMutableArray*)components;
- (NSPortCoder*) _makeOutRmc: (int)sequence;
- (int) _newMsgNumber;
@ -300,14 +308,6 @@ static NSMapTable *all_connections_local_targets = NULL;
static NSMapTable *all_connections_local_cached = NULL;
static NSLock *global_proxies_gate;
/* rmc handling */
static NSMutableArray *received_request_rmc_queue;
static NSLock *received_request_rmc_queue_gate;
static NSMutableArray *received_reply_rmc_queue;
static NSLock *received_reply_rmc_queue_gate;
static int messages_received_count;
@ -413,29 +413,33 @@ static int messages_received_count;
+ (void) initialize
{
connection_table =
NSCreateHashTable(NSNonRetainedObjectHashCallBacks, 0);
connection_table_gate = [NSLock new];
/* xxx When NSHashTable's are working, change this. */
all_connections_local_objects =
NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
NSObjectMapValueCallBacks, 0);
all_connections_local_targets =
NSCreateMapTable(NSIntMapKeyCallBacks,
NSNonOwnedPointerMapValueCallBacks, 0);
all_connections_local_cached =
NSCreateMapTable(NSIntMapKeyCallBacks,
NSObjectMapValueCallBacks, 0);
global_proxies_gate = [NSLock new];
received_request_rmc_queue = [[NSMutableArray alloc] initWithCapacity: 32];
received_request_rmc_queue_gate = [NSLock new];
received_reply_rmc_queue = [[NSMutableArray alloc] initWithCapacity: 32];
received_reply_rmc_queue_gate = [NSLock new];
root_object_map =
NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
NSObjectMapValueCallBacks, 0);
root_object_map_gate = [NSLock new];
messages_received_count = 0;
if (self == [NSConnection class])
{
connectionClass = self;
dateClass = [NSDate class];
distantObjectClass = [NSDistantObject class];
portCoderClass = [NSPortCoder class];
runLoopClass = [NSRunLoop class];
connection_table =
NSCreateHashTable(NSNonRetainedObjectHashCallBacks, 0);
connection_table_gate = [NSLock new];
/* xxx When NSHashTable's are working, change this. */
all_connections_local_objects =
NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
NSObjectMapValueCallBacks, 0);
all_connections_local_targets =
NSCreateMapTable(NSIntMapKeyCallBacks,
NSNonOwnedPointerMapValueCallBacks, 0);
all_connections_local_cached =
NSCreateMapTable(NSIntMapKeyCallBacks,
NSObjectMapValueCallBacks, 0);
global_proxies_gate = [NSLock new];
root_object_map =
NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
NSObjectMapValueCallBacks, 0);
root_object_map_gate = [NSLock new];
}
}
+ (id) new
@ -558,7 +562,7 @@ static int messages_received_count;
- (void) enableMultipleThreads
{
[self notImplemented: _cmd];
_multipleThreads = YES;
}
- (BOOL) independentConversationQueueing
@ -573,7 +577,7 @@ static int messages_received_count;
* -init returns the default connection.
*/
RELEASE(self);
return RETAIN([NSConnection defaultConnection]);
return RETAIN([connectionClass defaultConnection]);
}
/* This is the designated initializer for NSConnection */
@ -649,6 +653,12 @@ static int messages_received_count;
_repInCount = 0;
_reqInCount = 0;
/*
* These arrays cache NSPortCoder objects
*/
_cachedDecoders = [NSMutableArray new];
_cachedEncoders = [NSMutableArray new];
/*
* This is used to queue up incoming NSPortMessages representing requests
* that can't immediately be dealt with.
@ -710,7 +720,7 @@ static int messages_received_count;
* Set up request modes array and make sure the receiving port is
* added to the run loop to get data.
*/
loop = [NSRunLoop currentRunLoop];
loop = [runLoopClass currentRunLoop];
_runLoops = [[NSMutableArray alloc] initWithObjects: &loop count: 1];
_requestModes = [[NSMutableArray alloc] initWithCapacity: 2];
[self addRequestMode: NSDefaultRunLoopMode];
@ -871,8 +881,7 @@ static int messages_received_count;
- (BOOL) multipleThreadsEnabled
{
[self notImplemented: _cmd];
return NO;
return _multipleThreads;
}
- (NSPort*) receivePort
@ -988,7 +997,7 @@ static int messages_received_count;
- (NSArray*) requestModes
{
return [[_requestModes copy] autorelease];
return AUTORELEASE([_requestModes copy]);
}
- (NSTimeInterval) requestTimeout
@ -1023,7 +1032,10 @@ static int messages_received_count;
- (void) runInNewThread
{
[self notImplemented: _cmd];
[self removeRunLoop: [runLoopClass currentRunLoop]];
[NSThread detachNewThreadSelector: @selector(_runInNewThread)
toTarget: self
withObject: nil];
}
- (NSPort*) sendPort
@ -1106,10 +1118,6 @@ static int messages_received_count;
[d setObject: o forKey: NSConnectionLocalCount];
o = [NSNumber numberWithUnsignedInt: NSCountMapTable(_remoteProxies)];
[d setObject: o forKey: NSConnectionProxyCount];
M_LOCK(received_request_rmc_queue_gate);
o = [NSNumber numberWithUnsignedInt: [received_request_rmc_queue count]];
M_UNLOCK(received_request_rmc_queue_gate);
[d setObject: o forKey: @"Pending packets"];
M_UNLOCK(_refGate);
@ -1122,6 +1130,21 @@ static int messages_received_count;
@implementation NSConnection (GNUstepExtensions)
+ (NSConnection*) newRegisteringAtName: (NSString*)name
withRootObject: (id)anObject
{
NSConnection *conn;
conn = [[self alloc] initWithReceivePort: [NSPort port]
sendPort: nil];
[conn setRootObject: anObject];
if ([conn registerName: name] == NO)
{
DESTROY(conn);
}
return conn;
}
- (void) gcFinalize
{
CREATE_AUTORELEASE_POOL(arp);
@ -1190,8 +1213,8 @@ static int messages_received_count;
_replyMap = 0;
}
DESTROY(_cachedDecoder);
DESTROY(_cachedEncoder);
DESTROY(_cachedDecoders);
DESTROY(_cachedEncoders);
DESTROY(_refGate);
RELEASE(arp);
@ -1368,19 +1391,19 @@ static int messages_received_count;
/* Class-wide stats and collections. */
+ (int) messagesReceived
{
return messages_received_count;
}
+ (unsigned) connectionsCount
{
return NSCountHashTable(connection_table);
unsigned result;
M_LOCK(connection_table_gate);
result = NSCountHashTable(connection_table);
M_UNLOCK(connection_table_gate);
return result;
}
+ (unsigned) connectionsCountWithInPort: (NSPort*)aPort
{
unsigned count = 0;
unsigned count = 0;
NSHashEnumerator enumerator;
NSConnection *o;
@ -1419,7 +1442,7 @@ static int messages_received_count;
{
NSLog(@"handling packet of type %d (%@)", type, stringFromMsgType(type));
}
conn = [NSConnection connectionWithReceivePort: rp sendPort: sp];
conn = [connectionClass connectionWithReceivePort: rp sendPort: sp];
if (conn == nil)
{
NSLog(@"received port message for unknown connection - %@", msg);
@ -1542,6 +1565,14 @@ static int messages_received_count;
}
}
- (void) _runInNewThread
{
NSRunLoop *loop = [runLoopClass currentRunLoop];
[self addRunLoop: loop];
[loop run];
}
+ (void) setDebug: (int)val
{
debug_connection = val;
@ -1767,8 +1798,8 @@ static int messages_received_count;
}
else
{
[NSDistantObject proxyWithLocal: counter->object
connection: self];
[distantObjectClass proxyWithLocal: counter->object
connection: self];
[op encodeObject: nil];
if (debug_connection > 3)
NSLog(@"retained object (0x%x) target (0x%x) on connection(0x%x)",
@ -1843,17 +1874,6 @@ static int messages_received_count;
}
/* Running the connection, getting/sending requests/replies. */
- (void) runConnectionUntilDate: date
{
[NSRunLoop runUntilDate: date];
}
- (void) runConnection
{
[self runConnectionUntilDate: [NSDate distantFuture]];
}
/*
* Check the queue, then try to get it from the network by waiting
@ -1870,11 +1890,12 @@ static int messages_received_count;
{
if (timeout_date == nil)
{
timeout_date = [NSDate dateWithTimeIntervalSinceNow: _replyTimeout];
timeout_date
= [dateClass dateWithTimeIntervalSinceNow: _replyTimeout];
}
M_UNLOCK(_queueGate);
if ([NSRunLoop runOnceBeforeDate: timeout_date
forMode: NSConnectionReplyMode] == NO)
if ([runLoopClass runOnceBeforeDate: timeout_date
forMode: NSConnectionReplyMode] == NO)
{
[NSException raise: NSPortTimeoutException
format: @"timed out waiting for reply"];
@ -1904,33 +1925,30 @@ static int messages_received_count;
- (void) _doneInRmc: (NSPortCoder*)c
{
M_LOCK(_refGate);
if (_cachedDecoder == nil)
{
_cachedDecoder = c;
[c dispatch]; /* make coder release connection */
}
else
{
RELEASE(c);
}
[_cachedDecoders addObject: c];
[c dispatch]; /* Tell NSPortCoder to release the connection. */
RELEASE(c);
M_UNLOCK(_refGate);
}
- (NSPortCoder*) _makeInRmc: (NSMutableArray*)components
{
NSPortCoder *coder;
NSPortCoder *coder;
unsigned count;
NSParameterAssert(_isValid);
M_LOCK(_refGate);
if (_cachedDecoder == nil)
count = [_cachedDecoders count];
if (count > 0)
{
coder = [NSPortCoder allocWithZone: NSDefaultMallocZone()];
coder = [_cachedDecoders objectAtIndex: --count];
RETAIN(coder);
[_cachedDecoders removeObjectAtIndex: count];
}
else
{
coder = _cachedDecoder;
_cachedDecoder = nil;
coder = [portCoderClass allocWithZone: NSDefaultMallocZone()];
}
M_UNLOCK(_refGate);
@ -1942,19 +1960,22 @@ static int messages_received_count;
- (NSPortCoder*) _makeOutRmc: (int)sequence
{
NSPortCoder *coder;
NSPortCoder *coder;
unsigned count;
NSParameterAssert(_isValid);
M_LOCK(_refGate);
if (_cachedEncoder == nil)
count = [_cachedEncoders count];
if (count > 0)
{
coder = [NSPortCoder allocWithZone: NSDefaultMallocZone()];
coder = [_cachedEncoders objectAtIndex: --count];
RETAIN(coder);
[_cachedEncoders removeObjectAtIndex: count];
}
else
{
coder = _cachedEncoder;
_cachedEncoder = nil;
coder = [portCoderClass allocWithZone: NSDefaultMallocZone()];
}
M_UNLOCK(_refGate);
@ -1970,6 +1991,7 @@ static int messages_received_count;
NSDate *limit;
BOOL sent = NO;
BOOL raiseException = NO;
BOOL needsReply = NO;
NSMutableArray *components = [c _components];
if (_authenticateOut == YES)
@ -1985,7 +2007,30 @@ static int messages_received_count;
}
[components addObject: d];
}
limit = [NSDate dateWithTimeIntervalSinceNow: [self requestTimeout]];
switch (msgid)
{
case PROXY_RETAIN:
needsReply = YES;
case CONNECTION_SHUTDOWN:
case METHOD_REPLY:
case ROOTPROXY_REPLY:
case METHODTYPE_REPLY:
case PROXY_RELEASE:
case RETAIN_REPLY:
raiseException = NO;
break;
case METHOD_REQUEST:
case ROOTPROXY_REQUEST:
case METHODTYPE_REQUEST:
default:
raiseException = YES;
needsReply = YES;
break;
}
limit = [dateClass dateWithTimeIntervalSinceNow: _requestTimeout];
sent = [_sendPort sendBeforeDate: limit
msgid: msgid
components: components
@ -1993,41 +2038,35 @@ static int messages_received_count;
reserved: [_sendPort reservedSpaceLength]];
M_LOCK(_refGate);
if (_cachedEncoder == nil)
/*
* If we have sent out a request on a run loop that we don't already
* know about, it must be on a new thread - so if we have multipleThreads
* enabled, we must add the run loop of the new thread so that we can
* get the reply in this thread.
*/
if (_multipleThreads == YES && needsReply == YES)
{
_cachedEncoder = c;
[c dispatch]; /* make coder release connection */
}
else
{
RELEASE(c);
NSRunLoop *loop = [runLoopClass currentRunLoop];
if ([_runLoops indexOfObjectIdenticalTo: loop] == NSNotFound)
{
[self addRunLoop: loop];
}
}
/*
* We replace the code we have just used in the cache, and tell it not to
* retain this connection any more.
*/
[_cachedEncoders addObject: c];
[c dispatch]; /* Tell NSPortCoder to release the connection. */
RELEASE(c);
M_UNLOCK(_refGate);
if (sent == NO)
{
NSString *text;
NSString *text = stringFromMsgType(msgid);
switch (msgid)
{
case CONNECTION_SHUTDOWN:
case METHOD_REPLY:
case ROOTPROXY_REPLY:
case METHODTYPE_REPLY:
case PROXY_RELEASE:
case PROXY_RETAIN:
case RETAIN_REPLY:
raiseException = YES;
break;
case METHOD_REQUEST:
case ROOTPROXY_REQUEST:
case METHODTYPE_REQUEST:
default:
raiseException = YES;
break;
}
text = stringFromMsgType(msgid);
if (raiseException == YES)
{
[NSException raise: NSPortTimeoutException format: text];
@ -2085,7 +2124,7 @@ static int messages_received_count;
target = counter->target;
NSMapInsert(all_connections_local_objects, (void*)object, counter);
NSMapInsert(all_connections_local_targets, (void*)target, counter);
[counter release];
RELEASE(counter);
}
[anObj setProxyTarget: target];
NSMapInsert(_localTargets, (void*)target, anObj);
@ -2156,13 +2195,14 @@ static int messages_received_count;
if (timer == nil)
{
timer = [NSTimer scheduledTimerWithTimeInterval: 1.0
target: [NSConnection class]
selector: @selector(_timeout: )
target: connectionClass
selector: @selector(_timeout:)
userInfo: nil
repeats: YES];
}
item = [CachedLocalObject itemWithObject: counter time: 30];
item = [CachedLocalObject newWithObject: counter time: 30];
NSMapInsert(all_connections_local_cached, (void*)target, item);
RELEASE(item);
if (debug_connection > 3)
NSLog(@"placed local object (0x%x) target (0x%x) in cache",
(gsaddr)anObj, target);
@ -2289,7 +2329,7 @@ static int messages_received_count;
unsigned target = (unsigned int)[aProxy targetForProxy];
NSParameterAssert (_isValid);
NSParameterAssert(aProxy->isa == [NSDistantObject class]);
NSParameterAssert(aProxy->isa == distantObjectClass);
NSParameterAssert([aProxy connectionForProxy] == self);
M_LOCK(_proxiesGate);
if (NSMapGet(_remoteProxies, (void*)target))

View file

@ -278,7 +278,7 @@ typeCheck(char t1, char t2)
@interface NSPortCoder (Private)
@interface NSPortCoder (Headers)
- (void) _deserializeHeaderAt: (unsigned*)pos
version: (unsigned*)v
classes: (unsigned*)c
@ -294,6 +294,22 @@ typeCheck(char t1, char t2)
@implementation NSPortCoder
static Class connectionClass;
static Class mutableArrayClass;
static Class mutableDataClass;
static Class mutableDictionaryClass;
+ (void) initialize
{
if (self == [NSPortCoder class])
{
connectionClass = [NSConnection class];
mutableArrayClass = [NSMutableArray class];
mutableDataClass = [NSMutableData class];
mutableDictionaryClass = [NSMutableDictionary class];
}
}
+ (NSPortCoder*) portCoderWithReceivePort: (NSPort*)recv
sendPort: (NSPort*)send
components: (NSArray*)comp;
@ -326,6 +342,12 @@ typeCheck(char t1, char t2)
}
if (_clsAry != 0)
{
unsigned count = GSIArrayCount(_clsAry);
while (count-- > 0)
{
RELEASE(GSIArrayItemAtIndex(_clsAry, count).obj);
}
GSIArrayClear(_clsAry);
GSIArrayClear(_objAry);
GSIArrayClear(_ptrAry);
@ -422,7 +444,7 @@ typeCheck(char t1, char t2)
}
else if (pos == -2)
{
return [NSData data];
return [mutableDataClass data];
}
else
{
@ -646,8 +668,6 @@ typeCheck(char t1, char t2)
format: @"decoded nil class"];
}
classInfo = [GSClassInfo newWithClass: c andVersion: cver];
[_cInfo addObject: classInfo];
RELEASE(classInfo);
GSIArrayAddItem(_clsAry, (GSIArrayItem)classInfo);
*(Class*)address = classInfo->class;
/*
@ -925,7 +945,7 @@ typeCheck(char t1, char t2)
#if GS_HAVE_I64
bigval = val;
#else
val = GSSwapBigI64ToHost(val);
bigval = GSSwapBigI64ToHost(val);
#endif
break;
}
@ -1232,7 +1252,7 @@ typeCheck(char t1, char t2)
(*_eValImp)(self, eValSel, @encode(Class), &cls);
[obj encodeWithCoder: self];
}
else if (!_initialPass)
else
{
(*_xRefImp)(_dst, xRefSel, _GSC_ID | _GSC_XREF, node->value.uint);
}
@ -1592,7 +1612,8 @@ typeCheck(char t1, char t2)
case _C_ULNG_LNG:
(*_eTagImp)(_dst, eTagSel, _GSC_ULNG_LNG | _GSC_S_LNG_LNG);
(*_eSerImp)(_dst, eSerSel, (void*)buf, @encode(unsigned long long), nil);
(*_eSerImp)(_dst, eSerSel, (void*)buf, @encode(unsigned long long),
nil);
return;
case _C_FLT:
@ -1621,8 +1642,8 @@ typeCheck(char t1, char t2)
{
BOOL firstTime;
_conn = RETAIN([NSConnection connectionWithReceivePort: recv
sendPort: send]);
_conn = RETAIN([connectionClass connectionWithReceivePort: recv
sendPort: send]);
if (_comp == nil)
{
firstTime = YES;
@ -1657,8 +1678,8 @@ typeCheck(char t1, char t2)
* the start for use by the port when the encoded data is sent.
* Make the data item the first component of the array.
*/
_comp = [NSMutableArray new];
_dst = [_fastCls._NSMutableDataMalloc allocWithZone: _zone];
_comp = [mutableArrayClass new];
_dst = [mutableDataClass allocWithZone: _zone];
_dst = [_dst initWithLength: _cursor];
[_comp addObject: _dst];
RELEASE(_dst);
@ -1744,12 +1765,7 @@ typeCheck(char t1, char t2)
* _cInfo is a dictionary of objects for keeping track of the
* version numbers that the classes were encoded with.
*/
if (firstTime == YES)
{
_cInfo
= [[NSMutableArray allocWithZone: _zone] initWithCapacity: 16];
}
else
if (firstTime == NO)
{
[_cInfo removeAllObjects];
}
@ -1778,12 +1794,18 @@ typeCheck(char t1, char t2)
}
else
{
unsigned count = GSIArrayCount(_clsAry);
while (count-- > 0)
{
RELEASE(GSIArrayItemAtIndex(_clsAry, count).obj);
}
GSIArrayRemoveAllItems(_clsAry);
GSIArrayRemoveAllItems(_objAry);
GSIArrayRemoveAllItems(_ptrAry);
}
GSIArrayAddItem(_clsAry, (GSIArrayItem)0);
GSIArrayAddItem(_objAry, (GSIArrayItem)0);
GSIArrayAddItem(_clsAry, (GSIArrayItem)nil);
GSIArrayAddItem(_objAry, (GSIArrayItem)nil);
GSIArrayAddItem(_ptrAry, (GSIArrayItem)0);
}
NS_HANDLER
@ -1824,18 +1846,31 @@ typeCheck(char t1, char t2)
- (unsigned) versionForClassName: (NSString*)className
{
GSClassInfo *info;
GSClassInfo *info = nil;
unsigned version = NSNotFound;
unsigned count = [_cInfo count];
unsigned count = GSIArrayCount(_clsAry);
while (--count > 0)
/*
* Lazy ... we construct a dictionary of all the class information in
* the request the first time that class version info is asked for.
*/
if (_cInfo == nil)
{
info = [_cInfo objectAtIndex: count];
if ([[info className] isEqual: className] == YES)
_cInfo = [[mutableDictionaryClass alloc] initWithCapacity: count];
}
if ([_cInfo count] == 0)
{
while (count-- > 0)
{
version = info->version;
info = GSIArrayItemAtIndex(_clsAry, count).obj;
[_cInfo setObject: info forKey: NSStringFromClass(info->class)];
}
}
info = [_cInfo objectForKey: className];
if (info != nil)
{
version = info->version;
}
return version;
}
@ -1850,6 +1885,10 @@ typeCheck(char t1, char t2)
return _comp;
}
@end
@implementation NSPortCoder (Headers)
- (void) _deserializeHeaderAt: (unsigned*)pos
version: (unsigned*)v
classes: (unsigned*)c

View file

@ -51,8 +51,13 @@
extern int errno;
#if 0
#define DO_LOCK(X) {NSDebugMLLog(@"GSTcpHandle",@"lock %@",X); [X lock];}
#define DO_UNLOCK(X) {NSDebugMLLog(@"GSTcpHandle",@"unlock %@",X); [X unlock];}
#else
#define DO_LOCK(X) {[X lock];}
#define DO_UNLOCK(X) {[X unlock];}
#endif
#define GS_CONNECTION_MSG 0
#define NETBLOCK 8192
@ -305,6 +310,11 @@ newDataWithEncodedPort(GSTcpPort *port)
@implementation GSTcpHandle
static Class mutableArrayClass;
static Class mutableDataClass;
static Class portMessageClass;
static Class runLoopClass;
+ (id) allocWithZone: (NSZone*)zone
{
[NSException raise: NSGenericException
@ -344,6 +354,17 @@ newDataWithEncodedPort(GSTcpPort *port)
return AUTORELEASE(handle);
}
+ (void) initialize
{
if (self == [GSTcpHandle class])
{
mutableArrayClass = [NSMutableArray class];
mutableDataClass = [NSMutableData class];
portMessageClass = [NSPortMessage class];
runLoopClass = [NSRunLoop class];
}
}
- (BOOL) connectToPort: (GSTcpPort*)aPort beforeDate: (NSDate*)when
{
NSArray *addrs;
@ -428,7 +449,7 @@ newDataWithEncodedPort(GSTcpPort *port)
type: ET_WDESC
watcher: self
forMode: NSDefaultRunLoopMode];
while (state == GS_H_TRYCON && [when timeIntervalSinceNow] > 0)
while (state == GS_H_TRYCON && [when timeIntervalSinceNow] > 0)
{
[l runMode: NSDefaultRunLoopMode beforeDate: when];
}
@ -487,15 +508,16 @@ newDataWithEncodedPort(GSTcpPort *port)
- (void) dispatch
{
NSPortMessage *pm;
GSTcpPort *rp = [self recvPort];
pm = [NSPortMessage allocWithZone: NSDefaultMallocZone()];
pm = [portMessageClass allocWithZone: NSDefaultMallocZone()];
pm = [pm initWithSendPort: [self sendPort]
receivePort: [self recvPort]
receivePort: rp
components: rItems];
[pm setMsgid: rId];
rId = 0;
DESTROY(rItems);
[[self recvPort] handlePortMessage: pm];
[rp handlePortMessage: pm];
RELEASE(pm);
}
@ -536,15 +558,15 @@ newDataWithEncodedPort(GSTcpPort *port)
extra: (void*)extra
forMode: (NSString*)mode
{
NSDebugMLLog(@"GSTcpHandle", @"received %s event",
type == ET_RPORT ? "read" : "write");
NSDebugMLLog(@"GSTcpHandle", @"received %s event on 0x%x",
type == ET_RPORT ? "read" : "write", self);
/*
* If we have been invalidated (desc < 0) then we should ignore this
* event and remove ourself from the runloop.
*/
if (desc < 0)
{
NSRunLoop *l = [NSRunLoop currentRunLoop];
NSRunLoop *l = [runLoopClass currentRunLoop];
[l removeEvent: data
type: ET_WDESC
@ -565,7 +587,7 @@ newDataWithEncodedPort(GSTcpPort *port)
*/
if (rData == nil)
{
rData = [[NSMutableData alloc] initWithLength: NETBLOCK];
rData = [[mutableDataClass alloc] initWithLength: NETBLOCK];
rWant = sizeof(GSPortItemHeader);
rLength = 0;
want = NETBLOCK;
@ -648,7 +670,7 @@ newDataWithEncodedPort(GSTcpPort *port)
memcpy(bytes, bytes + rWant, rLength);
}
rWant = sizeof(GSPortItemHeader);
d = [NSData new];
d = [mutableDataClass new];
[rItems addObject: d];
RELEASE(d);
if (nItems == [rItems count])
@ -686,7 +708,9 @@ newDataWithEncodedPort(GSTcpPort *port)
rId = GSSwapBigI32ToHost(h->mId);
nItems = GSSwapBigI32ToHost(h->nItems);
NSAssert(nItems >0, NSInternalInconsistencyException);
rItems = [[NSMutableArray alloc] initWithCapacity: nItems];
rItems
= [mutableArrayClass allocWithZone: NSDefaultMallocZone()];
rItems = [rItems initWithCapacity: nItems];
if (rWant > sizeof(GSPortMsgHeader))
{
NSData *d;
@ -696,7 +720,7 @@ newDataWithEncodedPort(GSTcpPort *port)
* the header - so add it to the rItems array.
*/
rWant -= sizeof(GSPortMsgHeader);
d = [NSData alloc];
d = [mutableDataClass alloc];
d = [d initWithBytes: bytes + sizeof(GSPortMsgHeader)
length: rWant];
[rItems addObject: d];
@ -733,7 +757,8 @@ newDataWithEncodedPort(GSTcpPort *port)
NSData *d;
rType = GSP_NONE;
d = [[NSData alloc] initWithBytes: bytes length: rWant];
d = [mutableDataClass allocWithZone: NSDefaultMallocZone()];
d = [d initWithBytes: bytes length: rWant];
[rItems addObject: d];
RELEASE(d);
rLength -= rWant;
@ -838,7 +863,7 @@ newDataWithEncodedPort(GSTcpPort *port)
}
else
{
NSLog(@"No messages to write.");
NSLog(@"No messages to write on 0x%x.", self);
return;
}
}
@ -856,7 +881,8 @@ newDataWithEncodedPort(GSTcpPort *port)
}
else
{
NSDebugMLLog(@"GSTcpHandle", @"wrote %d bytes", res);
NSDebugMLLog(@"GSTcpHandle", @"wrote %d bytes on 0x%x",
res, self);
wLength += res;
if (wLength == l)
{
@ -877,12 +903,21 @@ newDataWithEncodedPort(GSTcpPort *port)
}
else
{
NSRunLoop *l = [runLoopClass currentRunLoop];
/*
* message completed - remove from list.
*/
NSDebugMLLog(@"GSTcpHandle", @"completed 0x%x on 0x%x",
components, self);
wData = nil;
wItem = 0;
[wMsgs removeObjectAtIndex: 0];
[l removeEvent: data
type: ET_WDESC
forMode: mode
all: NO];
}
}
}
@ -896,10 +931,11 @@ newDataWithEncodedPort(GSTcpPort *port)
BOOL sent = NO;
NSAssert([components count] > 0, NSInternalInconsistencyException);
NSDebugMLLog(@"GSTcpHandle", @"Sending message before %@", when);
NSDebugMLLog(@"GSTcpHandle", @"Sending message 0x%x on 0x%x(%d) before %@",
components, self, desc, when);
[wMsgs addObject: components];
l = [NSRunLoop currentRunLoop];
l = [runLoopClass currentRunLoop];
RETAIN(self);
@ -912,16 +948,17 @@ newDataWithEncodedPort(GSTcpPort *port)
{
[l runMode: NSDefaultRunLoopMode beforeDate: when];
}
[l removeEvent: (void*)(gsaddr)desc
type: ET_WDESC
forMode: NSDefaultRunLoopMode
all: NO];
/*
* NB. We will remove ourself from the run loop when the message send
* is completed, so we don't need to do it here.
*/
if ([wMsgs indexOfObjectIdenticalTo: components] == NSNotFound)
{
sent = YES;
}
RELEASE(self);
NSDebugMLLog(@"GSTcpHandle", @"Message send %d", sent);
NSDebugMLLog(@"GSTcpHandle", @"Message send 0x%x on 0x%x status %d",
components, self, sent);
return sent;
}
@ -1575,7 +1612,7 @@ static NSMapTable *tcpPortMap = 0;
*/
if (length == 0 && rl != 0)
{
header = [[NSMutableData alloc] initWithCapacity: NETBLOCK];
header = [[mutableDataClass alloc] initWithCapacity: NETBLOCK];
[header setLength: rl];
[components insertObject: header atIndex: 0];

View file

@ -359,7 +359,8 @@ static SEL eValSel = @selector(encodeValueOfObjCType:at:);
/*
* Second pass, write a cross-reference number.
*/
(*_xRefImp)(_dst, xRefSel, _GSC_PTR|_GSC_XREF, node->value.uint);
(*_xRefImp)(_dst, xRefSel, _GSC_PTR|_GSC_XREF,
node->value.uint);
}
}
return;
@ -425,8 +426,8 @@ static SEL eValSel = @selector(encodeValueOfObjCType:at:);
* of its subclasses are decoded and call
* [super initWithCoder:ccc]
*/
if (s == c || s == 0 ||
GSIMapNodeForKey(_clsMap, (GSIMapKey)(void*)s) != 0)
if (s == c || s == 0
|| GSIMapNodeForKey(_clsMap, (GSIMapKey)(void*)s) != 0)
{
done = YES;
}
@ -458,7 +459,7 @@ static SEL eValSel = @selector(encodeValueOfObjCType:at:);
if (node == 0)
{
node = GSIMapAddPair(_ptrMap,
(GSIMapKey)(void*)s, (GSIMapVal)++_xRefP);
(GSIMapKey)(void*)s, (GSIMapVal)++_xRefP);
(*_xRefImp)(_dst, xRefSel, _GSC_SEL, node->value.uint);
/*
* Encode selector.
@ -467,7 +468,8 @@ static SEL eValSel = @selector(encodeValueOfObjCType:at:);
}
else
{
(*_xRefImp)(_dst, xRefSel, _GSC_SEL|_GSC_XREF, node->value.uint);
(*_xRefImp)(_dst, xRefSel, _GSC_SEL|_GSC_XREF,
node->value.uint);
}
}
return;
@ -784,7 +786,7 @@ static SEL eValSel = @selector(encodeValueOfObjCType:at:);
(*_eValImp)(self, eValSel, @encode(Class), &cls);
[obj encodeWithCoder: self];
}
else if(!_initialPass)
else
{
(*_xRefImp)(_dst, xRefSel, _GSC_ID | _GSC_XREF, node->value.uint);
}

View file

@ -34,6 +34,20 @@ static int debug_proxy = 0;
static Class placeHolder = 0;
static Class distantObjectClass = 0;
typedef struct {
@defs(NSDistantObject)
} NSDO;
/* This is the proxy tag; it indicates where the local object is,
and determines whether the reply port to the Connection-where-the-
proxy-is-local needs to encoded/decoded or not. */
enum
{
PROXY_LOCAL_FOR_RECEIVER = 0,
PROXY_LOCAL_FOR_SENDER,
PROXY_REMOTE_FOR_BOTH
};
/*
@ -77,11 +91,172 @@ static Class distantObjectClass = 0;
+ (id) initWithCoder: (NSCoder*)aCoder
{
NSDistantObject *proxy;
gsu8 proxy_tag;
unsigned target;
id decoder_connection;
proxy = (NSDistantObject*)NSAllocateObject(distantObjectClass,
0, NSDefaultMallocZone());
return [proxy initWithCoder: aCoder];
/*
if ([aCoder isKindOfClass: [NSPortCoder class]] == NO)
{
[NSException raise: NSGenericException
format: @"NSDistantObject objects only decode with "
@"NSPortCoder class"];
}
*/
decoder_connection = [(NSPortCoder*)aCoder connection];
NSAssert(decoder_connection, NSInternalInconsistencyException);
/* First get the tag, so we know what values need to be decoded. */
[aCoder decodeValueOfObjCType: @encode(typeof(proxy_tag))
at: &proxy_tag];
switch (proxy_tag)
{
case PROXY_LOCAL_FOR_RECEIVER:
/*
* This was a proxy on the other side of the connection, but
* here it's local.
* Lookup the target handle to ensure that it exists here.
* Return a retained copy of the local target object.
*/
[aCoder decodeValueOfObjCType: @encode(typeof(target))
at: &target];
if (debug_proxy)
NSLog(@"Receiving a proxy for local object 0x%x "
@"connection 0x%x\n", target, (gsaddr)decoder_connection);
if (![[decoder_connection class] includesLocalTarget: target])
{
[NSException raise: @"ProxyDecodedBadTarget"
format: @"No local object with given target (0x%x)",
target];
}
else
{
NSDistantObject *o;
o = [decoder_connection includesLocalTarget: target];
if (debug_proxy)
{
NSLog(@"Local object is 0x%x (0x%x)\n",
(gsaddr)o, (gsaddr)o ? ((NSDO*)o)->_object : 0);
}
return o ? RETAIN(((NSDO*)o)->_object) : nil;
}
case PROXY_LOCAL_FOR_SENDER:
/*
* This was a local object on the other side of the connection,
* but here it's a proxy object. Get the target address, and
* send [NSDistantObject +proxyWithTarget:connection:]; this will
* return the proxy object we already created for this target, or
* create a new proxy object if necessary.
*/
[aCoder decodeValueOfObjCType: @encode(typeof(target))
at: &target];
if (debug_proxy)
NSLog(@"Receiving a proxy, was local 0x%x connection 0x%x\n",
target, (gsaddr)decoder_connection);
return [self initWithTarget: target
connection: decoder_connection];
case PROXY_REMOTE_FOR_BOTH:
/*
* This was a proxy on the other side of the connection, and it
* will be a proxy on this side too; that is, the local version
* of this object is not on this host, not on the host the
* NSPortCoder is connected to, but on a *third* host.
* This is why I call this a "triangle connection". In addition
* to decoding the target, we decode the OutPort object that we
* will use to talk directly to this third host. We send
* [NSConnection +newForInPort:outPort:ancestorConnection:]; this
* will either return the connection already created for this
* inPort/outPort pair, or create a new connection if necessary.
*/
{
NSConnection *proxy_connection;
NSPort *proxy_connection_out_port = nil;
unsigned intermediary;
/*
* There is an object on the intermediary host that is keeping
* that hosts proxy for the original object retained, thus
* ensuring that the original is not released. We create a
* proxy for that intermediate proxy. When we release this
* proxy, the intermediary will be free to release it's proxy
* and the original can then be released. Of course, by that
* time we will have obtained our own proxy for the original
* object ...
*/
[aCoder decodeValueOfObjCType: @encode(typeof(intermediary))
at: &intermediary];
AUTORELEASE([self initWithTarget: intermediary
connection: decoder_connection]);
/*
* Now we get the target number and port for the orignal object
* and (if necessary) get the originating process to retain the
* object for us.
*/
[aCoder decodeValueOfObjCType: @encode(typeof(target))
at: &target];
[aCoder decodeValueOfObjCType: @encode(id)
at: &proxy_connection_out_port];
NSAssert(proxy_connection_out_port, NSInternalInconsistencyException);
/*
# If there already exists a connection for talking to the
* out port, we use that one rather than creating a new one from
* our listening port.
*
* First we try for a connection from our receive port,
* Then we try any connection to the send port
* Finally we resort to creating a new connection - we don't
* release the newly created connection - it will get released
* automatically when no proxies are left on it.
*/
proxy_connection = [[decoder_connection class]
connectionWithReceivePort: [decoder_connection receivePort]
sendPort: proxy_connection_out_port];
if (debug_proxy)
NSLog(@"Receiving a triangle-connection proxy 0x%x "
@"connection 0x%x\n", target, (gsaddr)proxy_connection);
NSAssert(proxy_connection != decoder_connection,
NSInternalInconsistencyException);
NSAssert([proxy_connection isValid],
NSInternalInconsistencyException);
/*
* If we don't already have a proxy for the object on the
* remote system, we must tell the other end to retain its
* local object for our use.
*/
if ([proxy_connection includesProxyForTarget: target] == NO)
[proxy_connection retainTarget: target];
/*
* Finally - we get a proxy via a direct connection to the
* originating server. We have also created a proxy to an
* intermediate object - but this proxy has not been retained
* and will therefore go away when the current autorelease
* pool is destroyed.
*/
return [self initWithTarget: target
connection: proxy_connection];
}
default:
/* xxx This should be something different than NSGenericException. */
[NSException raise: NSGenericException
format: @"Bad proxy tag"];
}
/* Not reached. */
return nil;
}
+ (id) initWithLocal: (id)anObject connection: (NSConnection*)aConnection
@ -138,16 +313,6 @@ static Class distantObjectClass = 0;
@implementation NSDistantObject
/* This is the proxy tag; it indicates where the local object is,
and determines whether the reply port to the Connection-where-the-
proxy-is-local needs to encoded/decoded or not. */
enum
{
PROXY_LOCAL_FOR_RECEIVER = 0,
PROXY_LOCAL_FOR_SENDER,
PROXY_REMOTE_FOR_BOTH
};
+ (void) initialize
{
if (self == [NSDistantObject class])

View file

@ -881,7 +881,7 @@ mapClassName(NSUnarchiverObjectInfo *info)
#if GS_HAVE_I64
bigval = val;
#else
val = GSSwapBigI64ToHost(val);
bigval = GSSwapBigI64ToHost(val);
#endif
break;
}