WaitRedShedThread.c from redshed at Krugle
Show WaitRedShedThread.c syntax highlighted
/****************************************************************************************
WaitRedShedThread.c $Revision: 1.2 $
<http://rentzsch.com/redshedthreads>
Copyright © 2000-2002 Red Shed Software. All rights reserved.
by Jonathan 'Wolf' Rentzsch (jon at redshed dot net)
************************************************************************************/
#include "WaitRedShedThread.h"
#include "EventTasks.h"
#include "Align.h"
#include "require.h"
#include "CFMA5.h"
//#include "doubt.h"
#include "Multiprocessing.h"
//#define kEventTaskMessage (AtomicMessage)100
//#define kDeferredTaskMessage (AtomicMessage)101
#define kTimeTaskMessage (AtomicMessage)102
//#define kTimeDeferredTaskMessage kDeferredTaskMessage
/**************************
*
* Types
*
**************************/
#pragma mark (Types)
typedef struct {
EventTask et;
RedShedThread *thread;
} WEventTask;
typedef struct {
DeferredTask dt;
RedShedThread *thread;
long a5;
} WDeferredTask;
typedef struct {
TMTask tm;
RedShedThread *thread;
long a5;
Boolean sendMessage;
} WTMTask;
/**************************
*
* Funky Protos
*
**************************/
#pragma mark -
#pragma mark (Funky Protos)
void
WaitEventTaskProc(
WEventTask *task );
pascal
void
WaitDeferredTaskProc(
WDeferredTask *task );
#if TARGET_API_MAC_CARBON
DeferredTaskUPP gWaitDeferredTaskProc = NewDeferredTaskUPP( (DeferredTaskProcPtr) WaitDeferredTaskProc );
#else
#if TARGET_RT_MAC_CFM
RoutineDescriptor rdWaitDeferredTaskProc = BUILD_ROUTINE_DESCRIPTOR( uppDeferredTaskProcInfo, WaitDeferredTaskProc );
DeferredTaskUPP gWaitDeferredTaskProc = &rdWaitDeferredTaskProc;
#else
void WaitDeferredTaskProcGlue();
DeferredTaskUPP gWaitDeferredTaskProc = (DeferredTaskUPP) &WaitDeferredTaskProcGlue;
#endif
#endif
pascal
void
WaitTimeTaskProc(
WTMTask *task );
#if TARGET_API_MAC_CARBON
TimerUPP gWaitTimeTaskProc = NewTimerUPP( (TimerProcPtr) WaitTimeTaskProc );
#else
#if TARGET_RT_MAC_CFM
RoutineDescriptor rdWaitTimeTaskProc = BUILD_ROUTINE_DESCRIPTOR( uppTimerProcInfo, WaitTimeTaskProc );
TimerUPP gWaitTimeTaskProc = &rdWaitTimeTaskProc;
#else
void WaitTimeTaskProcGlue();
TimerUPP gWaitTimeTaskProc = (TimerUPP) &WaitTimeTaskProc;
#endif
#endif
AtomicMessageElement*
WaitOTEventProc(
AtomicMessageElement *message,
AtomicMessageQueue *queue );
OSStatus
WaitMPTaskProc(
void *parameter );
/****************************************************************************************
*
* Public
*
****************************************************************************************/
#pragma mark -
#pragma mark (Public)
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Wed, Feb 2, 2000 Created.
wolf Tue, May 1, 2001 Now returns the Boolean from ScheduleEventTask().
************************************************************************************/
Boolean
WaitEventTask(
RedShedThread *thread,
UInt32 sleep )
{
Boolean result;
DeclareAlignedVariable( WEventTask, task, kAtomicAlignment );
RequireRedShedThread( thread );
InitializeEventTask( (EventTask*) task );
task->et.proc = (EventTaskProc) WaitEventTaskProc;
task->thread = thread;
result = ScheduleEventTask( (EventTask*) task, sleep );
YieldRedShedThread( thread );
return( result );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Sat, Feb 19, 2000 Created.
wolf Sun, Apr 9, 2000 Updated for Red Shed Threads Version 6.
************************************************************************************/
void
WaitDeferredTask(
RedShedThread *thread )
{
WDeferredTask task;
OSErr err;
RequireRedShedThread( thread );
task.dt.qLink = nil;
task.dt.qType = dtQType;
task.dt.dtFlags = 0;
task.dt.dtAddr = gWaitDeferredTaskProc;
task.dt.dtParam = (long) &task;
task.dt.dtReserved = 0;
task.thread = thread;
task.a5 = GetA5();
ReadyRedShedThread( thread );
err = DTInstall( (DeferredTaskPtr) &task );
RequireNoErr( err );
BlockRedShedThread( thread );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Sat, Feb 19, 2000 Created.
wolf Sun, Apr 9, 2000 Updated for Red Shed Threads Version 6.
************************************************************************************/
void
WaitTimeTask(
RedShedThread *thread,
SInt32 sleep )
{
WTMTask task;
RequireRedShedThread( thread );
task.tm.qLink = nil;
task.tm.qType = 0;
task.tm.tmAddr = gWaitTimeTaskProc;
task.tm.tmCount = 0;
task.tm.tmWakeUp = 0;
task.tm.tmReserved = 0;
task.thread = thread;
task.a5 = GetA5();
task.sendMessage = false;
ReadyRedShedThread( thread );
InsTime( (QElemPtr) &task );
PrimeTime( (QElemPtr) &task, sleep );
BlockRedShedThread( thread );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Sat, Feb 19, 2000 Created.
************************************************************************************/
void
WaitTimeDeferredTask(
RedShedThread *thread,
SInt32 sleep )
{
RequireRedShedThread( thread );
WaitTimeTask( thread, sleep );
WaitDeferredTask( thread );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Thu, Jan 20, 2000 Created.
************************************************************************************/
OSStatus
WaitOTEvent(
RedShedThread *thread,
OTEventCode *event,
long *cookie,
SInt32 patience )
{
WTMTask task = { nil, 0, nil, 0, 0, 0, nil, 0, true };
OTEventCode gotEvent;
AtomicMessage message;
OSStatus result = kOTNoError;
task.tm.tmAddr = gWaitTimeTaskProc;
task.thread = thread;
task.a5 = GetA5();
RequireRedShedThread( thread );
RequirePtr( event );
RequirePtrIfNotNil( cookie );
//gDoubt << "thread " << thread << " is waiting for " << (void*) *event << doubt::end;
// Peek into the queue and see if there is already an OT event message there.
message = PeekRedShedThreadMessage( thread, nil, kOTEventMessage, (long*) &gotEvent,
nil, nil );
if( message == kNoAtomicMessage ) {
// No message pending.
if( patience ) {
// The user is impatient, start the timer.
InsTime( (QElemPtr) &task );
PrimeTime( (QElemPtr) &task, patience );
}
// Wait for either an OT event message or our timer message.
message = WaitPeekRedShedThreadMessage( thread, WaitOTEventProc,
kNoAtomicMessage, (long*) &gotEvent, nil, nil );
//Æ The following line should only be uncommented for debugging.
//WaitEventTask( thread, kPriority );
if( (task.tm.qType & kTMTaskActive) == kTMTaskActive ) {
// The Time Task is still outstanding, clear it.
RmvTime( (QElemPtr) &task );
}
}
switch( message ) {
case kOTEventMessage:
// We got an OT event message.
if( *event == 0 || *event == gotEvent ) {
// Either the client isn't picky and will accept any OT event (*event == 0)
// or it's just the event the client is looking for (*event == gotEvent).
// Either way, receive the event message.
//gDoubt << "thread " << thread << " got " << (void*) *event << doubt::end;
ReceiveRedShedThreadMessage( thread, nil, kNoAtomicMessage, (long*) event,
&result, cookie );
} else {
// It's not an event the client is willing to receive.
result = kOTLookErr;
}
break;
case kTimeTaskMessage:
// It's our time-out message, receive it.
//gDoubt << "thread " << thread << " gave up waiting for " << (void*) *event << doubt::end;
ReceiveRedShedThreadMessage( thread, nil, kNoAtomicMessage, nil, nil, nil );
result = kWaitOTMessageTimedOut;
break;
default:
RequireSwitch( message );
}
// It is possible that there still may be a kTimeTaskMessage in the queue.
// This can happen if the timer fired after the OT event, but before we removed the
// timer. Receive the message if it exists.
if( PeekRedShedThreadMessage( thread, nil, kTimeTaskMessage, nil, nil, nil ) == kTimeTaskMessage ) {
ReceiveRedShedThreadMessage( thread, nil, kTimeTaskMessage, nil, nil, nil );
}
return( result );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Tue, Jan 11, 2000 Created.
wolf Sat, Jul 1, 2000 Added explicit cast of code to long.
************************************************************************************/
pascal
void
NotifyRedShedThread(
void *contextPtr,
OTEventCode code,
OTResult result,
void *cookie )
{
RedShedThread *thread = (RedShedThread*) contextPtr;
OSErr err;
RequireRedShedThread( thread );
/*gDoubt << "OT event " << (void*) code << " was sent to thread " << thread
<< " with the result of " << result << doubt::end;*/
err = NewRedShedThreadMessage( thread, kOTEventMessage, (long) code, result, (long) cookie );
/*if( err ) {
gDoubt << "OT event " << (void*) code << " sent to thread " << (long) thread
<< " was dropped because NewRedShedThreadMessage() failed." << doubt::stop;
}*/
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Sat, Sep 2, 2000 Created.
************************************************************************************/
OSStatus
WaitMPTask(
RedShedThread *thread )
{
MPTaskID task;
OSStatus err;
RequireRedShedThread( thread );
ReadyRedShedThread( thread );
err = MPCreateTask( WaitMPTaskProc, thread, 0, 0, nil, nil, 0, &task );
if( !err ) {
BlockRedShedThread( thread );
}
return( err );
}
/****************************************************************************************
*
* Private
*
****************************************************************************************/
#pragma mark -
#pragma mark (Private)
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Fri, Feb 4, 2000 Created.
************************************************************************************/
void
WaitEventTaskProc(
WEventTask *task )
{
RequirePtrAlign( task, kAtomicAlignment );
RequireRedShedThread( task->thread );
PulseRedShedThread( task->thread );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Sat, Feb 19, 2000 Created.
************************************************************************************/
pascal
void
WaitDeferredTaskProc(
WDeferredTask *task )
{
long oldA5;
RequirePtr( task );
oldA5 = SwapA5( task->a5 );
RequireRedShedThread( task->thread );
PulseRedShedThread( task->thread );
RestoreA5( oldA5 );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Sat, Feb 19, 2000 Created.
************************************************************************************/
#if !TARGET_API_MAC_CARBON && !TARGET_RT_MAC_CFM
asm
void
WaitDeferredTaskProcGlue()
{
movem.l a4-a6/d4-d7, -(a7) // Save registers.
move.l a1, -(a7) // Push task.
jsr WaitDeferredTaskProc // Call the real guy.
movem.l (a7)+, a4-a6/d4-d7 // Restore registers.
rts // We're outta here.
}
#endif
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Sat, Feb 19, 2000 Created.
************************************************************************************/
pascal
void
WaitTimeTaskProc(
WTMTask *task )
{
long oldA5;
RequirePtr( task );
oldA5 = SwapA5( task->a5 );
RequireRedShedThread( task->thread );
if( task->sendMessage ) {
OSErr err = NewRedShedThreadMessage( task->thread, kTimeTaskMessage, 0, 0, 0 );
Require( !err );
} else {
PulseRedShedThread( task->thread );
}
RestoreA5( oldA5 );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Sat, Feb 19, 2000 Created.
************************************************************************************/
#if !TARGET_API_MAC_CARBON && !TARGET_RT_MAC_CFM
asm
void
WaitTimeTaskProcGlue()
{
movem.l d4-d7/a4-a6, -(sp) // Save registers.
move.l a1, -(sp) // Push task.
jsr WaitTimeTaskProc // Call the real guy.
movem.l (sp)+, d4-d7/a4-a6 // Restore registers.
rts // We're outta here.
}
#endif
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Thu, May 18, 2000 Created.
************************************************************************************/
AtomicMessageElement*
WaitOTEventProc(
AtomicMessageElement *message,
AtomicMessageQueue */*queue*/ )
{
if( message->message == kOTEventMessage || message->message == kTimeTaskMessage ) {
return( kFilterFoundAtomicMessage );
} else {
return( kFilterNextAtomicMessage );
}
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Sat, Sep 2, 2000 Created.
************************************************************************************/
OSStatus
WaitMPTaskProc(
void *parameter )
{
RedShedThread *thread = (RedShedThread*) parameter;
RequireRedShedThread( thread );
PulseRedShedThread( thread );
return( noErr );
}
See more files for this project here