Merged in 'dawn' CVS branch

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@3827 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
richard 1999-03-02 08:58:30 +00:00
parent a8ce39437a
commit 6d6a77062a
26 changed files with 1090 additions and 607 deletions

View file

@ -1,7 +1,7 @@
Announcement
************
The GNUstep Base Library, version 0.5.0, is now available.
The GNUstep Base Library, version 0.5.5, is now available.
What is the GNUstep Base Library?
=================================
@ -14,8 +14,7 @@ network ports, remote object messaging support (distributed objects),
event loops, and random number generators.
It provides functionality that aims to implement the non-graphical
portion of the OpenStep standard. In many cases, the `NS*' classes are
implemented as wrappers around more featureful GNU classes.
portion of the OpenStep standard (the Foundation library).
There is more information available at the GNUstep homepage at
`http://www.gnustep.org'.
@ -23,8 +22,8 @@ implemented as wrappers around more featureful GNU classes.
Where can you get it? How can you compile it?
==============================================
The gstepbase-0.5.0.tar.gz distribution file has been placed on
`ftp.gnu.org' in `pub/gnu'.
The gstepbase-0.5.5.tar.gz distribution file has been placed on
`ftp.gnu.org' in `pub/gnu/gstep'.
The library requires gcc 2.8.0 or higher. Significant sections of
the library do not work with the NeXT runtime, so we recommend using

34
AUTHORS
View file

@ -12,7 +12,6 @@ BinaryTreeNode.m
CircularArray.m
Collection.m
ConnectedCoder.m
Connection.m
Coder.m
CStream.m
Decoder.m
@ -25,22 +24,16 @@ Invocation.m
KeyedCollection.m
LinkedList.m
LinkedListNode.m
Lock.m
MachPort.m
Magnitude.m
MallocAddress.m
MappedCollector.m
MemoryStream.m
Notification.m
NotificationDispatcher.m
OrderedCollection.m
Port.m
Proxy.m
Queue.m
RawCStream.m
RBTree.m
RBTreeNode.m
RNGAdditiveCongruential.m
Set.m
SplayTree.m
Stack.m
@ -48,34 +41,23 @@ StdioStream.m
Stream.m
TcpPort.m
TextCStream.m
Time.m
UdpPort.m
behavior.m
preface.m
mframe.m
HashTable.m
List.m
objc/HashTable.h
objc/List.h
NSAllocateObject.m
NSArchiver.m
NSArray.m
NSAutoreleasePool.m
NSCoder.m
NSCopyObject.m
NSCountedSet.m
NSData.m
NSDeallocateObject.m
NSDictionary.m
NSEnumerator.m
NSGArchiver.m
NSGArray.m
NSGCountedSet.m
NSGCString.m
NSGDictionary.m
NSGSet.m
NSGString.m
NSInvocation.m
NSMethodSignature.m
NSNotification.m
NSNotificationCenter.m
@ -93,16 +75,10 @@ NSUser.m
Kresten Krab Thorup:
GapArray.m
objc-gnu2next.m
Storage.m
objc/Storage.h
Adam Fedor:
ostream.m
NXStringTable.m
NXStringTable_scan.c
objc/NXStringTable.h
NXStringTable_scan.l
NSAssertionHandler.m
NSBitmapCharSet.m
NSBundle.m
@ -189,12 +165,17 @@ NSZone.m
Richard Frith-Macdonald:
UnixFileHandle.m
NSData.m
NSDateFormatter.m
NSDebug.m
NSDistantObject.m
NSDistributedLock.m
NSDistributedNotificationCenter.m
NSFileHandle.m
NSFormatter.m
NSGDictionary.m
NSPipe.m
NSPort.m
NSPortNameServer.m
NSProxy.m
NSTask.m
NSUndoManager.m
@ -209,3 +190,8 @@ NSGString.m
Mike Kienenberger:
NSProtocolChecker.m
Manuel Guesdon:
NSURL.m
NSURLHandle.m

View file

@ -1,3 +1,42 @@
Tue Mar 2 08:04:00 1999 Richard Frith-Macdonald <richard@brainstorm.co.uk>
* Merge in 'dawn' CVS branch.
1999-03-01 Adam Fedor <fedor@gnu.org>
* Update documentation.
1999-02-28 Adam Fedor <fedor@gnu.org>
* Source/Makefile.postamble: Don't install services if not
root. (patches submitted by Christopher Seawood
<cls@seawood.org>).
Tue Feb 23 12:03:00 1999 Richard Frith-Macdonald <richard@brainstorm.co.uk>
* Source/include/NSObject.h: Fixed bugin in ASSIGNCOPY() macro and added
CREATE_AUTORELEASE_POOL() macro for libFoundation compatibility.
* Source/include/NSRunLoop.h: Added GCFinalization protocol.
* Source/NSRunLoop.m: Tidied a little, added GC macro use, fixed minor
bug, and added slight performance improvement.
Mon Feb 22 5:40:00 1999 Richard Frith-Macdonald <richard@brainstorm.co.uk>
Merged in alterations from main cvs branch made to wrong place 'cos
dawn branch was already created :-(
* Source/NSData.m: preserve file attributes when writing atomically
* Source/NSUser.m: Bugfixes for consistent naming of current user.
* Source/NSUserDefaults.m: Bugfixes so that running apps as root
doesn't mess up defaults database.
* Source/NSFileManager.m: Create files with correct ownership when
process is setuid to root - and provide facility for NSData to do same.
* Source/NSArray.m: Merged enumerator bugfix - missing @end
1999-02-22 Adam Fedor <fedor@gnu.org>
* Version: update version.
* Source/NSProcessInfo.m: Change missing main message.
Sun Feb 21 19:30:00 1999 Richard Frith-Macdonald <richard@brainstorm.co.uk>
* Source/NSFileManager.m: Attempt to fix problems with directory

View file

@ -35,9 +35,9 @@ DOCUMENT_NAME = gnustep-base
# The text documents to be generated
DOCUMENT_TEXT_NAME = \
TODO INSTALL NEWS CODING-STANDARDS README ANNOUNCE STATUS
INSTALL NEWS CODING-STANDARDS README ANNOUNCE
TOP_DOC_FILES = TODO INSTALL NEWS README ANNOUNCE STATUS
TOP_DOC_FILES = INSTALL NEWS README ANNOUNCE
gnustep-base_TEXI_FILES = \
version.tmpl.texi \
@ -47,9 +47,7 @@ announce.tmpl.texi \
coding-standards.tmpl.texi \
install.tmpl.texi \
news.tmpl.texi \
readme.tmpl.texi \
status.tmpl.texi \
todo.tmpl.texi
readme.tmpl.texi
TODO_TEXI_FILES = version.tmpl.texi
TODO_TEXT_MAIN = todo.tmpl.texi

View file

@ -6,5 +6,4 @@ remote object messaging support (distributed objects), event loops, and
random number generators.
It provides functionality that aims to implement the non-graphical
portion of the OpenStep standard. In many cases, the @samp{NS*} classes
are implemented as wrappers around more featureful GNU classes.
portion of the OpenStep standard (the Foundation library).

View file

@ -90,12 +90,6 @@ into another language, under the above conditions for modified versions.
@c News
@include news.texi
@c Status Report
@include status.texi
@c The ToDo
@include todo.texi
@c Generate Short Contents
@shortcontents

View file

@ -7,6 +7,31 @@
The currently released version of the library is
@samp{@value{GNUSTEP-BASE-VERSION}}.
@section Noteworthy changes in version @samp{0.5.5}
Too many changes to mention in detail, but here is a list of a few:
@itemize @bullet
@item
Many base classes have been rewritten with tonnes of performance
improvements that in many cases make it as fast as or faster than the
NeXT implementation.
@item
DO and archiving has received many improvements that help it work on a
variety of different platforms.
@item
Configuration and compilation has been greatly improved and fool
proofed.
@item
There are several new tools for handling services, defaults, and
pasteboards.
@end itemize
@section Noteworthy changes in version @samp{0.5.1}
@itemize @bullet

View file

@ -21,107 +21,13 @@ will be forthcoming, but the library needs to settle first. For now I
recommend reading the header files.
The headers for the classes are in @file{./src/include}.
The FAQ contains an outline of the class heirarchy, as well as a
list of the differences between GNUstep and NeXT's implementation of
OpenStep, and GNUstep's improvements over NeXT's implementation.
@section Overview of the classes
Here is partial list of non-OpenStep classes, grouped by functionality.
There are several GNU-specific protocols also. You can recognize the
protocols by their name: they all end with ``ing''.
@itemize @bullet
@item The collection objects all conform to the @samp{Collecting}
protocol. Reading @samp{src/include/Collecting.h} is a good place to
start. Protocols for collections that store their contents with keys
and with indices can be found in @samp{src/incliude/KeyedCollecting.h} and
@samp{src/include/IndexedCollecting.h} respectively. Examples of generic
collections are @samp{Set} and @samp{Bag}. The keyed collections are
@samp{Dictionary} and @samp{MappedCollector}. The classes @samp{Array},
@samp{Queue}, @samp{GapArray}, @samp{LinkedList}, @samp{BinaryTree},
@samp{RBTree} and @samp{SplayTree} are all indexed collections.
@item The string objects conform to the @samp{String} protocol.
@samp{CString} provides an interface to strings based on ASCII bytes,
and is currently the only concrete subclass of String. The interface
between GNU @samp{String} and OpenStep's @samp{NSString} needs cleaning
up and will change. For now, I recommend using @samp{NSString}.
@item The public magnitude classes are @samp{Time} and @samp{Random}.
The @samp{Random} class works in conjunction with pseudo-random number
generators that conform to the @samp{RandomGenerating} protocol. The
conforming class @samp{RNGBerkeley} provides identical behavior to the
BSD random() function. The class @samp{RNGAdditiveCongruential} is an
implementation of the additive congruential method.
@item Stream objects provide a consistent interface for reading and
writing bytes. Read @samp{src/include/Stream.h} to get the general
idea. @samp{StdioStream} objects work with files, file descriptors,
FILE pointers and pipes to/from executables. @samp{MemoryStream}
objects work with memory buffers.
@item CStream objects provide a way to write C variables to Stream
objects. Read @file{src/include/CStream.h} to understand the interface
of the abstract superclass. @samp{TextCStream} writes C variables in a
human-readable ASCII format that can be manipulated with a text editor
or with your choice of text-processing programs, like @samp{awk} or
@samp{perl}. @samp{BinaryCStream} writes C variables in a compact,
illegible stream of bytes. @samp{TextCStream} and @samp{BinaryCStream}
each write in machine-independant formats---so you can write on one
machine architecture, and successfully read on another.
@samp{RawCStream} is like @samp{BinaryCStream} accept it is
machine-dependant; it useful for efficient Distributed Objects
connections on the same machine.
@item Coders provide a formatted way of writing Objective C objects to
CStream objects. After a coder is initialized with a stream, the coder
can encode/decode interconnected webs of Objective C objects and C types
and successfully keep track of complex interconnections between objects.
See @samp{src/include/Coder.h} for the abstract superclass interface;
see @samp{src/include/Coding.h} for the protocol adopted by objects that
read and write themselves using coders. @samp{Archiver} and
@samp{Unarchiver} are concrete subclasses that are used for
writing/reading with files.
@samp{Coder}s and @samp{CStream}s and @samp{Stream}s can be mixed and
matched so that programmers can choose the destination and the format
separately.
@ignore
@item @samp{Notification}
@samp{NotificationDispatcher}
@end ignore
@item The distributed object support classes are @samp{NSConnection},
@samp{NSProxy}, @samp{ConnectedCoder}, @samp{Port} and @samp{TcpPort}.
This version of the distributed objects only works with sockets. A Mach
port back-end should be on the way.
@end itemize
@section Test Programs
Some of the programs I've used to test the library are in
@samp{./checks}. Many of them are pretty messy, (desperately trying to
tickle that late night bug), but at least they show some code that works
when the library compiles correctly. I'm looking for a volunteer to
write some nicely organized test cases using @samp{dejagnu}. Any
takers?
@section How can you help?
@itemize @bullet
@item Read the projects and questions in the @samp{TODO} file. If you
can volunteer for any of the projects, or if you have any useful
comments send me email!
@item
Give me feedback! Tell me what you like; tell me what you think
could be better. Send me bug reports.
Give us feedback! Tell us what you like; tell us what you think
could be better. Send bug reports to @email{bug-gnustep@@gnu.org}.
@item
Donate classes. If you write classes that fit in the libgnustep-base
@ -131,9 +37,4 @@ framework, I'd be happy to include them.
@example
Happy hacking!
Andrew McCallum
mccallum@@gnu.org
Adam Fedor
fedor@@gnu.org
@end example

View file

@ -5,6 +5,10 @@
@include version.tmpl.texi
@end ifset
The gnustep-base library is nearly complete, although a few things could
be fixed here and there and it could be ported to more systems. This
list is probably out of date. In the future we will be primarily adding
features and performance tuning.
Please send corrections to @email{fedor@@gnu.org}.
@emph{Key:}
@ -31,80 +35,62 @@ Unknown status.
(Many classes do not raise the proper NSExceptions yet.)
@table @strong
@item NSArchiver:: [8]
Doesn't yet call -awakeAfterUsingCoder:.
@item NSArchiver:: [9]
@item NSArray:: [9]
@item NSAssertionHandler:: [9]
@item NSAttributedString:: [8]
@item NSAttributedString:: [9]
@item NSAutoreleasePool:: [9]
But not exception- safe
@item NSBundle:: [8]
@item NSCalendarDate:: [7]
@item NSCharacterSet:: [8]
decomposableCharacterSet and illegalCharacter set missing
@item NSCoder:: [8]
Missing class name substitution methods.
@item NSBundle:: [9]
@item NSCalendarDate:: [8]
@item NSCharacterSet:: [9]
@item NSCoder:: [9]
@item NSConditionLock:: [8]
@item NSConnection:: [7]
GNU Connection, however, needs:
@itemize @bullet
@item to handle retain/release/dealloc properly
@item to be integrated with NSInvocation
@item to incorporate futzing with low-level TCP-backend for better speed
@item to have UDP-backend work
@item to cache ConnectedCoder's for better speed
@item Thread-safety overhaul, this is major
@end itemize
@item NSCountedSet:: [8]
@item NSData:: [8]
@item NSDate:: [8]
@item NSDeserializer:: [7]
@item NSDictionary:: [8]
@item NSDistantObject:: [7]
@item NSDistributedLock:: [7]
@item NSConnection:: [9]
@item NSCountedSet:: [9]
@item NSData:: [9]
@item NSDate:: [9]
@item NSDeserializer:: [8]
@item NSDictionary:: [9]
@item NSDistantObject:: [8]
@item NSDistributedLock:: [9]
@item NSEnumerator:: [9]
@item NSException:: [9]
But this needs integration with new, better
@item NSFileHandle:: [9]
@item NSFileManager:: [9]
@item NSHashTable:: [8]
@item NSHost:: [8]
@item NSInvocation:: [3]
@item NSLock:: [8]
@item NSMapTable:: [8]
@item NSMethodSignature:: [4]
@item NSMutableArray:: [8]
@item NSMutableCharacterSet:: [7]
@item NSMutableData:: [8]
@item NSMutableDictionary:: [8]
@item NSMutableSet:: [8]
@item NSMutableString:: [8]
@item NSHashTable:: [9]
@item NSHost:: [9]
@item NSInvocation:: [7]
@item NSLock:: [9]
@item NSMapTable:: [9]
@item NSMethodSignature:: [7]
@item NSMutableArray:: [9]
@item NSMutableCharacterSet:: [8]
@item NSMutableData:: [9]
@item NSMutableDictionary:: [9]
@item NSMutableSet:: [9]
@item NSMutableString:: [9]
@item NSNotification:: [9]
@item NSNotificationCenter:: [9]
@item NSNotificationQueue:: [6]
Needs integration with NSRunLoop, and efficiency improvements
@item NSNumber:: [9]
@item NSObject:: [10]
@item NSProcessInfo:: [9]
@item NSProxy:: [7]
@item NSRecursiveLock:: [8]
@item NSRunLoop:: [8]
NSTimer's not yet working, but everything else should be
@item NSScanner:: [8]
@item NSSerializer:: [7]
@item NSSet:: [8]
@item NSString:: [8]
Careful, relationship with GNU String is tricky; this could
also use fixing.
@item NSProxy:: [8]
@item NSRecursiveLock:: [9]
@item NSRunLoop:: [9]
@item NSScanner:: [9]
@item NSSerializer:: [8]
@item NSSet:: [9]
@item NSString:: [9]
@item NSTask:: [8]
@item NSThread:: [8]
@item NSTimeZone:: [8]
@item NSTimeZoneDetail:: [8]
@item NSTimer:: [6]
Working out bugs with returning doubles.
@item NSUnarchiver:: [8]
See NSArchvier
@item NSUserDefaults:: [8]
@item NSTimeZone:: [9]
@item NSTimeZoneDetail:: [9]
@item NSTimer:: [7]
@item NSUnarchiver:: [9]
@item NSUserDefaults:: [9]
@item NSValue:: [9]
@end table

View file

@ -10,161 +10,5 @@
@itemize @bullet
@item Implement Formatter classes (NSDateFormatter, etc) [5] (980722).
@item Implement NSDecimalNumber stuff [5] (981119).
@item Write tests for various classes using the testsuite built
by Richard Frith-Macdonald @email{richard@@brainstorm.co.uk}. Contact
him for details. [3, guile] (980629)
@item Check that every class implements coding (correctly). [2, NSCoder] (980721) - contribute to the testuite.
@item Check that every class implements copying (correctly) - i.e. non-mutable classes should just retain, etc. [1, NSCopying] (980721) - contribute to the testsuite.
@item Check that every class raises the NSExceptions it is supposed to.
Change many NSParameterAssert()'s into NSAssert()'s with
explanations. [2, exceptions] (970101) - contribute to the testsuite.
@item Improve initWithFormat related methods for NSString and find out how to implement the locale stuff [4 OPENSTEP/Rhapsody] (980712)
@item Make gstep-base 64bit clean [5, 64bit machine] (980629)
Donating internet access to a 64bit machine for someone else to do the
work on would also be helpful.
@item Make gstep-base smaller. Perhaps we can get rid of classes that
aren't strictly part of OpenStep and put them in an extensions-type
library. [5] (980629)
@item Fix NSLog so it conforms to specs. Need to check that write to
stderr went ok, and if not write to syslog. Also need to serialize
output (with threads). [3, OpenStep specs, threads] (980220)
@item Simplify NSException and NSAssertionHandler and make sure they
don't cause race conditions (if an exception is raised while processing
an exception. [4, exceptions, threads] (980220)
@item Fix all the places marked FIXME or xxx. [3-9] (980629)
@end itemize
@ignore
@c ==================================================================
@section Questions
I would greatly appreciate your feedback on the questions
below. Please email your thoughts to mccallum@@gnu.ai.mit.edu.
@itemize @bullet
@item
I want to put method names in texinfo indices, but the colons in the
method names are interfering with info's notion of menu item names and
node names. Help. Any ideas? (Kresten?)
@item
HashTable.m (-initKeyDesc:valueDesc:capacity:) I tried to make it
portable, but I didn't try very hard. Anyone want to send in fixes?
@item
I fixed -emptyCopy in all the subclasses, but the -emptyCopy scheme
seems pretty fragile. How about calling -initFoo: inside -emptyCopy?
This way we avoid having yet another method in which instance vars
must be initialized to some consistent state. -allocCopy would never
even get called. <<ObjC insiders: This is a less well-expressed
version of what we've just been discussing in email.>>
@item
Does anyone really need the ability to set the collection element
comparison function independent of the -compare: method?
@item
How about adding flexibity in the method name that a LinkedList sends a
LinkedListNode to get/set the link ivars. This would enable us to add a
node to more than one linked list.
@item
Something like this needed?
- elementDidChange: (elt*)elementPtr;
Currently you have to remove, change, add, for some classes.
@end itemize
@section Albin's To Do List
I'm sure that there're other things to do, but these are the ones I know now:
@subsection General
@itemize @bullet
@item Make thread-safe all of my code that should be.
@item Fully annotate all of my headers.
@item Document my work and the use of its fruit.
@end itemize
@subsection Critical
@itemize @bullet
@item Code:
@itemize +
@item (@file{src/array.m}) @samp{objects_array_check}
@item (@file{src/array.m}) @samp{objects_array_map_elements}
@item (@file{src/cbs-char-p.m}) @samp{objects_char_p_describe}
@item (@file{src/cbs-int-p.m}) @samp{objects_int_p_describe}
@item (@file{src/cbs-int.m}) @samp{objects_int_describe}
@item (@file{src/hash.m}) @samp{_objects_hash_hash}
@item (@file{src/hash.m}) @samp{objects_hash_check}
@item (@file{src/hash.m}) @samp{objects_hash_description}
@item (@file{src/list.m}) @samp{objects_list_is_equal_to_list}
@item (@file{src/map.m}) @samp{_objects_map_hash}
@item (@file{src/map.m}) @samp{objects_map_check}
@item (@file{src/map.m}) @samp{objects_map_description}
@end itemize
@item Correct:
@itemize +
@item (@file{src/array.m}) @samp{objects_array_dealloc}
@item (@file{src/cbs-int.m}) @samp{_GNUSTEP_BASE_NOT_AN_INT_MARKER}
@end itemize
@item Improve the error handling of:
@itemize +
@item (@file{src/array.m}) @samp{_objects_array_insert_bucket}
@item (@file{src/hash.m}) @samp{objects_hash_add_element_known_absent}
@item (@file{src/list.m}) @samp{objects_list_at_index_insert_element}
@item (@file{src/map.m}) @samp{objects_map_at_key_put_value_known_absent}
@end itemize
@end itemize
@subsection Not So Critical
@itemize @bullet
@item Strengthen my resolve on the correctness of:
@itemize +
@item (@file{src/cbs-char-p.m}) @samp{_GNUSTEP_BASE_NOT_A_CHAR_P_MARKER}
@item (@file{src/cbs-id.m}) @samp{_GNUSTEP_BASE_NOT_AN_ID_MARKER}
@item (@file{src/cbs-int-p.m}) @samp{_GNUSTEP_BASE_NOT_AN_INT_P_MARKER}
@item (@file{src/cbs-int-p.m}) @samp{objects_int_p_is_equal}
@item (@file{src/cbs-void-p.m}) @samp{_GNUSTEP_BASE_NOT_A_VOID_P_MARKER}
@item (@file{src/hash.m}) @samp{objects_hash_rightsize}
@item (@file{src/hash.m}) @samp{objects_hash_all_elements}
@item (@file{src/map.m}) @samp{objects_map_rightsize}
@item (@file{src/map.m}) @samp{objects_map_all_keys}
@item (@file{src/map.m}) @samp{objects_map_all_values}
@end itemize
@item Improve the efficiency of:
@itemize +
@item (@file{src/array.m}) @samp{_objects_array_insert_bucket}
@item (@file{src/hash.m}) @samp{objects_hash_minus_hash}
@item (@file{src/list.m}) @samp{objects_list_at_index_insert_list}
@end itemize
@end itemize
@end ignore

View file

@ -231,8 +231,11 @@ extern NSRecursiveLock *gnustep_global_lock;
#define AUTORELEASE(object) ((id)object)
#define ASSIGN(object,value) (object = value)
#define ASSIGNCOPY(object,value) (object = [value copy])
#define DESTROY(object) (object = nil)
#define CREATE_AUTORELEASE_POOL(X)
#else
#define RETAIN(object) [object retain]
@ -269,7 +272,7 @@ if (__value != object) \
{ \
if (__value) \
{ \
[__value copy]; \
__value = [__value copy]; \
} \
if (object) \
{ \
@ -285,6 +288,10 @@ if (__value != object) \
* object later.
*/
#define DESTROY(object) ([object release], object = nil)
#define CREATE_AUTORELEASE_POOL(X) \
NSAutoreleasePool *(X) = [NSAutoreleasePool new]
#endif
#endif /* __NSObject_h_GNUSTEP_BASE_INCLUDE */

View file

@ -26,29 +26,46 @@
#include <Foundation/NSObject.h>
@class NSMutableSet;
@class NSArray;
@class NSConnection;
@class NSDate;
@class NSRunLoop;
@class NSString;
extern NSString *NSPortTimeoutException; /* OPENSTEP */
@interface NSPort : NSObject <NSCoding, NSCopying>
{
BOOL is_valid;
id delegate;
BOOL is_valid;
id delegate;
}
+ (NSPort*) port;
+ (NSPort*) portWithMachPort: (int)machPort;
- delegate;
- (id) delegate;
- init;
- initWithMachPort: (int)machPort;
- (id) init;
- (id) initWithMachPort: (int)machPort;
- (void) invalidate;
- (BOOL) isValid;
- machPort;
- (void) setDelegate: anObject;
- (int) machPort;
- (void) setDelegate: (id)anObject;
#ifndef STRICT_OPENSTEP
- (void) addConnection: (NSConnection*)aConnection
toRunLoop: (NSRunLoop*)aLoop
forMode: (NSString*)aMode;
- (void) removeConnection: (NSConnection*)aConnection
fromRunLoop: (NSRunLoop*)aLoop
forMode: (NSString*)aMode;
- (unsigned) reservedSpaceLength;
- (void) sendBeforeDate: (NSDate*)when
components: (NSArray*)components
from: (NSPort*)receivingPort
reserved: (unsigned) length;
#endif
@end
#ifndef NO_GNUSTEP

View file

@ -29,8 +29,8 @@
@interface NSPortMessage : NSObject
{
unsigned msgid;
NSMutableArray *components;
unsigned msgid;
NSMutableArray *components;
}
- (id) initWithMachMessage: (void*)buffer;
- (id) initWithSendPort: (NSPort*)aPort
@ -42,6 +42,10 @@
- (NSPort*) receivePort;
- (void) setMsgid: (unsigned)anId;
- (unsigned) msgid;
#ifndef NO_GNUSTEP
- (void) addComponent: (id)aComponent;
#endif
@end
#endif

View file

@ -32,7 +32,7 @@
/* Mode strings. */
extern id NSDefaultRunLoopMode;
@interface NSRunLoop : NSObject
@interface NSRunLoop : NSObject <GCFinalization>
{
@private id _current_mode;
@private NSMapTable *_mode_2_timers;

View file

@ -74,7 +74,6 @@ after-distclean::
configure: configure.in
autoconf
autoheader
# Regenerate automatically generated files
regenerate: stamp-regenerate
@ -84,36 +83,3 @@ stamp-regenerate: ChangeLog configure
(cd $$i; $(MAKE) $(MAKEDEFINES) regenerate); \
done
touch stamp-regenerate
snapshot:
@echo Making $(PACKAGE_NAME) snapshot
cvs export -r snapshot-`date +%y%m%d` $(PACKAGE_NAME)
rm -f .name
echo $(PACKAGE_NAME)-`date +%y%m%d` >.name
rm -rf `cat .name`
mv $(PACKAGE_NAME) `cat .name`
tar -chvf `cat .name`.tar `cat .name`
rm -f `cat .name`.tar.gz
gzip -9 `cat .name`.tar
rm -rf `cat .name`
dist:
@echo Making $(PACKAGE_NAME) release $(VERSION)
cvs export -r release-`echo $(VERSION) | tr . -` $(PACKAGE_NAME)
mv $(PACKAGE_NAME) $(PACKAGE_NAME)-$(VERSION)
tar -chvf $(PACKAGE_NAME)-$(VERSION).tar \
$(PACKAGE_NAME)-$(VERSION)
rm -f $(PACKAGE_NAME)-$(VERSION).tar.gz
gzip -9 $(PACKAGE_NAME)-$(VERSION).tar
rm -rf $(PACKAGE_NAME)-$(VERSION)
snapshot-rtag:
@echo Tagging current base HEAD for snapshot `date +%y%m%d`
cvs rtag snapshot-`date +%y%m%d` $(PACKAGE_NAME)
dist-rtag:
@echo Tagging current base HEAD for release $(VERSION)
cvs rtag release-`echo $(VERSION) | tr . -` $(PACKAGE_NAME)
rdiff:
cvs rdiff -u -r $(OLD) $(PACKAGE_NAME)

20
NEWS
View file

@ -1,7 +1,25 @@
News
****
The currently released version of the library is `0.5.0'.
The currently released version of the library is `0.5.5'.
Noteworthy changes in version `0.5.5'
=====================================
Too many changes to mention in detail, but here is a list of a few:
* Many base classes have been rewritten with tonnes of performance
improvements that in many cases make it as fast as or faster than
the NeXT implementation.
* DO and archiving has received many improvements that help it work
on a variety of different platforms.
* Configuration and compilation has been greatly improved and fool
proofed.
* There are several new tools for handling services, defaults, and
pasteboards.
Noteworthy changes in version `0.5.1'
=====================================

99
README
View file

@ -9,8 +9,7 @@ remote object messaging support (distributed objects), event loops, and
random number generators.
It provides functionality that aims to implement the non-graphical
portion of the OpenStep standard. In many cases, the `NS*' classes are
implemented as wrappers around more featureful GNU classes.
portion of the OpenStep standard (the Foundation library).
Here is some introductory info to get you started:
@ -30,106 +29,14 @@ documentation will be forthcoming, but the library needs to settle
first. For now I recommend reading the header files. The headers for
the classes are in `./src/include'.
The FAQ contains an outline of the class heirarchy, as well as a
list of the differences between GNUstep and NeXT's implementation of
OpenStep, and GNUstep's improvements over NeXT's implementation.
Overview of the classes
=======================
Here is partial list of non-OpenStep classes, grouped by
functionality.
There are several GNU-specific protocols also. You can recognize the
protocols by their name: they all end with "ing".
* The collection objects all conform to the `Collecting' protocol.
Reading `src/include/Collecting.h' is a good place to start.
Protocols for collections that store their contents with keys and
with indices can be found in `src/incliude/KeyedCollecting.h' and
`src/include/IndexedCollecting.h' respectively. Examples of
generic collections are `Set' and `Bag'. The keyed collections are
`Dictionary' and `MappedCollector'. The classes `Array', `Queue',
`GapArray', `LinkedList', `BinaryTree', `RBTree' and `SplayTree'
are all indexed collections.
* The string objects conform to the `String' protocol. `CString'
provides an interface to strings based on ASCII bytes, and is
currently the only concrete subclass of String. The interface
between GNU `String' and OpenStep's `NSString' needs cleaning up
and will change. For now, I recommend using `NSString'.
* The public magnitude classes are `Time' and `Random'. The
`Random' class works in conjunction with pseudo-random number
generators that conform to the `RandomGenerating' protocol. The
conforming class `RNGBerkeley' provides identical behavior to the
BSD random() function. The class `RNGAdditiveCongruential' is an
implementation of the additive congruential method.
* Stream objects provide a consistent interface for reading and
writing bytes. Read `src/include/Stream.h' to get the general
idea. `StdioStream' objects work with files, file descriptors,
FILE pointers and pipes to/from executables. `MemoryStream'
objects work with memory buffers.
* CStream objects provide a way to write C variables to Stream
objects. Read `src/include/CStream.h' to understand the interface
of the abstract superclass. `TextCStream' writes C variables in a
human-readable ASCII format that can be manipulated with a text
editor or with your choice of text-processing programs, like `awk'
or `perl'. `BinaryCStream' writes C variables in a compact,
illegible stream of bytes. `TextCStream' and `BinaryCStream' each
write in machine-independant formats--so you can write on one
machine architecture, and successfully read on another.
`RawCStream' is like `BinaryCStream' accept it is
machine-dependant; it useful for efficient Distributed Objects
connections on the same machine.
* Coders provide a formatted way of writing Objective C objects to
CStream objects. After a coder is initialized with a stream, the
coder can encode/decode interconnected webs of Objective C objects
and C types and successfully keep track of complex
interconnections between objects. See `src/include/Coder.h' for
the abstract superclass interface; see `src/include/Coding.h' for
the protocol adopted by objects that read and write themselves
using coders. `Archiver' and `Unarchiver' are concrete subclasses
that are used for writing/reading with files.
`Coder's and `CStream's and `Stream's can be mixed and matched so
that programmers can choose the destination and the format
separately.
* The distributed object support classes are `NSConnection',
`NSProxy', `ConnectedCoder', `Port' and `TcpPort'. This version
of the distributed objects only works with sockets. A Mach port
back-end should be on the way.
Test Programs
=============
Some of the programs I've used to test the library are in
`./checks'. Many of them are pretty messy, (desperately trying to
tickle that late night bug), but at least they show some code that works
when the library compiles correctly. I'm looking for a volunteer to
write some nicely organized test cases using `dejagnu'. Any takers?
How can you help?
=================
* Read the projects and questions in the `TODO' file. If you can
volunteer for any of the projects, or if you have any useful
comments send me email!
* Give me feedback! Tell me what you like; tell me what you think
could be better. Send me bug reports.
* Give us feedback! Tell us what you like; tell us what you think
could be better. Send bug reports to <bug-gnustep@gnu.org>.
* Donate classes. If you write classes that fit in the
libgnustep-base framework, I'd be happy to include them.
Happy hacking!
Andrew McCallum
mccallum@gnu.org
Adam Fedor
fedor@gnu.org

View file

@ -58,19 +58,22 @@ after-install::
$(INSTALL_DATA) $(GNUSTEP_TARGET_CPU)/$(GNUSTEP_TARGET_OS)/mframe.h \
$(GNUSTEP_HEADERS)/$(GNUSTEP_TARGET_CPU)/$(GNUSTEP_TARGET_OS)
if [ "$(INSTALL_ROOT_DIR)" = "" ]; then \
if [ "`whoami`" != root ]; then \
echo "WARNING: Please add the following lines yourself"; \
fi; \
services=/etc/services; \
else \
mkdir -p $(INSTALL_ROOT_DIR)/etc; \
services=$(INSTALL_ROOT_DIR)/etc/services.add; \
echo "GNUstep addons for /etc/services written to $$services"; \
fi; \
if [ "`fgrep gdomap $$services 2>/dev/null`" = "" ]; then \
if [ "`whoami`" != root ]; then \
echo "WARNING: Please add the following lines to $$services"; \
echo "gdomap 538/tcp # GNUstep distrib objects"; \
echo "gdomap 538/udp # GNUstep distrib objects"; \
else \
if [ "`fgrep gdomap $$services 2>/dev/null`" = "" ]; then \
echo "GNUstep addons for /etc/services written to $$services"; \
set -x; \
echo "gdomap 538/tcp # GNUstep distrib objects" >> $$services; \
echo "gdomap 538/udp # GNUstep distrib objects" >> $$services; \
fi; \
fi
# Things to do before uninstalling

View file

@ -47,6 +47,8 @@
#include <Foundation/NSException.h>
#include <Foundation/NSLock.h>
#include <Foundation/NSThread.h>
#include <Foundation/NSPort.h>
#include <Foundation/NSPortMessage.h>
#include <Foundation/NSNotification.h>
NSString* NSConnectionReplyMode = @"NSConnectionReplyMode";
@ -184,6 +186,7 @@ static unsigned local_object_counter = 0;
@interface NSConnection (Private)
- _superInit;
- (void) handlePortMessage: (NSPortMessage*)msg;
+ setDebug: (int)val;
@end
@ -411,9 +414,14 @@ static int messages_received_count;
return delegate;
}
- (void) handlePortMessage: (NSPortMessage*)msg
{
[self notImplemented: _cmd];
}
- (BOOL) independantConversationQueueing
{
return independant_queueing;
return independant_queueing;
}
- (void) enableMultipleThreads

View file

@ -22,6 +22,7 @@
*/
#include <config.h>
#include <Foundation/NSException.h>
#include <Foundation/NSString.h>
#include <Foundation/NSNotificationQueue.h>
#include <Foundation/NSPort.h>
@ -38,17 +39,17 @@ NSString *NSPortTimeoutException
+ (NSPort*) port
{
return [[[NSPort alloc] init] autorelease];
return AUTORELEASE([NSPort new]);
}
+ (NSPort*) portWithMachPort: (int)machPort
{
return [[[NSPort alloc] initWithMachPort: machPort] autorelease];
return AUTORELEASE([[NSPort alloc] initWithMachPort: machPort]);
}
- (id) copyWithZone: (NSZone*)aZone
{
return [self retain];
return RETAIN(self);
}
- (id) delegate
@ -75,7 +76,7 @@ NSString *NSPortTimeoutException
- (id) initWithMachPort: (int)machPort
{
[self notImplemented: _cmd];
[self shouldNotImplement: _cmd];
return nil;
}
@ -96,10 +97,10 @@ NSString *NSPortTimeoutException
return is_valid;
}
- (id) machPort
- (int) machPort
{
[self notImplemented: _cmd];
return nil;
[self shouldNotImplement: _cmd];
return 0;
}
- (void) release
@ -126,8 +127,38 @@ NSString *NSPortTimeoutException
- (void) setDelegate: anObject
{
NSAssert([anObject respondsToSelector: @selector(handlePortMessage:)],
NSInvalidArgumentException);
delegate = anObject;
}
- (void) addConnection: (NSConnection*)aConnection
toRunLoop: (NSRunLoop*)aLoop
forMode: (NSString*)aMode
{
[self subclassResponsibility: _cmd];
}
- (void) removeConnection: (NSConnection*)aConnection
fromRunLoop: (NSRunLoop*)aLoop
forMode: (NSString*)aMode
{
[self subclassResponsibility: _cmd];
}
- (unsigned) reservedSpaceLength
{
[self subclassResponsibility: _cmd];
return 0;
}
- (void) sendBeforeDate: (NSDate*)when
components: (NSArray*)components
from: (NSPort*)receivingPort
reserved: (unsigned) length
{
[self subclassResponsibility: _cmd];
}
@end

View file

@ -32,21 +32,21 @@
- (void) dealloc
{
[components release];
[super dealloc];
RELEASE(components);
[super dealloc];
}
/* PortMessages MUST be initialised with ports and data. */
- (id) init
{
[self notImplemented: _cmd];
return nil;
[self shouldNotImplement: _cmd];
return nil;
}
- (id) initWithMachMessage: (void*)buffer
{
[self notImplemented: _cmd];
return nil;
[self shouldNotImplement: _cmd];
return nil;
}
/* This is the designated initialiser. */
@ -54,47 +54,61 @@
receivePort: (NSPort*)anotherPort
components: (NSArray*)items
{
self = [super init];
if (self) {
components = [[NSMutableArray allocWithZone: [self zone]]
initWithCapacity: [items count] + 2];
[components addObject: aPort];
[components addObject: anotherPort];
[components addObjectsFromArray: items];
self = [super init];
if (self)
{
components = [[NSMutableArray allocWithZone: [self zone]]
initWithCapacity: [items count] + 2];
[components addObject: aPort];
[components addObject: anotherPort];
[components addObjectsFromArray: items];
}
return self;
return self;
}
- (void) sendBeforeDate: (NSDate*)when
- (void) addComponent: (id)aComponent
{
[self notImplemented: _cmd];
NSAssert([aComponent isKindOfClass: [NSData class]]
|| [aComponent isKindOfClass: [NSPort class]],
NSInvalidArgumentException);
[components addObject: aComponent];
}
- (NSArray*) components
{
NSRange r = NSMakeRange(2, [components count]-2);
NSRange r = NSMakeRange(2, [components count]-2);
return [components subarrayWithRange: r];
}
- (NSPort*) sendPort
{
return [components objectAtIndex: 0];
}
- (NSPort*) receivePort
{
return [components objectAtIndex: 1];
}
- (void) setMsgid: (unsigned)anId
{
msgid = anId;
return [components subarrayWithRange: r];
}
- (unsigned) msgid
{
return msgid;
return msgid;
}
- (NSPort*) receivePort
{
return [components objectAtIndex: 1];
}
- (void) sendBeforeDate: (NSDate*)when
{
NSPort *port = [self sendPort];
[port sendBeforeDate: when
components: [self components]
from: [self receivePort]
reserved: [port reservedSpaceLength]];
}
- (NSPort*) sendPort
{
return [components objectAtIndex: 0];
}
- (void) setMsgid: (unsigned)anId
{
msgid = anId;
}
@end

View file

@ -74,12 +74,11 @@
/* This error message should be called only if the private main function
* was not executed successfully. This may heppen ONLY if onother library
* or kit defines its own main function (as libobjects does).
* or kit defines its own main function (as gnustep-base does).
*/
#define _GNU_MISSING_MAIN_FUNCTION_CALL @"Libobjects internal error: \
the private libobjects function to establish the argv and environment \
variables was not called. Please contact Tuparev@EMBL-Heidelberg.de for \
further information."
#define _GNU_MISSING_MAIN_FUNCTION_CALL @"GNUSTEP Internal Error: \
The private GNUstep function to establish the argv and environment \
variables was not called. Please report this error to bug-gnustep@gnu.org."
/*************************************************************************
*** _NSConcreteProcessInfo

View file

@ -107,10 +107,11 @@ static int debug_run_loop = 0;
* NB. This class is private to NSRunLoop and must not be subclassed.
*/
@interface RunLoopWatcher: NSObject
@interface RunLoopWatcher: NSObject <GCFinalization>
{
@public
BOOL invalidated;
BOOL handleEvent; // New-style event handling
void *data;
id receiver;
RunLoopEventType type;
@ -130,9 +131,9 @@ static int debug_run_loop = 0;
- (void) dealloc
{
[self invalidate];
[limit release];
[receiver release];
[self gcFinalize];
RELEASE(limit);
RELEASE(receiver);
[super dealloc];
}
@ -144,8 +145,7 @@ static int debug_run_loop = 0;
return;
}
if ([receiver respondsToSelector:
@selector(receivedEvent:type:extra:forMode:)])
if (handleEvent)
{
[receiver receivedEvent: data type: type extra: info forMode: mode];
}
@ -155,21 +155,27 @@ static int debug_run_loop = 0;
{
case ET_RDESC:
case ET_RPORT:
[receiver readyForReadingOnFileDescriptor: (int)info];
[receiver readyForReadingOnFileDescriptor: (int)(gsaddr)info];
break;
case ET_WDESC:
[receiver readyForWritingOnFileDescriptor: (int)info];
[receiver readyForWritingOnFileDescriptor: (int)(gsaddr)info];
break;
}
}
}
- initWithType: (RunLoopEventType)aType
receiver: (id)anObj
data: (void*)item
- (void) gcFinalize
{
[self invalidate];
}
- (id) initWithType: (RunLoopEventType)aType
receiver: (id)anObj
data: (void*)item
{
invalidated = NO;
switch (aType)
{
case ET_RDESC: type = aType; break;
@ -179,7 +185,12 @@ static int debug_run_loop = 0;
[NSException raise: NSInvalidArgumentException
format: @"NSRunLoop - unknown event type"];
}
receiver = [anObj retain];
receiver = RETAIN(anObj);
if ([receiver respondsToSelector:
@selector(receivedEvent:type:extra:forMode:)])
handleEvent = YES;
else
handleEvent = NO;
data = item;
return self;
}
@ -224,7 +235,7 @@ static int debug_run_loop = 0;
* messages which are due to be sent to objects once a particular
* runloop iteration has passed.
*/
@interface RunLoopPerformer: NSObject
@interface RunLoopPerformer: NSObject <GCFinalization>
{
SEL selector;
id target;
@ -252,10 +263,10 @@ static int debug_run_loop = 0;
- (void) dealloc
{
[timer invalidate];
[target release];
[argument release];
[modes release];
[self gcFinalize];
RELEASE(target);
RELEASE(argument);
RELEASE(modes);
[super dealloc];
}
@ -264,13 +275,18 @@ static int debug_run_loop = 0;
if (timer != nil)
{
timer = nil;
[[self retain] autorelease];
AUTORELEASE(RETAIN(self));
[[[NSRunLoop currentInstance] _timedPerformers]
removeObjectIdenticalTo: self];
}
[target performSelector: selector withObject: argument];
}
- (void) gcFinalize
{
[timer invalidate];
}
- initWithSelector: (SEL)aSelector
target: (id)aTarget
argument: (id)anArgument
@ -281,8 +297,8 @@ static int debug_run_loop = 0;
if (self)
{
selector = aSelector;
target = [aTarget retain];
argument = [anArgument retain];
target = RETAIN(aTarget);
argument = RETAIN(anArgument);
order = theOrder;
modes = [theModes copy];
}
@ -331,8 +347,8 @@ static int debug_run_loop = 0;
NSMutableArray *array;
int i;
[target retain];
[arg retain];
RETAIN(target);
RETAIN(arg);
array = [[NSRunLoop currentInstance] _timedPerformers];
for (i = [array count]; i > 0; i--)
{
@ -343,8 +359,8 @@ static int debug_run_loop = 0;
[array removeObjectAtIndex: i-1];
}
}
[arg release];
[target release];
RELEASE(arg);
RELEASE(target);
}
- (void) performSelector: (SEL)aSelector
@ -366,7 +382,7 @@ static int debug_run_loop = 0;
selector: @selector(fire)
userInfo: nil
repeats: NO]];
[item release];
RELEASE(item);
}
- (void) performSelector: (SEL)aSelector
@ -398,7 +414,7 @@ static int debug_run_loop = 0;
userInfo: nil
repeats: NO];
[item setTimer: timer];
[item release];
RELEASE(item);
for (i = 0; i < [modes count]; i++)
{
[loop addTimer: timer forMode: [modes objectAtIndex: i]];
@ -438,8 +454,8 @@ static int debug_run_loop = 0;
if (watchers == nil)
{
watchers = [NSMutableArray new];
NSMapInsert (_mode_2_watchers, mode, watchers);
[watchers release];
NSMapInsert(_mode_2_watchers, mode, watchers);
RELEASE(watchers);
count = 0;
}
else
@ -592,7 +608,7 @@ static int debug_run_loop = 0;
data: data];
/* Add the object to the array for the mode. */
[self _addWatcher:info forMode:mode];
[info release]; /* Now held in array. */
RELEASE(info); /* Now held in array. */
}
}
@ -683,11 +699,12 @@ static int debug_run_loop = 0;
/* Positive values are in the future. */
while (ti > 0 && mayDoMore == YES)
{
id arp = [NSAutoreleasePool new];
CREATE_AUTORELEASE_POOL(arp);
if (debug_run_loop)
printf ("\tNSRunLoop run until date %f seconds from now\n", ti);
mayDoMore = [self runMode: mode beforeDate: date];
[arp release];
RELEASE(arp);
ti = [date timeIntervalSinceNow];
}
}
@ -698,7 +715,7 @@ static int debug_run_loop = 0;
@implementation NSRunLoop
+ currentRunLoop
+ (NSRunLoop*) currentRunLoop
{
static NSString *key = @"NSRunLoopThreadKey";
NSRunLoop* r;
@ -710,7 +727,7 @@ static int debug_run_loop = 0;
{
r = [NSRunLoop new];
[[t threadDictionary] setObject: r forKey: key];
[r release];
RELEASE(r);
}
return r;
}
@ -722,7 +739,7 @@ static int debug_run_loop = 0;
}
/* This is the designated initializer. */
- init
- (id) init
{
[super init];
_current_mode = NSDefaultRunLoopMode;
@ -736,12 +753,17 @@ static int debug_run_loop = 0;
}
- (void) dealloc
{
[self gcFinalize];
RELEASE(_performers);
RELEASE(_timedPerformers);
[super dealloc];
}
- (void) gcFinalize
{
NSFreeMapTable(_mode_2_timers);
NSFreeMapTable(_mode_2_watchers);
[_performers release];
[_timedPerformers release];
[super dealloc];
}
- (NSString*) currentMode
@ -762,7 +784,7 @@ static int debug_run_loop = 0;
{
timers = [Heap new];
NSMapInsert (_mode_2_timers, mode, timers);
[timers release];
RELEASE(timers);
}
/* xxx Should we make sure it isn't already there? */
[timers addObject: timer];
@ -801,7 +823,7 @@ static int debug_run_loop = 0;
break;
}
[min_timer retain];
RETAIN(min_timer);
[timers removeFirstObject];
/* Firing will also increment its fireDate, if it is repeating. */
[min_timer fire];
@ -809,7 +831,7 @@ static int debug_run_loop = 0;
{
[timers addObject: min_timer];
}
[min_timer release];
RELEASE(min_timer);
min_timer = nil;
[NSNotificationQueue runLoopASAP]; /* Post notifications. */
}
@ -871,11 +893,11 @@ static int debug_run_loop = 0;
* If the watcher has been given a revised limit date -
* re-insert it into the queue in the correct place.
*/
[min_watcher retain];
RETAIN(min_watcher);
ASSIGN(min_watcher->limit, nxt);
[watchers removeObjectAtIndex: 0];
[self _addWatcher: min_watcher forMode: mode];
[min_watcher release];
RELEASE(min_watcher);
}
else
{
@ -1204,14 +1226,14 @@ static int debug_run_loop = 0;
{
id watcher = (id) NSMapGet (wfd_2_object, (void*)fd_index);
NSAssert(watcher, NSInternalInconsistencyException);
[watcher eventFor:(void*)fd_index mode:_current_mode];
[watcher eventFor: (void*)(gsaddr)fd_index mode: _current_mode];
[NSNotificationQueue runLoopASAP];
}
if (FD_ISSET (fd_index, &read_fds))
{
id watcher = (id) NSMapGet (rfd_2_object, (void*)fd_index);
NSAssert(watcher, NSInternalInconsistencyException);
[watcher eventFor:(void*)fd_index mode:_current_mode];
[watcher eventFor: (void*)(gsaddr)fd_index mode: _current_mode];
[NSNotificationQueue runLoopASAP];
}
}
@ -1250,12 +1272,12 @@ static int debug_run_loop = 0;
}
/* Use the earlier of the two dates we have. */
d = [[d earlierDate:date] retain];
d = RETAIN([d earlierDate: date]);
/* Wait, listening to our input sources. */
[self acceptInputForMode: mode beforeDate: d];
[d release];
RELEASE(d);
return YES;
}
@ -1297,8 +1319,8 @@ id NSDefaultRunLoopMode = @"NSDefaultRunLoopMode";
int count = [_performers count];
int i;
[target retain];
[argument retain];
RETAIN(target);
RETAIN(argument);
for (i = count; i > 0; i--)
{
item = (RunLoopPerformer*)[_performers objectAtIndex:(i-1)];
@ -1308,8 +1330,8 @@ id NSDefaultRunLoopMode = @"NSDefaultRunLoopMode";
[_performers removeObjectAtIndex:(i-1)];
}
}
[argument release];
[target release];
RELEASE(argument);
RELEASE(target);
}
- (void) configureAsServer
@ -1353,7 +1375,7 @@ id NSDefaultRunLoopMode = @"NSDefaultRunLoopMode";
[_performers addObject:item];
}
}
[item release];
RELEASE(item);
}
- (void) removePort: (NSPort*)port

View file

@ -44,6 +44,10 @@
#include <base/Invocation.h>
#include <Foundation/NSData.h>
#include <Foundation/NSDate.h>
#include <Foundation/NSHashTable.h>
#include <Foundation/NSHost.h>
#include <Foundation/NSMapTable.h>
#include <Foundation/NSPortMessage.h>
#include <Foundation/NSPortNameServer.h>
#include <stdio.h>
#include <stdlib.h>
@ -108,6 +112,698 @@ static int debug_tcp_port = 0;
/* Private interfaces */
@class GSTcpPort;
typedef struct {
gsu32 sendAddr;
gsu32 recvAddr;
gsu16 sendPort;
gsu16 recvPort;
gsu32 mesgId;
gsu32 mesgElems;
gsu32 remaining;
} GSTcpHeader;
@interface GSTcpHandle : NSObject <GCFinalization>
{
int desc; // Unix file descriptor.
NSLock *myLock; // Lock for This handle.
unsigned rLength; // Length of item read so far.
NSPortMessage *rMsg; // Message in progress.
unsigned rItem; // Index of current message item.
NSMutableData *rHeader; // Buffer for item data.
unsigned wLength;
NSPortMessage *wMsg;
unsigned wItem;
NSHashTable *ports;
}
+ (GSTcpHandle*) handleWithDescriptor: (int)descriptor;
- (void) addPort: (GSTcpPort*)p;
- (void) invalidate;
- (void) readData;
- (void) removePort: (GSTcpPort*)p;
- (void) writeData;
@end
@implementation GSTcpHandle
static NSRecursiveLock *tcpHandleLock = nil;
static NSHashTable *tcpHandleTable = 0;
+ (id) allocWithZone: (NSZone*)zone
{
[NSException raise: NSGenericException
format: @"attempt to alloc a GSTcpHandle!"];
return nil;
}
+ (void) initialize
{
if (tcpHandleLock == nil)
{
[gnustep_global_lock lock];
if (tcpHandleLock == nil)
{
tcpHandleLock = [NSRecursiveLock new];
tcpHandleTable =
NSCreateHashTable(NSNonRetainedObjectHashCallBacks, 0);
}
[gnustep_global_lock unlock];
}
}
+ (GSTcpHandle*) handleWithDescriptor: (int)descriptor
{
static GSTcpHandle *dummy = nil;
GSTcpHandle *handle;
if (descriptor < 0)
{
NSLog(@"illegal descriptor (%d) for Tcp Handle", descriptor);
return nil;
}
[tcpHandleLock lock];
if (dummy == nil)
dummy = (GSTcpHandle*)NSAllocateObject(self, 0, NSDefaultMallocZone());
dummy->desc = descriptor;
handle = (GSTcpHandle*)NSHashGet(tcpHandleTable, (void*)dummy);
if (handle == nil)
{
int e;
BOOL ok = YES;
if ((e = fcntl(descriptor, F_GETFL, 0)) >= 0)
{
e |= NBLK_OPT;
if (fcntl(descriptor, F_SETFL, e) < 0)
{
NSLog(@"unable to set non-blocking mode - %s", strerror(errno));
ok = NO;
}
}
else
{
NSLog(@"unable to get non-blocking mode - %s", strerror(errno));
ok = NO;
}
if (ok)
{
handle = (GSTcpHandle*)NSAllocateObject(self,0,NSDefaultMallocZone());
handle->desc = descriptor;
handle->ports =
NSCreateHashTable(NSNonRetainedObjectHashCallBacks, 0);
NSHashInsert(tcpHandleTable, (void*)handle);
AUTORELEASE(handle);
}
}
[tcpHandleLock unlock];
return handle;
}
- (void) addPort: (GSTcpPort*)p
{
[myLock lock];
NSHashInsert(ports, (void*)p);
[myLock unlock];
}
- (void) gcFinalize
{
[myLock lock];
[tcpHandleLock lock];
NSHashRemove(tcpHandleTable, (void*)self);
[tcpHandleLock unlock];
(void) close(desc);
desc = -1;
NSFreeHashTable(ports);
RELEASE(rHeader);
RELEASE(rMsg);
RELEASE(wMsg);
[myLock unlock];
RELEASE(myLock);
}
- (unsigned) hash
{
return (unsigned)desc;
}
- (void) invalidate
{
[myLock lock];
[myLock unlock];
}
- (BOOL) isEqual: (id)anObject
{
if (anObject == self)
return YES;
if ([anObject class] == [self class]
&& ((GSTcpHandle*)anObject)->desc == desc)
return YES;
return NO;
}
- (void) readData
{
int result;
unsigned want;
void *bytes = 0;
[myLock lock];
do
{
/*
* Get address and length of buffer for incoming data if we don't already
* have it from an earlier iteration of the loop. Create the buffer if
* necessary.
*/
if (bytes == 0)
{
if (rHeader == nil)
{
if (rItem == 0)
want = sizeof(GSTcpHeader);
else
want = 6;
rHeader = [[NSMutableData alloc] initWithLength: want];
bytes = [rHeader mutableBytes];
rLength = 0;
}
else
{
want = [rHeader length];
bytes = [rHeader mutableBytes];
}
}
/*
* Now we attempt to fill the buffer.
*/
result = read(desc, bytes + rLength, want - rLength);
if (result == 0)
{
NSLog(@"Unexpected EOF on descriptor %d", desc);
[self invalidate];
}
else if (result < 0)
{
if (errno != EAGAIN)
{
NSLog(@"Error reading on descriptor %d - %s",
desc, strerror(errno));
[self invalidate];
}
}
else
{
rLength += result;
if (rLength == want)
{
if (rItem == 0)
{
if (want == sizeof(GSTcpHeader))
{
}
else
{
}
}
else
{
}
}
}
}
while (result > 0);
[myLock unlock];
}
- (void) release
{
if ([self retainCount] == 1)
{
[super retain];
[self gcFinalize];
[super release];
}
[super release];
}
- (void) removePort: (GSTcpPort*)p
{
[myLock lock];
NSHashRemove(ports, (void*)p);
[myLock unlock];
}
- (void) writeData
{
[myLock lock];
[myLock unlock];
}
@end
@interface GSTcpPort : NSPort <GCFinalization>
{
NSRecursiveLock *myLock;
struct sockaddr_in addr;
int listener;
NSHashTable *handles;
}
+ (GSTcpPort*) portWithNumber: (gsu16)number
onHost: (NSHost*)host
beforeDate: (NSDate*)limit;
+ (GSTcpPort*) portWithAddress: (struct sockaddr_in*)address
andHandle: (GSTcpHandle*)handle
beforeDate: (NSDate*)limit;
- (void) addHandle: (GSTcpHandle*)h;
- (void) removeHandle: (GSTcpHandle*)h;
@end
@implementation GSTcpPort
static NSRecursiveLock *tcpPortLock = nil;
static NSMapTable *tcpPortMap = 0;
static GSTcpPort *dummyPort = nil;
+ (void) initialize
{
if (tcpPortLock == nil)
{
[gnustep_global_lock lock];
if (tcpPortLock == nil)
{
tcpPortLock = [NSRecursiveLock new];
tcpPortMap = NSCreateMapTable(NSIntMapKeyCallBacks,
NSNonOwnedPointerMapValueCallBacks, 0);
dummyPort = (GSTcpPort*)NSAllocateObject(self, 0,
NSDefaultMallocZone());
}
[gnustep_global_lock unlock];
}
}
+ (GSTcpPort*) portWithAddress: (struct sockaddr_in*)sockaddr
andHandle: (GSTcpHandle*)handle
beforeDate: (NSDate*)limit
{
GSTcpPort *port = nil;
NSMapTable *thePorts;
[tcpPortLock lock];
thePorts = (NSMapTable*)NSMapGet(tcpPortMap,
(void*)(gsaddr)sockaddr->sin_port);
if (thePorts == 0)
{
thePorts = NSCreateMapTable(NSIntMapKeyCallBacks,
NSNonOwnedPointerMapValueCallBacks, 0);
NSMapInsert(tcpPortMap,
(void*)(gsaddr)sockaddr->sin_port,
(void*)thePorts);
}
port = (GSTcpPort*)NSMapGet(tcpPortMap,
(void*)(gsaddr)sockaddr->sin_addr.s_addr);
if (port == nil)
{
port = (GSTcpPort*)NSAllocateObject(self,0,NSDefaultMallocZone());
port->listener = -1;
memcpy(&port->addr, sockaddr, sizeof(port->addr));
port->myLock = [NSRecursiveLock new];
port->handles = NSCreateHashTable(NSObjectHashCallBacks, 0);
NSMapInsert(thePorts, (void*)(gsaddr)sockaddr->sin_addr.s_addr,
(void*)port);
AUTORELEASE(port);
}
if (port != nil && handle != nil)
{
NSHashInsert(port->handles, (void*)handle);
[handle addPort: port];
}
[tcpPortLock unlock];
return port;
}
+ (GSTcpPort*) portWithNumber: (gsu16)number
onHost: (NSHost*)host
beforeDate: (NSDate*)limit
{
unsigned i;
GSTcpPort *port = nil;
NSHost *thisHost = [NSHost currentHost];
NSArray *addresses;
NSMapTable *thePorts;
if (host == nil)
{
host = thisHost;
}
addresses = [host addresses];
if ([addresses count] == 0)
{
NSLog(@"attempt to get port on host with no IP address");
return nil;
}
[tcpPortLock lock];
memset(&dummyPort->addr, '\0', sizeof(dummyPort->addr));
dummyPort->addr.sin_family = AF_INET;
dummyPort->addr.sin_port = GSSwapHostI16ToBig(number);
/*
* Get the map table of ports with the specified number.
*/
thePorts = (NSMapTable*)NSMapGet(tcpPortMap,
(void*)(gsaddr)dummyPort->addr.sin_port);
if (thePorts)
{
/*
* Check to see if we have a port for any one of the hosts IP addresses.
*/
for (i = 0; port == nil && i < [addresses count]; i++)
{
const char *a = [[addresses objectAtIndex: i] cString];
#ifndef HAVE_INET_ATON
dummyPort->sin_addr.s_addr = inet_addr(a);
#else
if (inet_aton(a, &dummyPort->addr.sin_addr) == 0)
{
NSLog(@"attempt to get port on host with bad address - '%s'", a);
continue;
}
#endif
port = (GSTcpPort*)NSMapGet(thePorts,
(void*)(gsaddr)dummyPort->addr.sin_addr.s_addr);
if (port != nil)
{
break;
}
}
}
if (port == nil)
{
if (host == thisHost)
{
int status = 1;
int desc;
port = (GSTcpPort*)NSAllocateObject(self,0,NSDefaultMallocZone());
port->listener = -1;
port->handles =
NSCreateHashTable(NSObjectHashCallBacks, 0);
port->addr.sin_addr.s_addr = GSSwapHostI32ToBig(INADDR_ANY);
if ((desc = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0)
{
NSLog(@"unable to create socket - %s", strerror(errno));
DESTROY(port);
}
else if (setsockopt(desc, SOL_SOCKET, SO_REUSEADDR, (char *)&status,
sizeof(status)) < 0)
{
(void) close(desc);
NSLog(@"unable to set reuse on socket - %s", strerror(errno));
DESTROY(port);
}
else if (bind(desc, (struct sockaddr *)&port->addr,
sizeof(port->addr)) < 0)
{
NSLog(@"unable to bind to port %s:%d - %s",
inet_ntoa(port->addr.sin_addr), number, strerror(errno));
(void) close(desc);
DESTROY(port);
}
else if (listen(desc, 5) < 0)
{
NSLog(@"unable to listen on port - %s", strerror(errno));
(void) close(desc);
DESTROY(port);
}
else if (getsockname(desc, (struct sockaddr*)&port->addr, &i) < 0)
{
NSLog(@"unable to get socket name - %s", strerror(errno));
(void) close(desc);
DESTROY(port);
}
else
{
port->listener = desc;
port->myLock = [NSRecursiveLock new];
/*
* Ok - now add the port for all the IP addresses it listens on.
*/
for (i = 0; i < [addresses count]; i++)
{
const char *a = [[addresses objectAtIndex: i] cString];
gsaddr val;
#ifndef HAVE_INET_ATON
dummyPort->addr.sin_addr.s_addr = inet_addr(a);
#else
if (inet_aton(a, &dummyPort->addr.sin_addr) == 0)
{
continue;
}
#endif
val = (gsaddr)dummyPort->addr.sin_addr.s_addr;
if (thePorts == 0)
{
/*
* No known ports within this port number -
* create the map table to add the new port to.
*/
thePorts = NSCreateMapTable(NSIntMapKeyCallBacks,
NSNonOwnedPointerMapValueCallBacks, 0);
NSMapInsert(tcpPortMap,
(void*)(gsaddr)port->addr.sin_port,
(void*)thePorts);
}
NSMapInsert(thePorts, (void*)val, (void*)port);
}
}
}
else if (number != 0) /* Can't connect to port zero */
{
for (i = 0; port == nil && i < [addresses count]; i++)
{
int desc;
const char *a = [[addresses objectAtIndex: i] cString];
port = (GSTcpPort*)NSAllocateObject(self,0,NSDefaultMallocZone());
port->listener = -1;
#ifndef HAVE_INET_ATON
port->addr.sin_addr.s_addr = inet_addr(a);
#else
if (inet_aton(a, &port->addr.sin_addr) == 0)
{
NSLog(@"opening port on host with bad address - '%s'", a);
continue;
}
#endif
if ((desc = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0)
{
NSLog(@"unable to create socket - %s", strerror(errno));
DESTROY(port);
}
else if (connect(desc, (struct sockaddr*)&port->addr,
sizeof(port->addr)) < 0)
{
NSLog(@"unable to make connection to %s:%d - %s", a,
GSSwapBigI16ToHost(port->addr.sin_port), strerror(errno));
DESTROY(port);
}
else
{
GSTcpHandle *handle;
port->myLock = [NSRecursiveLock new];
port->handles =
NSCreateHashTable(NSObjectHashCallBacks, 0);
handle = [GSTcpHandle handleWithDescriptor: desc];
NSHashInsert(port->handles, (void*)handle);
if (thePorts == 0)
{
/*
* No known ports within this port number -
* create the map table to add the new port to.
*/
thePorts = NSCreateMapTable(NSIntMapKeyCallBacks,
NSNonOwnedPointerMapValueCallBacks, 0);
NSMapInsert(tcpPortMap,
(void*)(gsaddr)port->addr.sin_port,
(void*)thePorts);
}
NSMapInsert(thePorts,
(void*)(gsaddr)port->addr.sin_addr.s_addr, (void*)port);
}
}
}
AUTORELEASE(port);
}
[tcpPortLock unlock];
return port;
}
- (void) addHandle: (GSTcpHandle*)h
{
[myLock lock];
NSHashInsert(handles, (void*)h);
[myLock unlock];
}
- (id) copyWithZone: (NSZone*)zone
{
return RETAIN(self);
}
- (void) gcFinalize
{
[self invalidate];
}
- (unsigned) hash
{
return (unsigned)(addr.sin_addr.s_addr ^ addr.sin_port);
}
- (void) invalidate
{
[myLock lock];
if ([self isValid])
{
NSMapTable *thePorts;
NSArray *handleArray;
unsigned i;
[tcpPortLock lock];
thePorts = NSMapGet(tcpPortMap, (void*)(gsaddr)addr.sin_port);
if (thePorts)
{
gsaddr val;
if (listener == -1)
{
val = (gsaddr)addr.sin_addr.s_addr;
NSMapRemove(thePorts, (void*)val);
}
else
{
unsigned i;
NSArray *addresses = [[NSHost currentHost] addresses];
for (i = 0; i < [addresses count]; i++)
{
const char *a = [[addresses objectAtIndex: i] cString];
#ifndef HAVE_INET_ATON
addr,sin_addr.s_addr = inet_addr(a);
#else
if (inet_aton(a, &addr.sin_addr) == 0)
{
continue;
}
#endif
val = (gsaddr)addr.sin_addr.s_addr;
NSMapRemove(thePorts, (void*)val);
}
}
}
[tcpPortLock unlock];
if (listener >= 0)
{
(void)close(listener);
listener = -1;
}
handleArray = NSAllHashTableObjects(handles);
i = [handleArray count];
while (i > 0)
{
GSTcpHandle *handle = [handleArray objectAtIndex: i];
[handle removePort: self];
}
NSFreeHashTable(handles);
[super invalidate];
}
[myLock unlock];
RELEASE(myLock);
}
- (BOOL) isEqual: (id)anObject
{
if (anObject == self)
return YES;
if ([anObject class] == [self class])
{
GSTcpPort *o = (GSTcpPort*)anObject;
if (o->addr.sin_port == addr.sin_port &&
o->addr.sin_addr.s_addr == addr.sin_addr.s_addr)
return YES;
}
return NO;
}
- (void) release
{
if ([self retainCount] == 1)
{
[super retain];
[self gcFinalize];
[super release];
}
[super release];
}
- (void) removeHandle: (GSTcpHandle*)h
{
[myLock lock];
NSHashRemove(handles, (void*)h);
[myLock unlock];
}
@end
@interface TcpInPort (Private)
- (int) _port_socket;
- (struct sockaddr_in*) _listeningSockaddr;

View file

@ -1,4 +1,5 @@
#include <stdio.h>
#include <Foundation/NSObject.h>
#include <Foundation/NSConnection.h>
#include <Foundation/NSDistantObject.h>
#include <Foundation/NSDictionary.h>
@ -11,7 +12,10 @@
#include <assert.h>
#include "server.h"
int main(int argc, char *argv[])
@class TcpInPort;
@class PortDecoder;
int main (int argc, char *argv[])
{
id a;
id p;
@ -36,13 +40,18 @@ int main(int argc, char *argv[])
const char *type;
NSAutoreleasePool *arp = [NSAutoreleasePool new];
GSDebugAllocationActive(YES);
[NSConnection setDebug: 10];
[NSDistantObject setDebug: 10];
[TcpInPort setDebug: 10];
[Coder setDebugging:YES];
[BinaryCStream setDebugging:YES];
#if NeXT_runtime
[NSDistantObject setProtocolForProxies:@protocol(AllProxies)];
#endif
printf("oneway %d\n", _F_ONEWAY);
if (argc > 1)
{
if (argc > 2)
@ -60,12 +69,16 @@ int main(int argc, char *argv[])
[c setReplyTimeout:180.0];
localObj = [[NSObject alloc] init];
[p outputStats:localObj];
fprintf(stderr, "XXXXXXXXXXXXXXXXA %d\n", GSDebugAllocationCount([PortDecoder class]));
[p getLong:&i];
fprintf(stderr,"XXXXXXXXXXXXXXXXB %d\n", GSDebugAllocationCount([PortDecoder class]));
[p getLong:&i];
[p outputStats:localObj];
fprintf(stderr,"XXXXXXXXXXXXXXXXC %d\n", GSDebugAllocationCount([PortDecoder class]));
type = [c typeForSelector:sel_get_any_uid("name")
remoteTarget:[p targetForProxy]];
printf("XXXXXXXXXXXXXXXXD %d\n", GSDebugAllocationCount([PortDecoder class]));
printf(">>type = %s\n", type);
printf(">>list proxy's hash is 0x%x\n",
(unsigned)[p hash]);
printf(">>list proxy's self is 0x%x = 0x%x\n",
@ -149,9 +162,11 @@ int main(int argc, char *argv[])
id remote_peer_obj = [p objectAt:j];
printf("triangle %d object proxy's hash is 0x%x\n",
j, (unsigned)[remote_peer_obj hash]);
#if 0
/* xxx look at this again after we use release/retain everywhere */
if ([remote_peer_obj isProxy])
[remote_peer_obj release];
#endif
remote_peer_obj = [p objectAt:j];
printf("repeated triangle %d object proxy's hash is 0x%x\n",
j, (unsigned)[remote_peer_obj hash]);
@ -170,9 +185,14 @@ int main(int argc, char *argv[])
printf("%s - %s\n", [k cString], [[v description] cString]);
}
[arp release];
arp = [NSAutoreleasePool new];
printf("%d\n", [c retainCount]);
printf("%s\n", [[[c statistics] description] cString]);
// printf("%s\n", GSDebugAllocationList(YES));
[NSRunLoop runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 20 * 60]];
[c invalidate];
[arp release];
exit(0);
}

View file

@ -7,12 +7,12 @@ GCC_VERSION=2.8.0
# The version number of this release.
MAJOR_VERSION=0
MINOR_VERSION=5
SUBMINOR_VERSION=0
SUBMINOR_VERSION=5
GNUSTEP_BASE_VERSION=${MAJOR_VERSION}.${MINOR_VERSION}.${SUBMINOR_VERSION}
VERSION=${GNUSTEP_BASE_VERSION}
GNUSTEP_BASE_FTP_MACHINE=ftp.gnu.org
GNUSTEP_BASE_FTP_DIRECTORY=pub/gnu
GNUSTEP_BASE_FTP_DIRECTORY=pub/gnu/gstep
GNUSTEP_BASE_SNAP_FTP_MACHINE=alpha.gnu.org
GNUSTEP_BASE_SNAP_FTP_DIRECTORY=gnu/gnustep