00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "CeylanThread.h"
00028
00029
00030 #include "CeylanOperators.h"
00031 #include "CeylanLogPlug.h"
00032 #include "CeylanStringUtils.h"
00033
00034
00035 #ifdef CEYLAN_USES_CONFIG_H
00036 #include "CeylanConfig.h"
00037 #endif // CEYLAN_USES_CONFIG_H
00038
00039
00040
00041 extern "C"
00042 {
00043
00044 #ifdef CEYLAN_USES_SYS_TYPES_H
00045
00046 #endif // CEYLAN_USES_SYS_TYPES_H
00047
00048 #ifdef CEYLAN_USES_UNISTD_H
00049
00050 #endif // CEYLAN_USES_UNISTD_H
00051
00052 #ifdef CEYLAN_USES_SYS_TIME_H
00053 #include <sys/time.h>
00054 #endif // CEYLAN_USES_SYS_TIME_H
00055
00056 }
00057
00058
00059 #include <cerrno>
00060 #include <list>
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073 using std::string ;
00074
00075 using namespace Ceylan ;
00076 using namespace Ceylan::System ;
00077 using namespace Ceylan::Log ;
00078 using namespace Ceylan::Features ;
00079
00080
00081
00082
00083 #ifdef CEYLAN_USES_PTHREAD_H
00084
00085 extern "C"
00086 {
00087
00088 #include "pthread.h"
00089
00090 }
00091
00092
00093
00094 struct Thread::SystemSpecificThreadIdentifier
00095 {
00096
00097 pthread_t _thread ;
00098
00099 } ;
00100
00101
00102
00103
00104 struct Thread::SystemSpecificThreadAttribute
00105 {
00106
00107 pthread_attr_t _threadAttribute ;
00108
00109 } ;
00110
00111
00112
00113
00114 struct Thread::SystemSpecificThreadCondition
00115 {
00116
00117 pthread_cond_t _threadCondition ;
00118
00119 } ;
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137 Synchronized<ThreadCount> * Thread::_Number
00138 = new Synchronized<ThreadCount>( 0 ) ;
00139
00140
00141
00142 #else // CEYLAN_USES_PTHREAD_H
00143
00144
00145
00146 Synchronized<ThreadCount> * Thread::_Number = 0 ;
00147
00148
00149 #endif // CEYLAN_USES_PTHREAD_H
00150
00151
00152
00153
00154 namespace
00155 {
00156
00157
00159 extern "C" void * Run( void * threadObject )
00160 {
00161
00162
00163
00164
00165
00166
00167 #if CEYLAN_DEBUG_THREADS
00168 LogPlug::debug( "::Run wrapper for Thread::Run called." ) ;
00169 #endif // CEYLAN_DEBUG_THREADS
00170
00171 Thread::Run( * reinterpret_cast<Thread * >( threadObject ) ) ;
00172
00173 return 0 ;
00174
00175 }
00176
00177 }
00178
00179
00180
00181 #ifdef CEYLAN_USES_PTHREAD_H
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192 struct Mutex::SystemSpecificMutexType
00193 {
00194 pthread_mutex_t _mutex ;
00195 } ;
00196
00197 #endif // CEYLAN_USES_PTHREAD_H
00198
00199
00200
00201
00202
00203 Thread::Thread() :
00204 Runnable( "Anonymous thread" ),
00205 _id( 0 ),
00206 _attr( 0 ),
00207 _terminated( false ),
00208 _clean ( false ),
00209 _running ( false ),
00210 _mustStop ( false )
00211 {
00212
00213 #ifdef CEYLAN_USES_PTHREAD_H
00214
00215 #if CEYLAN_DEBUG_THREADS
00216 LogPlug::debug( "Thread anonymous constructor: "
00217 "creation of an unnamed thread." ) ;
00218 #endif // CEYLAN_DEBUG_THREADS
00219
00220 _id = new SystemSpecificThreadIdentifier ;
00221 _attr = new SystemSpecificThreadAttribute ;
00222
00223 #else // CEYLAN_USES_PTHREAD_H
00224
00225 throw FeatureNotAvailableException( "Thread anonymous constructor: "
00226 "multithreading feature is not available" ) ;
00227
00228 #endif // CEYLAN_USES_PTHREAD_H
00229
00230 }
00231
00232
00233
00234 Thread::Thread( const string & name ) :
00235 Runnable( name ),
00236 _id( 0 ),
00237 _attr( 0 ),
00238 _terminated( false ),
00239 _clean ( false ),
00240 _running ( false ),
00241 _mustStop ( false )
00242 {
00243
00244 #ifdef CEYLAN_USES_PTHREAD_H
00245
00246 #if CEYLAN_DEBUG_THREADS
00247 LogPlug::debug( "Thread constructor: "
00248 "creation of a thread named '" + name + "'." ) ;
00249 #endif // CEYLAN_DEBUG_THREADS
00250
00251 _id = new SystemSpecificThreadIdentifier ;
00252 _attr = new SystemSpecificThreadAttribute ;
00253
00254 #else // CEYLAN_USES_PTHREAD_H
00255
00256 throw FeatureNotAvailableException( "Thread constructor for '"
00257 + name + "': multithreading feature is not available" ) ;
00258
00259 #endif // CEYLAN_USES_PTHREAD_H
00260
00261 }
00262
00263
00264
00265 Thread::~Thread() throw()
00266 {
00267
00268 #if CEYLAN_USES_THREADS
00269
00270 #if CEYLAN_DEBUG_THREADS
00271 LogPlug::debug( "Thread destructor: "
00272 "destruction of a thread named '" + getName() + "'." ) ;
00273 #endif // CEYLAN_DEBUG_THREADS
00274
00275 if ( isRunning() )
00276 cancel() ;
00277
00278 if ( *_Number > 0 )
00279 (*_Number)-- ;
00280
00281
00282
00283
00284
00285
00286
00287 if ( _id != 0 )
00288 {
00289 delete _id ;
00290 _id = 0 ;
00291 }
00292
00293 if ( _attr != 0 )
00294 {
00295 delete _attr ;
00296 _attr = 0 ;
00297 }
00298
00299 #endif // CEYLAN_USES_THREADS
00300
00301 }
00302
00303
00304
00305 void Thread::run()
00306 {
00307
00308 #ifdef CEYLAN_USES_PTHREAD_H
00309
00310 Sint32 error ;
00311
00312 #if CEYLAN_DEBUG_THREADS
00313 LogPlug::debug( "Thread::run: the '" + getName()
00314 + "' thread will run now." ) ;
00315 #endif // CEYLAN_DEBUG_THREADS
00316
00317 if ( ( error =::pthread_create(
00318 & _id->_thread,
00319 0,
00320 ::Run,
00321 dynamic_cast<void*>( this ) ) ) )
00322 {
00323 threadCreationFailed( error ) ;
00324 }
00325 else
00326 {
00327 (*_Number)++ ;
00328 }
00329
00330 #else // CEYLAN_USES_PTHREAD_H
00331
00332 throw RunnableException( "Thread::run: "
00333 "multithreading feature is not available" ) ;
00334
00335 #endif // CEYLAN_USES_PTHREAD_H
00336
00337 }
00338
00339
00340
00341
00342
00343
00344
00345 void Thread::askToStop()
00346 {
00347
00348 #if CEYLAN_DEBUG_THREADS
00349 LogPlug::debug( "Thread::askToStop: the '" + getName()
00350 + "' thread was asked to stop." ) ;
00351 #endif // CEYLAN_DEBUG_THREADS
00352
00353 _mustStop = true ;
00354
00355 }
00356
00357
00358
00359 Thread::SystemSpecificThreadIdentifier & Thread::id() const
00360 {
00361
00362 return *_id ;
00363
00364 }
00365
00366
00367
00368 bool Thread::isClean() const
00369 {
00370
00371 return _clean.getValue() ;
00372
00373 }
00374
00375
00376
00377 bool Thread::isRunning() const
00378 {
00379
00380 return _running.getValue() ;
00381
00382 }
00383
00384
00385
00386 bool Thread::hasTerminated() const
00387 {
00388
00389 return _terminated ;
00390
00391 }
00392
00393
00394
00395 bool Thread::stopDemanded() const
00396 {
00397
00398 return _mustStop ;
00399
00400 }
00401
00402
00403
00404 void Thread::waitUntilOver()
00405 {
00406
00407 #ifdef CEYLAN_USES_PTHREAD_H
00408
00409 #if CEYLAN_DEBUG_THREADS
00410 LogPlug::debug( "Thread::waitUntilOver: "
00411 "the current thread is suspended until the '" + getName()
00412 + "' thread is actually stopped." ) ;
00413 #endif // CEYLAN_DEBUG_THREADS
00414
00415
00416 void * threadReturn = 0 ;
00417 ::pthread_join( _id->_thread, & threadReturn ) ;
00418
00419 #endif // CEYLAN_USES_PTHREAD_H
00420
00421 }
00422
00423
00424
00425 const string Thread::toString( Ceylan::VerbosityLevels level ) const
00426 {
00427
00428 string res = "Thread whose Thread ID is " ;
00429
00430 #ifdef CEYLAN_USES_PTHREAD_H
00431
00432 res += Ceylan::toString( _id->_thread ) ;
00433
00434 #endif // CEYLAN_USES_PTHREAD_H
00435
00436
00437 if ( level == Ceylan::low )
00438 return res ;
00439
00440
00441 std::list<string> stateList ;
00442
00443 if ( _terminated )
00444 stateList.push_back( "It is terminated" ) ;
00445 else
00446 stateList.push_back( "It is not terminated" ) ;
00447
00448 if ( _clean )
00449 stateList.push_back( "It has been cleaned up" ) ;
00450 else
00451 stateList.push_back( "It has not been cleaned up" ) ;
00452
00453 if ( _running )
00454 stateList.push_back( "It is running" ) ;
00455 else
00456 stateList.push_back( "It is not running" ) ;
00457
00458 if ( _mustStop )
00459 stateList.push_back( "It has been requested to stop" ) ;
00460 else
00461 stateList.push_back( "It has not been requested to stop" ) ;
00462
00463
00464 res += Ceylan::formatStringList( stateList ) ;
00465
00466 if ( level == Ceylan::medium )
00467 return res ;
00468
00469 if ( _Number != 0 )
00470 res += "There are currently a total of "
00471 + Ceylan::toString( *_Number ) + " thread objects" ;
00472 else
00473 res += "No thread object currently existing" ;
00474
00475 return res ;
00476
00477 }
00478
00479
00480
00481
00482
00483
00484
00485 Ceylan::System::ThreadCount Thread::GetNumberOfThreads()
00486 {
00487
00488 if ( _Number != 0 )
00489 return *_Number ;
00490 else
00491 return 0 ;
00492
00493 }
00494
00495
00496
00497 void Thread::Sleep( System::Second seconds, System::Microsecond microseconds )
00498 {
00499
00500 #if CEYLAN_DEBUG_THREADS
00501 LogPlug::debug( "Thread::Sleep: current thread will be sleeping for "
00502 + Ceylan::toString( seconds ) + " second(s) and "
00503 + Ceylan::toString( microseconds ) + " microsecond(s)." ) ;
00504 #endif // CEYLAN_DEBUG_THREADS
00505
00506 try
00507 {
00508 System::basicSleep( seconds,
00509 1000 * microseconds ) ;
00510 }
00511 catch( const SystemException & e )
00512 {
00513 throw ThreadException( "Thread::Sleep failed: "
00514 + e.toString() ) ;
00515 }
00516
00517 }
00518
00519
00520
00521 void Thread::Run( Thread & thread )
00522 {
00523
00524 #ifdef CEYLAN_USES_PTHREAD_H
00525
00526 thread.setRunning( true ) ;
00527 ::pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, 0 ) ;
00528
00529 #if CEYLAN_DEBUG_THREADS
00530 LogPlug::debug( "Thread::Run: the '" + thread.getName()
00531 + "' thread is about to start." ) ;
00532 #endif // CEYLAN_DEBUG_THREADS
00533
00534
00535 thread.start() ;
00536
00537 thread.setRunning( false ) ;
00538
00539 thread.cleanup() ;
00540
00541
00542 #if CEYLAN_DEBUG_THREADS
00543 LogPlug::debug( "Thread::Run: the '" + thread.getName()
00544 + "' thread has finished cleanup." ) ;
00545 #endif // CEYLAN_DEBUG_THREADS
00546
00547
00548 #endif // CEYLAN_USES_PTHREAD_H
00549
00550 }
00551
00552
00553
00554
00555
00556
00557
00558 Thread::Waiter::Waiter() :
00559 Mutex(),
00560 _condition()
00561 {
00562
00563 #ifdef CEYLAN_USES_PTHREAD_H
00564
00565 #if CEYLAN_DEBUG_THREADS
00566 LogPlug::debug( "Thread::Waiter constructor: "
00567 "creation of a Waiter mutex." ) ;
00568 #endif // CEYLAN_DEBUG_THREADS
00569
00570 ::pthread_cond_init( & _condition->_threadCondition,
00571 0 ) ;
00572
00573 #else
00574
00575 throw FeatureNotAvailableException( "Thread::Waiter constructor: "
00576 "multithreading feature not available" ) ;
00577
00578 #endif // CEYLAN_USES_PTHREAD_H
00579
00580 }
00581
00582
00583
00584 Thread::Waiter::~Waiter() throw()
00585 {
00586
00587 #ifdef CEYLAN_USES_PTHREAD_H
00588
00589
00590 #if CEYLAN_DEBUG_THREADS
00591 LogPlug::debug( "Thread::Waiter constructor: "
00592 "destruction of a Waiter mutex." ) ;
00593 #endif // CEYLAN_DEBUG_THREADS
00594
00595
00596 if ( ::pthread_cond_destroy( & _condition->_threadCondition ) )
00597 {
00598 LogPlug::warning( "Thread::Waiter destructor: "
00599 "some threads are currently waiting on condition." ) ;
00600 }
00601
00602 #endif // CEYLAN_USES_PTHREAD_H
00603
00604 }
00605
00606
00607
00608 bool Thread::Waiter::wait( System::Second seconds )
00609 {
00610
00611 bool ret = true ;
00612
00613 #ifdef CEYLAN_USES_PTHREAD_H
00614
00615
00616 #if CEYLAN_DEBUG_THREADS
00617 LogPlug::debug( "Thread::Waiter::wait: waiter mutex will wait for "
00618 + Ceylan::toString( seconds ) + " second(s)." ) ;
00619 #endif // CEYLAN_DEBUG_THREADS
00620
00621
00622 if ( seconds == 0 )
00623 {
00624
00625 lock() ;
00626
00627 ::pthread_cond_wait( & _condition->_threadCondition,
00628 & getMutexReference()._mutex ) ;
00629
00630 unlock() ;
00631
00632 }
00633 else
00634 {
00635
00636 #if CEYLAN_DEBUG_THREADS
00637 LogPlug::debug( "Thread::Waiter::wait: locking waiting mutex." ) ;
00638 #endif // CEYLAN_DEBUG_THREADS
00639
00640 lock() ;
00641
00642 timeval now ;
00643 timespec timeout ;
00644 ::gettimeofday( & now, 0 ) ;
00645 timeout.tv_sec = now.tv_sec + seconds ;
00646 timeout.tv_nsec = now.tv_usec * 1000 ;
00647
00648
00649 #if CEYLAN_DEBUG_THREADS
00650 LogPlug::debug( "Thread::Waiter::wait: "
00651 "just before waiting condition variable..." ) ;
00652 #endif // CEYLAN_DEBUG_THREADS
00653
00654
00655 ret =::pthread_cond_timedwait(
00656 & _condition->_threadCondition,
00657 & getMutexReference()._mutex, & timeout ) == ETIMEDOUT ;
00658
00659
00660 #if CEYLAN_DEBUG_THREADS
00661 LogPlug::debug( "Thread::Waiter::wait: "
00662 "... condition variable signaled!" ) ;
00663 #endif // CEYLAN_DEBUG_THREADS
00664
00665 unlock() ;
00666
00667
00668 #if CEYLAN_DEBUG_THREADS
00669 LogPlug::debug( "Thread::Waiter::wait: waiting mutex unlocked." ) ;
00670 #endif // CEYLAN_DEBUG_THREADS
00671
00672 }
00673
00674 #endif // CEYLAN_USES_PTHREAD_H
00675
00676 return ret ;
00677
00678 }
00679
00680
00681
00682 bool Thread::Waiter::signal()
00683 {
00684
00685 #ifdef CEYLAN_USES_PTHREAD_H
00686
00687 lock() ;
00688
00689 #if CEYLAN_DEBUG_THREADS
00690 LogPlug::debug( "Thread::Waiter::signal: waiter mutex is signaled." ) ;
00691 #endif // CEYLAN_DEBUG_THREADS
00692
00693
00694 bool ret = ( ::pthread_cond_signal(
00695 & _condition->_threadCondition ) == 0 ) ;
00696
00697 unlock() ;
00698
00699 return ret ;
00700
00701 #else // CEYLAN_USES_PTHREAD_H
00702
00703 return true ;
00704
00705 #endif // CEYLAN_USES_PTHREAD_H
00706
00707 }
00708
00709
00710
00711 bool Thread::Waiter::broadcast()
00712 {
00713
00714 #ifdef CEYLAN_USES_PTHREAD_H
00715
00716 lock() ;
00717
00718 #if CEYLAN_DEBUG_THREADS
00719 LogPlug::debug( "Thread::Waiter::broadcast: waiter mutex is broadcasted" ) ;
00720 #endif // CEYLAN_DEBUG_THREADS
00721
00722 bool ret = ( ::pthread_cond_broadcast(
00723 & _condition->_threadCondition ) == 0 ) ;
00724
00725 unlock() ;
00726
00727 return ret ;
00728
00729 #else // CEYLAN_USES_PTHREAD_H
00730
00731 return true ;
00732
00733 #endif // CEYLAN_USES_PTHREAD_H
00734
00735 }
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745 void Thread::cancel()
00746 {
00747
00748 #ifdef CEYLAN_USES_PTHREAD_H
00749
00750 #if CEYLAN_DEBUG_THREADS
00751 LogPlug::debug( "Thread::cancel: cancelling thread '" + getName()
00752 + "'." ) ;
00753 #endif // CEYLAN_DEBUG_THREADS
00754
00755 _terminated = true ;
00756 _running = false ;
00757 ::pthread_cancel( _id->_thread ) ;
00758
00759 #endif // CEYLAN_USES_PTHREAD_H
00760
00761 }
00762
00763
00764
00765 void Thread::cleanup()
00766 {
00767
00768 #if CEYLAN_DEBUG_THREADS
00769 LogPlug::debug( "Thread::cleanup called." ) ;
00770 #endif // CEYLAN_DEBUG_THREADS
00771
00772 _clean = true ;
00773
00774 }
00775
00776
00777
00778 void Thread::setRunning( bool newRunningStatus )
00779 {
00780
00781 #if CEYLAN_DEBUG_THREADS
00782 LogPlug::debug( "Thread::setRunning: set to "
00783 + Ceylan::toString( newRunningStatus ) + "." ) ;
00784 #endif // CEYLAN_DEBUG_THREADS
00785
00786 _running = newRunningStatus ;
00787
00788 }
00789
00790
00791
00792 void Thread::threadCreationFailed( ErrorCode error )
00793 {
00794
00795 throw ThreadException( "Thread::threadCreationFailed: "
00796 "Thread::run call failed: " + System::explainError() ) ;
00797
00798 }
00799