ftp.nice.ch/pub/next/developer/resources/classes/misckit/MiscKit.1.10.0.s.gnutar.gz#/MiscKit/Source/MiscKit/MiscThreadedObject.m

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.