mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-31 00:30:53 +00:00
Cleanups in preparation for experimental changes to retain/relase over DO.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@17949 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
89b08c9c88
commit
b08343d175
4 changed files with 159 additions and 201 deletions
19
ChangeLog
19
ChangeLog
|
@ -1,3 +1,22 @@
|
||||||
|
Tue Oct 21 18:00:00 2003 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
|
* Source/NSDistantObject.m: Retain local objects on creation,
|
||||||
|
and release on deallocation ... don't depend on the connection
|
||||||
|
to do it.
|
||||||
|
* Source/NSConnection.m: Restructured handling of proxies ...
|
||||||
|
remove global tables of local object references and just look in all
|
||||||
|
connections and cache when a local object cannot be found in the
|
||||||
|
current connection.
|
||||||
|
Don't retain local objects ... depend on the NSDistantObject class
|
||||||
|
to do that.
|
||||||
|
Don't keep counters of the number of connections in which a local
|
||||||
|
object reference is used ... it's not needed if we don't need to
|
||||||
|
track whether to release the local object or not.
|
||||||
|
Shorten timeout for deferred deallocation of local object references
|
||||||
|
(temporary measure).
|
||||||
|
* Headers/Foundation/NSDistantObject.h: new ivar for future use
|
||||||
|
keeping track of number of times an object is vended.
|
||||||
|
|
||||||
Tue Oct 21 15:25:00 2003 Richard Frith-Macdonald <rfm@gnu.org>
|
Tue Oct 21 15:25:00 2003 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
* Testing/nsconnection_client.m: Add -r option.
|
* Testing/nsconnection_client.m: Add -r option.
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
id _object;
|
id _object;
|
||||||
unsigned _handle;
|
unsigned _handle;
|
||||||
Protocol *_protocol;
|
Protocol *_protocol;
|
||||||
|
unsigned _counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSDistantObject*) proxyWithLocal: (id)anObject
|
+ (NSDistantObject*) proxyWithLocal: (id)anObject
|
||||||
|
|
|
@ -104,7 +104,6 @@ static id dummyObject;
|
||||||
static Class connectionClass;
|
static Class connectionClass;
|
||||||
static Class dateClass;
|
static Class dateClass;
|
||||||
static Class distantObjectClass;
|
static Class distantObjectClass;
|
||||||
static Class localCounterClass;
|
|
||||||
static Class sendCoderClass;
|
static Class sendCoderClass;
|
||||||
static Class recvCoderClass;
|
static Class recvCoderClass;
|
||||||
static Class runLoopClass;
|
static Class runLoopClass;
|
||||||
|
@ -139,66 +138,26 @@ stringFromMsgType(int type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* GSLocalCounter is a trivial class to keep track of how
|
|
||||||
* many different connections a particular local object is vended
|
|
||||||
* over. This is required so that we know when to remove an object
|
|
||||||
* from the global list when it is removed from the list of objects
|
|
||||||
* vended on a particular connection.
|
|
||||||
*/
|
|
||||||
@interface GSLocalCounter : NSObject
|
|
||||||
{
|
|
||||||
@public
|
|
||||||
unsigned ref;
|
|
||||||
unsigned target;
|
|
||||||
id object;
|
|
||||||
}
|
|
||||||
+ (id) newWithObject: (id)ob;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation GSLocalCounter
|
|
||||||
|
|
||||||
static unsigned local_object_counter = 0;
|
|
||||||
|
|
||||||
+ (id) newWithObject: (id)obj
|
|
||||||
{
|
|
||||||
GSLocalCounter *counter;
|
|
||||||
|
|
||||||
counter = (GSLocalCounter*)NSAllocateObject(self, 0, NSDefaultMallocZone());
|
|
||||||
counter->ref = 1;
|
|
||||||
counter->object = RETAIN(obj);
|
|
||||||
counter->target = ++local_object_counter;
|
|
||||||
return counter;
|
|
||||||
}
|
|
||||||
- (void) dealloc
|
|
||||||
{
|
|
||||||
RELEASE(object);
|
|
||||||
NSDeallocateObject(self);
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CachedLocalObject is a trivial class to keep track of how
|
* CachedLocalObject is a trivial class to keep track of local
|
||||||
* many different connections a particular local object is vended
|
* proxies which have been removed from their connections and
|
||||||
* over. This is required so that we know when to remove an object
|
* need to persist a while in case another process needs them.
|
||||||
* from the global list when it is removed from the list of objects
|
|
||||||
* vended on a particular connection.
|
|
||||||
*/
|
*/
|
||||||
@interface CachedLocalObject : NSObject
|
@interface CachedLocalObject : NSObject
|
||||||
{
|
{
|
||||||
id obj;
|
NSDistantObject *obj;
|
||||||
int time;
|
int time;
|
||||||
}
|
}
|
||||||
- (BOOL) countdown;
|
- (BOOL) countdown;
|
||||||
- (id) obj;
|
- (NSDistantObject*) obj;
|
||||||
+ (id) newWithObject: (id)o time: (int)t;
|
+ (id) newWithObject: (NSDistantObject*)o time: (int)t;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation CachedLocalObject
|
@implementation CachedLocalObject
|
||||||
|
|
||||||
+ (id) newWithObject: (id)o time: (int)t
|
+ (id) newWithObject: (NSDistantObject*)o time: (int)t
|
||||||
{
|
{
|
||||||
CachedLocalObject *item;
|
CachedLocalObject *item;
|
||||||
|
|
||||||
|
@ -221,7 +180,7 @@ static unsigned local_object_counter = 0;
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id) obj
|
- (NSDistantObject*) obj
|
||||||
{
|
{
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
@ -338,10 +297,8 @@ setRootObjectForInPort(id anObj, NSPort *aPort)
|
||||||
F_UNLOCK(root_object_map_gate);
|
F_UNLOCK(root_object_map_gate);
|
||||||
}
|
}
|
||||||
|
|
||||||
static NSMapTable *objectToCounter = NULL;
|
|
||||||
static NSMapTable *targetToCounter = NULL;
|
|
||||||
static NSMapTable *targetToCached = NULL;
|
static NSMapTable *targetToCached = NULL;
|
||||||
static NSLock *global_proxies_gate = nil;
|
static NSLock *cached_proxies_gate = nil;
|
||||||
|
|
||||||
static BOOL multi_threaded = NO;
|
static BOOL multi_threaded = NO;
|
||||||
|
|
||||||
|
@ -370,9 +327,9 @@ static BOOL multi_threaded = NO;
|
||||||
{
|
{
|
||||||
connection_table_gate = [NSLock new];
|
connection_table_gate = [NSLock new];
|
||||||
}
|
}
|
||||||
if (global_proxies_gate == nil)
|
if (cached_proxies_gate == nil)
|
||||||
{
|
{
|
||||||
global_proxies_gate = [NSLock new];
|
cached_proxies_gate = [NSLock new];
|
||||||
}
|
}
|
||||||
if (root_object_map_gate == nil)
|
if (root_object_map_gate == nil)
|
||||||
{
|
{
|
||||||
|
@ -579,7 +536,6 @@ static BOOL multi_threaded = NO;
|
||||||
connectionClass = self;
|
connectionClass = self;
|
||||||
dateClass = [NSDate class];
|
dateClass = [NSDate class];
|
||||||
distantObjectClass = [NSDistantObject class];
|
distantObjectClass = [NSDistantObject class];
|
||||||
localCounterClass = [GSLocalCounter class];
|
|
||||||
sendCoderClass = [NSPortCoder class];
|
sendCoderClass = [NSPortCoder class];
|
||||||
recvCoderClass = [NSPortCoder class];
|
recvCoderClass = [NSPortCoder class];
|
||||||
runLoopClass = [NSRunLoop class];
|
runLoopClass = [NSRunLoop class];
|
||||||
|
@ -589,12 +545,6 @@ static BOOL multi_threaded = NO;
|
||||||
connection_table =
|
connection_table =
|
||||||
NSCreateHashTable(NSNonRetainedObjectHashCallBacks, 0);
|
NSCreateHashTable(NSNonRetainedObjectHashCallBacks, 0);
|
||||||
|
|
||||||
objectToCounter =
|
|
||||||
NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
|
|
||||||
NSObjectMapValueCallBacks, 0);
|
|
||||||
targetToCounter =
|
|
||||||
NSCreateMapTable(NSIntMapKeyCallBacks,
|
|
||||||
NSNonOwnedPointerMapValueCallBacks, 0);
|
|
||||||
targetToCached =
|
targetToCached =
|
||||||
NSCreateMapTable(NSIntMapKeyCallBacks,
|
NSCreateMapTable(NSIntMapKeyCallBacks,
|
||||||
NSObjectMapValueCallBacks, 0);
|
NSObjectMapValueCallBacks, 0);
|
||||||
|
@ -677,7 +627,7 @@ static BOOL multi_threaded = NO;
|
||||||
NSArray *cached_locals;
|
NSArray *cached_locals;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
M_LOCK(global_proxies_gate);
|
M_LOCK(cached_proxies_gate);
|
||||||
cached_locals = NSAllMapTableValues(targetToCached);
|
cached_locals = NSAllMapTableValues(targetToCached);
|
||||||
for (i = [cached_locals count]; i > 0; i--)
|
for (i = [cached_locals count]; i > 0; i--)
|
||||||
{
|
{
|
||||||
|
@ -685,8 +635,8 @@ static BOOL multi_threaded = NO;
|
||||||
|
|
||||||
if ([item countdown] == NO)
|
if ([item countdown] == NO)
|
||||||
{
|
{
|
||||||
GSLocalCounter *counter = [item obj];
|
NSDistantObject *obj = [item obj];
|
||||||
NSMapRemove(targetToCached, (void*)counter->target);
|
NSMapRemove(targetToCached, (void*)((ProxyStruct*)obj)->_handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ([cached_locals count] == 0)
|
if ([cached_locals count] == 0)
|
||||||
|
@ -694,7 +644,7 @@ static BOOL multi_threaded = NO;
|
||||||
[t invalidate];
|
[t invalidate];
|
||||||
timer = nil;
|
timer = nil;
|
||||||
}
|
}
|
||||||
M_UNLOCK(global_proxies_gate);
|
M_UNLOCK(cached_proxies_gate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1215,8 +1165,9 @@ static BOOL multi_threaded = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an array of all the local proxies to objects that
|
* Returns an array of all the local objects that have proxies at the
|
||||||
* are retained by the remote connection.
|
* remote end of the connection because they have been sent over the
|
||||||
|
* connection and not yet released by the far end.
|
||||||
*/
|
*/
|
||||||
- (NSArray*) localObjects
|
- (NSArray*) localObjects
|
||||||
{
|
{
|
||||||
|
@ -1322,7 +1273,7 @@ static BOOL multi_threaded = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an array of proxies to all the remote objects known to
|
* Returns an array of proxies to all the remote objects known to
|
||||||
* the NSConnection.
|
* the NSConnection.
|
||||||
*/
|
*/
|
||||||
- (NSArray *) remoteObjects
|
- (NSArray *) remoteObjects
|
||||||
|
@ -2495,6 +2446,10 @@ static void callEncoder (DOContext *ctxt)
|
||||||
}
|
}
|
||||||
NS_HANDLER
|
NS_HANDLER
|
||||||
{
|
{
|
||||||
|
if (debug_connection > 3)
|
||||||
|
NSLog(@"forwarding exception for (0x%x) - %@",
|
||||||
|
(gsaddr)self, localException);
|
||||||
|
|
||||||
/* Send the exception back to the client. */
|
/* Send the exception back to the client. */
|
||||||
if (_isValid == YES)
|
if (_isValid == YES)
|
||||||
{
|
{
|
||||||
|
@ -2672,7 +2627,7 @@ static void callEncoder (DOContext *ctxt)
|
||||||
[rmc decodeValueOfObjCType: @encode(unsigned) at: &target];
|
[rmc decodeValueOfObjCType: @encode(unsigned) at: &target];
|
||||||
[self _doneInRmc: rmc];
|
[self _doneInRmc: rmc];
|
||||||
p = [self includesLocalTarget: target];
|
p = [self includesLocalTarget: target];
|
||||||
o = ((ProxyStruct*)p)->_object;
|
o = (p != nil) ? ((ProxyStruct*)p)->_object : nil;
|
||||||
|
|
||||||
/* xxx We should make sure that TARGET is a valid object. */
|
/* xxx We should make sure that TARGET is a valid object. */
|
||||||
/* Not actually a Proxy, but we avoid the warnings "id" would have made. */
|
/* Not actually a Proxy, but we avoid the warnings "id" would have made. */
|
||||||
|
@ -3106,55 +3061,41 @@ static void callEncoder (DOContext *ctxt)
|
||||||
/* Managing objects and proxies. */
|
/* Managing objects and proxies. */
|
||||||
- (void) addLocalObject: (NSDistantObject*)anObj
|
- (void) addLocalObject: (NSDistantObject*)anObj
|
||||||
{
|
{
|
||||||
|
static unsigned local_object_counter = 0;
|
||||||
id object;
|
id object;
|
||||||
unsigned target;
|
unsigned target;
|
||||||
GSLocalCounter *counter;
|
|
||||||
GSIMapNode node;
|
GSIMapNode node;
|
||||||
|
|
||||||
M_LOCK(_proxiesGate);
|
M_LOCK(_proxiesGate);
|
||||||
M_LOCK(global_proxies_gate);
|
|
||||||
NSParameterAssert (_isValid);
|
NSParameterAssert (_isValid);
|
||||||
|
|
||||||
|
object = ((ProxyStruct*)anObj)->_object;
|
||||||
|
target = ((ProxyStruct*)anObj)->_handle;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there is no target allocated to the proxy, we add one.
|
||||||
|
*/
|
||||||
|
if (target == 0)
|
||||||
|
{
|
||||||
|
((ProxyStruct*)anObj)->_handle = target = ++local_object_counter;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Record the value in the _localObjects map, retaining it.
|
* Record the value in the _localObjects map, retaining it.
|
||||||
*/
|
*/
|
||||||
object = ((ProxyStruct*)anObj)->_object;
|
|
||||||
node = GSIMapNodeForKey(_localObjects, (GSIMapKey)object);
|
node = GSIMapNodeForKey(_localObjects, (GSIMapKey)object);
|
||||||
IF_NO_GC(RETAIN(anObj));
|
NSAssert(node == 0, NSInternalInconsistencyException);
|
||||||
if (node == 0)
|
node = GSIMapNodeForKey(_localTargets, (GSIMapKey)target);
|
||||||
{
|
NSAssert(node == 0, NSInternalInconsistencyException);
|
||||||
GSIMapAddPair(_localObjects, (GSIMapKey)object, (GSIMapVal)anObj);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RELEASE(node->value.obj);
|
|
||||||
node->value.obj = anObj;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
RETAIN(anObj);
|
||||||
* Keep track of local objects accross all connections.
|
GSIMapAddPair(_localObjects, (GSIMapKey)object, (GSIMapVal)anObj);
|
||||||
*/
|
|
||||||
counter = NSMapGet(objectToCounter, (void*)object);
|
|
||||||
if (counter)
|
|
||||||
{
|
|
||||||
counter->ref++;
|
|
||||||
target = counter->target;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
counter = [localCounterClass newWithObject: object];
|
|
||||||
target = counter->target;
|
|
||||||
NSMapInsert(objectToCounter, (void*)object, counter);
|
|
||||||
NSMapInsert(targetToCounter, (void*)target, counter);
|
|
||||||
RELEASE(counter);
|
|
||||||
}
|
|
||||||
((ProxyStruct*)anObj)->_handle = target;
|
|
||||||
GSIMapAddPair(_localTargets, (GSIMapKey)target, (GSIMapVal)anObj);
|
GSIMapAddPair(_localTargets, (GSIMapKey)target, (GSIMapVal)anObj);
|
||||||
|
|
||||||
if (debug_connection > 2)
|
if (debug_connection > 2)
|
||||||
NSLog(@"add local object (0x%x) target (0x%x) "
|
NSLog(@"add local object (0x%x) target (0x%x) "
|
||||||
@"to connection (0x%x) (ref %d)",
|
@"to connection (0x%x)", (gsaddr)object, target, (gsaddr) self);
|
||||||
(gsaddr)object, target, (gsaddr) self, counter->ref);
|
|
||||||
M_UNLOCK(global_proxies_gate);
|
|
||||||
M_UNLOCK(_proxiesGate);
|
M_UNLOCK(_proxiesGate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3183,60 +3124,46 @@ static void callEncoder (DOContext *ctxt)
|
||||||
{
|
{
|
||||||
NSDistantObject *prox;
|
NSDistantObject *prox;
|
||||||
unsigned target;
|
unsigned target;
|
||||||
GSLocalCounter *counter;
|
|
||||||
unsigned val = 0;
|
unsigned val = 0;
|
||||||
GSIMapNode node;
|
GSIMapNode node;
|
||||||
|
|
||||||
M_LOCK(global_proxies_gate);
|
|
||||||
M_LOCK(_proxiesGate);
|
M_LOCK(_proxiesGate);
|
||||||
|
|
||||||
node = GSIMapNodeForKey(_localObjects, (GSIMapKey)anObj);
|
node = GSIMapNodeForKey(_localObjects, (GSIMapKey)anObj);
|
||||||
if (node == 0)
|
if (node == 0)
|
||||||
{
|
{
|
||||||
M_UNLOCK(_proxiesGate);
|
M_UNLOCK(_proxiesGate);
|
||||||
M_UNLOCK(global_proxies_gate);
|
|
||||||
[NSException raise: NSInternalInconsistencyException
|
[NSException raise: NSInternalInconsistencyException
|
||||||
format: @"Attempt to remove non-existent local %@", anObj];
|
format: @"Attempt to remove non-existent local %@", anObj];
|
||||||
}
|
}
|
||||||
prox = node->value.obj;
|
prox = node->value.obj;
|
||||||
target = ((ProxyStruct*)prox)->_handle;
|
target = ((ProxyStruct*)prox)->_handle;
|
||||||
|
|
||||||
/*
|
if (1)
|
||||||
* If all references to a local proxy have gone - remove the
|
|
||||||
* global reference as well.
|
|
||||||
*/
|
|
||||||
counter = NSMapGet(objectToCounter, (void*)anObj);
|
|
||||||
if (counter)
|
|
||||||
{
|
{
|
||||||
counter->ref--;
|
id item;
|
||||||
if ((val = counter->ref) == 0)
|
|
||||||
|
M_LOCK(cached_proxies_gate);
|
||||||
|
/*
|
||||||
|
* If this proxy has been vended onwards by another process, we
|
||||||
|
* need to keep a reference to the local object around for a
|
||||||
|
* while in case that other process needs it.
|
||||||
|
*/
|
||||||
|
if (timer == nil)
|
||||||
{
|
{
|
||||||
if (1)
|
timer = [NSTimer scheduledTimerWithTimeInterval: 1.0
|
||||||
{
|
target: connectionClass
|
||||||
id item;
|
selector: @selector(_timeout:)
|
||||||
/*
|
userInfo: nil
|
||||||
* If this proxy has been vended onwards by another process, we
|
repeats: YES];
|
||||||
* need to keep a reference to the local object around for a
|
|
||||||
* while in case that other process needs it.
|
|
||||||
*/
|
|
||||||
if (timer == nil)
|
|
||||||
{
|
|
||||||
timer = [NSTimer scheduledTimerWithTimeInterval: 1.0
|
|
||||||
target: connectionClass
|
|
||||||
selector: @selector(_timeout:)
|
|
||||||
userInfo: nil
|
|
||||||
repeats: YES];
|
|
||||||
}
|
|
||||||
item = [CachedLocalObject newWithObject: counter time: 30];
|
|
||||||
NSMapInsert(targetToCached, (void*)target, item);
|
|
||||||
RELEASE(item);
|
|
||||||
if (debug_connection > 3)
|
|
||||||
NSLog(@"placed local object (0x%x) target (0x%x) in cache",
|
|
||||||
(gsaddr)anObj, target);
|
|
||||||
}
|
|
||||||
NSMapRemove(objectToCounter, (void*)anObj);
|
|
||||||
NSMapRemove(targetToCounter, (void*)target);
|
|
||||||
}
|
}
|
||||||
|
item = [CachedLocalObject newWithObject: prox time: 5];
|
||||||
|
NSMapInsert(targetToCached, (void*)target, item);
|
||||||
|
M_UNLOCK(cached_proxies_gate);
|
||||||
|
RELEASE(item);
|
||||||
|
if (debug_connection > 3)
|
||||||
|
NSLog(@"placed local object (0x%x) target (0x%x) in cache",
|
||||||
|
(gsaddr)anObj, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -3256,7 +3183,6 @@ static void callEncoder (DOContext *ctxt)
|
||||||
(gsaddr)anObj, target, (gsaddr)self, val);
|
(gsaddr)anObj, target, (gsaddr)self, val);
|
||||||
|
|
||||||
M_UNLOCK(_proxiesGate);
|
M_UNLOCK(_proxiesGate);
|
||||||
M_UNLOCK(global_proxies_gate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) _release_targets: (unsigned*)list count: (unsigned)number
|
- (void) _release_targets: (unsigned*)list count: (unsigned)number
|
||||||
|
@ -3302,64 +3228,79 @@ static void callEncoder (DOContext *ctxt)
|
||||||
NSDistantObject *proxy = nil;
|
NSDistantObject *proxy = nil;
|
||||||
GSIMapNode node;
|
GSIMapNode node;
|
||||||
|
|
||||||
M_LOCK(global_proxies_gate);
|
M_LOCK(_proxiesGate);
|
||||||
node = GSIMapNodeForKey(_localTargets, (GSIMapKey)target);
|
node = GSIMapNodeForKey(_localTargets, (GSIMapKey)target);
|
||||||
if (node != 0)
|
if (node != 0)
|
||||||
{
|
{
|
||||||
proxy = node->value.obj;
|
proxy = node->value.obj;
|
||||||
M_UNLOCK(global_proxies_gate);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
/*
|
||||||
|
* If not found in the current connection, try all other existing
|
||||||
|
* connections.
|
||||||
|
*/
|
||||||
|
if (proxy == nil)
|
||||||
{
|
{
|
||||||
GSLocalCounter *counter;
|
NSHashEnumerator enumerator;
|
||||||
|
NSConnection *c;
|
||||||
|
|
||||||
counter = NSMapGet (targetToCounter, (void*)target);
|
M_LOCK(connection_table_gate);
|
||||||
if (counter == nil)
|
enumerator = NSEnumerateHashTable(connection_table);
|
||||||
|
while (proxy == nil
|
||||||
|
&& (c = (NSConnection*)NSNextHashEnumeratorItem(&enumerator)) != nil)
|
||||||
{
|
{
|
||||||
CachedLocalObject *cached;
|
if (c != self && [c isValid] == YES)
|
||||||
|
|
||||||
/*
|
|
||||||
* If the target doesn't exist for any connection, but still
|
|
||||||
* persists in the cache (ie it was recently released) then
|
|
||||||
* we move it back from the cache to the main maps so we can
|
|
||||||
* retain it on this connection.
|
|
||||||
*/
|
|
||||||
cached = NSMapGet (targetToCached, (void*)target);
|
|
||||||
if (cached != nil)
|
|
||||||
{
|
{
|
||||||
unsigned t;
|
M_LOCK(c->_proxiesGate);
|
||||||
id o;
|
node = GSIMapNodeForKey(c->_localTargets, (GSIMapKey)target);
|
||||||
|
if (node != 0)
|
||||||
counter = [cached obj];
|
{
|
||||||
|
proxy = node->value.obj;
|
||||||
t = counter->target;
|
/*
|
||||||
o = counter->object;
|
* Found in another connection ... add to this one.
|
||||||
|
*/
|
||||||
NSMapInsert(objectToCounter, (void*)o, counter);
|
[self addLocalObject: proxy];
|
||||||
NSMapInsert(targetToCounter, (void*)t, counter);
|
}
|
||||||
NSMapRemove(targetToCached, (void*)t);
|
M_UNLOCK(c->_proxiesGate);
|
||||||
if (debug_connection > 3)
|
|
||||||
NSLog(@"target (0x%x) moved from cache", target);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RETAIN(counter);
|
NSEndHashTableEnumeration(&enumerator);
|
||||||
M_UNLOCK(global_proxies_gate);
|
M_UNLOCK(connection_table_gate);
|
||||||
if (counter == nil)
|
}
|
||||||
|
|
||||||
|
if (proxy == nil)
|
||||||
|
{
|
||||||
|
CachedLocalObject *cached;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the target doesn't exist for any connection, but still
|
||||||
|
* persists in the cache (ie it was recently released) then
|
||||||
|
* we move it back from the cache to the connection so we can
|
||||||
|
* retain it on this connection.
|
||||||
|
*/
|
||||||
|
M_LOCK(cached_proxies_gate);
|
||||||
|
cached = NSMapGet (targetToCached, (void*)target);
|
||||||
|
if (cached != nil)
|
||||||
{
|
{
|
||||||
if(debug_connection > 3)
|
proxy = [cached obj];
|
||||||
NSLog(@"target (0x%x) not found anywhere", target);
|
/*
|
||||||
}
|
* Found in cache ... add to this connection.
|
||||||
else
|
*/
|
||||||
{
|
ASSIGN(((ProxyStruct*)proxy)->_connection, self);
|
||||||
NSAssert([counter isKindOfClass: [GSLocalCounter class]],
|
[self addLocalObject: proxy];
|
||||||
@"Local counter is wrong kind of class.");
|
NSMapRemove(targetToCached, (void*)target);
|
||||||
proxy = [distantObjectClass proxyWithLocal: counter->object
|
|
||||||
connection: self];
|
|
||||||
if (debug_connection > 3)
|
if (debug_connection > 3)
|
||||||
NSLog(@"retained object (0x%x) target (0x%x) on connection(0x%x)",
|
NSLog(@"target (0x%x) moved from cache", target);
|
||||||
counter->object, counter->target, self);
|
|
||||||
RELEASE(counter);
|
|
||||||
}
|
}
|
||||||
|
M_UNLOCK(cached_proxies_gate);
|
||||||
|
}
|
||||||
|
|
||||||
|
M_UNLOCK(_proxiesGate);
|
||||||
|
|
||||||
|
if (proxy == nil)
|
||||||
|
{
|
||||||
|
if (debug_connection > 3)
|
||||||
|
NSLog(@"target (0x%x) not found anywhere", target);
|
||||||
}
|
}
|
||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
|
@ -3369,8 +3310,8 @@ static void callEncoder (DOContext *ctxt)
|
||||||
NS_DURING
|
NS_DURING
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Tell the remote app that it must retain the local object
|
* Tell the remote app that it must retain the local object
|
||||||
* for the target on this connection.
|
* for the target on this connection.
|
||||||
*/
|
*/
|
||||||
if (_receivePort && _isValid)
|
if (_receivePort && _isValid)
|
||||||
{
|
{
|
||||||
|
@ -3442,7 +3383,7 @@ static void callEncoder (DOContext *ctxt)
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) addProxy: (NSDistantObject*) aProxy
|
- (void) addProxy: (NSDistantObject*)aProxy
|
||||||
{
|
{
|
||||||
unsigned target;
|
unsigned target;
|
||||||
GSIMapNode node;
|
GSIMapNode node;
|
||||||
|
|
|
@ -726,15 +726,10 @@ enum
|
||||||
return new_proxy;
|
return new_proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
_object = RETAIN(anObject);
|
||||||
* We don't need to retain the object here - the connection
|
|
||||||
* will retain the proxies local object if necessary (and release it
|
|
||||||
* when all proxies referring to it have been released).
|
|
||||||
*/
|
|
||||||
_object = anObject;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We register this proxy with the connection using it.
|
* We register this proxy with the connection using it.
|
||||||
*/
|
*/
|
||||||
_connection = RETAIN(aConnection);
|
_connection = RETAIN(aConnection);
|
||||||
[_connection addLocalObject: self];
|
[_connection addLocalObject: self];
|
||||||
|
@ -831,7 +826,7 @@ enum
|
||||||
return sig;
|
return sig;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Simlarly, when we fetch a method signature form the remote end,
|
* Simlarly, when we fetch a method signature from the remote end,
|
||||||
* we get a proxy, and when we build a local signature we need to
|
* we get a proxy, and when we build a local signature we need to
|
||||||
* ask the proxy for its types ... and must avoid recursion again.
|
* ask the proxy for its types ... and must avoid recursion again.
|
||||||
*/
|
*/
|
||||||
|
@ -986,19 +981,21 @@ enum
|
||||||
NSLog(@"retain count for connection (0x%x) is now %u\n",
|
NSLog(@"retain count for connection (0x%x) is now %u\n",
|
||||||
(gsaddr)_connection, [_connection retainCount]);
|
(gsaddr)_connection, [_connection retainCount]);
|
||||||
/*
|
/*
|
||||||
* A proxy for local object does not retain it's target - the
|
* A proxy for local object retains its target - so we release it.
|
||||||
* NSConnection class does that for us - so we need not release it.
|
|
||||||
* For a local object the connection also retains this proxy, so we
|
* For a local object the connection also retains this proxy, so we
|
||||||
* can't be deallocated unless we are already removed from the
|
* can't be deallocated unless we are already removed from the
|
||||||
* connection.
|
* connection, and there is no need to remove self from connection.
|
||||||
*
|
*
|
||||||
* A proxy retains it's connection so that the connection will
|
* A proxy has a nil local object, and retains it's connection so
|
||||||
* continue to exist as long as there is a something to use it.
|
* that the connection will continue to exist as long as there is
|
||||||
|
* a something to use it.
|
||||||
* So we release our reference to the connection here just as soon
|
* So we release our reference to the connection here just as soon
|
||||||
* as we have removed ourself from the connection.
|
* as we have removed ourself from the connection.
|
||||||
*/
|
*/
|
||||||
if (_object == nil)
|
if (_object == nil)
|
||||||
[_connection removeProxy: self];
|
[_connection removeProxy: self];
|
||||||
|
else
|
||||||
|
DESTROY(_object);
|
||||||
RELEASE(_connection);
|
RELEASE(_connection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue