Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
•Mac_Classes/TThread.cp
// TThread.cp - Macintosh Thread class object |
// |
// Apple Macintosh Developer Technical Support |
// Written by: Vinne Moscaritolo |
// |
// Copyright (work in progress) Apple Computer, Inc All rights reserved. |
// |
// You may incorporate this sample code into your applications without |
// restriction, though the sample code has been provided "AS IS" and the |
// responsibility for its operation is 100% yours. However, what you are |
// not permitted to do is to redistribute the source as "DSC Sample Code" |
// after having made changes. If you're going to re-distribute the source, |
// we require that you make it clear in the source that the code was |
// descended from Apple Sample Code, but that you've made changes. |
// |
#include "TMacException.h" |
#include "TThread.h" |
#include "TNetworkException.h" |
#include <strstream.h> |
// =========================================================================== |
// Static member variables |
// =========================================================================== |
Boolean TThread::fgInited = false; // is Thread class library inited |
ProcessSerialNumber TThread::fgPSN; // application's PSN |
ThreadTaskRef TThread::fgThreadTaskRef; // thread task ref |
// --------------------------------------------------------------------------- |
// DoEntry (pascal wrapper function) |
// --------------------------------------------------------------------------- |
// Thread manager Callback for thread entry |
pascal void* TThread::DoEntry(void *arg) |
{ |
TThread *theThread = (TThread*) arg; |
void* theResult; |
// try |
{ |
theResult = theThread->Run(); |
} |
// catch(...) |
{ |
// stop error prop |
} |
// Recycle thread |
theThread->Stop(theResult); |
// cant get here... |
ThrowMsg("TThread :DoEntry returned from dispose"); |
return nil; |
} |
// --------------------------------------------------------------------------- |
// DoTermination (pascal wrapper function) |
// --------------------------------------------------------------------------- |
// Thread manager Callback for thread termination |
pascal void TThread::DoTermination(ThreadID theID, void *arg) |
{ |
TThread *theThread = (TThread*) arg; |
theThread->fTID = kNoThreadID; |
try |
{ |
theThread->Done(); |
} |
catch(...) |
{ |
// all we want is to stop error propagation |
} |
} |
// --------------------------------------------------------------------------- |
// DoSwapIn (pascal wrapper function) |
// --------------------------------------------------------------------------- |
// Thread manager Callback for thread Swap in |
pascal void TThread::DoSwapIn(ThreadID, void *arg) |
{ |
TThread* theThread = (TThread*) arg; |
theThread->fContext.Restore(); |
} |
// --------------------------------------------------------------------------- |
// DoSwapOut (pascal wrapper function) |
// --------------------------------------------------------------------------- |
// Thread manager Callback for thread Swap Out |
pascal void TThread::DoSwapOut(ThreadID, void *arg) |
{ |
TThread *theThread = (TThread*) arg; |
theThread->fContext.Save(); |
} |
// --------------------------------------------------------------------------- |
// TThread |
// --------------------------------------------------------------------------- |
// Default Constructor |
TThread::TThread() |
{ |
// Check if first time to use thread package |
if (!fgInited) Initialize(); |
// Set state |
fTID = kNoThreadID; |
} |
// --------------------------------------------------------------------------- |
// ~TThread |
// --------------------------------------------------------------------------- |
// Destructor |
TThread::~TThread() |
{ |
// Kill thread if it's running |
Stop(0); |
fTID = kNoThreadID; |
} |
// --------------------------------------------------------------------------- |
// Start |
// --------------------------------------------------------------------------- |
// Setup thread for execution |
void TThread::Start() |
{ |
OSErr ErrNo; |
try { |
// Create thread |
ThrowIfOSErr (::NewThread( kCooperativeThread, // kCooperativeThread,kPreemptiveThread |
DoEntry, // thread entry proc |
this, // param to entry proc |
0, // Stack space |
(kReadyThreadState // starting state (ready) |
| kCreateIfNeeded), // try to get from pool |
(void**) &fResult, // place to put quit result |
&fTID)); // place to put task ID |
// set terminator and thread switch procs |
ThrowIfOSErr(::SetThreadSwitcher(fTID, DoSwapIn, this, true)); |
ThrowIfOSErr(::SetThreadSwitcher(fTID, DoSwapOut, this, false)); |
ThrowIfOSErr(::SetThreadTerminator(fTID, DoTermination, this)); |
} |
catch(...){ |
if (fTID != kNoThreadID) { |
::SetThreadTerminator(fTID, nil, nil); |
::DisposeThread(fTID, nil, true); |
fTID = kNoThreadID; |
} |
throw; |
} |
} |
// --------------------------------------------------------------------------- |
// Stop |
// --------------------------------------------------------------------------- |
// Stop thread execution |
void TThread::Stop(void * theResult) |
{ |
if(fTID != kNoThreadID){ |
ThreadID ourThread = fTID; |
fTID = kNoThreadID; // this might be the last thing this thread does |
::DisposeThread(ourThread,theResult, true); // so juggle the Tid |
}; |
} |
// --------------------------------------------------------------------------- |
// Sleep |
// --------------------------------------------------------------------------- |
// Sleep Thread |
void TThread::Sleep() |
{ |
if(fTID != kNoThreadID) |
ThrowIfOSErr(::SetThreadState(fTID,kStoppedThreadState,kCurrentThreadID)); |
} |
// --------------------------------------------------------------------------- |
// WakeUp |
// --------------------------------------------------------------------------- |
// Wake up Thread |
void TThread::WakeUp() |
{ |
ThreadState threadState; |
if( (fTID != kNoThreadID) |
&& (::GetThreadStateGivenTaskRef(fgThreadTaskRef, fTID,&threadState) != noErr) |
&& (threadState == kStoppedThreadState)) |
::SetThreadReadyGivenTaskRef(fgThreadTaskRef, fTID); |
} |
// --------------------------------------------------------------------------- |
// Yield |
// --------------------------------------------------------------------------- |
// Yield time to next thread |
void TThread::Yield() |
{ |
::YieldToAnyThread(); |
} |
// --------------------------------------------------------------------------- |
// Run |
// --------------------------------------------------------------------------- |
// default thread Run |
void* TThread::Run() |
{ |
while(true) { |
Yield(); |
} |
return nil; |
} |
// --------------------------------------------------------------------------- |
// Done |
// --------------------------------------------------------------------------- |
// default thread Done |
void TThread::Done() |
{ |
} |
// --------------------------------------------------------------------------- |
// Allocate (static public) |
// --------------------------------------------------------------------------- |
// Allocate memory for Thread manager |
void TThread::Allocate(short numToCreate, Size stackSize) |
{ |
ThrowIfOSErr(::CreateThreadPool(kCooperativeThread, numToCreate, stackSize)); |
} |
// --------------------------------------------------------------------------- |
// Initialize |
// --------------------------------------------------------------------------- |
// Will run when first thread is started |
void TThread::Initialize() |
{ |
// is the Thread Manager running ? |
/* if (!UEnvironment::HasFeature(env_HasThreadsManager)) |
{ |
ThrowOSErr_(threadProtocolErr); |
} |
*/ |
// low-level initialisation |
ThrowIfOSErr( ::GetCurrentProcess(&fgPSN)); |
ThrowIfOSErr( ::GetThreadCurrentTaskRef(&fgThreadTaskRef)); |
fgInited = true; |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14