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.