This is MiscThreadedObject.m in view mode; [Download] [Up]
/*
* File: MiscThreadedObject.m
* Version: 1.0
* Author: Steve Quirk
* Summary: Provides basic threading mechanism to Object
*
* Revision History:
* Nov 1994 steveq created
*
* Copyright 1994 Steve Quirk steveq@telerate.com
*
* A threaded object can run in it's own thread. Simply send a
* runInNewThread message to the instance & a thread will be created
* and the instance's 'run' method will be invoked. The thread will
* be destroyed when the run method returns. Optionally, the instance will
* also be freed as well when run returns.
*
* To be useful, a subclass must override the run method - this
* implementation simply returns self.
*
*/
#import <misckit/MiscThreadedObject.h>
#import <objc/objc-runtime.h>
#import <mach/mach_traps.h>
#import <errno.h>
#define CTHREAD_NULL (cthread_t)NULL
#define TINFO_NULL (thread_info_t)NULL
@implementation MiscThreadedObject
/*
* get/set thread count limit for task
*/
+ (int)getThreadLimit
{
return cthread_limit();
}
+ (void)setThreadLimit:(int)newLimit
{
cthread_set_limit(newLimit);
}
+ (int)errno
{
return cthread_errno();
}
- init
{
[super init];
freeOnReturnFromRun = YES;
info = TINFO_NULL;
schedInfo = TINFO_NULL;
objThread = CTHREAD_NULL;
return self;
}
- free
{
if (info != TINFO_NULL)
free(info);
if (schedInfo != TINFO_NULL)
free(schedInfo);
return [super free];
}
- (BOOL)freeAfterRun
{
return freeOnReturnFromRun;
}
- freeAfterRun:(BOOL)yesOrNo
{
freeOnReturnFromRun = (yesOrNo != 0); /* force 0/1 */
return self;
}
- run
{
return self; /* a hasty exit */
}
static any_t spawn(id self)
{
any_t result;
result = ([self run] == self) ? (any_t)0 : (any_t)1;
/*
* believe it or not, yielding clears up a lot of race conditions (especially
* in DO wrt invalidation notification).
*/
cthread_yield();
if ([self freeAfterRun])
[self free];
cthread_exit(result);
return 0; /* never reached... (to keep compiler happy) */
}
/*
* spawns new thread & detaches
*/
- runInNewThread
{
if ([self fork] == self) {
cthread_detach(objThread);
return self;
} else
return nil;
}
- fork
{
static BOOL runTimeInit = NO;
int limit;
if (runTimeInit == NO) { /* make sure this is taken care of */
objc_setMultithreaded(YES);
cthread_init();
runTimeInit = YES;
}
/*
* make sure we don't exceed the thread limit for this task...
*/
limit = cthread_limit(); /* (limit == 0) => no limit */
if (limit && (limit == cthread_count())) {
cthread_set_errno_self(EAGAIN); /* no more processes... */
return nil;
}
objThread = cthread_fork((cthread_fn_t)spawn, (any_t)self);
cthread_set_name(objThread, [self name]);
return self;
}
- (any_t)join
{
if (objThread != CTHREAD_NULL) {
/*
* caller must not be in self's thread, otherwise a deadlock would occur
*/
if (thread_self() == cthread_thread(objThread))
[self error:"Attempt to join thread from self"];
return cthread_join(objThread);
} else
return ((any_t)-1); /* probably should [self error:...] */
}
- (thread_info_t)threadInfo /* returns basic thread information */
{
int count = THREAD_BASIC_INFO_COUNT;
if ((objThread != CTHREAD_NULL) && (info == TINFO_NULL))
info = NXZoneCalloc([self zone], count, sizeof(int));
if (info != TINFO_NULL) {
kern_return_t success;
success = thread_info(cthread_thread(objThread),
THREAD_BASIC_INFO, info, &count);
if (success != KERN_SUCCESS)
return TINFO_NULL;
}
return info;
}
- (thread_info_t)threadSchedInfo /* returns scheduling thread information */
{
int count = THREAD_SCHED_INFO_COUNT;
if ((objThread != CTHREAD_NULL) && (schedInfo == TINFO_NULL))
schedInfo = NXZoneCalloc([self zone], count, sizeof(int));
if (schedInfo != TINFO_NULL) {
kern_return_t success;
success = thread_info(cthread_thread(objThread),
THREAD_SCHED_INFO, schedInfo, &count);
if (success != KERN_SUCCESS)
return TINFO_NULL;
}
return schedInfo;
}
- suspend /* suspend's the receiver's thread */
{
if (objThread != CTHREAD_NULL)
thread_suspend(cthread_thread(objThread));
else
return nil;
return self;
}
- resume /* undoes a suspend */
{
if (objThread != CTHREAD_NULL)
thread_resume(cthread_thread(objThread));
else
return nil;
return self;
}
- abort /* terminate's receiver's thread */
{
if (objThread != CTHREAD_NULL)
cthread_abort(objThread);
else
return nil;
return self;
}
- switchTo /* causes a context switch into the receivers thread */
{
if (objThread == CTHREAD_NULL)
return nil;
else {
kern_return_t success;
success = thread_switch(cthread_thread(objThread),SWITCH_OPTION_NONE,0);
if (success != KERN_SUCCESS)
return nil;
}
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.