libs-base/Source/NSThread.m

230 lines
6.2 KiB
Mathematica
Raw Normal View History

1996-05-13 15:53:36 +00:00
/* Control of executable units within a shared virtual memory space
Copyright (C) 1996 Free Software Foundation, Inc.
1996-05-13 15:53:36 +00:00
Original Author: Scott Christley <scottc@net-community.com>
Rewritten by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
Created: 1996
This file is part of the GNUstep Objective-C Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <config.h>
#include <Foundation/NSThread.h>
#include <Foundation/NSLock.h>
#include <Foundation/NSString.h>
#include <gnustep/base/o_map.h>
1996-05-13 15:53:36 +00:00
#include <gnustep/base/Notification.h>
// Class variables
1996-05-13 15:53:36 +00:00
#define USING_THREAD_COLLECTION 0
#if USING_THREAD_COLLECTION
/* For managing the collection of all NSThread objects. Note, however,
threads that have not yet called +currentThread will not be in the
collection.
xxx Do we really need this collection anyway?
How about getting rid of it? */
static NSRecursiveLock *thread_lock;
static o_map_t thread_id_2_nsthread;
#endif
1996-05-13 15:53:36 +00:00
/* Flag indicating whether the objc runtime ever went multi-threaded. */
static BOOL entered_multi_threaded_state;
1996-05-13 15:53:36 +00:00
@implementation NSThread
// Class initialization
1996-05-13 15:53:36 +00:00
+ (void) initialize
{
if (self == [NSThread class])
{
1996-05-13 15:53:36 +00:00
#if USING_THREAD_COLLECTION
thread_id_2_nsthread = o_map_of_non_owned_void_p ();
thread_lock = [[[NSRecursiveLock alloc] init]
autorelease];
#endif
entered_multi_threaded_state = NO;
}
}
1996-05-13 15:53:36 +00:00
// Initialization
1996-05-13 15:53:36 +00:00
- (void)dealloc
{
[_thread_dictionary release];
[super dealloc];
}
- init
{
[super init];
/* Make it easy and fast to get this NSThread object from the thread. */
objc_thread_set_data (self);
1996-05-13 15:53:36 +00:00
/* initialize our ivars. */
_thread_dictionary = nil; // Initialize this later only when needed
_exception_handler = NULL;
init_autorelease_thread_vars (&_autorelease_vars);
1996-05-13 15:53:36 +00:00
#if USING_THREAD_COLLECTION
/* Register ourselves in the maptable of all threads. */
// Lock the thread list so it doesn't change on us
1996-05-13 15:53:36 +00:00
[thread_lock lock];
// Save the thread in our thread map; NOTE: this will not retain it
o_map_at_key_put_value_known_absent (thread_id_2_nsthread, tid, t);
[thread_lock unlock];
#endif
1996-05-13 15:53:36 +00:00
return self;
}
1996-05-13 15:53:36 +00:00
// Creating an NSThread
1996-05-13 15:53:36 +00:00
+ (NSThread*) currentThread
{
id t = (id) objc_thread_get_data ();
/* If an NSThread object for this thread has already been created
and stashed away, return it. This depends on the objc runtime
initializing objc_thread_get_data() to 0 for newly-created
threads. */
if (t)
return t;
/* We haven't yet created an NSThread object for this thread; create
it. (Doing this here instead of in +detachNewThread.. not only
avoids the race condition, it also nicely provides an NSThread on
request for the single thread that exists at application
start-up, and for thread's created by calling
objc_thread_detach() directly.) */
t = [[NSThread alloc] init];
return t;
}
1996-05-13 15:53:36 +00:00
+ (void) detachNewThreadSelector:(SEL)aSelector
toTarget:(id)aTarget
withObject:(id)anArgument
{
/* Post a notification if this is the first new thread to be created.
Won't work properly if threads are not all created by this class.
xxx Should the notification be done before the new thread starts,
or after? */
if (!entered_multi_threaded_state)
{
entered_multi_threaded_state = YES;
[NotificationDispatcher
postNotificationName: NSBecomingMultiThreaded
object: nil];
}
// Have the runtime detach the thread
1996-05-13 15:53:36 +00:00
objc_thread_detach (aSelector, aTarget, anArgument);
1996-05-13 15:53:36 +00:00
/* NOTE we can't create the new NSThread object for this thread here
because there would be a race condition. The newly created
thread might ask for its NSThread object before we got to create
it. */
}
1996-05-13 15:53:36 +00:00
// Querying a thread
1996-05-13 15:53:36 +00:00
+ (BOOL) isMultiThreaded
{
1996-05-13 15:53:36 +00:00
return entered_multi_threaded_state;
}
/* Thread dictionary
NB. This cannot be autoreleased, since we cannot be sure that the
autorelease pool for the thread will continue to exist for the entire
life of the thread!
*/
1996-05-13 15:53:36 +00:00
- (NSMutableDictionary*) threadDictionary
{
if (!_thread_dictionary)
_thread_dictionary = [NSMutableDictionary new];
1996-05-13 15:53:36 +00:00
return _thread_dictionary;
}
// Delaying a thread
1996-05-13 15:53:36 +00:00
+ (void) sleepUntilDate: (NSDate*)date
{
NSTimeInterval delay;
// delay is always the number of seconds we still need to wait
delay = [date timeIntervalSinceNow];
// Avoid integer overflow by breaking up long sleeps
// We assume usleep can accept a value at least 31 bits in length
while (delay > 30.0*60.0)
{
// sleep 30 minutes
usleep (30*60*1000000);
delay = [date timeIntervalSinceNow];
}
// usleep may return early because of signals
while (delay > 0)
{
usleep (delay*1000000.0);
delay = [date timeIntervalSinceNow];
}
}
// Terminating a thread
// What happens if the thread doesn't call +exit?
1996-05-13 15:53:36 +00:00
+ (void) exit
{
NSThread *t;
// the current NSThread
t = [NSThread currentThread];
1996-05-13 15:53:36 +00:00
// Post the notification
[NotificationDispatcher
postNotificationName: NSThreadExiting
object: t];
#if USING_THREAD_COLLECTION
{
_objc_thread_t tid;
// Get current thread id from runtime
tid = objc_thread_id();
// Lock the thread list so it doesn't change on us
[thread_lock lock];
// Remove the thread from the map
o_map_remove_key (thread_id_2_nsthread, tid);
// Unlock the thread list
[thread_lock unlock];
}
#endif
// Release the thread object
[t release];
// xxx Clean up any outstanding NSAutoreleasePools here.
// Tell the runtime to exit the thread
1996-05-13 15:53:36 +00:00
objc_thread_exit ();
}
@end