home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 1998 May
/
Pcwk5b98.iso
/
Borland
/
Cplus45
/
BC45
/
CLASSSRC.PAK
/
THREAD.CPP
< prev
next >
Wrap
Text File
|
1995-08-29
|
12KB
|
500 lines
/*------------------------------------------------------------------------*/
/* */
/* THREAD.CPP */
/* */
/* Copyright (c) 1993, 1994 Borland International */
/* All Rights Reserved */
/* */
/*------------------------------------------------------------------------*/
#if !defined( __PROCESS_H )
#include <process.h>
#endif
#if !defined( __STDLIB_H )
#include <stdlib.h>
#endif
#if !defined( __CHECKS_H )
#include <checks.h>
#endif
#if !defined( CLASSLIB_DEFS_H )
#include <classlib/defs.h>
#endif
#if !defined( CLASSLIB_THREAD_H )
#include <classlib/thread.h>
#endif
DIAG_DEFINE_GROUP(Threads,1,0);
#if defined( BI_PLAT_WIN32 )
//------------------------------------------------
//
// WIN32
//
// Use OS call to close thread handle.
//
inline void InternalCloseHandle( TThread::THandle Handle )
{
::CloseHandle(Handle);
}
//------------------------------------------------
//
// WIN32
//
// Use OS call to suspend thread.
//
inline DWORD InternalSuspendThread( TThread::THandle Handle )
{
return ::SuspendThread(Handle);
}
//------------------------------------------------
//
// WIN32
//
// Use OS call to suspend thread.
//
inline DWORD InternalResumeThread( TThread::THandle Handle )
{
return ::ResumeThread(Handle);
}
//------------------------------------------------
//
// WIN32
//
// Use OS call to wait for thread termination.
//
inline unsigned long InternalWaitForThread( TThread::THandle Handle,
unsigned long timeout )
{
return ::WaitForSingleObject( Handle, timeout );
}
//------------------------------------------------
//
// WIN32
//
// Use OS call to get thread priority.
//
inline int InternalGetThreadPriority( TThread::THandle Handle )
{
return ::GetThreadPriority( Handle );
}
//------------------------------------------------
//
// WIN32
//
// Use OS call to set thread priority.
//
inline int InternalSetThreadPriority( TThread::THandle Handle, int pri )
{
return ::SetThreadPriority( Handle, pri );
}
#endif
#if defined( BI_PLAT_OS2 )
//------------------------------------------------
//
// OS/2
//
// Don't need to close the handle.
//
inline void InternalCloseHandle( TThread::THandle )
{
}
//------------------------------------------------
//
// OS/2
//
// Use OS call to suspend thread.
//
inline ULONG InternalSuspendThread( TThread::THandle Handle )
{
return ::DosSuspendThread(Handle);
}
//------------------------------------------------
//
// OS/2
//
// Use OS call to suspend thread.
//
inline ULONG InternalResumeThread( TThread::THandle Handle )
{
return ::DosResumeThread(Handle);
}
//------------------------------------------------
//
// OS/2
//
// Use OS call to wait for thread termination.
//
inline ULONG InternalWaitForThread( TThread::THandle &Handle,
unsigned long timeout )
{
return ::DosWaitThread( &Handle, timeout );
}
#endif
//------------------------------------------------
//
// TThread constructors
//
TThread::TThread() :
#if defined( BI_PLAT_WIN32 )
ThreadId(0),
#elif defined( BI_PLAT_OS2 )
Priority(0),
#endif
Handle(0),
Stat(Created),
TerminationRequested(0)
{
}
TThread::TThread( const TThread& ) :
#if defined( BI_PLAT_WIN32 )
ThreadId(0),
#elif defined( BI_PLAT_OS2 )
Priority(0),
#endif
Handle(0),
Stat(Created),
TerminationRequested(0)
{
}
//------------------------------------------------
//
// TThread assignment operator
//
// Used when assigning derived objects. Attempting to
// assign from a running object is an error, since the
// data fields in the running object can be changing
// asynchronously.
//
const TThread& TThread::operator = ( const TThread& thread )
{
switch( GetStatus() )
{
case Created:
case Suspended:
case Finished:
{
if( this != &thread )
{
Handle = 0;
#if defined( BI_PLAT_WIN32 )
ThreadId = 0;
#elif defined( BI_PLAT_OS2 )
Priority = 0;
#endif
Stat = Created;
TerminationRequested = 0;
}
return *this;
}
default:
throw ThreadError(ThreadError::AssignError);
}
}
//------------------------------------------------
//
// TThread destructor
//
// If the thread hasn't finished, destroying its control
// object is an error.
//
TThread::~TThread()
{
if( GetStatus() != Finished )
throw ThreadError(ThreadError::DestroyBeforeExit);
InternalCloseHandle(Handle);
}
//------------------------------------------------
//
// TThread::Start()
//
// Starts the thread executing. The actual call depends on the
// operating system. After the system call we check status.
//
TThread::THandle TThread::Start()
{
#if defined( BI_PLAT_WIN32 )
#if defined( __MT__ )
Handle = (HANDLE)::_beginthreadNT( &TThread::Execute, 4096, this, 0, 0, &ThreadId );
#else
Handle = ::CreateThread( 0, 0, &TThread::Execute, this, 0, &ThreadId );
#endif
#else
#if defined( __MT__ )
Handle = ::_beginthread( &TThread::Execute, 4096, this );
#else
APIRET res =
::DosCreateThread( &Handle,
(void (__syscall*)(unsigned long))&TThread::Execute,
REINTERPRET_CAST(unsigned long,this),
FALSE,
4000 );
#endif
#endif
if( Handle != 0 )
{
TRACEX( Threads, 1, "Thread started [id:" << Handle << ']' );
Stat = Running;
}
else
{
TRACEX(Threads, 2, "Thread failed to start" );
Stat = Invalid;
throw ThreadError(ThreadError::CreationFailure);
}
return Handle;
}
//------------------------------------------------
//
// TThread::Suspend()
//
// It's an error to try to suspend a thread that
// hasn't been started or that has already terminated.
//
unsigned long TThread::Suspend()
{
switch( GetStatus() )
{
case Created:
TRACEX( Threads, 2, "Illegal thread suspension [id:" << Handle << ']' );
throw ThreadError(ThreadError::SuspendBeforeRun);
case Finished:
TRACEX( Threads, 2, "Illegal thread suspension [id:" << Handle << ']' );
throw ThreadError(ThreadError::SuspendAfterExit);
default:
TRACEX( Threads, 0, "Thread suspended [id:" << Handle << ']' );
Stat = Suspended;
return InternalSuspendThread(Handle);
}
}
//------------------------------------------------
//
// TThread::Resume()
//
// It's an error to try to resume a thread that hasn't
// been suspended.
//
unsigned long TThread::Resume()
{
switch( GetStatus() )
{
case Created:
TRACEX( Threads, 2, "Illegal thread resumption [id:" << Handle << ']' );
throw ThreadError(ThreadError::ResumeBeforeRun);
case Running:
TRACEX( Threads, 2, "Illegal thread resumption [id:" << Handle << ']' );
throw ThreadError(ThreadError::ResumeDuringRun);
case Finished:
throw ThreadError(ThreadError::ResumeAfterExit);
default:
TRACEX( Threads, 0, "Thread resumed [id:" << Handle << ']' );
unsigned long res = InternalResumeThread(Handle);
if( res == 0 )
Stat = Running;
return res;
}
}
//------------------------------------------------
//
// TThread::Terminate()
//
// Mark the thread for termination.
//
void TThread::Terminate()
{
TRACEX( Threads, 1, "Thread termination requested [handle:" << Handle << ']' );
TerminationRequested = 1;
}
//------------------------------------------------
//
// TThread::WaitForExit()
//
// Block until the thread terminates.
//
// IMPORTANT: the meaning of the 'timeout' parameter is
// different for NT and OS/2. Under NT it specifies how long
// to wait for termination. Under OS/2 it specifies whether
// to wait or to return immediately if the thread hasn't
// terminated.
//
unsigned long TThread::WaitForExit( unsigned long timeout )
{
TRACEX( Threads, 1, "Waiting for thread exit [id:" << Handle << ']' );
if( Stat == Running )
return ::InternalWaitForThread( Handle, timeout );
else
return -1;
}
//------------------------------------------------
//
// TThread::TerminateAndWait()
//
// See note for WaitForExit().
//
unsigned long TThread::TerminateAndWait( unsigned long timeout )
{
Terminate();
return WaitForExit( timeout );
}
//------------------------------------------------
//
// TThread::SetPriority()
//
// Set the thread's priority.
//
int TThread::SetPriority( int pri )
{
TRACEX( Threads, 1, "Thread priority changed to " << pri << " [id:" << Handle << ']' );
#if defined( BI_PLAT_WIN32 )
return ::SetThreadPriority(Handle,pri);
#else
APIRET res = DosSetPriority( PRTYS_THREAD,
PRTYC_NOCHANGE,
pri-Priority,
Handle );
if( res != 0 )
Priority = pri;
return res;
#endif
}
//------------------------------------------------
//
// TThread::Execute()
//
// Run the thread.
//
#if defined( __MT__ )
void _USERENTRY TThread::Execute( void *thread )
{
STATIC_CAST(TThread*,thread)->Run();
}
#elif defined( BI_PLAT_WIN32 )
unsigned long _stdcall TThread::Execute( void *thread )
{
return STATIC_CAST(TThread*,thread)->Run();
}
#else
void __stdcall TThread::Execute( unsigned long thread )
{
REINTERPRET_CAST(TThread*,thread)->Run();
}
#endif
//------------------------------------------------
//
// TThread::CheckStatus()
//
// Call only when Stat claims that the thread is Running.
//
#if defined( BI_PLAT_WIN32 )
TThread::Status TThread::CheckStatus() const
{
DWORD ExitCode;
::GetExitCodeThread( Handle, &ExitCode );
if( ExitCode == STILL_ACTIVE )
return Running;
else
return Finished;
}
#elif defined( BI_PLAT_OS2 )
TThread::Status TThread::CheckStatus() const
{
if( ::DosWaitThread( CONST_CAST(THandle *,&Handle), DCWW_NOWAIT ) == ERROR_THREAD_NOT_TERMINATED )
return Running;
else
return Finished;
}
#endif
//------------------------------------------------
//
// TThread::ThreadError constructor
//
TThread::ThreadError::ThreadError(ErrorType type) :
xmsg(MakeString(type)),
Type(type)
{
}
//------------------------------------------------
//
// TThread::ThreadError::MakeString()
//
// Translates an error code into a string.
//
string TThread::ThreadError::MakeString(ErrorType type)
{
static char *Names[] =
{
"Suspend() before Run()",
"Resume() before Run()",
"Resume() during Run()",
"Suspend() after Exit()",
"Resume() after Exit()",
"creation failure",
"destroyed before Exit()",
"illegal assignment"
};
string Msg;
Msg.reserve(40);
Msg = "Error[thread]: ";
Msg += Names[type];
return Msg;
}