summaryrefslogtreecommitdiff
path: root/libcult/cult/sched
diff options
context:
space:
mode:
Diffstat (limited to 'libcult/cult/sched')
-rw-r--r--libcult/cult/sched/condition.cxx49
-rw-r--r--libcult/cult/sched/condition.hxx42
-rw-r--r--libcult/cult/sched/exception.hxx30
-rw-r--r--libcult/cult/sched/lock.cxx13
-rw-r--r--libcult/cult/sched/lock.hxx58
-rw-r--r--libcult/cult/sched/mutex.cxx54
-rw-r--r--libcult/cult/sched/mutex.hxx41
-rw-r--r--libcult/cult/sched/spin.cxx28
-rw-r--r--libcult/cult/sched/spin.hxx41
-rw-r--r--libcult/cult/sched/spin.ixx43
-rw-r--r--libcult/cult/sched/thread.cxx211
-rw-r--r--libcult/cult/sched/thread.hxx86
12 files changed, 696 insertions, 0 deletions
diff --git a/libcult/cult/sched/condition.cxx b/libcult/cult/sched/condition.cxx
new file mode 100644
index 0000000..5f547c8
--- /dev/null
+++ b/libcult/cult/sched/condition.cxx
@@ -0,0 +1,49 @@
+// file : cult/sched/condition.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/condition.hxx>
+#include <cult/sched/exception.hxx>
+
+namespace Cult
+{
+ namespace Sched
+ {
+ Condition::
+ ~Condition ()
+ {
+ if (Int e = pthread_cond_destroy (&cond_))
+ throw Implementation (e);
+ }
+
+ Condition::
+ Condition (Mutex& mutex)
+ : mutex_ (mutex)
+ {
+ if (Int e = pthread_cond_init (&cond_, 0))
+ throw Implementation (e);
+ }
+
+ Void Condition::
+ signal ()
+ {
+ if (Int e = pthread_cond_signal (&cond_))
+ throw Implementation (e);
+ }
+
+ Void Condition::
+ broadcast ()
+ {
+ if (Int e = pthread_cond_broadcast (&cond_))
+ throw Implementation (e);
+ }
+
+ Void Condition::
+ wait ()
+ {
+ if (Int e = pthread_cond_wait (&cond_, &mutex_.mutex_))
+ throw Implementation (e);
+ }
+ }
+}
diff --git a/libcult/cult/sched/condition.hxx b/libcult/cult/sched/condition.hxx
new file mode 100644
index 0000000..b1a0f30
--- /dev/null
+++ b/libcult/cult/sched/condition.hxx
@@ -0,0 +1,42 @@
+// file : cult/sched/condition.hxx
+// author : Boris Kolpackov <boris@kolpackov.net>
+// copyright : Copyright (c) 2005-2010 Boris Kolpackov
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+#ifndef CULT_SCHED_CONDITION_HXX
+#define CULT_SCHED_CONDITION_HXX
+
+#include <cult/types/fundamental.hxx>
+
+#include <cult/sched/mutex.hxx>
+
+#include <pthread.h>
+
+namespace Cult
+{
+ namespace Sched
+ {
+ class Condition: public NonCopyable
+ {
+ public:
+ ~Condition ();
+
+ Condition (Mutex& mutex);
+
+ Void
+ signal ();
+
+ Void
+ broadcast ();
+
+ Void
+ wait ();
+
+ private:
+ Mutex& mutex_;
+ pthread_cond_t cond_;
+ };
+ }
+}
+
+#endif // CULT_SCHED_CONDITION_HXX
diff --git a/libcult/cult/sched/exception.hxx b/libcult/cult/sched/exception.hxx
new file mode 100644
index 0000000..3fa6e5f
--- /dev/null
+++ b/libcult/cult/sched/exception.hxx
@@ -0,0 +1,30 @@
+// file : cult/sched/exception.hxx
+// author : Boris Kolpackov <boris@kolpackov.net>
+// copyright : Copyright (c) 2005-2010 Boris Kolpackov
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+#ifndef CULT_SCHED_EXCEPTION_HXX
+#define CULT_SCHED_EXCEPTION_HXX
+
+#include <cult/types/fundamental.hxx>
+
+#include <cult/eh/exception.hxx>
+#include <cult/os/exception.hxx>
+
+namespace Cult
+{
+ namespace Sched
+ {
+ struct Exception: virtual EH::Exception {};
+
+ struct Implementation: virtual Exception, virtual OS::Exception
+ {
+ Implementation (Int code) throw ()
+ : OS::Exception (code)
+ {
+ }
+ };
+ }
+}
+
+#endif // CULT_SCHED_EXCEPTION_HXX
diff --git a/libcult/cult/sched/lock.cxx b/libcult/cult/sched/lock.cxx
new file mode 100644
index 0000000..853d9b0
--- /dev/null
+++ b/libcult/cult/sched/lock.cxx
@@ -0,0 +1,13 @@
+// file : cult/sched/lock.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/lock.hxx>
+
+namespace Cult
+{
+ namespace Sched
+ {
+ }
+}
diff --git a/libcult/cult/sched/lock.hxx b/libcult/cult/sched/lock.hxx
new file mode 100644
index 0000000..1ecf3fb
--- /dev/null
+++ b/libcult/cult/sched/lock.hxx
@@ -0,0 +1,58 @@
+// file : cult/sched/lock.hxx
+// author : Boris Kolpackov <boris@kolpackov.net>
+// copyright : Copyright (c) 2005-2010 Boris Kolpackov
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+#ifndef CULT_SCHED_LOCK_HXX
+#define CULT_SCHED_LOCK_HXX
+
+#include <cult/types/fundamental.hxx>
+
+namespace Cult
+{
+ namespace Sched
+ {
+ class Lock: public NonCopyable
+ {
+ public:
+ ~Lock ()
+ {
+ unlock ();
+ }
+
+ template <typename X>
+ Lock (X& x)
+ : x_ (reinterpret_cast<Void*>(&x)),
+ unlock_ (&unlock<X>),
+ locked_ (true)
+ {
+ x.lock ();
+ }
+
+ Void
+ unlock ()
+ {
+ if (locked_)
+ {
+ unlock_ (x_);
+ locked_ = false;
+ }
+ }
+
+ private:
+ template <typename X>
+ static Void
+ unlock (Void* p)
+ {
+ reinterpret_cast<X*> (p)->unlock ();
+ }
+
+ private:
+ Void* x_;
+ Void (*unlock_) (Void*);
+ Boolean locked_;
+ };
+ }
+}
+
+#endif // CULT_SCHED_LOCK_HXX
diff --git a/libcult/cult/sched/mutex.cxx b/libcult/cult/sched/mutex.cxx
new file mode 100644
index 0000000..9667a67
--- /dev/null
+++ b/libcult/cult/sched/mutex.cxx
@@ -0,0 +1,54 @@
+// file : cult/sched/mutex.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/mutex.hxx>
+#include <cult/sched/exception.hxx>
+
+namespace Cult
+{
+ namespace Sched
+ {
+ Mutex::
+ ~Mutex ()
+ {
+ if (Int e = pthread_mutex_destroy (&mutex_))
+ throw Implementation (e);
+ }
+
+ Mutex::
+ Mutex ()
+ {
+ if (Int e = pthread_mutex_init (&mutex_, 0))
+ throw Implementation (e);
+ }
+
+ Void Mutex::
+ lock ()
+ {
+ if (Int e = pthread_mutex_lock (&mutex_))
+ throw Implementation (e);
+ }
+
+ Boolean Mutex::
+ try_lock ()
+ {
+ Int e (pthread_mutex_trylock (&mutex_));
+
+ switch (e)
+ {
+ case 0: return true;
+ case EBUSY: return false;
+ default: throw Implementation (e);
+ }
+ }
+
+ Void Mutex::
+ unlock ()
+ {
+ if (Int e = pthread_mutex_unlock (&mutex_))
+ throw Implementation (e);
+ }
+ }
+}
diff --git a/libcult/cult/sched/mutex.hxx b/libcult/cult/sched/mutex.hxx
new file mode 100644
index 0000000..0c6daee
--- /dev/null
+++ b/libcult/cult/sched/mutex.hxx
@@ -0,0 +1,41 @@
+// file : cult/sched/mutex.hxx
+// author : Boris Kolpackov <boris@kolpackov.net>
+// copyright : Copyright (c) 2005-2010 Boris Kolpackov
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+#ifndef CULT_SCHED_MUTEX_HXX
+#define CULT_SCHED_MUTEX_HXX
+
+#include <cult/types/fundamental.hxx>
+
+#include <pthread.h>
+
+namespace Cult
+{
+ namespace Sched
+ {
+ class Mutex: public NonCopyable
+ {
+ public:
+ ~Mutex ();
+
+ Mutex ();
+
+ Void
+ lock ();
+
+ Boolean
+ try_lock ();
+
+ Void
+ unlock ();
+
+ private:
+ friend class Condition;
+
+ pthread_mutex_t mutex_;
+ };
+ }
+}
+
+#endif // CULT_SCHED_MUTEX_HXX
diff --git a/libcult/cult/sched/spin.cxx b/libcult/cult/sched/spin.cxx
new file mode 100644
index 0000000..54df7ce
--- /dev/null
+++ b/libcult/cult/sched/spin.cxx
@@ -0,0 +1,28 @@
+// file : cult/sched/spin.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/spin.hxx>
+#include <cult/sched/exception.hxx>
+
+namespace Cult
+{
+ namespace Sched
+ {
+ Spin::
+ ~Spin ()
+ {
+ if (Int e = pthread_spin_destroy (&spin_))
+ throw Implementation (e);
+ }
+
+ Spin::
+ Spin ()
+ {
+ if (Int e = pthread_spin_init (&spin_, PTHREAD_PROCESS_PRIVATE))
+ throw Implementation (e);
+ }
+ }
+}
+
diff --git a/libcult/cult/sched/spin.hxx b/libcult/cult/sched/spin.hxx
new file mode 100644
index 0000000..c32e836
--- /dev/null
+++ b/libcult/cult/sched/spin.hxx
@@ -0,0 +1,41 @@
+// file : cult/sched/spin.hxx
+// author : Boris Kolpackov <boris@kolpackov.net>
+// copyright : Copyright (c) 2005-2010 Boris Kolpackov
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+#ifndef CULT_SCHED_SPIN_HXX
+#define CULT_SCHED_SPIN_HXX
+
+#include <cult/types/fundamental.hxx>
+
+#include <pthread.h>
+
+namespace Cult
+{
+ namespace Sched
+ {
+ class Spin: public NonCopyable
+ {
+ public:
+ ~Spin ();
+
+ Spin ();
+
+ Void
+ lock ();
+
+ Boolean
+ try_lock ();
+
+ Void
+ unlock ();
+
+ private:
+ pthread_spinlock_t spin_;
+ };
+ }
+}
+
+#include <cult/sched/spin.ixx>
+
+#endif // CULT_SCHED_SPIN_HXX
diff --git a/libcult/cult/sched/spin.ixx b/libcult/cult/sched/spin.ixx
new file mode 100644
index 0000000..2accdde
--- /dev/null
+++ b/libcult/cult/sched/spin.ixx
@@ -0,0 +1,43 @@
+// file : cult/sched/spin.ixx
+// 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/exception.hxx>
+
+namespace Cult
+{
+ namespace Sched
+ {
+ inline
+ Void Spin::
+ lock ()
+ {
+ if (Int e = pthread_spin_lock (&spin_))
+ throw Implementation (e);
+ }
+
+ inline
+ Boolean Spin::
+ try_lock ()
+ {
+ Int e (pthread_spin_trylock (&spin_));
+
+ switch (e)
+ {
+ case 0: return true;
+ case EBUSY: return false;
+ default: throw Implementation (e);
+ }
+ }
+
+ inline
+ Void Spin::
+ unlock ()
+ {
+ if (Int e = pthread_spin_unlock (&spin_))
+ throw Implementation (e);
+ }
+ }
+}
+
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);
+ }
+ }
+ }
+}
diff --git a/libcult/cult/sched/thread.hxx b/libcult/cult/sched/thread.hxx
new file mode 100644
index 0000000..49d6225
--- /dev/null
+++ b/libcult/cult/sched/thread.hxx
@@ -0,0 +1,86 @@
+// file : cult/sched/thread.hxx
+// author : Boris Kolpackov <boris@kolpackov.net>
+// copyright : Copyright (c) 2005-2010 Boris Kolpackov
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+#ifndef CULT_SCHED_THREAD_HXX
+#define CULT_SCHED_THREAD_HXX
+
+#include <cult/types/fundamental.hxx>
+#include <cult/types/shptr.hxx>
+
+#include <cult/sched/mutex.hxx>
+#include <cult/sched/exception.hxx>
+
+#include <cult/mm/new.hxx>
+
+#include <pthread.h>
+
+namespace Cult
+{
+ namespace Sched
+ {
+ // Instantiating an automatic variable of type Thread results
+ // in undefined behavior (read core dump).
+ //
+ class Thread: public MM::ServiceAwareObject
+ {
+ public:
+ struct Exception: virtual Sched::Exception {};
+
+ public:
+ virtual
+ ~Thread ();
+
+ Thread (Void* (*StartRoutine) (Void*), Void* arg = 0);
+
+ // Adopt an existing thread. Adoption of a detached thread
+ // results in undefined behavior. Adoption of an already
+ // adopted thread results in Adopted exception.
+ //
+
+ struct Adopted: virtual Exception {};
+
+ Thread ();
+
+ public:
+ // Joining an already joined thread results in Joined exception.
+ //
+
+ struct Joined: virtual Exception {};
+
+ //@@ Need to work out the cancelled case.
+ //
+ Void*
+ join ();
+
+ Void
+ cancel ();
+
+ public:
+ static Void
+ exit (Void* ret);
+
+ // self() may not be called in TSD destructors. Call to self() from
+ // a foreign thread (i.e., one that is neither native nor adopted)
+ // results in Foreign exception.
+ //
+
+ struct Foreign: virtual Exception {};
+
+ static Shptr<Thread>
+ self ();
+
+ static Void
+ test_cancel ();
+
+ private:
+ pthread_t id_;
+
+ Boolean detached_;
+ Mutex mutex_;
+ };
+ }
+}
+
+#endif // CULT_SCHED_THREAD_HXX