home *** CD-ROM | disk | FTP | other *** search
/ C Programming Starter Kit 2.0 / SamsPublishing-CProgrammingStarterKit-v2.0-Win31.iso / bc45 / classsrc.pak / THREAD.CPP < prev    next >
Text File  |  1997-07-23  |  12KB  |  500 lines

  1. /*------------------------------------------------------------------------*/
  2. /*                                                                        */
  3. /*  THREAD.CPP                                                            */
  4. /*                                                                        */
  5. /*  Copyright (c) 1993, 1994 Borland International                        */
  6. /*  All Rights Reserved                                                   */
  7. /*                                                                        */
  8. /*------------------------------------------------------------------------*/
  9.  
  10. #if !defined( __PROCESS_H )
  11. #include <process.h>
  12. #endif
  13.  
  14. #if !defined( __STDLIB_H )
  15. #include <stdlib.h>
  16. #endif
  17.  
  18. #if !defined( __CHECKS_H )
  19. #include <checks.h>
  20. #endif
  21.  
  22. #if !defined( CLASSLIB_DEFS_H )
  23. #include <classlib/defs.h>
  24. #endif
  25.  
  26. #if !defined( CLASSLIB_THREAD_H )
  27. #include <classlib/thread.h>
  28. #endif
  29.  
  30. DIAG_DEFINE_GROUP(Threads,1,0);
  31.  
  32. #if defined( BI_PLAT_WIN32 )
  33.  
  34. //------------------------------------------------
  35. //
  36. //  WIN32
  37. //
  38. //  Use OS call to close thread handle.
  39. //
  40.  
  41. inline void InternalCloseHandle( TThread::THandle Handle )
  42. {
  43.     ::CloseHandle(Handle);
  44. }
  45.  
  46. //------------------------------------------------
  47. //
  48. //  WIN32
  49. //
  50. //  Use OS call to suspend thread.
  51. //
  52.  
  53. inline DWORD InternalSuspendThread( TThread::THandle Handle )
  54. {
  55.     return ::SuspendThread(Handle);
  56. }
  57.  
  58. //------------------------------------------------
  59. //
  60. //  WIN32
  61. //
  62. //  Use OS call to suspend thread.
  63. //
  64.  
  65. inline DWORD InternalResumeThread( TThread::THandle Handle )
  66. {
  67.     return ::ResumeThread(Handle);
  68. }
  69.  
  70. //------------------------------------------------
  71. //
  72. //  WIN32
  73. //
  74. //  Use OS call to wait for thread termination.
  75. //
  76.  
  77. inline unsigned long InternalWaitForThread( TThread::THandle Handle,
  78.                                             unsigned long timeout )
  79. {
  80.     return ::WaitForSingleObject( Handle, timeout );
  81. }
  82.  
  83. //------------------------------------------------
  84. //
  85. //  WIN32
  86. //
  87. //  Use OS call to get thread priority.
  88. //
  89.  
  90. inline int InternalGetThreadPriority( TThread::THandle Handle )
  91. {
  92.     return ::GetThreadPriority( Handle );
  93. }
  94.  
  95. //------------------------------------------------
  96. //
  97. //  WIN32
  98. //
  99. //  Use OS call to set thread priority.
  100. //
  101.  
  102. inline int InternalSetThreadPriority( TThread::THandle Handle, int pri )
  103. {
  104.     return ::SetThreadPriority( Handle, pri );
  105. }
  106.  
  107. #endif
  108.  
  109. #if defined( BI_PLAT_OS2 )
  110.  
  111. //------------------------------------------------
  112. //
  113. //  OS/2
  114. //
  115. //  Don't need to close the handle.
  116. //
  117. inline void InternalCloseHandle( TThread::THandle )
  118. {
  119. }
  120.  
  121. //------------------------------------------------
  122. //
  123. //  OS/2
  124. //
  125. //  Use OS call to suspend thread.
  126. //
  127.  
  128. inline ULONG InternalSuspendThread( TThread::THandle Handle )
  129. {
  130.     return ::DosSuspendThread(Handle);
  131. }
  132.  
  133. //------------------------------------------------
  134. //
  135. //  OS/2
  136. //
  137. //  Use OS call to suspend thread.
  138. //
  139.  
  140. inline ULONG InternalResumeThread( TThread::THandle Handle )
  141. {
  142.     return ::DosResumeThread(Handle);
  143. }
  144.  
  145. //------------------------------------------------
  146. //
  147. //  OS/2
  148. //
  149. //  Use OS call to wait for thread termination.
  150. //
  151.  
  152. inline ULONG InternalWaitForThread( TThread::THandle &Handle,
  153.                                                          unsigned long timeout )
  154. {
  155.     return ::DosWaitThread( &Handle, timeout );
  156. }
  157.  
  158. #endif
  159.  
  160. //------------------------------------------------
  161. //
  162. //  TThread constructors
  163. //
  164.  
  165. TThread::TThread() :
  166. #if defined( BI_PLAT_WIN32 )
  167.     ThreadId(0),
  168. #elif defined( BI_PLAT_OS2 )
  169.     Priority(0),
  170. #endif
  171.     Handle(0),
  172.     Stat(Created),
  173.     TerminationRequested(0)
  174. {
  175. }
  176.  
  177. TThread::TThread( const TThread& ) :
  178. #if defined( BI_PLAT_WIN32 )
  179.     ThreadId(0),
  180. #elif defined( BI_PLAT_OS2 )
  181.     Priority(0),
  182. #endif
  183.     Handle(0),
  184.     Stat(Created),
  185.     TerminationRequested(0)
  186. {
  187. }
  188.  
  189. //------------------------------------------------
  190. //
  191. //  TThread assignment operator
  192. //
  193. //  Used when assigning derived objects. Attempting to
  194. //  assign from a running object is an error, since the
  195. //  data fields in the running object can be changing
  196. //  asynchronously.
  197. //
  198.  
  199. const TThread& TThread::operator = ( const TThread& thread )
  200. {
  201.     switch( GetStatus() )
  202.         {
  203.         case Created:
  204.         case Suspended:
  205.         case Finished:
  206.             {
  207.             if( this != &thread )
  208.                 {
  209.                 Handle = 0;
  210. #if defined( BI_PLAT_WIN32 )
  211.                 ThreadId = 0;
  212. #elif defined( BI_PLAT_OS2 )
  213.                 Priority = 0;
  214. #endif
  215.                 Stat = Created;
  216.                 TerminationRequested = 0;
  217.                 }
  218.             return *this;
  219.             }
  220.         default:
  221.             throw ThreadError(ThreadError::AssignError);
  222.         }
  223. }
  224.  
  225. //------------------------------------------------
  226. //
  227. //  TThread destructor
  228. //
  229. //  If the thread hasn't finished, destroying its control
  230. //  object is an error.
  231. //
  232.  
  233. TThread::~TThread()
  234. {
  235.     if( GetStatus() != Finished )
  236.         throw ThreadError(ThreadError::DestroyBeforeExit);
  237.     InternalCloseHandle(Handle);
  238. }
  239.  
  240. //------------------------------------------------
  241. //
  242. //  TThread::Start()
  243. //
  244. //  Starts the thread executing. The actual call depends on the
  245. //  operating system. After the system call we check status.
  246. //
  247.  
  248. TThread::THandle TThread::Start()
  249. {
  250. #if defined( BI_PLAT_WIN32 )
  251. #if defined( __MT__ )
  252.     Handle = (HANDLE)::_beginthreadNT( &TThread::Execute, 4096, this, 0, 0, &ThreadId );
  253. #else
  254.     Handle = ::CreateThread( 0, 0, &TThread::Execute, this, 0, &ThreadId );
  255. #endif
  256. #else
  257. #if defined( __MT__ )
  258.     Handle = ::_beginthread( &TThread::Execute, 4096, this );
  259. #else
  260.     APIRET res =
  261.         ::DosCreateThread( &Handle,
  262.                            (void (__syscall*)(unsigned long))&TThread::Execute,
  263.                            REINTERPRET_CAST(unsigned long,this),
  264.                            FALSE,
  265.                            4000 );
  266. #endif
  267. #endif
  268.  
  269.     if( Handle != 0 )
  270.         {
  271.         TRACEX( Threads, 1, "Thread started [id:" << Handle << ']' );
  272.         Stat = Running;
  273.         }        
  274.     else
  275.         {
  276.         TRACEX(Threads, 2, "Thread failed to start" );
  277.         Stat = Invalid;
  278.         throw ThreadError(ThreadError::CreationFailure);
  279.         }
  280.  
  281.     return Handle;
  282. }
  283.  
  284. //------------------------------------------------
  285. //
  286. //  TThread::Suspend()
  287. //
  288. //  It's an error to try to suspend a thread that
  289. //  hasn't been started or that has already terminated.
  290. //
  291.  
  292. unsigned long TThread::Suspend()
  293. {
  294.     switch( GetStatus() )
  295.         {
  296.         case Created:
  297.             TRACEX( Threads, 2, "Illegal thread suspension [id:" << Handle << ']' );
  298.             throw ThreadError(ThreadError::SuspendBeforeRun);
  299.         case Finished:
  300.             TRACEX( Threads, 2, "Illegal thread suspension [id:" << Handle << ']' );
  301.             throw ThreadError(ThreadError::SuspendAfterExit);
  302.         default:
  303.             TRACEX( Threads, 0, "Thread suspended [id:" << Handle << ']' );
  304.             Stat = Suspended;
  305.             return InternalSuspendThread(Handle);
  306.         }
  307. }
  308.  
  309. //------------------------------------------------
  310. //
  311. //  TThread::Resume()
  312. //
  313. //  It's an error to try to resume a thread that hasn't
  314. //  been suspended.
  315. //
  316.  
  317. unsigned long TThread::Resume()
  318. {
  319.     switch( GetStatus() )
  320.         {
  321.         case Created:
  322.             TRACEX( Threads, 2, "Illegal thread resumption [id:" << Handle << ']' );
  323.             throw ThreadError(ThreadError::ResumeBeforeRun);
  324.         case Running:
  325.             TRACEX( Threads, 2, "Illegal thread resumption [id:" << Handle << ']' );
  326.             throw ThreadError(ThreadError::ResumeDuringRun);
  327.         case Finished:
  328.             throw ThreadError(ThreadError::ResumeAfterExit);
  329.         default:
  330.             TRACEX( Threads, 0, "Thread resumed [id:" << Handle << ']' );
  331.             unsigned long res = InternalResumeThread(Handle);
  332.             if( res == 0 )
  333.                 Stat = Running;
  334.             return res;
  335.         }        
  336. }
  337.  
  338. //------------------------------------------------
  339. //
  340. //  TThread::Terminate()
  341. //
  342. //  Mark the thread for termination.
  343. //
  344.  
  345. void TThread::Terminate()
  346. {
  347.     TRACEX( Threads, 1, "Thread termination requested [handle:" << Handle << ']' );
  348.     TerminationRequested = 1;
  349. }
  350.  
  351. //------------------------------------------------
  352. //
  353. //  TThread::WaitForExit()
  354. //
  355. //  Block until the thread terminates.
  356. //
  357. //  IMPORTANT: the meaning of the 'timeout' parameter is
  358. //  different for NT and OS/2. Under NT it specifies how long
  359. //  to wait for termination. Under OS/2 it specifies whether
  360. //  to wait or to return immediately if the thread hasn't
  361. //  terminated.
  362. //
  363.  
  364. unsigned long TThread::WaitForExit( unsigned long timeout )
  365. {
  366.     TRACEX( Threads, 1, "Waiting for thread exit [id:" << Handle << ']' );
  367.     if( Stat == Running )
  368.         return ::InternalWaitForThread( Handle, timeout );
  369.     else
  370.         return -1;
  371. }
  372.  
  373. //------------------------------------------------
  374. //
  375. //  TThread::TerminateAndWait()
  376. //
  377. //  See note for WaitForExit().
  378. //
  379.  
  380. unsigned long TThread::TerminateAndWait( unsigned long timeout )
  381. {
  382.     Terminate();
  383.     return WaitForExit( timeout );
  384. }
  385.  
  386. //------------------------------------------------
  387. //
  388. //  TThread::SetPriority()
  389. //
  390. //  Set the thread's priority.
  391. //
  392.  
  393. int TThread::SetPriority( int pri )
  394. {
  395.     TRACEX( Threads, 1, "Thread priority changed to " << pri << " [id:" << Handle << ']' );
  396. #if defined( BI_PLAT_WIN32 )
  397.     return ::SetThreadPriority(Handle,pri);
  398. #else
  399.     
  400.     APIRET res = DosSetPriority( PRTYS_THREAD,
  401.                                  PRTYC_NOCHANGE,
  402.                                  pri-Priority,
  403.                                  Handle );
  404.     if( res != 0 )
  405.         Priority = pri;
  406.     return res;
  407. #endif
  408. }
  409.  
  410. //------------------------------------------------
  411. //
  412. //  TThread::Execute()
  413. //
  414. //  Run the thread.
  415. //
  416.  
  417. #if defined( __MT__ )
  418. void _USERENTRY TThread::Execute( void *thread )
  419. {
  420.     STATIC_CAST(TThread*,thread)->Run();
  421. }
  422. #elif defined( BI_PLAT_WIN32 )
  423. unsigned long _stdcall TThread::Execute( void *thread )
  424. {
  425.     return STATIC_CAST(TThread*,thread)->Run();
  426. }
  427. #else
  428. void __stdcall TThread::Execute( unsigned long thread )
  429. {
  430.     REINTERPRET_CAST(TThread*,thread)->Run();
  431. }
  432. #endif
  433.  
  434. //------------------------------------------------
  435. //
  436. //  TThread::CheckStatus()
  437. //
  438. //  Call only when Stat claims that the thread is Running.
  439. //
  440.  
  441. #if defined( BI_PLAT_WIN32 )
  442. TThread::Status TThread::CheckStatus() const
  443. {
  444.     DWORD ExitCode;
  445.     ::GetExitCodeThread( Handle, &ExitCode );
  446.     if( ExitCode == STILL_ACTIVE )
  447.         return Running;
  448.     else
  449.         return Finished;
  450. }
  451. #elif defined( BI_PLAT_OS2 )
  452. TThread::Status TThread::CheckStatus() const
  453. {
  454.     if( ::DosWaitThread( CONST_CAST(THandle *,&Handle), DCWW_NOWAIT ) == ERROR_THREAD_NOT_TERMINATED )
  455.         return Running;
  456.     else
  457.         return Finished;
  458. }
  459. #endif
  460.  
  461. //------------------------------------------------
  462. //
  463. //  TThread::ThreadError constructor
  464. //
  465.  
  466. TThread::ThreadError::ThreadError(ErrorType type) :
  467.     xmsg(MakeString(type)),
  468.     Type(type)
  469. {
  470. }
  471.  
  472. //------------------------------------------------
  473. //
  474. //  TThread::ThreadError::MakeString()
  475. //
  476. //  Translates an error code into a string.
  477. //
  478.  
  479. string TThread::ThreadError::MakeString(ErrorType type)
  480. {
  481.     static char *Names[] =
  482.         {
  483.         "Suspend() before Run()",
  484.         "Resume() before Run()",
  485.         "Resume() during Run()",
  486.         "Suspend() after Exit()",
  487.         "Resume() after Exit()",
  488.         "creation failure",
  489.         "destroyed before Exit()",
  490.         "illegal assignment"
  491.         };
  492.     string Msg;
  493.     Msg.reserve(40);
  494.     Msg = "Error[thread]: ";
  495.     Msg += Names[type];
  496.     return Msg;
  497. }
  498.  
  499. 
  500.