Code Search for Developers
 
 
  

EventTasks.c from redshed at Krugle


Show EventTasks.c syntax highlighted

/****************************************************************************************
	EventTasks.c $Revision: 22 $
		<http://rentzsch.com/eventTasks>
	
	Copyright © 1999-2002 Red Shed Software. All rights reserved.
	by Jonathan 'Wolf' Rentzsch (jon at redshed dot net)
	
	************************************************************************************/

#include	"EventTasks.h"
#include	"require.h"
#include	"Align.h"

/**************************
*	
*	Macros
*	
**************************/
#pragma mark	(Macros)

/*	Adventures in Carbonating...
	
	EventTasks is designed to be called at interrupt time. So, it may need to get the
	current tick count at interrupt time. It used to call TickCount(). Then Tech Note
	1104 : "Interrupt-Safe Routines", came out which revealed:
	
	"TickCount is not interrupt-safe. This is because it supports the (long-obsolete)
	Journaling Mechanism, as described in Inside Macintosh I ,page 261. Interrupt time
	code should use LMGetTicks instead."
	
	So I replaced my use of TickCount() with LMGetTicks().
	
	Then Carbon came out. It doesn't export LMGetTicks(). The spec says to use TickCount()
	instead. However, TickCount() wasn't officially interrupt-safe until CarbonLib 1.0.2.
	
	Then again, a lot of code uses TickCount() at interrupt time and doesn't seem any worse
	for it. I suspect call TickCount() at interrupt time on CarbonLib before 1.0.2 won't have
	any ill effects.
*/

#if	TARGET_API_MAC_CARBON
	#define	MyTickCount		TickCount
#else
	#define	MyTickCount		LMGetTicks
#endif

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

typedef	struct	{
	Pad			padding[ kAtomicAlignment ];
	AtomicList	list;
}	AlignedAtomicList;

AlignedAtomicList	alignedPriority;
AlignedAtomicList	alignedSchedule;
AlignedAtomicList	alignedLoop;
AtomicList			*gPriority = nil;
AtomicList			*gSchedule = nil;
AtomicList			*gLoop = nil;

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

#define		ShouldInitializeEventTasks()	gPriority == nil

	void
InitializeEventTasks();

	Boolean
ScheduleForeverEventTask(
	EventTask	*task,
	UInt32		sleep );

	Boolean
SchedulePriorityEventTask(
	EventTask	*task,
	UInt32		sleep );

	Boolean
ScheduleLoopEventTask(
	EventTask	*task,
	UInt32		sleep );

	Boolean
ScheduleScheduleEventTask(
	EventTask	*task,
	UInt32		sleep );

	Boolean
NoUserEvents();

	void
PerformPriorityTasks();

	void
PerformScheduledTasks();

	void
PerformEventLoopTasks();

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

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

	void
InitializeEventTask(
	EventTask	*task )
{
	RequirePtrAlign( task, kAtomicAlignment );
	
	task->element.next	= nil;
	task->element.list	= nil;
	task->wakeup		= nil;
	task->proc			= nil;
	task->refCon		= nil;
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Wed, Apr 14, 1999	Created.
	
	************************************************************************************/

	Boolean
ScheduleEventTask(
	EventTask	*task,
	UInt32		sleep )
{
	Boolean	result;
	
	RequirePtrAlign( task, kAtomicAlignment );
	
	//	Make sure there's enough time left in the future to actually schedule the task.
	//	This could happen when a program is run continually for 2 years and schedules
	//	a task two years out. Paranoid, yes.
	Require( ( 0xFFFFFFFF - MyTickCount() ) > sleep );
	
	if( ShouldInitializeEventTasks() ) {
		InitializeEventTasks();
	}
	
	switch( sleep ) {
		case kForever:
			result = ScheduleForeverEventTask( task, sleep );
			break;
		case kPriority:
			result = SchedulePriorityEventTask( task, sleep );
			break;
		case kEventLoop:
			result = ScheduleLoopEventTask( task, sleep );
			break;
		default:
			result = ScheduleScheduleEventTask( task, sleep );
	}
	
	return( result );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Wed, Apr 14, 1999	Created.
	wolf		Tue, Aug 10, 1999	Added maxTaskTime functionality.
	
	************************************************************************************/

	UInt32
PerformEventTasks(
	UInt32	maxTaskTime	)
{
	EventTask	*task = nil;
	Boolean		noUserEvents = false;
	UInt32		stopTime = MyTickCount() + maxTaskTime;
	
	if( ShouldInitializeEventTasks() )
		InitializeEventTasks();
	
	PerformPriorityTasks();
	noUserEvents = NoUserEvents();
	
	if( ( stopTime > MyTickCount() ) && noUserEvents ) {
		PerformScheduledTasks();
		noUserEvents = NoUserEvents();
	}
	
	if( ( stopTime > MyTickCount() ) && noUserEvents ) {
		PerformEventLoopTasks();
		noUserEvents = NoUserEvents();
	}
	
	if( noUserEvents ) {
		task = PeekGuardedAtomicListType( gSchedule, EventTask, element );
		if( task ) {
			if( task->wakeup > MyTickCount() )
				return( task->wakeup - MyTickCount() );
			else
				return( 0 );
		} else
			return( 0xFFFFFFFF );
	} else
		return( 0 );
}

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

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Tue, Feb 22, 2000	Created.
	
	************************************************************************************/

	void
InitializeEventTasks()
{
	if( ShouldInitializeEventTasks() ) {
		gPriority = (AtomicList*) AlignXDirect( &alignedPriority, kAtomicAlignment );
		gPriority->next = nil;
		RequirePtrAlign( gPriority, kAtomicAlignment );
		
		gSchedule = (AtomicList*) AlignXDirect( &alignedSchedule, kAtomicAlignment );
		gSchedule->next = nil;
		RequirePtrAlign( gSchedule, kAtomicAlignment );
		
		gLoop = (AtomicList*) AlignXDirect( &alignedLoop, kAtomicAlignment );
		gLoop->next = nil;
		RequirePtrAlign( gLoop, kAtomicAlignment );
	}
}

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

	Boolean
ScheduleForeverEventTask(
	EventTask	*task,
	UInt32		sleep )
{
#pragma	unused( sleep )
	long	result = true;
	
	RequirePtrAlign( task, kAtomicAlignment );
	Require( sleep == kForever );
	
	if( task->element.list ) {
		result = RemoveGuardedAtomicListType( task, (AtomicList*) task->element.list,
												EventTask, element );
	}
	
	if( result )
		task->wakeup = kForever;
	return( result ? true : false );
}

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

	Boolean
SchedulePriorityEventTask(
	EventTask	*task,
	UInt32		sleep )
{
#pragma	unused( sleep )
	long	result = true;
	
	RequirePtrAlign( gPriority, kAtomicAlignment );
	RequirePtrAlign( task, kAtomicAlignment );
	Require( sleep == kPriority );
	
	if( task->element.list ) {
		result = RemoveGuardedAtomicListType( task, (AtomicList*) task->element.list, EventTask, element );
	}
	if( result ) {
		result = PutLastGuardedAtomicListType( task, gPriority, EventTask, element );
		if( result ) {
			task->wakeup = kPriority;
			if( gThisProcessSerialNumber )
				WakeUpProcess( gThisProcessSerialNumber );
		}
	}
	return( result ? true : false );
}

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

	Boolean
ScheduleLoopEventTask(
	EventTask	*task,
	UInt32		sleep )
{
#pragma	unused( sleep )
	long	result = true;
	
	RequirePtrAlign( gLoop, kAtomicAlignment );
	RequirePtrAlign( task, kAtomicAlignment );
	Require( sleep == kEventLoop );
	
	if( task->element.list ) {
		result = RemoveGuardedAtomicListType( task, (AtomicList*) task->element.list, EventTask, element );
	}
	if( result ) {
		result = PutLastGuardedAtomicListType( task, gLoop, EventTask, element );
		if( result )
			task->wakeup = kEventLoop;
	}
	return( result ? true : false );
}

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

	Boolean
ScheduleScheduleEventTask(
	EventTask	*task,
	UInt32		sleep )
{
	EventTask	*current, *next;
	long		result = true;
	
	RequirePtrAlign( gSchedule, kAtomicAlignment );
	RequirePtrAlign( task, kAtomicAlignment );
	Require( sleep != kForever && sleep != kPriority && sleep != kEventLoop );
	
	if( task->element.list ) {
		result = RemoveGuardedAtomicListType( task, (AtomicList*) task->element.list, EventTask, element );
	}
	if( result ) {
		task->wakeup = MyTickCount() + sleep;
	restart:
		current = nil;
		if( !IterateGuardedAtomicListType( &current, &next, gSchedule, EventTask, element ) )
			goto restart;
		while( current && task->wakeup > current->wakeup && next && task->wakeup > next->wakeup ) {
			if( !IterateGuardedAtomicListType( &current, &next, gSchedule, EventTask, element ) )
				goto restart;
		}
		if( current && task->wakeup > current->wakeup )
			result = PutAfterGuardedAtomicListType( task, current, next, gSchedule, EventTask, element );
		else
			result = PutFirstGuardedAtomicListType( task, gSchedule, EventTask, element );
	}
	
	return( result ? true : false );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Mon, Apr 12, 1999	Created.
	
	************************************************************************************/

	Boolean
NoUserEvents()
{
	EventRecord	ignored;
	return( !EventAvail( everyEvent, &ignored ) );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Wed, Apr 14, 1999	Created.
	
	************************************************************************************/

	void
PerformPriorityTasks()
{
	EventTask	*task;
	
	RequirePtrAlign( gPriority, kAtomicAlignment );
	
	task = RemoveFirstGuardedAtomicListType( gPriority, EventTask, element );
	while( task ) {
		RequirePtrAlign( task, kAtomicAlignment );
		task->wakeup = kForever;
		RequireProcPtr( task->proc );
		task->proc( task );
		task = RemoveFirstGuardedAtomicListType( gPriority, EventTask, element );
	}
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Wed, Apr 14, 1999	Created.
	
	************************************************************************************/

	void
PerformScheduledTasks()
{
	EventTask	*task;
	
	RequirePtrAlign( gSchedule, kAtomicAlignment );
	
	task = RemoveFirstGuardedAtomicListType( gSchedule, EventTask, element );
	
	while( task ) {
		RequirePtrAlign( task, kAtomicAlignment );
		if( task->wakeup > MyTickCount() ) {
			//	Oops. This task isn't ready yet, put it back.
			PutFirstGuardedAtomicListType( task, gSchedule, EventTask, element );
			return;
		}
		
		task->wakeup = kForever;
		
		PerformPriorityTasks();
		
		RequireProcPtr( task->proc );
		task->proc( task );
		task = RemoveFirstGuardedAtomicListType( gSchedule, EventTask, element );
	}
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Wed, Apr 14, 1999	Created.
	
	************************************************************************************/

	void
PerformEventLoopTasks()
{
	EventTask	*task;
	DeclareAlignedVariable( AtomicList, list, kAtomicAlignment );
	
	RequirePtrAlign( gLoop, kAtomicAlignment );
	RequirePtrAlign( list, kAtomicAlignment );
	
	StealGuardedAtomicList( gLoop, list );
	task = RemoveFirstGuardedAtomicListType( list, EventTask, element );
	while( task ) {
		RequirePtrAlign( task, kAtomicAlignment );
		task->wakeup = kForever;
			
		PerformPriorityTasks();
			
		RequireProcPtr( task->proc );
		task->proc( task );
		
		task = RemoveFirstGuardedAtomicListType( list, EventTask, element );
	}
}

#ifdef	__cplusplus
/****************************************************************************************
*	
*	TEventTask
*	
****************************************************************************************/
#pragma mark	-
#pragma mark	(TEventTask)

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

TEventTask::TEventTask(
	UInt32	sleep )
{
	InitializeEventTask( this );
	proc = HandleEventTask_;
	refCon = this;
	if( sleep != kForever ) {
		Boolean	scheduled = ::ScheduleEventTask( this, sleep );
		Require( scheduled );
	}
}

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

TEventTask::~TEventTask()
{
	Boolean	scheduled = ::ScheduleEventTask( this, kForever );
	Require( scheduled );
}

/****************************************************************************************
	Commenter	Date				Comment
	---------	-----------------	-----------------------------------------------------
	wolf		Thu, Oct 21, 1999	Created.
	
	************************************************************************************/

	Boolean
TEventTask::ScheduleEventTask(
	UInt32	sleep )
{
	return( ::ScheduleEventTask( this, sleep ) );
}

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

	void
TEventTask::HandleEventTask()
{
	//	stub
}

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

	void
TEventTask::HandleEventTask_(
	EventTask	*task )
{
	RequirePtrAlign( task, kAtomicAlignment );
	RequireProcPtr( task->proc );
	Require( task->proc == HandleEventTask_ );
	
	TEventTask	*thisTask = (TEventTask*) task->refCon;
				RequirePtr( thisTask );
	thisTask->HandleEventTask();
}

#endif



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

  EventTasks.c
  EventTasks.h