mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
DO patch from Richard Frith-MacDonald <richard@brainstorm.co.uk>
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@2410 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
4d6732922c
commit
79c7545d62
9 changed files with 384 additions and 149 deletions
28
ChangeLog
28
ChangeLog
|
@ -1,3 +1,31 @@
|
|||
Tue Sep 9 10:15:00 1997 Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
||||
|
||||
* src/NSConnection.m: Made numerous changes to fix memory leak with
|
||||
ports never being released and to fix problems in port invalidation
|
||||
associated with that. Also added code to cope with odd cases like
|
||||
when a remote application dires while we are waiting for a response
|
||||
from it.
|
||||
|
||||
* src/NSPort.m: Added [-release] method which ensures that ports
|
||||
are invlidated before they are finally deallocated.
|
||||
|
||||
* src/NSPortCoder.m: Catch exceptions during attempt to write data.
|
||||
|
||||
* src/NSRunLoop.m: Fixed this so that a count is kept of the
|
||||
number of times a port has been added to the run loop as per the
|
||||
OPENSTEP documentation.
|
||||
|
||||
* src/TcpPort.m: Fixed a minor retain/release problem.
|
||||
|
||||
* src/UnixFileHandle.m: Added loads of checks so that attempts to
|
||||
use a file handle which has been closed will fail/generate an exception
|
||||
rather than crashing things! Also modified for changes to NSRunLoop.
|
||||
|
||||
* src/include/NSRunLoop.h: Modified the interface for adding watchers
|
||||
for events with a count of the number of times they have been added.
|
||||
|
||||
* src/include/Port.h: Removed [-isValid] - now in NSPort.
|
||||
|
||||
Tue Aug 26 15:47:54 1997 Adam Fedor <fedor@doc.com>
|
||||
|
||||
* src/NSCTemplateValue.m ([NSCTemplateValue -description]): New
|
||||
|
|
|
@ -143,7 +143,12 @@ typedef enum {
|
|||
/*
|
||||
* These next two are general purpose methods for letting objects
|
||||
* ask the runloop to watch for events for them. Only one object
|
||||
* at a time may be watching for a particular event in a mode.
|
||||
* at a time may be watching for a particular event in a mode, but
|
||||
* that object may add itsself as a watcher many times as long as
|
||||
* each addition is matched by a removal (the run loop keeps count).
|
||||
* Alternatively, the 'removeAll' parameter may be set to 'YES' for
|
||||
* [-removeEvent:type:forMode:all:] in order to remove the watcher
|
||||
* irrespective of the number of times it has been added.
|
||||
*/
|
||||
- (void) addEvent: (void*)data
|
||||
type: (RunLoopEventType)type
|
||||
|
@ -151,7 +156,8 @@ typedef enum {
|
|||
forMode: (NSString*)mode;
|
||||
- (void) removeEvent: (void*)data
|
||||
type: (RunLoopEventType)type
|
||||
forMode: (NSString*)mode;
|
||||
forMode: (NSString*)mode
|
||||
all: (BOOL)removeAll;
|
||||
/*
|
||||
* The next four methods are rendered obsolete by
|
||||
* [-addEvent:type:watcher:forMode:] and
|
||||
|
|
|
@ -40,7 +40,6 @@
|
|||
{
|
||||
}
|
||||
- (void) invalidate;
|
||||
- (BOOL) isValid;
|
||||
- (void) close;
|
||||
|
||||
+ (Class) outPacketClass;
|
||||
|
|
|
@ -278,9 +278,10 @@ static int messages_received_count;
|
|||
|
||||
+ new
|
||||
{
|
||||
id newPort = [default_receive_port_class newForReceiving];
|
||||
id newConn =
|
||||
[NSConnection newForInPort:newPort outPort:nil ancestorConnection:nil];
|
||||
id newPort = [[default_receive_port_class newForReceiving] autorelease];
|
||||
id newConn = [NSConnection newForInPort:newPort
|
||||
outPort:nil
|
||||
ancestorConnection:nil];
|
||||
return newConn;
|
||||
}
|
||||
|
||||
|
@ -291,7 +292,7 @@ static int messages_received_count;
|
|||
if (p == nil) {
|
||||
return nil;
|
||||
}
|
||||
return [self rootProxyAtPort: p];
|
||||
return [self rootProxyAtPort: [p autorelease]];
|
||||
}
|
||||
|
||||
- (void) addRequestMode: (NSString*)mode
|
||||
|
@ -308,14 +309,24 @@ static int messages_received_count;
|
|||
if (debug_connection)
|
||||
printf("deallocating 0x%x\n", (unsigned)self);
|
||||
[self invalidate];
|
||||
|
||||
/* Remove rootObject from root_object_dictionary
|
||||
if this is last connection */
|
||||
if (![NSConnection connectionsCountWithInPort:receive_port])
|
||||
[NSConnection setRootObject:nil forInPort:receive_port];
|
||||
[NotificationDispatcher removeObserver: self];
|
||||
|
||||
/* Remove receive port from run loop. */
|
||||
[self setRequestMode: nil];
|
||||
[[NSRunLoop currentRunLoop] removePort: receive_port
|
||||
forMode: NSConnectionReplyMode];
|
||||
[request_modes release];
|
||||
|
||||
/* Finished with ports - releasing them may generate a notification */
|
||||
[receive_port release];
|
||||
[send_port release];
|
||||
[request_modes release];
|
||||
|
||||
/* Don't need notifications any more - so remove self as observer. */
|
||||
[NotificationDispatcher removeObserver: self];
|
||||
|
||||
[proxiesHashGate lock];
|
||||
NSFreeMapTable (remote_proxies);
|
||||
|
@ -339,9 +350,10 @@ static int messages_received_count;
|
|||
|
||||
- (id) init
|
||||
{
|
||||
id newPort = [default_receive_port_class newForReceiving];
|
||||
id newConn =
|
||||
[NSConnection newForInPort:newPort outPort:nil ancestorConnection:nil];
|
||||
id newPort = [[default_receive_port_class newForReceiving] autorelease];
|
||||
id newConn = [NSConnection newForInPort:newPort
|
||||
outPort:nil
|
||||
ancestorConnection:nil];
|
||||
[self release];
|
||||
return newConn;
|
||||
}
|
||||
|
@ -365,6 +377,12 @@ static int messages_received_count;
|
|||
{
|
||||
is_valid = 0;
|
||||
|
||||
/*
|
||||
* We can't be the ancestor of anything if we are invalid.
|
||||
*/
|
||||
if (self == NSMapGet(receive_port_2_ancestor, receive_port))
|
||||
NSMapRemove(receive_port_2_ancestor, receive_port);
|
||||
|
||||
/*
|
||||
* If we have been invalidated, we don't need to retain proxies
|
||||
* for local objects any more. In fact, we want to get rid of
|
||||
|
@ -515,7 +533,7 @@ static int messages_received_count;
|
|||
while ([request_modes count]>1) {
|
||||
[self removeRequestMode:[request_modes objectAtIndex:1]];
|
||||
}
|
||||
if ([request_modes count] == 0) {
|
||||
if (mode != nil && [request_modes count] == 0) {
|
||||
[self addRequestMode:mode];
|
||||
}
|
||||
}
|
||||
|
@ -667,7 +685,7 @@ static int messages_received_count;
|
|||
id newPort;
|
||||
id newConn;
|
||||
|
||||
newPort = [default_receive_port_class newForReceiving];
|
||||
newPort = [[default_receive_port_class newForReceiving] autorelease];
|
||||
newConn = [self newForInPort:newPort outPort:nil
|
||||
ancestorConnection:nil];
|
||||
[self setRootObject:anObj forInPort:newPort];
|
||||
|
@ -687,8 +705,9 @@ static int messages_received_count;
|
|||
id newConn;
|
||||
|
||||
newPort = [default_receive_port_class newForReceivingFromRegisteredName: n];
|
||||
newConn = [self newForInPort:newPort outPort:nil
|
||||
ancestorConnection:nil];
|
||||
newConn = [self newForInPort:[newPort autorelease]
|
||||
outPort:nil
|
||||
ancestorConnection:nil];
|
||||
[self setRootObject:anObj forInPort:newPort];
|
||||
return newConn;
|
||||
}
|
||||
|
@ -706,10 +725,12 @@ static int messages_received_count;
|
|||
+ (NSDistantObject*) rootProxyAtPort: (NSPort*)anOutPort
|
||||
{
|
||||
id newInPort = [default_receive_port_class newForReceiving];
|
||||
return [self rootProxyAtPort: anOutPort withInPort: newInPort];
|
||||
return [self rootProxyAtPort: anOutPort
|
||||
withInPort: [newInPort autorelease]];
|
||||
}
|
||||
|
||||
+ (NSDistantObject*) rootProxyAtPort: (NSPort*)anOutPort withInPort: (NSPort *)anInPort
|
||||
+ (NSDistantObject*) rootProxyAtPort: (NSPort*)anOutPort
|
||||
withInPort: (NSPort *)anInPort
|
||||
{
|
||||
NSConnection *newConn = [self newForInPort:anInPort
|
||||
outPort:anOutPort
|
||||
|
@ -809,10 +830,6 @@ static int messages_received_count;
|
|||
if (!(ancestor = NSMapGet (receive_port_2_ancestor, ip)))
|
||||
{
|
||||
NSMapInsert (receive_port_2_ancestor, ip, newConn);
|
||||
[[NSRunLoop currentRunLoop] addPort: (NSPort*)ip
|
||||
forMode: NSDefaultRunLoopMode];
|
||||
[[NSRunLoop currentRunLoop] addPort: (NSPort*)ip
|
||||
forMode: NSConnectionReplyMode];
|
||||
/* This will cause the connection with the registered name
|
||||
to receive the -invokeWithObject: from the IN_PORT.
|
||||
This ends up being the ancestor of future new NSConnections
|
||||
|
@ -837,8 +854,16 @@ static int messages_received_count;
|
|||
newConn->independant_queueing = NO;
|
||||
newConn->reply_depth = 0;
|
||||
newConn->delegate = nil;
|
||||
/*
|
||||
* Set up request modes array and make sure the receiving port is
|
||||
* added to the run loop to get data.
|
||||
*/
|
||||
newConn->request_modes = [[NSMutableArray arrayWithObject:
|
||||
NSDefaultRunLoopMode] retain];
|
||||
[[NSRunLoop currentRunLoop] addPort: (NSPort*)ip
|
||||
forMode: NSDefaultRunLoopMode];
|
||||
[[NSRunLoop currentRunLoop] addPort: (NSPort*)ip
|
||||
forMode: NSConnectionReplyMode];
|
||||
|
||||
/* Ssk the delegate for permission, (OpenStep-style and GNUstep-style). */
|
||||
|
||||
|
@ -967,6 +992,7 @@ static int messages_received_count;
|
|||
int seq_num;
|
||||
|
||||
NSParameterAssert (is_valid);
|
||||
[[self retain] autorelease];
|
||||
op = [self newSendingRequestRmc];
|
||||
seq_num = [op sequenceNumber];
|
||||
|
||||
|
@ -1018,6 +1044,11 @@ static int messages_received_count;
|
|||
/* If we didn't get the reply packet yet, get it now. */
|
||||
if (!ip)
|
||||
{
|
||||
if (!is_valid)
|
||||
{
|
||||
[NSException raise: NSGenericException
|
||||
format: @"connection waiting for request was shut down"];
|
||||
}
|
||||
/* xxx Why do we get the reply packet in here, and not
|
||||
just before calling dissect_method_return() below? */
|
||||
ip = [self _getReceivedReplyRmcWithSequenceNumber:seq_num];
|
||||
|
@ -1100,6 +1131,11 @@ static int messages_received_count;
|
|||
if (op == nil)
|
||||
{
|
||||
BOOL is_exception = NO;
|
||||
/* It is possible that our connection died while the method was
|
||||
being called - in this case we mustn't try to send the result
|
||||
back to the remote application! */
|
||||
if (!is_valid)
|
||||
return;
|
||||
op = [self newSendingReplyRmcWithSequenceNumber:
|
||||
reply_sequence_number];
|
||||
[op encodeValueOfCType: @encode(BOOL)
|
||||
|
@ -1152,13 +1188,16 @@ static int messages_received_count;
|
|||
[op release];
|
||||
|
||||
/* Send the exception back to the client. */
|
||||
op = [self newSendingReplyRmcWithSequenceNumber: reply_sequence_number];
|
||||
[op encodeValueOfCType: @encode(BOOL)
|
||||
at: &is_exception
|
||||
withName: @"Exceptional reply flag"];
|
||||
[op encodeBycopyObject: localException
|
||||
withName: @"Exception object"];
|
||||
[op dismiss];
|
||||
if (is_valid)
|
||||
{
|
||||
op=[self newSendingReplyRmcWithSequenceNumber: reply_sequence_number];
|
||||
[op encodeValueOfCType: @encode(BOOL)
|
||||
at: &is_exception
|
||||
withName: @"Exceptional reply flag"];
|
||||
[op encodeBycopyObject: localException
|
||||
withName: @"Exception object"];
|
||||
[op dismiss];
|
||||
}
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
|
||||
|
@ -1315,18 +1354,20 @@ static int messages_received_count;
|
|||
|
||||
- (void) _handleRmc: rmc
|
||||
{
|
||||
NSConnection* conn = [[rmc connection] retain];
|
||||
|
||||
switch ([rmc identifier])
|
||||
{
|
||||
case ROOTPROXY_REQUEST:
|
||||
/* It won't take much time to handle this, so go ahead and service
|
||||
it, even if we are waiting for a reply. */
|
||||
[[rmc connection] _service_rootObject: rmc];
|
||||
[conn _service_rootObject: rmc];
|
||||
[rmc dismiss];
|
||||
break;
|
||||
case METHODTYPE_REQUEST:
|
||||
/* It won't take much time to handle this, so go ahead and service
|
||||
it, even if we are waiting for a reply. */
|
||||
[[rmc connection] _service_typeForSelector: rmc];
|
||||
[conn _service_typeForSelector: rmc];
|
||||
[rmc dismiss];
|
||||
break;
|
||||
case METHOD_REQUEST:
|
||||
|
@ -1343,15 +1384,17 @@ static int messages_received_count;
|
|||
then we may still want to service it now if DELAY_DIALOG_INTERRUPTIONS
|
||||
is false. */
|
||||
if (reply_depth == 0
|
||||
|| ([rmc connection] == self && independant_queueing == NO)
|
||||
|| (conn == self && independant_queueing == NO)
|
||||
|| !delay_dialog_interruptions)
|
||||
{
|
||||
[[rmc connection] _service_forwardForProxy: rmc];
|
||||
[self retain];
|
||||
[conn _service_forwardForProxy: rmc];
|
||||
/* Service any requests that were queued while we
|
||||
were waiting for replies.
|
||||
xxx Is this the right place for this check? */
|
||||
if (reply_depth == 0)
|
||||
[self _handleQueuedRmcRequests];
|
||||
[self release];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1370,18 +1413,20 @@ static int messages_received_count;
|
|||
break;
|
||||
case CONNECTION_SHUTDOWN:
|
||||
{
|
||||
[[rmc connection] _service_shutdown: rmc forConnection: self];
|
||||
[conn _service_shutdown: rmc forConnection: self];
|
||||
break;
|
||||
}
|
||||
case PROXY_RELEASE:
|
||||
{
|
||||
[[rmc connection] _service_release: rmc forConnection: self];
|
||||
[conn _service_release: rmc forConnection: self];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
[conn release];
|
||||
[NSException raise: NSGenericException
|
||||
format: @"unrecognized NSPortCoder identifier"];
|
||||
}
|
||||
[conn release];
|
||||
}
|
||||
|
||||
- (void) _handleQueuedRmcRequests
|
||||
|
@ -1389,7 +1434,7 @@ static int messages_received_count;
|
|||
id rmc;
|
||||
|
||||
[received_request_rmc_queue_gate lock];
|
||||
while ((rmc = [received_request_rmc_queue dequeueObject]))
|
||||
while (is_valid && (rmc = [received_request_rmc_queue dequeueObject]))
|
||||
{
|
||||
[received_request_rmc_queue_gate unlock];
|
||||
[self _handleRmc: rmc];
|
||||
|
@ -1561,34 +1606,44 @@ static int messages_received_count;
|
|||
|
||||
- (void) _release_targets: (unsigned int*)list count:(unsigned int)number
|
||||
{
|
||||
/*
|
||||
* Tell the remote app that it can release its local objects
|
||||
* for the targets in the specified list since we don't have
|
||||
* proxies for them any more.
|
||||
*/
|
||||
if (receive_port && is_valid && number > 0) {
|
||||
id op;
|
||||
unsigned int i;
|
||||
NS_DURING
|
||||
{
|
||||
/*
|
||||
* Tell the remote app that it can release its local objects
|
||||
* for the targets in the specified list since we don't have
|
||||
* proxies for them any more.
|
||||
*/
|
||||
if (receive_port && is_valid && number > 0) {
|
||||
id op;
|
||||
unsigned int i;
|
||||
|
||||
op = [[self encodingClass]
|
||||
newForWritingWithConnection: self
|
||||
sequenceNumber: [self _newMsgNumber]
|
||||
identifier: PROXY_RELEASE];
|
||||
op = [[self encodingClass]
|
||||
newForWritingWithConnection: self
|
||||
sequenceNumber: [self _newMsgNumber]
|
||||
identifier: PROXY_RELEASE];
|
||||
|
||||
[op encodeValueOfCType: @encode(typeof(number))
|
||||
at: &number
|
||||
withName: NULL];
|
||||
|
||||
for (i = 0; i < number; i++) {
|
||||
unsigned int target = list[i];
|
||||
|
||||
[op encodeValueOfCType: @encode(typeof(target))
|
||||
at: &target
|
||||
[op encodeValueOfCType: @encode(typeof(number))
|
||||
at: &number
|
||||
withName: NULL];
|
||||
}
|
||||
|
||||
[op dismiss];
|
||||
for (i = 0; i < number; i++) {
|
||||
unsigned int target = list[i];
|
||||
|
||||
[op encodeValueOfCType: @encode(typeof(target))
|
||||
at: &target
|
||||
withName: NULL];
|
||||
}
|
||||
|
||||
[op dismiss];
|
||||
}
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
if (debug_connection)
|
||||
fprintf (stderr, "failed to release targets - %s\n",
|
||||
[[localException name] cStringNoCopy]);
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
}
|
||||
|
||||
- (void) removeProxy: (NSDistantObject*)aProxy
|
||||
|
@ -1828,33 +1883,29 @@ static int messages_received_count;
|
|||
|
||||
/* Shutting down and deallocating. */
|
||||
|
||||
/* We register this method with NotificationDispatcher for when a port dies. */
|
||||
/*
|
||||
* We register this method for a notification when a port dies.
|
||||
* NB. It is possible that the death of a port could be notified
|
||||
* to us after we are invalidated - in which case we must ignore it.
|
||||
*/
|
||||
- (void) portIsInvalid: notification
|
||||
{
|
||||
id port = [notification object];
|
||||
if (is_valid) {
|
||||
id port = [notification object];
|
||||
|
||||
NSParameterAssert (is_valid);
|
||||
if (debug_connection)
|
||||
fprintf (stderr, "Received port invalidation notification for "
|
||||
"connection 0x%x\n\t%s\n", (unsigned)self,
|
||||
[[port description] cStringNoCopy]);
|
||||
/* We shouldn't be getting any port invalidation notifications,
|
||||
except from our own ports; this is how we registered ourselves
|
||||
with the NotificationDispatcher in
|
||||
+newForInPort:outPort:ancestorConnection. */
|
||||
NSParameterAssert (port == receive_port || port == send_port);
|
||||
if (debug_connection)
|
||||
fprintf (stderr, "Received port invalidation notification for "
|
||||
"connection 0x%x\n\t%s\n", (unsigned)self,
|
||||
[[port description] cStringNoCopy]);
|
||||
|
||||
/* xxx This also needs to be done properly in cases where the
|
||||
Connection invalidates itself. */
|
||||
/* Remove ourselves from the receive_port_2_ancestor, if necessary. */
|
||||
{
|
||||
id ancestor;
|
||||
if ([port isKindOfClass: [InPort class]]
|
||||
&& (self == (ancestor = NSMapGet (receive_port_2_ancestor, port))))
|
||||
NSMapRemove (receive_port_2_ancestor, port);
|
||||
}
|
||||
[self invalidate];
|
||||
/* xxx Anything else? */
|
||||
/* We shouldn't be getting any port invalidation notifications,
|
||||
except from our own ports; this is how we registered ourselves
|
||||
with the NotificationDispatcher in
|
||||
+newForInPort:outPort:ancestorConnection. */
|
||||
NSParameterAssert (port == receive_port || port == send_port);
|
||||
|
||||
[self invalidate];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/* Implementation of abstract superclass port for use with Connection
|
||||
Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
|
||||
Created: July 1994
|
||||
Written by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
||||
Created: August 1997
|
||||
|
||||
This file is part of the GNUstep Base Library.
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include <Foundation/NSString.h>
|
||||
#include <Foundation/NSPort.h>
|
||||
#include <Foundation/NSAutoreleasePool.h>
|
||||
|
||||
NSString* NSPortDidBecomeInvalidNotification
|
||||
= @"NSPortDidBecomeInvalidNotification";
|
||||
|
@ -91,6 +92,27 @@ NSString *NSPortTimeoutException
|
|||
return nil;
|
||||
}
|
||||
|
||||
- (void) release
|
||||
{
|
||||
if (is_valid && [self retainCount] == 1) {
|
||||
NSAutoreleasePool *arp;
|
||||
|
||||
/*
|
||||
* If the port is about to have a final release deallocate it
|
||||
* we must invalidate it. Use a local autorelease pool when
|
||||
* invalidating so that we know that anything refering to this
|
||||
* port during the invalidation process is released immediately.
|
||||
* Also - bracket with retain/release pair to prevent recursion.
|
||||
*/
|
||||
[super retain];
|
||||
arp = [[NSAutoreleasePool alloc] init];
|
||||
[self invalidate];
|
||||
[arp release];
|
||||
[super release];
|
||||
}
|
||||
[super release];
|
||||
}
|
||||
|
||||
- (void) setDelegate: anObject
|
||||
{
|
||||
delegate = anObject;
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <gnustep/base/CStream.h>
|
||||
#include <gnustep/base/Port.h>
|
||||
#include <gnustep/base/MemoryStream.h>
|
||||
#include <Foundation/NSException.h>
|
||||
#include <Foundation/DistributedObjects.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
@ -103,8 +104,19 @@ static BOOL debug_connected_coder = NO;
|
|||
- (void) dismiss
|
||||
{
|
||||
id packet = [cstream stream];
|
||||
[(OutPort*)[connection sendPort] sendPacket: packet
|
||||
NS_DURING
|
||||
{
|
||||
[(OutPort*)[connection sendPort] sendPacket: packet
|
||||
timeout: [connection requestTimeout]];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
if (debug_connected_coder)
|
||||
fprintf(stderr, "dismiss 0x%x: #=%d i=%d write failed - %s\n",
|
||||
(unsigned)self, sequence_number, identifier,
|
||||
[[localException reason] cStringNoCopy]);
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
if (debug_connected_coder)
|
||||
fprintf(stderr, "dismiss 0x%x: #=%d i=%d %d\n",
|
||||
(unsigned)self, sequence_number, identifier,
|
||||
|
|
|
@ -115,12 +115,15 @@ static int debug_run_loop = 0;
|
|||
id receiver;
|
||||
RunLoopEventType type;
|
||||
NSDate* limit;
|
||||
unsigned count;
|
||||
}
|
||||
- (void) eventFor: (void*)info mode: (NSString*)mode;
|
||||
- (void*) getData;
|
||||
- (NSDate*) getLimit;
|
||||
- (id) getReceiver;
|
||||
- (RunLoopEventType) getType;
|
||||
- (BOOL) decrement;
|
||||
- (void) increment;
|
||||
- initWithType: (RunLoopEventType)type
|
||||
receiver: (id)anObj
|
||||
data: (void*)data;
|
||||
|
@ -135,11 +138,23 @@ static int debug_run_loop = 0;
|
|||
|
||||
- (void) dealloc
|
||||
{
|
||||
[self invalidate];
|
||||
[limit release];
|
||||
[receiver release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (BOOL) decrement
|
||||
{
|
||||
if (count > 0) {
|
||||
count--;
|
||||
if (count > 0) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void) eventFor: (void*)info mode: (NSString*)mode
|
||||
{
|
||||
if ([self isValid] == NO) {
|
||||
|
@ -184,6 +199,11 @@ static int debug_run_loop = 0;
|
|||
return type;
|
||||
}
|
||||
|
||||
- (void) increment
|
||||
{
|
||||
count++;
|
||||
}
|
||||
|
||||
- initWithType: (RunLoopEventType)aType
|
||||
receiver: (id)anObj
|
||||
data: (void*)item
|
||||
|
@ -202,6 +222,7 @@ static int debug_run_loop = 0;
|
|||
[self setReceiver:anObj];
|
||||
[self setData:item];
|
||||
[self setLimit:nil];
|
||||
count = 0;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
@ -239,10 +260,11 @@ static int debug_run_loop = 0;
|
|||
|
||||
- (void) setReceiver: anObject
|
||||
{
|
||||
id obj = [anObject retain];
|
||||
id obj = receiver;
|
||||
|
||||
[receiver release];
|
||||
receiver = obj;
|
||||
receiver = [anObject retain];
|
||||
|
||||
[obj release];
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -333,8 +355,15 @@ static int debug_run_loop = 0;
|
|||
|
||||
@interface NSRunLoop (Private)
|
||||
|
||||
- (void) _addWatcher: (RunLoopWatcher*) item forMode: (NSString*)mode;
|
||||
- (void) _addWatcher: (RunLoopWatcher*)item
|
||||
forMode: (NSString*)mode;
|
||||
- (void) _checkPerformers;
|
||||
- (RunLoopWatcher*) _getWatcher: (void*)data
|
||||
type: (RunLoopEventType)type
|
||||
forMode: (NSString*)mode;
|
||||
- (void) _removeWatcher: (void*)data
|
||||
type: (RunLoopEventType)type
|
||||
forMode: (NSString*)mode;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -344,14 +373,14 @@ static int debug_run_loop = 0;
|
|||
limit-date order. */
|
||||
- (void) _addWatcher: (RunLoopWatcher*) item forMode: (NSString*)mode
|
||||
{
|
||||
Array *watchers;
|
||||
id obj;
|
||||
NSDate* limit;
|
||||
int count;
|
||||
NSMutableArray *watchers;
|
||||
id obj;
|
||||
NSDate *limit;
|
||||
int count;
|
||||
|
||||
watchers = NSMapGet (_mode_2_watchers, mode);
|
||||
if (watchers == nil) {
|
||||
watchers = [Array new];
|
||||
watchers = [NSMutableArray new];
|
||||
NSMapInsert (_mode_2_watchers, mode, watchers);
|
||||
[watchers release];
|
||||
count = 0;
|
||||
|
@ -463,15 +492,26 @@ static int debug_run_loop = 0;
|
|||
if (mode == nil)
|
||||
mode = _current_mode;
|
||||
|
||||
/* Remove any existing handler for the specified descriptor. */
|
||||
[self removeEvent: data type: type forMode: mode];
|
||||
info = [self _getWatcher: data type: type forMode: mode];
|
||||
|
||||
/* Create new object to hold information. */
|
||||
info = [[RunLoopWatcher alloc] initWithType: type
|
||||
receiver: watcher
|
||||
data: data];
|
||||
[self _addWatcher:info forMode:mode];
|
||||
[info release];
|
||||
if (info && [info getReceiver] == watcher) {
|
||||
/* Increment usage count for this watcher. */
|
||||
[info increment];
|
||||
}
|
||||
else {
|
||||
/* Remove any existing handler for another watcher. */
|
||||
[self _removeWatcher: data type: type forMode: mode];
|
||||
|
||||
/* Create new object to hold information. */
|
||||
info = [[RunLoopWatcher alloc] initWithType: type
|
||||
receiver: watcher
|
||||
data: data];
|
||||
/* Add the object to the array for the mode and keep count. */
|
||||
[self _addWatcher:info forMode:mode];
|
||||
[info increment];
|
||||
|
||||
[info release]; /* Now held in array. */
|
||||
}
|
||||
}
|
||||
|
||||
- (void) addReadDescriptor: (int)fd
|
||||
|
@ -498,38 +538,35 @@ static int debug_run_loop = 0;
|
|||
- (void) removeEvent: (void*)data
|
||||
type: (RunLoopEventType)type
|
||||
forMode: (NSString*)mode
|
||||
all: (BOOL)removeAll
|
||||
{
|
||||
Array* watchers;
|
||||
if (mode == nil)
|
||||
mode = _current_mode;
|
||||
|
||||
if (removeAll) {
|
||||
[self _removeWatcher: data type: type forMode: mode];
|
||||
}
|
||||
else {
|
||||
RunLoopWatcher *info;
|
||||
|
||||
if (mode == nil )
|
||||
mode = _current_mode;
|
||||
|
||||
watchers = NSMapGet (_mode_2_watchers, mode);
|
||||
if (watchers) {
|
||||
int i;
|
||||
|
||||
for (i = [watchers count]; i > 0; i--) {
|
||||
RunLoopWatcher* info;
|
||||
|
||||
info = (RunLoopWatcher*)[watchers objectAtIndex:(i-1)];
|
||||
if ([info getType] == type && [info getData] == data) {
|
||||
[info invalidate];
|
||||
[watchers removeObject: info];
|
||||
}
|
||||
}
|
||||
info = [self _getWatcher: data type: type forMode: mode];
|
||||
|
||||
if (info && [info decrement] == NO) {
|
||||
[self _removeWatcher: data type: type forMode: mode];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void) removeReadDescriptor: (int)fd
|
||||
forMode: (NSString*)mode
|
||||
{
|
||||
return [self removeEvent:(void*)fd type: ET_RDESC forMode:mode];
|
||||
return [self removeEvent:(void*)fd type: ET_RDESC forMode:mode all:NO];
|
||||
}
|
||||
|
||||
- (void) removeWriteDescriptor: (int)fd
|
||||
forMode: (NSString*)mode
|
||||
{
|
||||
return [self removeEvent:(void*)fd type: ET_WDESC forMode:mode];
|
||||
return [self removeEvent:(void*)fd type: ET_WDESC forMode:mode all:NO];
|
||||
}
|
||||
|
||||
- (BOOL) runOnceBeforeDate: date
|
||||
|
@ -646,7 +683,7 @@ static int debug_run_loop = 0;
|
|||
Heap *timers;
|
||||
NSTimer *min_timer = nil;
|
||||
RunLoopWatcher *min_watcher = nil;
|
||||
Array *watchers;
|
||||
NSArray *watchers;
|
||||
NSDate *when;
|
||||
|
||||
saved_mode = _current_mode;
|
||||
|
@ -872,10 +909,62 @@ static int debug_run_loop = 0;
|
|||
wfd_2_object = NSCreateMapTable (NSIntMapKeyCallBacks,
|
||||
NSObjectMapValueCallBacks, 0);
|
||||
|
||||
- (RunLoopWatcher*) _getWatcher: (void*)data
|
||||
type: (RunLoopEventType)type
|
||||
forMode: (NSString*)mode
|
||||
{
|
||||
NSArray *watchers;
|
||||
RunLoopWatcher *info;
|
||||
int count;
|
||||
|
||||
if (mode == nil)
|
||||
mode = _current_mode;
|
||||
|
||||
watchers = NSMapGet (_mode_2_watchers, mode);
|
||||
if (watchers == nil) {
|
||||
return nil;
|
||||
}
|
||||
for (count = 0; count < [watchers count]; count++) {
|
||||
info = [watchers objectAtIndex: count];
|
||||
|
||||
if ([info getType] == type) {
|
||||
if ([info getData] == data) {
|
||||
return info;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void) _removeWatcher: (void*)data
|
||||
type: (RunLoopEventType)type
|
||||
forMode: (NSString*)mode
|
||||
{
|
||||
NSMutableArray *watchers;
|
||||
|
||||
if (mode == nil )
|
||||
mode = _current_mode;
|
||||
|
||||
watchers = NSMapGet (_mode_2_watchers, mode);
|
||||
if (watchers) {
|
||||
int i;
|
||||
|
||||
for (i = [watchers count]; i > 0; i--) {
|
||||
RunLoopWatcher* info;
|
||||
|
||||
info = (RunLoopWatcher*)[watchers objectAtIndex:(i-1)];
|
||||
if ([info getType] == type && [info getData] == data) {
|
||||
[info invalidate];
|
||||
[watchers removeObject: info];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Do the pre-listening set-up for the file descriptors of this mode. */
|
||||
{
|
||||
Array* watchers;
|
||||
NSArray *watchers;
|
||||
|
||||
watchers = NSMapGet (_mode_2_watchers, mode);
|
||||
if (watchers) {
|
||||
|
@ -1117,7 +1206,7 @@ id NSDefaultRunLoopMode = @"NSDefaultRunLoopMode";
|
|||
- (void) removePort: (NSPort*)port
|
||||
forMode: (NSString*)mode
|
||||
{
|
||||
return [self removeEvent:(void*)port type: ET_RPORT forMode:mode];
|
||||
return [self removeEvent:(void*)port type: ET_RPORT forMode:mode all:NO];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -699,7 +699,7 @@ static NSMapTable* port_number_2_port;
|
|||
if ((p = (id) NSMapGet (port_number_2_port, (void*)((int)n))))
|
||||
{
|
||||
assert (p->is_valid);
|
||||
return p;
|
||||
return [p retain];
|
||||
}
|
||||
|
||||
/* There isn't already a TcpInPort for this port number, so create
|
||||
|
@ -878,6 +878,7 @@ static NSMapTable* port_number_2_port;
|
|||
want to wait for one directly from a port, you can use this method. */
|
||||
- newPacketReceivedBeforeDate: date
|
||||
{
|
||||
NSString* saved_mode = [NSRunLoop currentMode];
|
||||
id saved_packet_invocation;
|
||||
id packet = nil;
|
||||
id handle_packet (id p)
|
||||
|
@ -894,7 +895,7 @@ static NSMapTable* port_number_2_port;
|
|||
/* Make sure we're in the run loop, and run it, waiting for the
|
||||
incoming packet. */
|
||||
[[NSRunLoop currentRunLoop] addPort: self
|
||||
forMode: [NSRunLoop currentMode]];
|
||||
forMode: saved_mode];
|
||||
while ([NSRunLoop runOnceBeforeDate: date]
|
||||
&& !packet)
|
||||
;
|
||||
|
@ -904,7 +905,7 @@ static NSMapTable* port_number_2_port;
|
|||
this run loop. */
|
||||
_packet_invocation = saved_packet_invocation;
|
||||
[[NSRunLoop currentRunLoop] removePort: self
|
||||
forMode: [NSRunLoop currentMode]];
|
||||
forMode: saved_mode];
|
||||
return packet;
|
||||
}
|
||||
|
||||
|
@ -1347,7 +1348,7 @@ static NSMapTable *out_port_bag = NULL;
|
|||
work because sin_zero's may differ. */
|
||||
{
|
||||
assert (p->is_valid);
|
||||
return p;
|
||||
return [p retain];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1681,8 +1682,7 @@ static NSMapTable *out_port_bag = NULL;
|
|||
|
||||
- (void) dealloc
|
||||
{
|
||||
if (is_valid)
|
||||
[self invalidate];
|
||||
[self invalidate];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
|
|
@ -144,14 +144,16 @@ getAddr(NSString* name, NSString* svc, NSString* pcl, struct sockaddr_in *sin)
|
|||
[self ignoreReadDescriptor];
|
||||
[self ignoreWriteDescriptor];
|
||||
|
||||
if (closeOnDealloc == YES)
|
||||
if (descriptor != -1)
|
||||
{
|
||||
close(descriptor);
|
||||
descriptor = -1;
|
||||
if (closeOnDealloc == YES)
|
||||
{
|
||||
close(descriptor);
|
||||
descriptor = -1;
|
||||
}
|
||||
else if (isNonBlocking != wasNonBlocking)
|
||||
[self setNonBlocking:wasNonBlocking];
|
||||
}
|
||||
else if (isNonBlocking != wasNonBlocking)
|
||||
[self setNonBlocking:wasNonBlocking];
|
||||
|
||||
[readInfo release];
|
||||
[writeInfo release];
|
||||
[super dealloc];
|
||||
|
@ -531,9 +533,11 @@ getAddr(NSString* name, NSString* svc, NSString* pcl, struct sockaddr_in *sin)
|
|||
- (NSData*)availableData
|
||||
{
|
||||
char buf[NETBUF_SIZE];
|
||||
NSMutableData* d = [NSMutableData dataWithCapacity:0];
|
||||
NSMutableData* d;
|
||||
int len;
|
||||
|
||||
[self checkRead];
|
||||
d = [NSMutableData dataWithCapacity:0];
|
||||
if (isStandardFile)
|
||||
{
|
||||
while ((len = read(descriptor, buf, sizeof(buf))) > 0)
|
||||
|
@ -560,9 +564,11 @@ getAddr(NSString* name, NSString* svc, NSString* pcl, struct sockaddr_in *sin)
|
|||
- (NSData*)readDataToEndOfFile
|
||||
{
|
||||
char buf[NETBUF_SIZE];
|
||||
NSMutableData* d = [NSMutableData dataWithCapacity:0];
|
||||
NSMutableData* d;
|
||||
int len;
|
||||
|
||||
[self checkRead];
|
||||
d = [NSMutableData dataWithCapacity:0];
|
||||
while ((len = read(descriptor, buf, sizeof(buf))) > 0)
|
||||
{
|
||||
[d appendBytes:buf length:len];
|
||||
|
@ -578,9 +584,11 @@ getAddr(NSString* name, NSString* svc, NSString* pcl, struct sockaddr_in *sin)
|
|||
|
||||
- (NSData*)readDataOfLength:(unsigned int)len
|
||||
{
|
||||
NSMutableData* d = [NSMutableData dataWithCapacity:len];
|
||||
NSMutableData* d;
|
||||
int pos;
|
||||
|
||||
[self checkRead];
|
||||
d = [NSMutableData dataWithCapacity:len];
|
||||
if ((pos = read(descriptor, [d mutableBytes], len)) < 0)
|
||||
{
|
||||
[NSException raise: NSFileHandleOperationException
|
||||
|
@ -598,6 +606,7 @@ getAddr(NSString* name, NSString* svc, NSString* pcl, struct sockaddr_in *sin)
|
|||
unsigned int len = [item length];
|
||||
unsigned int pos = 0;
|
||||
|
||||
[self checkWrite];
|
||||
while (pos < len)
|
||||
{
|
||||
int toWrite = len - pos;
|
||||
|
@ -678,7 +687,7 @@ getAddr(NSString* name, NSString* svc, NSString* pcl, struct sockaddr_in *sin)
|
|||
{
|
||||
off_t result = -1;
|
||||
|
||||
if (isStandardFile)
|
||||
if (isStandardFile && descriptor >= 0)
|
||||
result = lseek(descriptor, 0, SEEK_CUR);
|
||||
if (result < 0)
|
||||
{
|
||||
|
@ -693,7 +702,7 @@ getAddr(NSString* name, NSString* svc, NSString* pcl, struct sockaddr_in *sin)
|
|||
{
|
||||
off_t result = -1;
|
||||
|
||||
if (isStandardFile)
|
||||
if (isStandardFile && descriptor >= 0)
|
||||
result = lseek(descriptor, 0, SEEK_END);
|
||||
if (result < 0)
|
||||
{
|
||||
|
@ -708,7 +717,7 @@ getAddr(NSString* name, NSString* svc, NSString* pcl, struct sockaddr_in *sin)
|
|||
{
|
||||
off_t result = -1;
|
||||
|
||||
if (isStandardFile)
|
||||
if (isStandardFile && descriptor >= 0)
|
||||
result = lseek(descriptor, (off_t)pos, SEEK_SET);
|
||||
if (result < 0)
|
||||
{
|
||||
|
@ -739,6 +748,10 @@ getAddr(NSString* name, NSString* svc, NSString* pcl, struct sockaddr_in *sin)
|
|||
|
||||
(void)close(descriptor);
|
||||
descriptor = -1;
|
||||
acceptOK = NO;
|
||||
connectOK = NO;
|
||||
readOK = NO;
|
||||
writeOK = NO;
|
||||
}
|
||||
|
||||
- (void)synchronizeFile
|
||||
|
@ -749,7 +762,7 @@ getAddr(NSString* name, NSString* svc, NSString* pcl, struct sockaddr_in *sin)
|
|||
|
||||
- (void)truncateFileAtOffset:(unsigned long long)pos
|
||||
{
|
||||
if (isStandardFile)
|
||||
if (isStandardFile && descriptor >= 0)
|
||||
(void)ftruncate(descriptor, pos);
|
||||
[self seekToFileOffset:pos];
|
||||
}
|
||||
|
@ -855,13 +868,15 @@ getAddr(NSString* name, NSString* svc, NSString* pcl, struct sockaddr_in *sin)
|
|||
{
|
||||
[l removeEvent: (void*)descriptor
|
||||
type: ET_RDESC
|
||||
forMode: [modes objectAtIndex:i]];
|
||||
forMode: [modes objectAtIndex:i]
|
||||
all: YES];
|
||||
}
|
||||
}
|
||||
else
|
||||
[l removeEvent: (void*)descriptor
|
||||
type: ET_RDESC
|
||||
forMode: NSDefaultRunLoopMode];
|
||||
forMode: NSDefaultRunLoopMode
|
||||
all: YES];
|
||||
}
|
||||
|
||||
- (void)ignoreWriteDescriptor
|
||||
|
@ -887,19 +902,25 @@ getAddr(NSString* name, NSString* svc, NSString* pcl, struct sockaddr_in *sin)
|
|||
{
|
||||
[l removeEvent: (void*)descriptor
|
||||
type: ET_WDESC
|
||||
forMode: [modes objectAtIndex:i]];
|
||||
forMode: [modes objectAtIndex:i]
|
||||
all: YES];
|
||||
}
|
||||
}
|
||||
else
|
||||
[l removeEvent: (void*)descriptor
|
||||
type: ET_WDESC
|
||||
forMode: NSDefaultRunLoopMode];
|
||||
forMode: NSDefaultRunLoopMode
|
||||
all: YES];
|
||||
}
|
||||
|
||||
- (void)watchReadDescriptorForModes:(NSArray*)modes;
|
||||
{
|
||||
NSRunLoop* l = [NSRunLoop currentRunLoop];
|
||||
NSRunLoop* l;
|
||||
|
||||
if (descriptor < 0)
|
||||
return;
|
||||
|
||||
l = [NSRunLoop currentRunLoop];
|
||||
[self setNonBlocking:YES];
|
||||
if (modes && [modes count])
|
||||
{
|
||||
|
@ -925,6 +946,9 @@ getAddr(NSString* name, NSString* svc, NSString* pcl, struct sockaddr_in *sin)
|
|||
|
||||
- (void)watchWriteDescriptor
|
||||
{
|
||||
if (descriptor < 0)
|
||||
return;
|
||||
|
||||
if ([writeInfo count] > 0)
|
||||
{
|
||||
NSMutableDictionary* info = [writeInfo objectAtIndex:0];
|
||||
|
@ -1020,8 +1044,9 @@ getAddr(NSString* name, NSString* svc, NSString* pcl, struct sockaddr_in *sin)
|
|||
}
|
||||
}
|
||||
else if (type == ET_WDESC) {
|
||||
NSMutableDictionary* info = [writeInfo objectAtIndex:0];
|
||||
NSMutableDictionary* info;
|
||||
|
||||
info = [writeInfo objectAtIndex:0];
|
||||
operation = [info objectForKey:NotificationKey];
|
||||
if (operation == GSFileHandleWriteCompletionNotification) {
|
||||
NSData* item;
|
||||
|
@ -1073,6 +1098,9 @@ getAddr(NSString* name, NSString* svc, NSString* pcl, struct sockaddr_in *sin)
|
|||
{
|
||||
int e;
|
||||
|
||||
if (descriptor < 0)
|
||||
return;
|
||||
|
||||
if (isStandardFile)
|
||||
return;
|
||||
|
||||
|
|
Loading…
Reference in a new issue