Code Search for Developers
 
 
  

atomicity.c from redshed at Krugle


Show atomicity.c syntax highlighted

/****************************************************************************************
	atomicity.c $Revision: 74 $
		<http://redshed.net/atomicity>
	
	Copyright © 1998-2002 Red Shed Software. All rights reserved.
	by Jonathan 'Wolf' Rentzsch (jon at redshed dot net)
	
	This code requires a 68020 or later or any PowerPC. No habla 68000 or x86.
	
	************************************************************************************/

#include	"atomicity.h"

/**************************
*	
*	Requirements
*	
**************************/
#pragma mark	(Requirements)

#include	"require.h"	//	Comment out this line to disable requirement checking.
#ifndef	GenerateRequirements
	#define	Require( CODE )
	#define	RequireIf( TEST, CODE )
	#define	RequirePtr( PTR )
	#define	RequirePtrAlign( PTR, ALIGN )
	#define	RequirePtrAlignIfNotNil( PTR, ALIGN )
	#define	RequirePtrIfNotNil( PTR )
	#define	RequirePtrAlignIf( TEST, PTR, ALIGN )
#endif
#define	RequireOffset( OFFSET )	Require( OFFSET < 1024 )

/**************************
*	
*	Conditional Compilation Flags
*	
**************************/
#pragma mark	-
#pragma mark	(Conditional Compilation Flags)

#if	0	//	Set to 1 if you're not using Universal Interfaces 3 or later.
	#define	TARGET_CPU_PPC		1
	#define	TARGET_CPU_68K		0
	#define	TARGET_RT_MAC_CFM	0
	
	/*	Psuedocode explaining the above conditional compilation flags.
		You'll need to set these flags manually if you're not using
		Universal Interfaces 3 or later.
		
	if( TARGET_CPU_PPC == 1 ) {
		generate PowerPC code;
	} else if( TARGET_CPU_68K == 1 ) {
		if( TARGET_RT_MAC_CFM == 1 ) {
			generate CFM68K code;
		} else {
			generate Classic 68K code;
		}
	}*/
#endif

/**************************
*	
*	Types
*	
**************************/
#pragma mark	-
#pragma mark	(Types)

typedef	struct	{
	char		padding[ kAtomicAlignment ];
	AtomicStack	stack;
}	AlignedAtomicStack;

/**************************
*	
*	Funky Protos
*	
**************************/
#pragma mark	-
#pragma mark	(Funky Protos)

#if		defined(DontUseOpenTransport)
#elif	defined(OnlyUseOpenTransport)
#else	//	UseOpenTransportIfAvailable
	Boolean
IsOpenTransportAvailable();
#endif

	AtomicStack*
AlignAtomicStack(
	AlignedAtomicStack	*stack );

	void
AddOffset(
	void	**ptr,
	size_t	offset );

	void
SubOffset(
	void	**ptr,
	size_t	offset );

/****************************************************************************************
	Some of the functions below are written in assembly language to access atomic
	instructions inaccessable from a high-level language like C. We want to compile to
	differing platforms from a single source file, so we use conditional #defines to
	generate 68K or PowerPC code depending on what the compiler is generating.
	
	In addition to conditionally generating 68K or PowerPC assembly, when generating 68K
	code, we conditionally generate Classic 68K or CFM-68K code.
	
	Classic 68K:
		Classic 68K doesn't define a standard parameter passing convention, so we use
		the Pascal calling convention. We use the 'pascal' keyword so the compiler
		generates code that uses the Pascal calling convention.
		
		The Pascal calling convention requires the caller make space for the callee's
		result (if any) and all parameters. The parameters are pushed from left to right,
		followed by the return address. The callee is responsible for popping all
		paramaters before returning to the caller. The function result (if any) is left
		on the stack.
		
		The Pascal calling convention doesn't explictly state what registers should be
		saved, so we use the rather strict CFM-68K register preservation guideline, which
		requires we preserve registers d3-d7 and a2-a7. That leaves us with d0, d1, d2
		and a0, a1.
	CFM-68K:
		CFM-68K defines a standard parameter passing convention, so the 'pascal'
		keyword (required when generating Classic 68K code) is ignored.
		
		Under CFM-68K, parameters are pushed from right to left onto the stack,
		followed by the return address. The function's result (if any) is returned
		in register D0. CFM-68K requires we preserve registers d3-d7 and a2-a7. That
		leaves us with d0, d1, d2 and a0, a1.
	PowerPC:
		PowerPC code always uses CFM parameter passing conventions, so the 'pascal'
		keyword (required when generating Classic 68K code) is ignored.
		
		Under PowerPC, parameters are passed in registers left to right, starting with
		register r3. The function's result (if any) is stored in register r3.
	
	************************************************************************************/

/****************************************************************************************
*	
*	Atomic Basis Functions
*	
****************************************************************************************/
#pragma mark	-
#pragma mark	(Atomic Basis Functions)

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Wed, Sep 15, 1999	Created.
	
	************************************************************************************/

	asm
	pascal
	long
MyAtomicStore(
	long	/*oldValue*/,
	long	/*newValue*/,
	void	*/*address*/ )
{
#if		TARGET_CPU_PPC
retry:
	lwarx	r6, 0, r5		//	currentValue = *address;
	cmpw	r6, r3			//	if( currentValue != oldValue )
	bne		fail			//		goto fail;
	sync					//	Sync with pending stores.
	stwcx.	r4, 0, r5		//	if( reservation == address ) *address = newValue;
	bne-	retry			//	else goto retry;
	sync					//	Broadcast store.
	li		r3, 1			//	Return true.
	blr						//	We're outta here.
fail:
	sync					//	Sync with pending stores.
	stwcx.	r6, 0, r5		//	Clear reservation.
	li		r3, 0			//	Return false.
	blr						//	We're outta here.
#elif	TARGET_CPU_68K
	#if	TARGET_RT_MAC_CFM
		movea.l	(a7)+, a0		//	Pop return address.
		move.l	(a7)+, d0		//	Pop oldValue param.
		move.l	(a7)+, d1		//	Pop newValue param.
		movea.l	(a7)+, a1		//	Pop address param.
		dc.l	0x0ED10040		//	CWPro5 doesn't know cas. Here's the raw opcode.
	//	cas.l	d0, d1, (a1)	//	if( *address == oldValue ) *address = newValue;
		bne.s	fail			//	else goto fail.
		moveq.l	#1, d0			//	Return true in register d0.
		jmp		(a0)			//	We're outta here.
	fail:
		moveq.l	#0, d0			//	Return false in register d0.
		jmp		(a0)			//	We're outta here.
	#else
		movea.l	(a7)+, a0		//	Pop return address.
		movea.l	(a7)+, a1		//	Pop address param.
		move.l	(a7)+, d0		//	Pop newValue param.
		move.l	(a7)+, d1		//	Pop oldValue param.
		dc.l	0x0ED10001		//	CWPro5 doesn't know cas. Here's the raw opcode.
	//	cas.l	d1, d0, (a1)	//	If the *address == oldValue, *address = newValue.
		bne.s	fail			//	Else fail.
		move.l	#1, (a7)		//	Return true.
		jmp		(a0)			//	We're outta here.
	fail:
		move.l	#0, (a7)		//	Return false.
		jmp		(a0)			//	We're outta here.
	#endif
#else
	#error	atomicity doesnt support this processor
#endif
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Thu, Sep 16, 1999	Created.
	
	************************************************************************************/

	pascal
	long
MyAtomicStorePtr(
	void	*oldValue,
	void	*newValue,
	void	*address )
{
	RequirePtrIfNotNil( oldValue );
	RequirePtrIfNotNil( newValue );
	RequirePtrAlign( address, kAtomicAlignment );
	
	return( MyAtomicStore( (long) oldValue, (long) newValue, address ) );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Thu, Sep 16, 1999	Created.
	
	************************************************************************************/

	asm
	pascal
	long
AtomicStore2(
	long	/*oldValue*/,
	long	/*newValue*/,
	void	*/*address*/,
	long	/*oldValue2*/,
	void	*/*address2*/ )
{
#if		TARGET_CPU_PPC
retry:
	lwarx	r8, 0, r5		//	currentValue = *address;
	cmpw	r8, r3			//	if( currentValue != oldValue )
	bne		fail			//		goto fail;
	lwz		r9, 0(r7)		//	currentValue2 = *address2;
	cmpw	r9, r6			//	if( currentValue2 != oldValue2 )
	bne		fail			//		goto fail;
	sync					//	Sync with pending stores.
	stwcx.	r4, 0, r5		//	if( reservation == address ) *address = newValue;
	bne-	retry			//	else goto retry;
	sync					//	Broadcast store.
	li		r3, 1			//	Return true.
	blr						//	We're outta here.
fail:
	sync					//	Sync with pending stores.
	stwcx.	r8, 0, r5		//	Clear the reservation.
	li		r3, 0			//	Return false.
	blr						//	We're outta here.
#elif	TARGET_CPU_68K
	#if	TARGET_RT_MAC_CFM
		move.l	4(a7), d0				//	Load oldValue param.
		move.l	8(a7), d1				//	Load newValue param.
		movea.l	12(a7), a0				//	Load address param.
		move.l	16(a7), d2				//	Load oldValue2 param.
		movea.l	20(a7), a1				//	Load address2 param.
		dc.l	0x0EFC8040				//	CWPro5 doesn't know
		dc.w	0x9082					//	cas2. Here's the raw opcodes.
	//	cas2.l	d0:d2, d1:d2, (a0):(a1)	//	if( *a0 == d0 && *a1 == d2 ) {
										//		*a0 = d1; *a1 = d2 /*nop*/;
		bne.s	fail					//	} else fail;
		move.l	#1, d0					//	Set result to true.
		bra.s	done
	fail:
		move.l	#0, d0					//	Set result to false.
	done:
		movea.l	(a7)+, a0				//	Pop return address.
		add.l	#20, a7					//	Pop all parameters.
		jmp		(a0)					//	We're outta here.
	#else
		move.l	20(a7), d0				//	Load oldValue param.
		move.l	16(a7), d1				//	Load newValue param.
		movea.l	12(a7), a0				//	Load address param.
		move.l	8(a7), d2				//	Load oldValue2 param.
		movea.l	4(a7), a1				//	Load address2 param.
		dc.l	0x0EFC8040				//	CWPro5 doesn't know
		dc.w	0x9082					//	cas2. Here's the raw opcodes.
	//	cas2.l	d0:d2, d1:d2, (a0):(a1)	//	if( *a0 == d0 && *a1 == d2 ) {
										//		*a0 = d1; *a1 = d2 /*nop*/;
		bne.s	fail					//	} else fail;
		move.l	#1, d0					//	Set result to true.
		bra.s	done
	fail:
		move.l	#0, d0					//	Set result to false.
	done:
		movea.l	(a7)+, a0				//	Pop return address.
		add.l	#20, a7					//	Pop all parameters.
		move.l	d0, (a7)				//	Return the result.
		jmp		(a0)					//	We're outta here.
	#endif
#else
	#error	atomicity doesnt support this processor
#endif
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Thu, Sep 16, 1999	Created.
	
	************************************************************************************/

	pascal
	long
AtomicStore2Ptr(
	void	*oldValue,
	void	*newValue,
	void	*address,
	void	*oldValue2,
	void	*address2 )
{
	RequirePtrIfNotNil( oldValue );
	RequirePtrIfNotNil( newValue );
	RequirePtrAlign( address, kAtomicAlignment );
	RequirePtrIfNotNil( oldValue2 );
	RequirePtrAlign( address2, kAtomicAlignment );
	
	return( AtomicStore2( (long) oldValue, (long) newValue, address,
								(long) oldValue2, address2 ) );
}

/****************************************************************************************
*	
*	Atomic Stack Functions
*	
****************************************************************************************/
#pragma mark	-
#pragma mark	(Atomic Stack Functions)

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Oct 26, 1998	Created.
	wolf		Mon, Nov 9, 1998	PowerPC code rolled in.
	wolf		Tue, Mar 23, 1999	Rewrote PowerPC code. After more study of the
									programming model, I learned I need not save and
									restore the Link Register (I don't modify it) and
									the Condition Register (the cr0 field is marked
									volatile). This saves 8 instructions including
									two loads and two stores.
									However, I now use a more complex double-load-with-
									sync technique to eliminate the possibility of
									livelock in a multiprocessor environment. The
									overhead of the sync instruction probably negates
									the speed gain of omitting the 8 instructions.
	wolf		Thu, Apr 1, 1999	Rewrote PowerPC code to be a tad more efficient.
	wolf		Fri, Sep 10, 1999	Rewrote in C.
	
	************************************************************************************/

	void
MyPushAtomicStack(
	AtomicElement	*element,
	AtomicStack		*stack )
{
	AtomicElement	*next;
	long			stored;
	
	RequirePtrAlign( element, kAtomicAlignment );
	RequirePtrAlign( stack, kAtomicAlignment );
	
	do {
		next = (AtomicElement*) stack->next;
		element->next = next;
		stored = AtomicStorePtr( next, element, stack );
	} while( !stored );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Oct 26, 1998	Created.
	wolf		Mon, Nov 9, 1998	PowerPC code rolled in.
	wolf		Wed, Nov 25, 1998	Fixed function result bug in Classic 68K code.
									I was returning the result in the space allocated
									for the stack parameter, not the result space right
									above it.
	wolf		Tue, Mar 23, 1999	Rewrote PowerPC code. After more study of the
									programming model, I learned I need not save and
									restore the Link Register (I don't modify it) and
									the Condition Register (the cr0 field is marked
									volatile). This saves 8 instructions including
									two loads and two stores.
	wolf		Thu, Apr 1, 1999	I moved the test for a nil stack out of the
									reservation code, which should help performance.
	wolf		Fri, Sep 10, 1999	Rewrote in C.
	
	************************************************************************************/

	AtomicElement*
MyPopAtomicStack(
	AtomicStack		*stack )
{
	AtomicElement	*next, *element;
	long			stored;
	
	RequirePtrAlign( stack, kAtomicAlignment );
	
	do {
		element = (AtomicElement*) stack->next;
		RequirePtrAlignIfNotNil( element, kAtomicAlignment );
		if( element ) {
			next = (AtomicElement*) element->next;
			stored = AtomicStorePtr( element, next, stack );
		} else {
			stored = true;
		}
	} while( !stored );
	
	return( (AtomicElement*) element );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Oct 26, 1998	Created.
	wolf		Mon, Nov 9, 1998	PowerPC code rolled in.
	wolf		Wed, Nov 25, 1998	Fixed function result bug in Classic 68K code.
									I was returning the result in the space allocated
									for the stack parameter, not the result space right
									above it.
	wolf		Thu, Mar 4, 1999	On the PowerPC side, I mistakenly moved r4 (which
									is always set to nil) into the result register, r3.
									This resulted in StealAtomicStack() always returning
									nil when executing PowerPC. Now I correctly move r5
									into r3.
									It's very strange that I didn't catch this obvious
									error in my test matrix. Perhaps I forgot to test the
									PowerPC side and only tested the 68K sides.
	wolf		Thu, Apr 1, 1999	I moved the test for a nil stack out of the
									reservation code, which should help performance.
	wolf		Fri, Sep 10, 1999	Rewrote in C.
	wolf		Mon, Nov 1, 1999	Modified to take two parameters instead of one. This
									is conceptually clearer.
	
	************************************************************************************/

	void 
StealAtomicStack(
	AtomicStack		*fromStack,
	AtomicStack		*toStack )
{
	AtomicElement	*result;
	long			stored;
	
	RequirePtrAlign( fromStack, kAtomicAlignment );
	RequirePtrAlign( toStack, kAtomicAlignment );
	
	do {
		result = (AtomicElement*) fromStack->next;
		RequirePtrAlignIfNotNil( result, kAtomicAlignment );
		stored = AtomicStorePtr( result, nil, fromStack );
	} while( !stored );
	
	toStack->next = result;
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Fri, Apr 30, 1999	Created.
	
	************************************************************************************/

	AtomicElement*
PeekAtomicStack(
	AtomicStack		*stack )
{
	AtomicElement	*result;
	
	RequirePtrAlign( stack, kAtomicAlignment );
	
	result = (AtomicElement*) stack->next;
	RequirePtrAlignIfNotNil( result, kAtomicAlignment );
	return( result );
}

/****************************************************************************************
*	
*	Atomic Stack Offset Functions
*	
****************************************************************************************/
#pragma mark	-
#pragma mark	(Atomic Stack Offset Functions)

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Wed, Nov 25, 1998	Created.
	
	************************************************************************************/

	void
PushAtomicStackOff(
	void			*element,
	AtomicStack		*stack,
	size_t			offset )
{
	RequirePtr( element );
	RequireOffset( offset );
	RequirePtrAlign( stack, kAtomicAlignment );
	
	AddOffset( &element, offset );
		RequirePtrAlign( element, kAtomicAlignment );
	PushAtomicStack( (AtomicElement*) element, stack );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Wed, Nov 25, 1998	Created.
	
	************************************************************************************/

	AtomicElement*
PopAtomicStackOff(
	AtomicStack		*stack,
	size_t			offset )
{
	AtomicElement	*result;
	
	RequirePtrAlign( stack, kAtomicAlignment );
	RequireOffset( offset );
	
	result = PopAtomicStack( stack );
		RequirePtrAlignIfNotNil( result, kAtomicAlignment );
	SubOffset( (void**) &result, offset );
	
	return( result );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Fri, Apr 30, 1999	Created.
	
	************************************************************************************/

	AtomicElement*
PeekAtomicStackOff(
	AtomicStack		*stack,
	size_t			offset )
{
	AtomicElement	*result;
	
	RequirePtrAlign( stack, kAtomicAlignment );
	RequireOffset( offset );
	
	result = PeekAtomicStack( stack );
		RequirePtrAlignIfNotNil( result, kAtomicAlignment );
	SubOffset( (void**)&result, offset );
	
	return( result );
}

/****************************************************************************************
*	
*	Atomic Lock Functions
*	
****************************************************************************************/
#pragma mark	-
#pragma mark	(Atomic Lock Functions)

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Wed, Mar 31, 1999	Created.
	wolf		Thu, Apr 1, 1999	I moved the test for a nonzero lock out of the
									reservation code, which should help performance.
	wolf		Fri, Sep 10, 1999	Rewrote in C.
	
	************************************************************************************/

	long
MyGrabAtomicLock(
	AtomicLock	*lock )
{
	RequirePtrAlign( (void*) lock, kAtomicAlignment );
	
	return( AtomicStore( 0, 1, (void*) lock ) );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Tue, Mar 23, 1999	Created.
	
	************************************************************************************/

	void
ReleaseAtomicLock(
	AtomicLock	*lock )
{
	RequirePtrAlign( (void*) lock, kAtomicAlignment );
	Require( *lock );
	
	*lock = 0;
}


/****************************************************************************************
*	
*	Atomic Flags Functions
*	
****************************************************************************************/
#pragma mark	-
#pragma mark	(Atomic Flags Functions)

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Fri, Apr 7, 2000	Created.
	
	************************************************************************************/

	Boolean
GetAtomicFlag(
	AtomicFlags	*flags,
	AtomicFlag	flag )
{
	RequirePtrAlign( (void*) flags, kAtomicAlignment );
	
	return( ( *flags & flag ) == flag );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Fri, Apr 7, 2000	Created.
	wolf		Sat, Jul 1, 2000	Added explicit casts to long.
	
	************************************************************************************/

	Boolean
SetAtomicFlag(
	AtomicFlags	*flags,
	AtomicFlag	flag )
{
	AtomicFlags	flagsCopy;
	long		stored;
	Boolean		wasClear;
	
	RequirePtrAlign( (void*) flags, kAtomicAlignment );
	
	do {
		flagsCopy = *flags;
		wasClear = (flagsCopy & flag) == 0;
		stored = AtomicStore( (long) flagsCopy, (long) (flagsCopy | flag), (void*) flags );
	} while( !stored );
	
	return( wasClear );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Fri, Apr 7, 2000	Created.
	wolf		Sat, Jul 1, 2000	Added explicit casts to long.
	
	************************************************************************************/

	Boolean
ClearAtomicFlag(
	AtomicFlags	*flags,
	AtomicFlag	flag )
{
	AtomicFlags	flagsCopy;
	long		stored;
	Boolean		wasSet;
	
	RequirePtrAlign( (void*) flags, kAtomicAlignment );
	
	do {
		flagsCopy = *flags;
		wasSet = (flagsCopy & flag) == flag;
		stored = AtomicStore( (long) flagsCopy, (long) (flagsCopy & (~flag)), (void*) flags );
	} while( !stored );
	
	return( wasSet );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Fri, Apr 7, 2000	Created.
	
	************************************************************************************/

	Boolean
FlipAtomicFlag(
	AtomicFlags	*flags,
	AtomicFlag	flag,
	Boolean		value )
{
	Boolean	result;
	
	RequirePtrAlign( (void*) flags, kAtomicAlignment );
	Require( value == true || value == false );
	
	if( value )
		result = SetAtomicFlag( flags, flag );
	else
		result = ClearAtomicFlag( flags, flag );
	
	return( result );
}

/****************************************************************************************
*	
*	Open Transport Compatibility Layer
*
*	The the following functions (PushAtomicStack, PopAtomicStack,
*	IsOpenTransportAvailable, OpenAtomicity, CloseAtomicity and UseOTAtomicity) are only
*	compiled if UseOpenTransportIfAvailable is defined. Otherwise zero-runtime-overhead
*	macros are used.
*	
****************************************************************************************/
#pragma mark	-
#pragma mark	(Open Transport Compatibility Layer)

#if		defined(DontUseOpenTransport)
#elif	defined(OnlyUseOpenTransport)
#else	//	UseOpenTransportIfAvailable

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Thu, Sep 16, 1999	Created.
	
	************************************************************************************/

	long
AtomicStore(
	long	oldValue,
	long	newValue,
	void	*address )
{
	long	result;
	
	RequirePtrAlign( address, kAtomicAlignment );
	
	if( IsOpenTransportAvailable() )
		result = OTCompareAndSwap32( (UInt32) oldValue, (UInt32) newValue, (UInt32*) address );
	else
		result = MyAtomicStore( oldValue, newValue, address );
	
	return( result );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Thu, Sep 16, 1999	Created.
	
	************************************************************************************/

	long
AtomicStorePtr(
	void	*oldValue,
	void	*newValue,
	void	*address )
{
	long	result;
	
	RequirePtrIfNotNil( oldValue );
	RequirePtrIfNotNil( newValue );
	RequirePtrAlign( address, kAtomicAlignment );
	
	if( IsOpenTransportAvailable() )
		result = OTCompareAndSwapPtr( oldValue, newValue, (void**) address );
	else
		result = MyAtomicStorePtr( oldValue, newValue, address );
	
	return( result );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Mar 29, 1999	Created.
	
	************************************************************************************/

	void
PushAtomicStack(
	AtomicElement	*element,
	AtomicStack		*stack )
{
	RequirePtrAlign( element, kAtomicAlignment );
	RequirePtrAlign( stack, kAtomicAlignment );
	
	if( IsOpenTransportAvailable() )
		OTLIFOEnqueue( (OTLIFO*) stack, (OTLink*) element );
	else
		MyPushAtomicStack( element, stack );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Mar 29, 1999	Created.
	
	************************************************************************************/

	AtomicElement*
PopAtomicStack(
	AtomicStack	*stack )
{
	AtomicElement	*result;
	
	RequirePtrAlign( stack, kAtomicAlignment );
	
	if( IsOpenTransportAvailable() )
		result = (AtomicElement*) OTLIFODequeue( (OTLIFO*) stack );
	else
		result = MyPopAtomicStack( stack );
	
	RequirePtrAlignIfNotNil( result, kAtomicAlignment );
	return( result );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Wed, Mar 31, 1999	Created.
	
	************************************************************************************/

	Boolean
GrabAtomicLock(
	AtomicLock	*lock )
{
	Boolean	result;
	
	RequirePtrAlign( (void*) lock, kAtomicAlignment );
	
	if( IsOpenTransportAvailable() )
		result = OTCompareAndSwap32( 0, 1, (unsigned long*) lock );
	else
		result = MyGrabAtomicLock( lock ) == true;
	
	return( result );
}

Boolean	gHasOT = (Boolean) -1;

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Mar 29, 1999	Created.
	
	************************************************************************************/

	Boolean
IsOpenTransportAvailable()
{
	long	ignored;
	
	if( gHasOT == -1 ) {
		if( !Gestalt( gestaltOpenTpt, &ignored ) && OTLIFOEnqueue != nil )
			gHasOT = true;
		else
			gHasOT = false;
	}
	
	return( gHasOT );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Aug 23, 1999	Created.
	wolf		Sun, Jan 30, 2000	Carbonized.
	
	************************************************************************************/

	OSStatus
#if	TARGET_API_MAC_CARBON
OpenAtomicity(
	OTInitializationFlags 	flags,
	OTClientContextPtr *	outClientContext )
#else
OpenAtomicity()
#endif
{
	OSStatus	err;
	
#if	TARGET_API_MAC_CARBON
	err = InitOpenTransportInContext( flags, outClientContext );
#else
	err = InitOpenTransport();
#endif
	
	if( err ) {
		gHasOT = false;
	} else {
		if( OTLIFOEnqueue == nil )
			gHasOT = false;
		else
			gHasOT = true;
	}
	
	return( err );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Aug 23, 1999	Created.
	wolf		Sun, Jan 30, 2000	Carbonized.
	
	************************************************************************************/

	void
#if	TARGET_API_MAC_CARBON
CloseAtomicity(
	OTClientContextPtr	clientContext )
#else
CloseAtomicity()
#endif
{
	if( gHasOT == true ) {
#if	TARGET_API_MAC_CARBON
		CloseOpenTransportInContext( clientContext );
#else
		CloseOpenTransport();
#endif
	}
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Tue, Aug 24, 1999	Created.
	
	************************************************************************************/

	void
UseOTAtomicity(
	Boolean	value )
{
	gHasOT = value;
}

#endif	//	UseOpenTransportIfAvailable

/****************************************************************************************
*	
*	Guarded Atomic Stack Functions
*	
****************************************************************************************/
#pragma mark	-
#pragma mark	(Guarded Atomic Stack Functions)

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Tue, Sep 28, 1999	Created.
	
	************************************************************************************/

	long
GrabAtomicElement(
	GuardedAtomicElement	*element,
	void					*list )
{
	RequirePtrAlign( element, kAtomicAlignment );
	RequirePtrAlignIfNotNil( (void*) element->list, kAtomicAlignment );
	RequirePtrAlignIfNotNil( list, kAtomicAlignment );
	
	return( AtomicStorePtr( nil, list, &element->list ) );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Tue, Sep 28, 1999	Created.
	
	************************************************************************************/

	void
ReleaseAtomicElement(
	GuardedAtomicElement	*element )
{
	RequirePtrAlign( element, kAtomicAlignment );
	
	element->list = nil;
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Nov 23, 1998	Created.
	wolf		Mon, Nov 30, 1998	Broke out element count incrementing code into its
									own atomic function: IncrementGuardedAtomicStack().
									It takes three instructions to increment a value in
									memory on a PowerPC, so we need to use the special
									syncronization instructions offered by the PowerPC.
	wolf		Wed, Mar 31, 1999	Migrated to Atomic Locks.
	wolf		Sat, Jul 1, 2000	Changed result type from Boolean to long to placate
									compiler.
	
	************************************************************************************/

	long
PushGuardedAtomicStack(
	GuardedAtomicElement	*element,
	AtomicStack				*stack )
{
	long	result;
	
	RequirePtrAlign( element, kAtomicAlignment );
	RequirePtrAlign( stack, kAtomicAlignment );
	
	result = GrabAtomicElement( element, stack );
	if( result )
		PushAtomicStack( (AtomicElement*) element, stack );
	
	return( result );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Nov 23, 1998	Created.
	wolf		Wed, Mar 31, 1999	Migrated to Atomic Locks.
	wolf		Mon, Sep 13, 1999	Added requirement that a freshly popped element's
									lock should have been set before we clear it.
	
	************************************************************************************/

	GuardedAtomicElement*
PopGuardedAtomicStack(
	AtomicStack				*stack )
{
	GuardedAtomicElement	*result;
	
	RequirePtrAlign( stack, kAtomicAlignment );
	
	result = (GuardedAtomicElement*) PopAtomicStack( stack );
		RequirePtrAlignIfNotNil( result, kAtomicAlignment );

	if( result ) {
		Require( result->list == stack );
		ReleaseAtomicElement( result );
	}
	
	return( result );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Tue, Nov 2, 1999	Created.
	
	************************************************************************************/

	void
StealGuardedAtomicStack(
	AtomicStack		*fromStack,
	AtomicStack		*toStack )
{
	GuardedAtomicElement	*result;
	long					stored;
	
	RequirePtrAlign( fromStack, kAtomicAlignment );
	RequirePtrAlign( toStack, kAtomicAlignment );
	
	do {
		result = (GuardedAtomicElement*) fromStack->next;
		RequirePtrAlignIfNotNil( result, kAtomicAlignment );
		stored = AtomicStorePtr( result, nil, fromStack );
	} while( !stored );
	
	toStack->next = (AtomicElement*) result;
	
	while( result ) {
		result->list = toStack;
		result = (GuardedAtomicElement*) result->next;
	}
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, May 3, 1999	Created.
	wolf		Mon, Sep 13, 1999	Added the requirement that if a element is
									successfully peeked at, its lock must be set.
	
	************************************************************************************/

	GuardedAtomicElement*
PeekGuardedAtomicStack(
	AtomicStack		*stack )
{
	GuardedAtomicElement	*result;
	
	RequirePtrAlign( stack, kAtomicAlignment );
	
	result = (GuardedAtomicElement*) stack->next;
		RequireIf( result, result->list == stack );
	
	return( result );
}

/****************************************************************************************
*	
*	Guarded Atomic Stack Offset Functions
*	
****************************************************************************************/
#pragma mark	-
#pragma mark	(Guarded Atomic Stack Offset Functions)

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Wed, Nov 25, 1998	Created.
	
	************************************************************************************/

	long
PushGuardedAtomicStackOff(
	void			*element,
	AtomicStack		*stack,
	size_t			offset )
{
	long	result;
	
	RequirePtr( element );
	RequirePtrAlign( stack, kAtomicAlignment );
	RequireOffset( offset );
	
	AddOffset( &element, offset );
		RequirePtrAlign( element, kAtomicAlignment );
		RequirePtrAlignIfNotNil( (void*)((GuardedAtomicElement*) element)->list, kAtomicAlignment );
	result = PushGuardedAtomicStack( (GuardedAtomicElement*) element, stack );
		RequireIf( result, ((GuardedAtomicElement*) element)->list == stack );
	return( result );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Wed, Nov 25, 1998	Created.
	
	************************************************************************************/

	GuardedAtomicElement*
PopGuardedAtomicStackOff(
	AtomicStack		*stack,
	size_t			offset )
{
	GuardedAtomicElement	*result;
	
	RequirePtrAlign( stack, kAtomicAlignment );
	RequireOffset( offset );
	
	result = PopGuardedAtomicStack( stack );
		RequirePtrAlignIfNotNil( result, kAtomicAlignment );
		RequireIf( result, ((GuardedAtomicElement*) result)->list == nil );
	SubOffset( (void**)&result, offset );
	
	return( result );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, May 3, 1999	Created.
	
	************************************************************************************/

	GuardedAtomicElement*
PeekGuardedAtomicStackOff(
	AtomicStack		*stack,
	size_t			offset )
{
	GuardedAtomicElement	*result;
	
	RequirePtrAlign( stack, kAtomicAlignment );
	RequireOffset( offset );
	
	result = PeekGuardedAtomicStack( stack );
		RequirePtrAlignIfNotNil( result, kAtomicAlignment );
		RequireIf( result, ((GuardedAtomicElement*) result)->list == stack );
	SubOffset( (void**)&result, offset );
	
	return( result );
}

/****************************************************************************************
*	
*	Atomic Queue Functions
*	
****************************************************************************************/
#pragma mark	-
#pragma mark	(Atomic Queue Functions)

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Wed, Nov 18, 1998	Created.
	
	An atomic queue is simply a queue that uses an atomic stack as its input list.
	
	************************************************************************************/

	void
PushAtomicQueue(
	AtomicElement	*element,
	AtomicQueue		*queue )
{
	RequirePtrAlign( element, kAtomicAlignment );
	RequirePtrAlign( queue, kAtomicAlignment );
	
	PushAtomicStack( element, &queue->input );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Thu, Mar 16, 2000	Created.
	
	************************************************************************************/

	void
PushFrontAtomicQueue(
	AtomicElement	*element,
	AtomicQueue		*queue )
{
	RequirePtrAlign( element, kAtomicAlignment );
	RequirePtrAlign( queue, kAtomicAlignment );
	
	PushAtomicStack( element, &queue->output );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Wed, Nov 18, 1998	Created.
	wolf		Thu, Jan 20, 2000	stolenStack is now explicitly aligned.
	
	When the client wants the next element in the queue, we try to pop the element
	off the output stack. If the output stack is empty, then we have to refill the output
	stack from the input stack.
	
	We do this by atomically "stealing" the entire stack. Once we have the stack, we
	"reverse" the stack (make a first-in-last-out list into a first-in-first-out list) by
	popping each element from the stolen stack and pushing it onto the output stack.
	
	If all this stealing, popping and pushing sounds expensive, it isn't. The reversal
	operates in linear time, which is acceptable. However, if you don't need the
	sequential access of a queue, by all means use a stack, as it operates in fast
	constant time.
	
	************************************************************************************/

	AtomicElement*
PopAtomicQueue(
	AtomicQueue			*queue )
{
	AlignedAtomicStack	alignedStolenStack;
	AtomicStack			*stolenStack;
	AtomicElement		*current;
	
	RequirePtrAlign( queue, kAtomicAlignment );
	
	current = PopAtomicStack( &queue->output );
	RequirePtrAlignIfNotNil( current, kAtomicAlignment );
	
	stolenStack = AlignAtomicStack( &alignedStolenStack );
	RequirePtrAlign( stolenStack, kAtomicAlignment );
	
	if( current == nil ) {
		//	Nothing to pop. Refill the queue from the input stack.
		StealAtomicStack( &queue->input, stolenStack );
		current = PopAtomicStack( stolenStack );
		while( current ) {
			RequirePtrAlign( current, kAtomicAlignment );
			PushAtomicStack( current, &queue->output );
			current = PopAtomicStack( stolenStack );
		}
		current = PopAtomicStack( &queue->output );
		RequirePtrAlignIfNotNil( current, kAtomicAlignment );
	}
	
	return( current );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Thu, Apr 15, 1999	Created.
	wolf		Mon, Sep 13, 1999	Rewrote. Before, I would do an PopAtomicQueue()
									followed by a PushAtomicStack() on the output stack.
									While this was easy, this actually modified stack,
									and quickly put it back into place, which created a
									small window where someone could preempt and Pop or
									Peek the queue and find something different than
									what is really there. While I haven't seen this
									cause any trouble yet, I figure I'll just Do The
									Right Thing.
	wolf		Thu, Jan 20, 2000	stolenStack now explicitly aligned.
	wolf		Wed, Jun 4, 2003	Was accidently calling PopAtomicStack instead of
									PeekAtomicStack. Fixed.
	
	************************************************************************************/

	AtomicElement*
PeekAtomicQueue(
	AtomicQueue		*queue )
{
	AlignedAtomicStack	alignedStolenStack;
	AtomicStack			*stolenStack;
	AtomicElement		*current;
	
	RequirePtrAlign( queue, kAtomicAlignment );
	
	current = PeekAtomicStack( &queue->output );
	RequirePtrAlignIfNotNil( current, kAtomicAlignment );
	
	stolenStack = AlignAtomicStack( &alignedStolenStack );
	RequirePtrAlign( stolenStack, kAtomicAlignment );
	
	if( current == nil ) {
		//	Nothing to pop. Refill the queue from the input stack.
		StealAtomicStack( &queue->input, stolenStack );
		current = PopAtomicStack( stolenStack );
		while( current ) {
			RequirePtrAlign( current, kAtomicAlignment );
			PushAtomicStack( current, &queue->output );
			current = PopAtomicStack( stolenStack );
		}
		current = PeekAtomicStack( &queue->output );
		RequirePtrAlignIfNotNil( current, kAtomicAlignment );
	}
	
	return( current );
}

/****************************************************************************************
*	
*	Atomic Queue Offset Functions
*	
****************************************************************************************/
#pragma mark	-
#pragma mark	(Atomic Queue Offset Functions)

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Wed, Nov 25, 1998	Created.
	
	************************************************************************************/

	void
PushAtomicQueueOff(
	void			*element,
	AtomicQueue		*queue,
	size_t			offset )
{
	RequirePtr( element );
	RequirePtrAlign( queue, kAtomicAlignment );
	RequireOffset( offset );
	
	AddOffset( &element, offset );
		RequirePtrAlign( element, kAtomicAlignment );
	PushAtomicQueue( (AtomicElement*) element, queue );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Thu, Mar 16, 2000	Created.
	
	************************************************************************************/

	void
PushFrontAtomicQueueOff(
	void			*element,
	AtomicQueue		*queue,
	size_t			offset )
{
	RequirePtr( element );
	RequirePtrAlign( queue, kAtomicAlignment );
	RequireOffset( offset );
	
	AddOffset( &element, offset );
		RequirePtrAlign( element, kAtomicAlignment );
	PushFrontAtomicQueue( (AtomicElement*) element, queue );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Wed, Nov 25, 1998	Created.
	
	************************************************************************************/

	AtomicElement*
PopAtomicQueueOff(
	AtomicQueue		*queue,
	size_t			offset )
{
	AtomicElement	*result;
	
	RequirePtrAlign( queue, kAtomicAlignment );
	RequireOffset( offset );
	
	result = PopAtomicQueue( queue );
		RequirePtrAlignIfNotNil( result, kAtomicAlignment );
	SubOffset( (void**)&result, offset );
		
	return( result );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Thu, Apr 15, 1999	Created.
	
	************************************************************************************/

	AtomicElement*
PeekAtomicQueueOff(
	AtomicQueue		*queue,
	size_t			offset )
{
	AtomicElement	*result;
	
	RequirePtrAlign( queue, kAtomicAlignment );
	RequireOffset( offset );
	
	result = PeekAtomicQueue( queue );
		RequirePtrAlignIfNotNil( result, kAtomicAlignment );
	SubOffset( (void**)&result, offset );
	
	return( result );
}

/****************************************************************************************
*	
*	Guarded Atomic Queue Functions
*	
****************************************************************************************/
#pragma mark	-
#pragma mark	(Guarded Atomic Queue Functions)

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Nov 23, 1998	Created.
	
	************************************************************************************/

	long
PushGuardedAtomicQueue(
	GuardedAtomicElement	*element,
	AtomicQueue				*queue )
{
	RequirePtrAlign( element, kAtomicAlignment );
	RequirePtrAlign( queue, kAtomicAlignment );
	
	return( PushGuardedAtomicStack( element, &queue->input ) );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Thu, Mar 16, 2000	Created.
	
	************************************************************************************/

	long
PushFrontGuardedAtomicQueue(
	GuardedAtomicElement	*element,
	AtomicQueue				*queue )
{
	RequirePtrAlign( element, kAtomicAlignment );
	RequirePtrAlign( queue, kAtomicAlignment );
	
	return( PushGuardedAtomicStack( element, &queue->output ) );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Nov 23, 1998	Created.
	wolf		Thu, Jan 20, 2000	stolenStack now explicitly aligned.
	
	************************************************************************************/

	GuardedAtomicElement*
PopGuardedAtomicQueue(
	AtomicQueue				*queue )
{
	AlignedAtomicStack		alignedStolenStack;
	AtomicStack				*stolenStack;
	GuardedAtomicElement	*current;
	
	RequirePtrAlign( queue, kAtomicAlignment );
	
	current = PopGuardedAtomicStack( &queue->output );
	RequirePtrAlignIfNotNil( current, kAtomicAlignment );
	
	stolenStack = AlignAtomicStack( &alignedStolenStack );
	RequirePtrAlign( stolenStack, kAtomicAlignment );
	
	if( current == nil ) {
		//	Nothing to pop. Refill the queue from the input stack.
		StealGuardedAtomicStack( &queue->input, stolenStack );
		current = PopGuardedAtomicStack( stolenStack );
		while( current ) {
			RequirePtrAlign( current, kAtomicAlignment );
			PushGuardedAtomicStack( current, &queue->output );
			current = PopGuardedAtomicStack( stolenStack );
		}
		current = PopGuardedAtomicStack( &queue->output );
		RequirePtrAlignIfNotNil( current, kAtomicAlignment );
	}
	
	return( current );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Thu, Apr 15, 1999	Created.
	wolf		Thu, Jan 20, 2000	stolenStack now explicitly aligned.
	wolf		Sat, Feb 19, 2000	Removed a wrong requirement.
	wolf		Mon, Feb 21, 2000	Fixed an insanely stupid bug. I was pushing the
									freshly stolen elements back into the stolen list,
									resulting in a nice infinite loop.
	
	************************************************************************************/

	GuardedAtomicElement*
PeekGuardedAtomicQueue(
	AtomicQueue		*queue )
{
	AlignedAtomicStack		alignedStolenStack;
	AtomicStack				*stolenStack;
	GuardedAtomicElement	*current;
	
	RequirePtrAlign( queue, kAtomicAlignment );
	
	stolenStack = AlignAtomicStack( &alignedStolenStack );
	RequirePtrAlign( stolenStack, kAtomicAlignment );
	
	if( queue->output.next == nil ) {
		//	Nothing to pop. Refill the queue from the input stack.
		StealGuardedAtomicStack( &queue->input, stolenStack );
		current = PopGuardedAtomicStack( stolenStack );
		while( current ) {
			RequirePtrAlign( current, kAtomicAlignment );
			PushGuardedAtomicStack( current, &queue->output );
			current = PopGuardedAtomicStack( stolenStack );
		}
	}
	
	return( (GuardedAtomicElement*) queue->output.next );
}

/****************************************************************************************
*	
*	Guarded Atomic Queue Offset Functions
*	
****************************************************************************************/
#pragma mark	-
#pragma mark	(Guarded Atomic Queue Offset Functions)

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Wed, Nov 25, 1998	Created.
	
	************************************************************************************/

	long
PushGuardedAtomicQueueOff(
	void			*element,
	AtomicQueue		*queue,
	size_t			offset )
{
	long	result;
	
	RequirePtr( element );
	RequirePtrAlign( queue, kAtomicAlignment );
	RequireOffset( offset );
	
	AddOffset( &element, offset );
		RequirePtrAlign( element, kAtomicAlignment );
		RequirePtrAlignIfNotNil( (void*)((GuardedAtomicElement*) element)->list, kAtomicAlignment );
	result = PushGuardedAtomicQueue( (GuardedAtomicElement*) element, queue );
		RequireIf( result, ((GuardedAtomicElement*) element)->list == queue );
	return( result );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Thu, Mar 16, 2000	Created.
	wolf		Tue, Apr 11, 2000	Fixed a bug in a requirement.
	
	************************************************************************************/

	long
PushFrontGuardedAtomicQueueOff(
	void			*element,
	AtomicQueue		*queue,
	size_t			offset )
{
	long	result;
	
	RequirePtr( element );
	RequirePtrAlign( queue, kAtomicAlignment );
	RequireOffset( offset );
	
	AddOffset( &element, offset );
		RequirePtrAlign( element, kAtomicAlignment );
		RequirePtrAlignIfNotNil( (void*)((GuardedAtomicElement*) element)->list, kAtomicAlignment );
	result = PushFrontGuardedAtomicQueue( (GuardedAtomicElement*) element, queue );
		RequireIf( result, ((GuardedAtomicElement*) element)->list == &queue->output );
	return( result );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Wed, Nov 25, 1998	Created.
	
	************************************************************************************/

	GuardedAtomicElement*
PopGuardedAtomicQueueOff(
	AtomicQueue		*queue,
	size_t			offset )
{
	GuardedAtomicElement	*result;
	
	RequirePtrAlign( queue, kAtomicAlignment );
	RequireOffset( offset );
	
	result = PopGuardedAtomicQueue( queue );
		RequirePtrAlignIfNotNil( result, kAtomicAlignment );
		RequireIf( result, ((GuardedAtomicElement*) result)->list == nil );
	SubOffset( (void**)&result, offset );
	
	return( result );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Thu, Apr 15, 1999	Created.
	wolf		Mon, Feb 21, 2000	Fixed a broken requirement.
	
	************************************************************************************/

	GuardedAtomicElement*
PeekGuardedAtomicQueueOff(
	AtomicQueue		*queue,
	size_t			offset )
{
	GuardedAtomicElement	*result;
	
	RequirePtrAlign( queue, kAtomicAlignment );
	RequireOffset( offset );
	
	result = PeekGuardedAtomicQueue( queue );
		RequirePtrAlignIfNotNil( result, kAtomicAlignment );
		RequireIf( result, ((GuardedAtomicElement*) result)->list == &queue->output );
	SubOffset( (void**)&result, offset );
	
	return( result );
}

/****************************************************************************************
*	
*	Atomic List Functions
*	
****************************************************************************************/
#pragma mark	-
#pragma mark	(Atomic List Functions)

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Wed, Sep 15, 1999	Created.
	
	************************************************************************************/

	void
PutFirstAtomicList(
	AtomicElement	*element,
	AtomicList		*list )
{
	RequirePtrAlign( element, kAtomicAlignment );
	RequirePtrAlign( list, kAtomicAlignment );
	
	PushAtomicStack( element, list );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Sep 20, 1999	Created.
	
	************************************************************************************/

	long
PutAfterAtomicList(
	AtomicElement	*element,
	AtomicElement	*after,
	AtomicElement	*oldElement,
	AtomicList		*list )
{
	RequirePtrAlign( element, kAtomicAlignment );
	RequirePtrAlignIfNotNil( after, kAtomicAlignment );
	RequirePtrAlignIfNotNil( oldElement, kAtomicAlignment );
	RequirePtrAlign( list, kAtomicAlignment );
	
	if( after ) {
		element->next = oldElement;
		return( AtomicStorePtr( oldElement, element, after ) );
	} else {
		PutFirstAtomicList( element, list );
		return( true );
	}
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Tue, Sep 14, 1999	Created.
	
	************************************************************************************/

	void
PutLastAtomicList(
	AtomicElement	*element,
	AtomicList		*list )
{
	AtomicElement	*current, *next, *temp;
	long			stored;
	
	element->next = nil;
	
restart:
	current = list;
	next = (AtomicElement*) current->next;
	for(;;) {
		if( next ) {
			temp = (AtomicElement*) next->next;
			stored = AtomicStorePtr( next, next, current );
			if( !stored )
				goto restart;
			current = next;
			next = temp;
		} else {
			stored = AtomicStorePtr( next, element, current );
			if( stored )
				return;
			else
				goto restart;
		}
	}
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Wed, Sep 15, 1999	Created.
	
	************************************************************************************/

	AtomicElement*
RemoveFirstAtomicList(
	AtomicList		*list )
{
	AtomicElement	*result;
	
	RequirePtrAlign( list, kAtomicAlignment );
	
	result = PopAtomicStack( list );
	RequirePtrAlignIfNotNil( result, kAtomicAlignment );
	if( result )
		++result->next;	//	Superfical, meaningless modification.
	
	return( result );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Wed, Sep 15, 1999	Created.
	
	************************************************************************************/

	long
RemoveAtomicList(
	AtomicElement	*element,
	AtomicList		*list )
{
	AtomicElement	*current, *next, *newNext, *temp;
	long			stored;
	
restart:
	current = list;
	next = (AtomicElement*) current->next;
	while( next ) {
		if( next == element ) {
			newNext = (AtomicElement*) element->next;
			stored = AtomicStore2Ptr( next, newNext, current, newNext, element );
			if( stored ) {
				++element->next;	//	Superfical, meaningless modification.
				return( true );
			} else
				goto restart;
		} else {
			temp = (AtomicElement*) next->next;
			stored = AtomicStorePtr( next, next, current );
			if( !stored )
				goto restart;
			current = next;
			next = temp;
		}
	}
	return( false );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Sep 20, 1999	Created.
	wolf		Wed, Sep 29, 1999	When *current == nil and the stack was empty, *next
									was being set to *nil -- not a good thing. Fixed.
	
	************************************************************************************/

	long
IterateAtomicList(
	AtomicElement	**current,
	AtomicElement	**next,
	AtomicList		*list )
{
	AtomicElement	*temp;
	
	RequirePtr( current );
	RequirePtrAlignIfNotNil( *current, kAtomicAlignment );
	RequirePtr( next );
	RequirePtrAlignIf( *current && *next, *next, kAtomicAlignment );
	RequirePtrAlign( list, kAtomicAlignment );
	
	if( *current == nil ) {
		*current = (AtomicElement*) list->next;
		*next = *current ? ((AtomicElement*) (**current).next) : nil;
	} else {
		temp = *next ? ((AtomicElement*) (**next).next) : nil;
		if( !AtomicStorePtr( *next, *next, *current ) )
			return( false );
		*current = *next;
		*next = temp;
	}
	return( true );
}

/****************************************************************************************
*	
*	Atomic List Offset Functions
*	
****************************************************************************************/
#pragma mark-
#pragma mark	(Atomic List Offset Functions)

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Thu, Sep 16, 1999	Created.
	
	************************************************************************************/

	void
PutFirstAtomicListOff(
	void		*element,
	AtomicList	*list,
	size_t		offset )
{
	RequirePtr( element );
	RequirePtrAlign( list, kAtomicAlignment );
	RequireOffset( offset );
	
	AddOffset( &element, offset );
		RequirePtrAlign( element, kAtomicAlignment );
	PutFirstAtomicList( (AtomicElement*) element, list );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Sep 20, 1999	Created.
	
	************************************************************************************/

	long
PutAfterAtomicListOff(
	void		*element,
	void		*after,
	void		*oldElement,
	AtomicList	*list,
	size_t		offset )
{
	RequirePtr( element );
	RequirePtrIfNotNil( after );
	RequirePtrIfNotNil( oldElement );
	RequirePtrAlign( list, kAtomicAlignment );
	RequireOffset( offset );
	
	AddOffset( &element, offset );
		RequirePtrAlign( element, kAtomicAlignment );
	AddOffset( &after, offset );
		RequirePtrAlignIfNotNil( after, kAtomicAlignment );
	AddOffset( &oldElement, offset );
		RequirePtrAlignIfNotNil( oldElement, kAtomicAlignment );
	return( PutAfterAtomicList( (AtomicElement*) element, (AtomicElement*) after,
								(AtomicElement*) oldElement, list ) );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Thu, Sep 16, 1999	Created.
	
	************************************************************************************/

	void
PutLastAtomicListOff(
	void		*element,
	AtomicList	*list,
	size_t		offset )
{
	RequirePtr( element );
	RequirePtrAlign( list, kAtomicAlignment );
	RequireOffset( offset );
	
	AddOffset( &element, offset );
		RequirePtrAlign( element, kAtomicAlignment );
	PutLastAtomicList( (AtomicElement*) element, list );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Thu, Sep 16, 1999	Created.
	
	************************************************************************************/

	AtomicElement*
RemoveFirstAtomicListOff(
	AtomicList		*list,
	size_t			offset )
{
	AtomicElement	*result;
	
	RequirePtrAlign( list, kAtomicAlignment );
	RequireOffset( offset );
	
	result = RemoveFirstAtomicList( list );
		RequirePtrAlignIfNotNil( result, kAtomicAlignment );
	SubOffset( (void**)&result, offset );
		
	return( result );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Thu, Sep 16, 1999	Created.
	
	************************************************************************************/

	long
RemoveAtomicListOff(
	void		*element,
	AtomicList	*list,
	size_t		offset )
{
	RequirePtrAlign( element, kAtomicAlignment );
	RequirePtrAlign( list, kAtomicAlignment );
	RequireOffset( offset );
	
	AddOffset( &element, offset );
	return( RemoveAtomicList( (AtomicElement*) element, list ) );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Tue, Sep 21, 1999	Created.
	wolf		Thu, Sep 23, 1999	Testing brought up an interesting case. *current is
									allowed to be set to nil, which tells
									IterateAtomicList() to start from the beginning.
									In that case, the value in *next should be ingored
									since it will merely be overwritten. Thus in the
									test program's subroutine call, it was passing an
									uninitalized *next value.
									However, AddOffset() wants a valid pointer if not
									nil. So I added an if statement to only call
									AddOffset() on next when *current is not nil.
	
	************************************************************************************/

	long
IterateAtomicListOff(
	void		**current,
	void		**next,
	AtomicList	*list,
	size_t		offset )
{
	long	result;
	
	RequirePtr( current );
	RequirePtrIfNotNil( *current );
	RequirePtr( next );
	RequirePtrAlignIf( *current && *next, *next, kAtomicAlignment );
	RequirePtrAlign( list, kAtomicAlignment );
	RequireOffset( offset );
	
	AddOffset( current, offset );
		RequirePtrAlignIfNotNil( *current, kAtomicAlignment );
	if( *current ) {
		AddOffset( next, offset );
		RequirePtrAlignIfNotNil( *next, kAtomicAlignment );
	}
	result = IterateAtomicList( (AtomicElement**) current, (AtomicElement**) next, list );
	SubOffset( current, offset );
	SubOffset( next, offset );
	
	return( result );
}

/****************************************************************************************
*	
*	Guarded Atomic List Functions
*	
****************************************************************************************/
#pragma mark	-
#pragma mark	(Guarded Atomic List Functions)

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Thu, Sep 16, 1999	Created.
	
	************************************************************************************/

	long
PutFirstGuardedAtomicList(
	GuardedAtomicElement	*element,
	AtomicList				*list )
{
	RequirePtrAlign( element, kAtomicAlignment );
	RequirePtrAlignIfNotNil( (void*) element->list, kAtomicAlignment );
	RequirePtrAlign( list, kAtomicAlignment );
	
	if( GrabAtomicElement( element, list ) ) {
		PutFirstAtomicList( (AtomicElement*) element, list );
		Require( element->list == list );
		return( true );
	} else
		return( false );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Sep 20, 1999	Created.
	
	************************************************************************************/

	long
PutAfterGuardedAtomicList(
	GuardedAtomicElement	*element,
	GuardedAtomicElement	*after,
	GuardedAtomicElement	*oldElement,
	AtomicList				*list )
{
	long	result;
	
	RequirePtrAlign( element, kAtomicAlignment );
	RequirePtrAlignIfNotNil( (void*) element->list, kAtomicAlignment );
	RequirePtrAlignIfNotNil( after, kAtomicAlignment );
	RequireIf( after, after->list == list );
	RequirePtrAlignIfNotNil( oldElement, kAtomicAlignment );
	RequireIf( oldElement, oldElement->list == list );
	RequirePtrAlign( list, kAtomicAlignment );
	
	result = GrabAtomicElement( element, list );
	if( result ) {
		Require( element->list == list );
		result = PutAfterAtomicList( (AtomicElement*) element, (AtomicElement*) after,
										(AtomicElement*) oldElement, list );
			RequireIf( result, element->list == list );
			RequireIf( result && after, after->list == list );
			RequireIf( result && oldElement, oldElement->list == list );
		if( !result )
			ReleaseAtomicElement( element );
	}
	
	return( result );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Thu, Sep 16, 1999	Created.
	
	************************************************************************************/

	long
PutLastGuardedAtomicList(
	GuardedAtomicElement	*element,
	AtomicList				*list )
{
	RequirePtrAlign( element, kAtomicAlignment );
	RequirePtrAlignIfNotNil( (void*) element->list, kAtomicAlignment );
	RequirePtrAlign( list, kAtomicAlignment );
	
	if( GrabAtomicElement( element, list ) ) {
		PutLastAtomicList( (AtomicElement*) element, list );
		Require( element->list == list );
		return( true );
	} else
		return( false );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Thu, Sep 16, 1999	Created.
	
	************************************************************************************/

	GuardedAtomicElement*
RemoveFirstGuardedAtomicList(
	AtomicList		*list )
{
	GuardedAtomicElement	*result;
	
	RequirePtrAlign( list, kAtomicAlignment );
	
	result = (GuardedAtomicElement*) RemoveFirstAtomicList( list );
		RequirePtrAlignIfNotNil( result, kAtomicAlignment );
	if( result ) {
		Require( result->list == list );
		ReleaseAtomicElement( result );
	}
	
	RequireIf( result, result->list == nil );
	return( result );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Thu, Sep 16, 1999	Created.
	
	************************************************************************************/

	long
RemoveGuardedAtomicList(
	GuardedAtomicElement	*element,
	AtomicList				*list )
{
	long	result;
	
	RequirePtrAlign( element, kAtomicAlignment );
	RequirePtrAlignIfNotNil( (void*) element->list, kAtomicAlignment );
	RequirePtrAlign( list, kAtomicAlignment );
	
	result = RemoveAtomicList( (AtomicElement*) element, list );
	if( result ) {
		Require( element->list == list );
		ReleaseAtomicElement( element );
	}
	
	RequireIf( result, element->list == nil );
	return( result );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Sep 27, 1999	Created.
	
	************************************************************************************/

	long
IterateGuardedAtomicList(
	GuardedAtomicElement	**current,
	GuardedAtomicElement	**next,
	AtomicList				*list )
{
	long	result;
	
	RequirePtr( current );
	RequirePtrAlignIfNotNil( *current, kAtomicAlignment );
	RequirePtr( next );
	RequirePtrAlignIf( *current && *next, *next, kAtomicAlignment );
	RequirePtrAlign( list, kAtomicAlignment );
	
	result = IterateAtomicList( (AtomicElement**) current, (AtomicElement**) next, list );
		RequireIf( result && *current, (**current).list == list );
		RequireIf( result && *next, (**next).list == list );
	
	return( result );
}

/****************************************************************************************
*	
*	Guarded Atomic List Offset Functions
*	
****************************************************************************************/
#pragma mark	-
#pragma mark	(Guarded Atomic List Offset Functions)

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Thu, Sep 16, 1999	Created.
	
	************************************************************************************/

	long
PutFirstGuardedAtomicListOff(
	void		*element,
	AtomicList	*list,
	size_t		offset )
{
	long	result;
	
	RequirePtr( element );
	RequirePtrAlign( list, kAtomicAlignment );
	RequireOffset( offset );
	
	AddOffset( &element, offset );
		RequirePtrAlign( element, kAtomicAlignment );
		RequirePtrAlignIfNotNil( (void*)((GuardedAtomicElement*) element)->list, kAtomicAlignment );
	result = PutFirstGuardedAtomicList( (GuardedAtomicElement*) element, list );
		RequireIf( result, ((GuardedAtomicElement*) element)->list == list );
	return( result );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Sep 20, 1999	Created.
	
	************************************************************************************/

	long
PutAfterGuardedAtomicListOff(
	void		*element,
	void		*after,
	void		*oldElement,
	AtomicList	*list,
	size_t		offset )
{
	long	result;
	
	RequirePtrAlign( element, kAtomicAlignment );
	RequirePtrAlignIfNotNil( after, kAtomicAlignment );
	RequirePtrAlignIfNotNil( oldElement, kAtomicAlignment );
	RequirePtrAlign( list, kAtomicAlignment );
	RequireOffset( offset );
	
	AddOffset( &element, offset );
		RequirePtrAlign( element, kAtomicAlignment );
		RequirePtrAlignIfNotNil( (void*)((GuardedAtomicElement*) element)->list, kAtomicAlignment );
	AddOffset( &after, offset );
		RequirePtrAlignIfNotNil( after, kAtomicAlignment );
	AddOffset( &oldElement, offset );
		RequirePtrAlignIfNotNil( oldElement, kAtomicAlignment );
	result = PutAfterGuardedAtomicList( (GuardedAtomicElement*) element,
										(GuardedAtomicElement*) after,
										(GuardedAtomicElement*) oldElement,
										list );
		RequireIf( result, ((GuardedAtomicElement*) element)->list == list );
		RequireIf( result && after, ((GuardedAtomicElement*) after)->list == list );
		RequireIf( result && oldElement, ((GuardedAtomicElement*) oldElement)->list == list );
	return( result );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Fri, Sep 17, 1999	Created.
	
	************************************************************************************/

	long
PutLastGuardedAtomicListOff(
	void		*element,
	AtomicList	*list,
	size_t		offset )
{
	long	result;
	
	RequirePtr( element );
	RequirePtrAlign( list, kAtomicAlignment );
	RequireOffset( offset );
	
	AddOffset( &element, offset );
		RequirePtrAlign( element, kAtomicAlignment );
		RequirePtrAlignIfNotNil( (void*)((GuardedAtomicElement*) element)->list, kAtomicAlignment );
	result = PutLastGuardedAtomicList( (GuardedAtomicElement*) element, list );
		RequireIf( result, ((GuardedAtomicElement*) element)->list == list );
	return( result );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Thu, Sep 16, 1999	Created.
	
	************************************************************************************/

	GuardedAtomicElement*
RemoveFirstGuardedAtomicListOff(
	AtomicList		*list,
	size_t			offset )
{
	GuardedAtomicElement	*result;
	
	RequirePtrAlign( list, kAtomicAlignment );
	RequireOffset( offset );
	
	result = RemoveFirstGuardedAtomicList( list );
		RequirePtrAlignIfNotNil( result, kAtomicAlignment );
	SubOffset( (void**)&result, offset );
	
	return( result );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Fri, Sep 17, 1999	Created.
	
	************************************************************************************/

	long
RemoveGuardedAtomicListOff(
	void		*element,
	AtomicList	*list,
	size_t		offset )
{
	long	result;
	
	RequirePtr( element );
	RequirePtrAlign( list, kAtomicAlignment );
	RequireOffset( offset );
	
	AddOffset( &element, offset );
		RequirePtrAlign( element, kAtomicAlignment );
	result = RemoveGuardedAtomicList( (GuardedAtomicElement*) element, list );
		RequireIf( result, ((GuardedAtomicElement*) element)->list == nil );
	return( result );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Sep 27, 1999	Created.
	
	************************************************************************************/

	long
IterateGuardedAtomicListOff(
	void		**current,
	void		**next,
	AtomicList	*list,
	size_t		offset )
{
	long	result;
	
	RequirePtr( current );
	RequirePtrIfNotNil( *current );
	RequirePtr( next );
	RequirePtrAlignIf( *current && *next, *next, kAtomicAlignment );
	RequirePtrAlign( list, kAtomicAlignment );
	RequireOffset( offset );
	
	AddOffset( current, offset );
		RequirePtrAlignIfNotNil( *current, kAtomicAlignment );
	if( *current ) {
		AddOffset( next, offset );
		RequirePtrAlignIfNotNil( *next, kAtomicAlignment );
	}
	result = IterateGuardedAtomicList( (GuardedAtomicElement**) current,
										(GuardedAtomicElement**) next, list );
		RequireIf( result && *current, ((GuardedAtomicElement*) *current)->list == list );
		RequireIf( result && *next, ((GuardedAtomicElement*) *next)->list = list );
	SubOffset( current, offset );
	SubOffset( next, offset );
	
	return( result );
}

/****************************************************************************************
*	
*	Private Pointer Manipulation Functions
*	
****************************************************************************************/
#pragma mark	-
#pragma mark	(Private Pointer Manipulation Functions)

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Thu, Jan 20, 2000	Created.
	wolf		Sat, Jan 22, 2000	Now aligns the stack based on the kAtomicAlignment
									constant.
	
	************************************************************************************/

	AtomicStack*
AlignAtomicStack(
	AlignedAtomicStack	*stack )
{
	long		result = (long) stack;
	
	RequirePtr( stack );
	
	result &= ~(kAtomicAlignment - 1);	//	Strip lower (kAtomicAlignment log 2) bits.
	result += kAtomicAlignment;			//	Move pointer up kAtomicAlignment bytes.
	RequirePtrAlign( (void*) result, kAtomicAlignment );
	return( (AtomicStack*) result );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Sep 13, 1999	Created.
	
	************************************************************************************/

	void
AddOffset(
	void	**ptr,
	size_t	offset )
{
	char	*p;
	
	RequirePtr( ptr );
	RequirePtrIfNotNil( *ptr );
	RequireOffset( offset );
	
	p = (char*) *ptr;
	if( p ) {
		p += offset;
		*ptr = p;
	}
	RequirePtrIfNotNil( *ptr );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Sep 13, 1999	Created.
	
	************************************************************************************/

	void
SubOffset(
	void	**ptr,
	size_t	offset )
{
	char	*p;
	
	RequirePtr( ptr );
	RequirePtrIfNotNil( *ptr );
	RequireOffset( offset );
	
	p = (char*) *ptr;
	if( p ) {
		p -= offset;
		*ptr = p;
	}
	RequirePtrIfNotNil( *ptr );
}



See more files for this project here

redshed

Code for Mac+WebObjects.

Project homepage: http://sourceforge.net/projects/redshed
Programming language(s): C,Java,Objective C
License: other

  MacsBug/
    atomicity.mbug
    atomicity.mbug.r
    mxwt_template.rsrc
  TestAtomicity.cp
  atomicity.c
  atomicity.config.h
  atomicity.h