macemu/BasiliskII/src/MacOSX/NNThread.m
2004-05-25 07:50:14 +00:00

257 lines
5.0 KiB
Objective-C

//
// NNThread.m -Not Nextstep Thread?
// Nigel's Nice Thread?
//
// Revision 1.4, Tuesday May 25 2004
//
// Created by Nigel Pearson on Tue Nov 28 2000.
// Public Domain. No rights reserved.
//
#import "NNThread.h"
#import <objc/objc-runtime.h> // For objc_msgSend() prototype
@implementation NNThread
// Define the wrapper first so that init knows about it without having to put it in the .h
#ifdef USE_NSTHREAD
- (void) wrapper
{
machThread = mach_thread_self();
if ( object == nil || sel == (SEL) nil || suspended )
thread_suspend (machThread); // Suspend myself
if ( allocPool )
pool = [NSAutoreleasePool new];
// [object sel] caused "cannot find method" warnings, so I do it a non-obvious way:
objc_msgSend (object, sel);
completed = YES;
if ( allocPool )
[pool release];
}
#endif
#ifdef USE_PTHREAD
void *
pthreadWrapper (void *arg)
{
struct pthreadArgs *args = arg;
if ( args -> allocPool )
args -> pool = [NSAutoreleasePool new];
objc_msgSend (*(args->object), *(args->sel));
*(args->completed) = YES;
if ( args -> allocPool )
[args -> pool release];
return NULL;
}
- (BOOL) wrapper
{
int error;
pthreadArgs.object = &object;
pthreadArgs.sel = &sel;
pthreadArgs.allocPool = allocPool;
pthreadArgs.completed = &completed;
pthreadArgs.pool = nil;
if ( object == nil || sel == (SEL) nil || suspended )
error = pthread_create_suspended_np (&pThread, NULL, &pthreadWrapper, &pthreadArgs);
else
error = pthread_create (&pThread, NULL, &pthreadWrapper, &pthreadArgs);
if ( error )
NSLog(@"%s - pthread_create failed");
else
machThread = pthread_mach_thread_np (pThread);
return ! error;
}
#endif
- (NNThread *) initSuspended: (BOOL) startSuspended
withAutoreleasePool: (BOOL) allocatePool
{
self = [super init];
allocPool = allocatePool;
completed = NO;
suspended = startSuspended;
object = nil;
sel = (SEL) nil;
#ifdef USE_NSTHREAD
[NSThread detachNewThreadSelector:@selector(wrapper)
toTarget:self
withObject:nil];
#endif
#ifdef USE_PTHREAD
if ( ! [self wrapper] ) // Wrapper does the thread creation
{
NSLog(@"%s - pthread wrapper failed", __PRETTY_FUNCTION__);
return nil;
}
#endif
return self;
}
- (NNThread *) init
{
return [self initSuspended: YES withAutoreleasePool: NO];
}
- (NNThread *) initWithAutoReleasePool
{
return [self initSuspended: YES withAutoreleasePool: YES];
}
- (BOOL) completed
{
return completed;
}
- (void) perform: (SEL)action of: (id)receiver
{
object = receiver, sel = action;
}
- (void) resume
{
if ( suspended )
[self start];
else
NSLog (@"%s - thread not suspended", __PRETTY_FUNCTION__);
}
- (BOOL) start
{
kern_return_t error;
if ( object == nil || sel == (SEL) nil )
{
NSLog (@"%s - cannot start thread, object or selector invalid", __PRETTY_FUNCTION__);
return NO;
}
if ( ( error = thread_resume (machThread) ) != KERN_SUCCESS )
NSLog (@"%s - thread_resume() failed, returned %d", __PRETTY_FUNCTION__, error);
suspended = NO;
return YES;
}
- (void) suspend
{
if ( ! suspended )
{
kern_return_t error;
if ( ( error = thread_suspend (machThread) ) != KERN_SUCCESS )
NSLog (@"%s - thread_resume() failed, returned %d", __PRETTY_FUNCTION__, error);
suspended = YES;
}
}
- (void) terminate
{
kern_return_t error;
if ( ( error = thread_terminate (machThread) ) != KERN_SUCCESS )
NSLog (@"%s - thread_terminate() failed, returned %d", __PRETTY_FUNCTION__, error);
}
@end
@implementation NNTimer
- (NNTimer *) init
{
self = [super init];
repeating = YES;
return self;
}
- (NNTimer *) initWithAutoRelPool
{
self = [super init];
allocPool = YES;
repeating = YES;
return self;
}
- (void) changeIntervalTo: (int)number
units: (NNTimeUnits)units
{
switch ( units )
{
case NNnanoSeconds:
delay.tv_nsec = number;
delay.tv_sec = 0;
break;
case NNmicroSeconds:
delay.tv_nsec = number * 1000;
delay.tv_sec = 0;
break;
case NNmilliSeconds:
delay.tv_nsec = number * 1000000;
delay.tv_sec = 0;
break;
case NNseconds:
delay.tv_nsec = 0;
delay.tv_sec = number;
break;
default:
NSLog (@"%s illegal units(%d)", __PRETTY_FUNCTION__, units);
}
}
- (void) invalidate
{
repeating = NO;
}
- (void) timerLoop
{
// For some strange reason, Mac OS X does not have this prototype
extern int nanosleep (const struct timespec *rqtp, struct timespec *rmtp);
while ( repeating )
{
nanosleep(&delay, NULL);
completed = NO;
// This caused a few warnings:
// [timerObject timerSel];
// so I do it a non-obvious way:
objc_msgSend (timerObject, timerSel);
completed = YES;
}
}
- (void) perform: (SEL)action of: (id)receiver
after: (int)number units: (NNTimeUnits)units
{
object = self, sel = @selector(timerLoop),
timerObject = receiver, timerSel = action, repeating = NO;
[self changeIntervalTo: number units: units];
}
- (void) repeat: (SEL)action of: (id)receiver
every: (int)number units: (NNTimeUnits)units
{
object = self, sel = @selector(timerLoop),
timerObject = receiver, timerSel = action, repeating = YES;
[self changeIntervalTo: number units: units];
}
@end