24 #include <core/threading/thread.h> 25 #include <core/threading/mutex.h> 26 #include <core/threading/mutex_locker.h> 27 #include <core/threading/barrier.h> 28 #include <core/threading/wait_condition.h> 29 #include <core/threading/read_write_lock.h> 30 #include <core/threading/thread_finalizer.h> 31 #include <core/threading/thread_notification_listener.h> 32 #include <core/exceptions/software.h> 33 #include <core/exceptions/system.h> 34 #include <core/utils/lock_list.h> 36 #if defined(__gnu_linux__) && ! defined(_GNU_SOURCE) 188 pthread_mutex_t Thread::__thread_key_mutex = PTHREAD_MUTEX_INITIALIZER;
192 pthread_key_t Thread::THREAD_KEY = PTHREAD_KEYS_MAX;
194 #define MAIN_THREAD_NAME "__MainThread__" 219 __constructor(name, op_mode);
244 Thread::__constructor(
const char *name,
OpMode op_mode)
248 __prepfin_conc_loop =
false;
249 __coalesce_wakeups =
false;
251 __name = strdup(name);
255 __sleep_mutex =
new Mutex();
257 __waiting_for_wakeup =
true;
259 __sleep_condition = NULL;
260 __sleep_mutex = NULL;
261 __waiting_for_wakeup =
false;
269 __delete_on_exit =
false;
270 __prepfin_hold =
false;
271 __pending_wakeups = 0;
277 __loop_done_mutex =
new Mutex();
281 __prepfin_hold_mutex =
new Mutex();
282 __prepfin_hold_waitcond =
new WaitCondition(__prepfin_hold_mutex);
283 __startup_barrier =
new Barrier(2);
293 delete __sleep_condition;
294 delete __sleep_mutex;
297 delete __notification_listeners;
299 delete __startup_barrier;
300 delete __prepfin_hold_mutex;
301 delete __prepfin_hold_waitcond;
302 delete __loop_done_waitcond;
303 delete __loop_done_mutex;
317 throw Exception(
"You may not use copy constructor of class Thread");
326 Thread::operator=(
const Thread &t)
328 throw Exception(
"You may not use assignment operator of class Thread");
391 __prepfin_hold_mutex->
lock();
392 while (__prepfin_hold) {
393 __prepfin_hold_waitcond->
wait();
395 if (! __prepfin_conc_loop) {
401 if (! __prepfin_conc_loop) {
405 __prepfin_hold_mutex->
unlock();
515 throw Exception(
"You cannot start the same thread twice!");
523 if ( (err = pthread_create(&__thread_id, NULL, Thread::entry,
this)) != 0) {
525 throw Exception(
"Could not start thread", err);
527 #if defined(_GNU_SOURCE) && defined(__GLIBC__) && ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 12) || __GLIBC__ > 2) 529 strncpy(tmpname, __name, 15);
531 pthread_setname_np(__thread_id, tmpname);
534 if (__wait) __startup_barrier->
wait();
539 Thread::lock_sleep_mutex()
542 __sleep_mutex->
lock();
553 Thread::entry(
void *pthis)
561 set_tsd_thread_instance(t);
564 t->lock_sleep_mutex();
567 t->notify_of_startup();
570 if (t->__wait) t->__startup_barrier->
wait();
578 if ( t->__detached ) {
581 t->__started =
false;
596 if ( __delete_on_exit ) {
600 __waiting_for_wakeup =
false;
614 pthread_join(__thread_id, &dont_care);
617 if ( __sleep_mutex != NULL ) {
643 pthread_detach(__thread_id);
653 if ( __started && ! __cancelled ) {
654 if ( pthread_cancel(__thread_id) == 0 ) {
655 __waiting_for_wakeup =
false;
670 pthread_kill(__thread_id, sig);
693 throw Exception(
"Cannot set thread opmode while running");
699 delete __sleep_condition;
700 delete __sleep_mutex;
701 __sleep_condition = NULL;
702 __sleep_mutex = NULL;
705 __sleep_mutex =
new Mutex();
729 __prepfin_conc_loop = concurrent;
745 __coalesce_wakeups = coalesce;
749 __coalesce_wakeups = coalesce;
764 va_start(va, format);
765 char *old_name = __name;
766 if (vasprintf(&__name, format, va) == -1) {
773 #if defined(_GNU_SOURCE) && defined(__GLIBC__) && ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 12) || __GLIBC__ > 2) 776 strncpy(tmpname, __name, 15);
778 pthread_setname_np(__thread_id, tmpname);
796 __prepfin_hold_mutex->
lock();
798 __prepfin_hold_mutex->
unlock();
799 throw Exception(
"Thread(%s)::set_prepfin_hold: prepare_finalize() has " 800 "been called already()", __name);
802 __prepfin_hold = hold;
804 __prepfin_hold_waitcond->
wake_all();
806 __prepfin_hold_mutex->
unlock();
881 return __waiting_for_wakeup;
891 pthread_testcancel();
919 return ( pthread_equal(__thread_id, thread.__thread_id) != 0 );
944 while (__pending_wakeups == 0) {
945 __waiting_for_wakeup =
true;
946 __sleep_condition->
wait();
948 __pending_wakeups -= 1;
963 __loop_done_mutex->
lock();
965 __loop_done_mutex->
unlock();
971 __sleep_mutex->
lock();
978 __sleep_mutex->
lock();
980 __sleep_mutex->
lock();
983 while (__pending_wakeups == 0) {
984 __waiting_for_wakeup =
true;
985 __sleep_condition->
wait();
987 __pending_wakeups -= 1;
1006 throw Exception(
"Thread(%s): wakeup() cannot be called if loop is running " 1007 "with barrier already", __name);
1010 if (__coalesce_wakeups) __pending_wakeups = 1;
1011 else __pending_wakeups += 1;
1012 if (__waiting_for_wakeup) {
1014 __waiting_for_wakeup =
false;
1031 if ( barrier == NULL ) {
1036 if ( ! __waiting_for_wakeup && __barrier) {
1037 throw Exception(
"Thread %s already running with barrier, cannot wakeup %i %p", __name,
1038 __waiting_for_wakeup, __barrier);
1041 __pending_wakeups += 1;
1042 __barrier = barrier;
1043 if (__waiting_for_wakeup) {
1045 __waiting_for_wakeup =
false;
1055 __loop_done_mutex->
lock();
1056 while (! __loop_done) {
1057 __loop_done_waitcond->
wait();
1059 __loop_done_mutex->
unlock();
1070 if ( __delete_on_exit ) {
1101 __delete_on_exit = del;
1113 return (__pending_wakeups > 0);
1140 __flags &= 0xFFFFFFFF ^ flag;
1172 __notification_listeners->push_back_locked(notification_listener);
1182 __notification_listeners->remove_locked(notification_listener);
1190 Thread::notify_of_startup()
1192 __notification_listeners->lock();
1194 while (i != __notification_listeners->end()) {
1195 if (! (*i)->thread_started(
this)) {
1196 i = __notification_listeners->erase(i);
1201 __notification_listeners->unlock();
1212 __notification_listeners->lock();
1214 while (i != __notification_listeners->end()) {
1215 if ( ! (*i)->thread_init_failed(
this) ) {
1216 i = __notification_listeners->erase(i);
1221 __notification_listeners->unlock();
1229 Thread::init_thread_key()
1231 pthread_mutex_lock(&__thread_key_mutex);
1232 if ( THREAD_KEY == PTHREAD_KEYS_MAX ) {
1235 if ( (err = pthread_key_create(&THREAD_KEY, NULL)) != 0 ) {
1236 if ( ENOMEM == err ) {
1238 "specific data (reference to thread)");
1240 throw Exception(
"Thread key for reference to thread could not be created", err);
1244 pthread_mutex_unlock(&__thread_key_mutex);
1254 Thread::set_tsd_thread_instance(
Thread *t)
1257 if ( (err = pthread_setspecific(THREAD_KEY, t)) != 0 ) {
1258 if ( ENOMEM == err ) {
1261 throw Exception(
"Could not set specific data (reference to thread), unknown reason");
1274 Thread *t =
new Thread(MAIN_THREAD_NAME, pthread_self());
1275 set_tsd_thread_instance(t);
1288 if ( strcmp(t->
name(), MAIN_THREAD_NAME) == 0 ) {
1291 throw Exception(
"Main thread can only be destroyed in main thread");
1304 return pthread_self();
1320 if ( THREAD_KEY == PTHREAD_KEYS_MAX ) {
1321 throw Exception(
"No thread has been initialized");
1323 return (
Thread *)pthread_getspecific(THREAD_KEY);
1336 if ( THREAD_KEY == PTHREAD_KEYS_MAX ) {
1339 return (
Thread *)pthread_getspecific(THREAD_KEY);
1352 int oldstate = PTHREAD_CANCEL_ENABLE;
1353 int newstate = PTHREAD_CANCEL_ENABLE;
1355 newstate = PTHREAD_CANCEL_DISABLE;
1358 pthread_setcancelstate(newstate, &oldstate);
1360 if ( old_state != NULL ) {
1361 if ( oldstate == PTHREAD_CANCEL_DISABLE ) {
bool operator==(const Thread &thread)
Check if two threads are the same.
Thread(const char *name)
Constructor.
void add_notification_listener(ThreadNotificationListener *notification_listener)
Add notification listener.
Wait until a given condition holds.
virtual void once()
Execute an action exactly once.
void unset_flag(uint32_t flag)
Unset flag.
bool finalize_prepared
True if prepare_finalize() has been called and was not stopped with a cancel_finalize(), false otherwise.
Fawkes library namespace.
void unlock()
Unlock the mutex.
virtual void wait()
Wait for other threads.
void wake_all()
Wake up all waiting threads.
virtual ~Thread()
Virtual destructor.
virtual void run()
Code to execute in the thread.
OpMode
Thread operation mode.
bool running() const
Check if the thread is running.
Thread notification listener interface.
void cancel_finalize()
Cancel finalization.
bool flagged_bad() const
Check if FLAG_BAD was set.
bool wakeup_pending()
Check if wakeups are pending.
thread cannot be cancelled
A NULL pointer was supplied where not allowed.
Thread class encapsulation of pthreads.
bool waiting() const
Check if thread is currently waiting for wakeup.
static void init_main()
Initialize Thread wrapper instance for main thread.
void set_prepfin_conc_loop(bool concurrent=true)
Set concurrent execution of prepare_finalize() and loop().
Mutex * loop_mutex
Mutex that is used to protect a call to loop().
virtual bool prepare_finalize_user()
Prepare finalization user implementation.
static void set_cancel_state(CancelState new_state, CancelState *old_state=0)
Set the cancel state of the current thread.
static Thread * current_thread_noexc()
Similar to current_thread, but does never throw an exception.
bool cancelled() const
Check if thread has been cancelled.
void wait_loop_done()
Wait for the current loop iteration to finish.
OpMode opmode() const
Get operation mode.
Mutex * loopinterrupt_antistarve_mutex
Mutex to avoid starvation when trying to lock loop_mutex.
void wakeup()
Wake up thread.
void set_name(const char *format,...)
Set name of thread.
Base class for exceptions in Fawkes.
static pthread_t current_thread_id()
Get the ID of the currently running thread.
static void destroy_main()
Destroy main thread wrapper instance.
virtual void finalize()
Finalize the thread.
bool started() const
Check if thread has been started.
bool prepare_finalize()
Prepare finalization.
operate in continuous mode (default)
void set_delete_on_exit(bool del)
Set whether the thread should be deleted on exit.
void set_opmode(OpMode op_mode)
Set operation mode.
static Thread * current_thread()
Get the Thread instance of the currently running thread.
void remove_notification_listener(ThreadNotificationListener *notification_listener)
Remove notification listener.
const char * name() const
Get name of thread.
void notify_of_failed_init()
Notify of failed init.
static const unsigned int FLAG_BAD
Standard thread flag: "thread is bad".
void set_coalesce_wakeups(bool coalesce=true)
Set wakeup coalescing.
bool try_lock()
Tries to lock the mutex.
void wait()
Wait for the condition forever.
void cancel()
Cancel a thread.
void kill(int sig)
Send signal to a thread.
void test_cancel()
Set cancellation point.
bool detached() const
Check if thread has been detached.
virtual void loop()
Code to execute in the thread.
void yield()
Yield the processor to another thread or process.
pthread_t thread_id() const
Get ID of thread.
Thread cannot be finalized.
void detach()
Detach the thread.
void join()
Join the thread.
void set_prepfin_hold(bool hold)
Hold prepare_finalize().
void lock()
Lock this mutex.
virtual void init()
Initialize the thread.
void set_flag(uint32_t flag)
Set flag for the thread.
operate in wait-for-wakeup mode
Mutex mutual exclusion lock.
void exit()
Exit the thread.
void stopby()
Shortly stop by at the mutex.
A barrier is a synchronization tool which blocks until a given number of threads have reached the bar...
System ran out of memory and desired operation could not be fulfilled.
void set_flags(uint32_t flags)
Set all flags in one go.
void start(bool wait=true)
Call this method to start the thread.