diff options
Diffstat (limited to 'libcult/cult/sched/thread.cxx')
-rw-r--r-- | libcult/cult/sched/thread.cxx | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/libcult/cult/sched/thread.cxx b/libcult/cult/sched/thread.cxx new file mode 100644 index 0000000..89368b6 --- /dev/null +++ b/libcult/cult/sched/thread.cxx @@ -0,0 +1,211 @@ +// file : cult/sched/thread.cxx +// author : Boris Kolpackov <boris@kolpackov.net> +// copyright : Copyright (c) 2005-2010 Boris Kolpackov +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include <cult/sched/thread.hxx> +#include <cult/sched/lock.hxx> +#include <cult/sched/exception.hxx> + +#include <cult/mm/counter.hxx> // MM::inc_ref + +#include <cult/trace/stream.hxx> + +namespace Cult +{ + namespace Sched + { + namespace + { + Trace::Stream tout ("Cult::Sched::Thread", 7); + } + + namespace Bits + { + typedef Void* (*Routine) (Void*); + + struct StartData + { + StartData (Shptr<Thread> const& thread, Routine routine, void* arg) + : thread_ (thread), routine_ (routine), arg_ (arg) + { + } + + ~StartData () + { + tout << 8 << "start data is being destroyed."; + } + + Shptr<Thread> thread_; + Routine routine_; + Void* arg_; + }; + + static pthread_key_t key; + static pthread_once_t key_once = PTHREAD_ONCE_INIT; + + extern "C" Void + cult_thread_dtor (Void* p) + { + // Exception in this function will result in the call + // to std::terminate(). + // + + tout << "cult_thread_dtor is being executed."; + + Shptr<Thread> self (reinterpret_cast<Thread*> (p)); + } + + extern "C" Void + cult_thread_make_key () + { + if (Int e = pthread_key_create (&key, &cult_thread_dtor)) + throw Implementation (e); + } + + extern "C" Void* + cult_thread_trampoline (Void* arg) + { + // Any failure in this function will result in the call + // to std::terminate(). + // + + Routine routine; + + { + Shptr<StartData> data (reinterpret_cast<StartData*> (arg)); + + Thread* p (data->thread_.get ()); + + if (Int e = pthread_setspecific (key, p)) + throw Implementation (e); + else + MM::inc_ref (p); + + routine = data->routine_; + arg = data->arg_; + } + + return routine (arg); + } + } + + Thread:: + Thread (Void* (*routine) (Void*), Void* arg) + : detached_ (false) + { + using Bits::StartData; + + tout << "thread is being constructed."; + + pthread_once (&Bits::key_once, &Bits::cult_thread_make_key); + + Shptr<Thread> self (MM::inc_ref (this)); + + Shptr<StartData> data (new StartData (self, routine, arg)); + + if (Int e = pthread_create (&id_, + 0, + &Bits::cult_thread_trampoline, + data.get ())) + { + throw Implementation (e); + } + else + { + // If pthread_create did not fail then thread_trampoline + // will release the data. + // + data.release (); + } + } + + Thread:: + Thread () + : id_ (pthread_self ()), detached_ (false) //@@ We can't be sure + // the it is detached. + { + tout << "thread is being adopted."; + + pthread_once (&Bits::key_once, &Bits::cult_thread_make_key); + + if (pthread_getspecific (Bits::key) != 0) + throw Adopted (); + + Shptr<Thread> self (MM::inc_ref (this)); + + if(Int e = pthread_setspecific (Bits::key, this)) + { + throw Implementation (e); + } + else + { + // TSD slot has the reference now. + // + self.release (); + } + } + + Void* Thread:: + join () + { + Lock lock (mutex_); + + if (detached_) + throw Joined (); + + Void* r; + + if (Int e = pthread_join (id_, &r)) + throw Implementation (e); + + detached_ = true; + + return r; + } + + Void Thread:: + cancel () + { + if (Int e = pthread_cancel (id_)) + throw Implementation (e); + } + + Void Thread:: + exit (Void* ret) + { + pthread_exit (ret); + } + + Shptr<Thread> Thread:: + self () + { + Thread* p (reinterpret_cast<Thread*> (pthread_getspecific (Bits::key))); + + if (p != 0) + return Shptr<Thread> (MM::inc_ref (p)); + else + throw Foreign (); + } + + Void Thread:: + test_cancel () + { + pthread_testcancel (); + } + + Thread:: + ~Thread () + { + tout << "thread is being destroyed."; + + Lock lock (mutex_); + + if (!detached_) + { + if (Int e = pthread_detach (id_)) + throw Implementation (e); + } + } + } +} |