aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/mt
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/mt')
-rw-r--r--src/lib/mt/CMakeLists.txt24
-rw-r--r--src/lib/mt/CondVar.cpp91
-rw-r--r--src/lib/mt/CondVar.h225
-rw-r--r--src/lib/mt/Lock.cpp42
-rw-r--r--src/lib/mt/Lock.h49
-rw-r--r--src/lib/mt/Mutex.cpp58
-rw-r--r--src/lib/mt/Mutex.h79
-rw-r--r--src/lib/mt/Thread.cpp187
-rw-r--r--src/lib/mt/Thread.h210
-rw-r--r--src/lib/mt/XMT.cpp29
-rw-r--r--src/lib/mt/XMT.h30
-rw-r--r--src/lib/mt/XThread.h37
12 files changed, 1061 insertions, 0 deletions
diff --git a/src/lib/mt/CMakeLists.txt b/src/lib/mt/CMakeLists.txt
new file mode 100644
index 0000000..9ee5ea4
--- /dev/null
+++ b/src/lib/mt/CMakeLists.txt
@@ -0,0 +1,24 @@
+# barrier -- mouse and keyboard sharing utility
+# Copyright (C) 2012-2016 Symless Ltd.
+# Copyright (C) 2009 Nick Bolton
+#
+# This package is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# found in the file LICENSE that should have accompanied this file.
+#
+# This package is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+file(GLOB headers "*.h")
+file(GLOB sources "*.cpp")
+
+if (BARRIER_ADD_HEADERS)
+ list(APPEND sources ${headers})
+endif()
+
+add_library(mt STATIC ${sources})
diff --git a/src/lib/mt/CondVar.cpp b/src/lib/mt/CondVar.cpp
new file mode 100644
index 0000000..11318f9
--- /dev/null
+++ b/src/lib/mt/CondVar.cpp
@@ -0,0 +1,91 @@
+/*
+ * barrier -- mouse and keyboard sharing utility
+ * Copyright (C) 2012-2016 Symless Ltd.
+ * Copyright (C) 2002 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file LICENSE that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mt/CondVar.h"
+#include "arch/Arch.h"
+#include "base/Stopwatch.h"
+
+//
+// CondVarBase
+//
+
+CondVarBase::CondVarBase(Mutex* mutex) :
+ m_mutex(mutex)
+{
+ assert(m_mutex != NULL);
+ m_cond = ARCH->newCondVar();
+}
+
+CondVarBase::~CondVarBase()
+{
+ ARCH->closeCondVar(m_cond);
+}
+
+void
+CondVarBase::lock() const
+{
+ m_mutex->lock();
+}
+
+void
+CondVarBase::unlock() const
+{
+ m_mutex->unlock();
+}
+
+void
+CondVarBase::signal()
+{
+ ARCH->signalCondVar(m_cond);
+}
+
+void
+CondVarBase::broadcast()
+{
+ ARCH->broadcastCondVar(m_cond);
+}
+
+bool
+CondVarBase::wait(Stopwatch& timer, double timeout) const
+{
+ double remain = timeout-timer.getTime();
+ // Some ARCH wait()s return prematurely, retry until really timed out
+ // In particular, ArchMultithreadPosix::waitCondVar() returns every 100ms
+ do {
+ // Always call wait at least once, even if remain is 0, to give
+ // other thread a chance to grab the mutex to avoid deadlocks on
+ // busy waiting.
+ if (remain<0.0) remain=0.0;
+ if (wait(remain))
+ return true;
+ remain = timeout - timer.getTime();
+ } while (remain >= 0.0);
+ return false;
+}
+
+bool
+CondVarBase::wait(double timeout) const
+{
+ return ARCH->waitCondVar(m_cond, m_mutex->m_mutex, timeout);
+}
+
+Mutex*
+CondVarBase::getMutex() const
+{
+ return m_mutex;
+}
diff --git a/src/lib/mt/CondVar.h b/src/lib/mt/CondVar.h
new file mode 100644
index 0000000..0ab956b
--- /dev/null
+++ b/src/lib/mt/CondVar.h
@@ -0,0 +1,225 @@
+/*
+ * barrier -- mouse and keyboard sharing utility
+ * Copyright (C) 2012-2016 Symless Ltd.
+ * Copyright (C) 2002 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file LICENSE that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "mt/Mutex.h"
+#include "common/basic_types.h"
+
+class Stopwatch;
+
+//! Generic condition variable
+/*!
+This class provides functionality common to all condition variables
+but doesn't provide the actual variable storage. A condition variable
+is a multiprocessing primitive that can be waited on. Every condition
+variable has an associated mutex.
+*/
+class CondVarBase {
+public:
+ /*!
+ \c mutex must not be NULL. All condition variables have an
+ associated mutex. The mutex needn't be unique to one condition
+ variable.
+ */
+ CondVarBase(Mutex* mutex);
+ ~CondVarBase();
+
+ //! @name manipulators
+ //@{
+
+ //! Lock the condition variable's mutex
+ /*!
+ Lock the condition variable's mutex. The condition variable should
+ be locked before reading or writing it. It must be locked for a
+ call to wait(). Locks are not recursive; locking a locked mutex
+ will deadlock the thread.
+ */
+ void lock() const;
+
+ //! Unlock the condition variable's mutex
+ void unlock() const;
+
+ //! Signal the condition variable
+ /*!
+ Wake up one waiting thread, if there are any. Which thread gets
+ woken is undefined.
+ */
+ void signal();
+
+ //! Signal the condition variable
+ /*!
+ Wake up all waiting threads, if any.
+ */
+ void broadcast();
+
+ //@}
+ //! @name accessors
+ //@{
+
+ //! Wait on the condition variable
+ /*!
+ Wait on the condition variable. If \c timeout < 0 then wait until
+ signalled, otherwise up to \c timeout seconds or until signalled,
+ whichever comes first. Returns true if the object was signalled
+ during the wait, false otherwise.
+
+ The proper way to wait for a condition is:
+ \code
+ cv.lock();
+ while (cv-expr) {
+ cv.wait();
+ }
+ cv.unlock();
+ \endcode
+ where \c cv-expr involves the value of \c cv and is false when the
+ condition is satisfied.
+
+ (cancellation point)
+ */
+ bool wait(double timeout = -1.0) const;
+
+ //! Wait on the condition variable
+ /*!
+ Same as \c wait(double) but use \c timer to compare against \c timeout.
+ Since clients normally wait on condition variables in a loop, clients
+ can use this to avoid recalculating \c timeout on each iteration.
+ Passing a stopwatch with a negative \c timeout is pointless (it will
+ never time out) but permitted.
+
+ (cancellation point)
+ */
+ bool wait(Stopwatch& timer, double timeout) const;
+
+ //! Get the mutex
+ /*!
+ Get the mutex passed to the c'tor.
+ */
+ Mutex* getMutex() const;
+
+ //@}
+
+private:
+ // not implemented
+ CondVarBase(const CondVarBase&);
+ CondVarBase& operator=(const CondVarBase&);
+
+private:
+ Mutex* m_mutex;
+ ArchCond m_cond;
+};
+
+//! Condition variable
+/*!
+A condition variable with storage for type \c T.
+*/
+template <class T>
+class CondVar : public CondVarBase {
+public:
+ //! Initialize using \c value
+ CondVar(Mutex* mutex, const T& value);
+ //! Initialize using another condition variable's value
+ CondVar(const CondVar&);
+ ~CondVar();
+
+ //! @name manipulators
+ //@{
+
+ //! Assigns the value of \c cv to this
+ /*!
+ Set the variable's value. The condition variable should be locked
+ before calling this method.
+ */
+ CondVar& operator=(const CondVar& cv);
+
+ //! Assigns \c value to this
+ /*!
+ Set the variable's value. The condition variable should be locked
+ before calling this method.
+ */
+ CondVar& operator=(const T& v);
+
+ //@}
+ //! @name accessors
+ //@{
+
+ //! Get the variable's value
+ /*!
+ Get the variable's value. The condition variable should be locked
+ before calling this method.
+ */
+ operator const volatile T&() const;
+
+ //@}
+
+private:
+ volatile T m_data;
+};
+
+template <class T>
+inline
+CondVar<T>::CondVar(
+ Mutex* mutex,
+ const T& data) :
+ CondVarBase(mutex),
+ m_data(data)
+{
+ // do nothing
+}
+
+template <class T>
+inline
+CondVar<T>::CondVar(
+ const CondVar& cv) :
+ CondVarBase(cv.getMutex()),
+ m_data(cv.m_data)
+{
+ // do nothing
+}
+
+template <class T>
+inline
+CondVar<T>::~CondVar()
+{
+ // do nothing
+}
+
+template <class T>
+inline
+CondVar<T>&
+CondVar<T>::operator=(const CondVar<T>& cv)
+{
+ m_data = cv.m_data;
+ return *this;
+}
+
+template <class T>
+inline
+CondVar<T>&
+CondVar<T>::operator=(const T& data)
+{
+ m_data = data;
+ return *this;
+}
+
+template <class T>
+inline
+CondVar<T>::operator const volatile T&() const
+{
+ return m_data;
+}
diff --git a/src/lib/mt/Lock.cpp b/src/lib/mt/Lock.cpp
new file mode 100644
index 0000000..80721b9
--- /dev/null
+++ b/src/lib/mt/Lock.cpp
@@ -0,0 +1,42 @@
+/*
+ * barrier -- mouse and keyboard sharing utility
+ * Copyright (C) 2012-2016 Symless Ltd.
+ * Copyright (C) 2002 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file LICENSE that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mt/Lock.h"
+#include "mt/CondVar.h"
+#include "mt/Mutex.h"
+
+//
+// Lock
+//
+
+Lock::Lock(const Mutex* mutex) :
+ m_mutex(mutex)
+{
+ m_mutex->lock();
+}
+
+Lock::Lock(const CondVarBase* cv) :
+ m_mutex(cv->getMutex())
+{
+ m_mutex->lock();
+}
+
+Lock::~Lock()
+{
+ m_mutex->unlock();
+}
diff --git a/src/lib/mt/Lock.h b/src/lib/mt/Lock.h
new file mode 100644
index 0000000..4a3f311
--- /dev/null
+++ b/src/lib/mt/Lock.h
@@ -0,0 +1,49 @@
+/*
+ * barrier -- mouse and keyboard sharing utility
+ * Copyright (C) 2012-2016 Symless Ltd.
+ * Copyright (C) 2002 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file LICENSE that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "common/common.h"
+
+class Mutex;
+class CondVarBase;
+
+//! Mutual exclusion lock utility
+/*!
+This class locks a mutex or condition variable in the c'tor and unlocks
+it in the d'tor. It's easier and safer than manually locking and
+unlocking since unlocking must usually be done no matter how a function
+exits (including by unwinding due to an exception).
+*/
+class Lock {
+public:
+ //! Lock the mutex \c mutex
+ Lock(const Mutex* mutex);
+ //! Lock the condition variable \c cv
+ Lock(const CondVarBase* cv);
+ //! Unlock the mutex or condition variable
+ ~Lock();
+
+private:
+ // not implemented
+ Lock(const Lock&);
+ Lock& operator=(const Lock&);
+
+private:
+ const Mutex* m_mutex;
+};
diff --git a/src/lib/mt/Mutex.cpp b/src/lib/mt/Mutex.cpp
new file mode 100644
index 0000000..e9a62e8
--- /dev/null
+++ b/src/lib/mt/Mutex.cpp
@@ -0,0 +1,58 @@
+/*
+ * barrier -- mouse and keyboard sharing utility
+ * Copyright (C) 2012-2016 Symless Ltd.
+ * Copyright (C) 2002 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file LICENSE that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mt/Mutex.h"
+
+#include "arch/Arch.h"
+
+//
+// Mutex
+//
+
+Mutex::Mutex()
+{
+ m_mutex = ARCH->newMutex();
+}
+
+Mutex::Mutex(const Mutex&)
+{
+ m_mutex = ARCH->newMutex();
+}
+
+Mutex::~Mutex()
+{
+ ARCH->closeMutex(m_mutex);
+}
+
+Mutex&
+Mutex::operator=(const Mutex&)
+{
+ return *this;
+}
+
+void
+Mutex::lock() const
+{
+ ARCH->lockMutex(m_mutex);
+}
+
+void
+Mutex::unlock() const
+{
+ ARCH->unlockMutex(m_mutex);
+}
diff --git a/src/lib/mt/Mutex.h b/src/lib/mt/Mutex.h
new file mode 100644
index 0000000..51a9649
--- /dev/null
+++ b/src/lib/mt/Mutex.h
@@ -0,0 +1,79 @@
+/*
+ * barrier -- mouse and keyboard sharing utility
+ * Copyright (C) 2012-2016 Symless Ltd.
+ * Copyright (C) 2002 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file LICENSE that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "arch/IArchMultithread.h"
+
+//! Mutual exclusion
+/*!
+A non-recursive mutual exclusion object. Only one thread at a time can
+hold a lock on a mutex. Any thread that attempts to lock a locked mutex
+will block until the mutex is unlocked. At that time, if any threads are
+blocked, exactly one waiting thread will acquire the lock and continue
+running. A thread may not lock a mutex it already owns the lock on; if
+it tries it will deadlock itself.
+*/
+class Mutex {
+public:
+ Mutex();
+ //! Equivalent to default c'tor
+ /*!
+ Copy c'tor doesn't copy anything. It just makes it possible to
+ copy objects that contain a mutex.
+ */
+ Mutex(const Mutex&);
+ ~Mutex();
+
+ //! @name manipulators
+ //@{
+
+ //! Does nothing
+ /*!
+ This does nothing. It just makes it possible to assign objects
+ that contain a mutex.
+ */
+ Mutex& operator=(const Mutex&);
+
+ //@}
+ //! @name accessors
+ //@{
+
+ //! Lock the mutex
+ /*!
+ Locks the mutex, which must not have been previously locked by the
+ calling thread. This blocks if the mutex is already locked by another
+ thread.
+
+ (cancellation point)
+ */
+ void lock() const;
+
+ //! Unlock the mutex
+ /*!
+ Unlocks the mutex, which must have been previously locked by the
+ calling thread.
+ */
+ void unlock() const;
+
+ //@}
+
+private:
+ friend class CondVarBase;
+ ArchMutex m_mutex;
+};
diff --git a/src/lib/mt/Thread.cpp b/src/lib/mt/Thread.cpp
new file mode 100644
index 0000000..7474c16
--- /dev/null
+++ b/src/lib/mt/Thread.cpp
@@ -0,0 +1,187 @@
+/*
+ * barrier -- mouse and keyboard sharing utility
+ * Copyright (C) 2012-2016 Symless Ltd.
+ * Copyright (C) 2002 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file LICENSE that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mt/Thread.h"
+
+#include "mt/XMT.h"
+#include "mt/XThread.h"
+#include "arch/Arch.h"
+#include "base/Log.h"
+#include "base/IJob.h"
+
+//
+// Thread
+//
+
+Thread::Thread(IJob* job)
+{
+ m_thread = ARCH->newThread(&Thread::threadFunc, job);
+ if (m_thread == NULL) {
+ // couldn't create thread
+ delete job;
+ throw XMTThreadUnavailable();
+ }
+}
+
+Thread::Thread(const Thread& thread)
+{
+ m_thread = ARCH->copyThread(thread.m_thread);
+}
+
+Thread::Thread(ArchThread adoptedThread)
+{
+ m_thread = adoptedThread;
+}
+
+Thread::~Thread()
+{
+ ARCH->closeThread(m_thread);
+}
+
+Thread&
+Thread::operator=(const Thread& thread)
+{
+ // copy given thread and release ours
+ ArchThread copy = ARCH->copyThread(thread.m_thread);
+ ARCH->closeThread(m_thread);
+
+ // cut over
+ m_thread = copy;
+
+ return *this;
+}
+
+void
+Thread::exit(void* result)
+{
+ throw XThreadExit(result);
+}
+
+void
+Thread::cancel()
+{
+ ARCH->cancelThread(m_thread);
+}
+
+void
+Thread::setPriority(int n)
+{
+ ARCH->setPriorityOfThread(m_thread, n);
+}
+
+void
+Thread::unblockPollSocket()
+{
+ ARCH->unblockPollSocket(m_thread);
+}
+
+Thread
+Thread::getCurrentThread()
+{
+ return Thread(ARCH->newCurrentThread());
+}
+
+void
+Thread::testCancel()
+{
+ ARCH->testCancelThread();
+}
+
+bool
+Thread::wait(double timeout) const
+{
+ return ARCH->wait(m_thread, timeout);
+}
+
+void*
+Thread::getResult() const
+{
+ if (wait())
+ return ARCH->getResultOfThread(m_thread);
+ else
+ return NULL;
+}
+
+IArchMultithread::ThreadID
+Thread::getID() const
+{
+ return ARCH->getIDOfThread(m_thread);
+}
+
+bool
+Thread::operator==(const Thread& thread) const
+{
+ return ARCH->isSameThread(m_thread, thread.m_thread);
+}
+
+bool
+Thread::operator!=(const Thread& thread) const
+{
+ return !ARCH->isSameThread(m_thread, thread.m_thread);
+}
+
+void*
+Thread::threadFunc(void* vjob)
+{
+ // get this thread's id for logging
+ IArchMultithread::ThreadID id;
+ {
+ ArchThread thread = ARCH->newCurrentThread();
+ id = ARCH->getIDOfThread(thread);
+ ARCH->closeThread(thread);
+ }
+
+ // get job
+ IJob* job = static_cast<IJob*>(vjob);
+
+ // run job
+ void* result = NULL;
+ try {
+ // go
+ LOG((CLOG_DEBUG1 "thread 0x%08x entry", id));
+ job->run();
+ LOG((CLOG_DEBUG1 "thread 0x%08x exit", id));
+ }
+ catch (XThreadCancel&) {
+ // client called cancel()
+ LOG((CLOG_DEBUG1 "caught cancel on thread 0x%08x", id));
+ delete job;
+ throw;
+ }
+ catch (XThreadExit& e) {
+ // client called exit()
+ result = e.m_result;
+ LOG((CLOG_DEBUG1 "caught exit on thread 0x%08x, result %p", id, result));
+ }
+ catch (XBase& e) {
+ LOG((CLOG_ERR "exception on thread 0x%08x: %s", id, e.what()));
+ delete job;
+ throw;
+ }
+ catch (...) {
+ LOG((CLOG_ERR "exception on thread 0x%08x: <unknown>", id));
+ delete job;
+ throw;
+ }
+
+ // done with job
+ delete job;
+
+ // return exit result
+ return result;
+}
diff --git a/src/lib/mt/Thread.h b/src/lib/mt/Thread.h
new file mode 100644
index 0000000..a7434fd
--- /dev/null
+++ b/src/lib/mt/Thread.h
@@ -0,0 +1,210 @@
+/*
+ * barrier -- mouse and keyboard sharing utility
+ * Copyright (C) 2012-2016 Symless Ltd.
+ * Copyright (C) 2002 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file LICENSE that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "arch/IArchMultithread.h"
+
+class IJob;
+
+//! Thread handle
+/*!
+Creating a Thread creates a new context of execution (i.e. thread) that
+runs simulatenously with the calling thread. A Thread is only a handle
+to a thread; deleting a Thread does not cancel or destroy the thread it
+refers to and multiple Thread objects can refer to the same thread.
+
+Threads can terminate themselves but cannot be forced to terminate by
+other threads. However, other threads can signal a thread to terminate
+itself by cancelling it. And a thread can wait (block) on another thread
+to terminate.
+
+Most functions that can block for an arbitrary time are cancellation
+points. A cancellation point is a function that can be interrupted by
+a request to cancel the thread. Cancellation points are noted in the
+documentation.
+*/
+// note -- do not derive from this class
+class Thread {
+public:
+ //! Run \c adoptedJob in a new thread
+ /*!
+ Create and start a new thread executing the \c adoptedJob. The
+ new thread takes ownership of \c adoptedJob and will delete it.
+ */
+ Thread(IJob* adoptedJob);
+
+ //! Duplicate a thread handle
+ /*!
+ Make a new thread object that refers to an existing thread.
+ This does \b not start a new thread.
+ */
+ Thread(const Thread&);
+
+ //! Release a thread handle
+ /*!
+ Release a thread handle. This does not terminate the thread. A thread
+ will keep running until the job completes or calls exit() or allows
+ itself to be cancelled.
+ */
+ ~Thread();
+
+ //! @name manipulators
+ //@{
+
+ //! Assign thread handle
+ /*!
+ Assign a thread handle. This has no effect on the threads, it simply
+ makes this thread object refer to another thread. It does \b not
+ start a new thread.
+ */
+ Thread& operator=(const Thread&);
+
+ //! Terminate the calling thread
+ /*!
+ Terminate the calling thread. This function does not return but
+ the stack is unwound and automatic objects are destroyed, as if
+ exit() threw an exception (which is, in fact, what it does). The
+ argument is saved as the result returned by getResult(). If you
+ have \c catch(...) blocks then you should add the following before
+ each to avoid catching the exit:
+ \code
+ catch(ThreadExit&) { throw; }
+ \endcode
+ or add the \c RETHROW_XTHREAD macro to the \c catch(...) block.
+ */
+ static void exit(void*);
+
+ //! Cancel thread
+ /*!
+ Cancel the thread. cancel() never waits for the thread to
+ terminate; it just posts the cancel and returns. A thread will
+ terminate when it enters a cancellation point with cancellation
+ enabled. If cancellation is disabled then the cancel is
+ remembered but not acted on until the first call to a
+ cancellation point after cancellation is enabled.
+
+ A cancellation point is a function that can act on cancellation.
+ A cancellation point does not return if there's a cancel pending.
+ Instead, it unwinds the stack and destroys automatic objects, as
+ if cancel() threw an exception (which is, in fact, what it does).
+ Threads must take care to unlock and clean up any resources they
+ may have, especially mutexes. They can \c catch(XThreadCancel) to
+ do that then rethrow the exception or they can let it happen
+ automatically by doing clean up in the d'tors of automatic
+ objects (like Lock). Clients are strongly encouraged to do the latter.
+ During cancellation, further cancel() calls are ignored (i.e.
+ a thread cannot be interrupted by a cancel during cancellation).
+
+ Clients that \c catch(XThreadCancel) must always rethrow the
+ exception. Clients that \c catch(...) must either rethrow the
+ exception or include a \c catch(XThreadCancel) handler that
+ rethrows. The \c RETHROW_XTHREAD macro may be useful for that.
+ */
+ void cancel();
+
+ //! Change thread priority
+ /*!
+ Change the priority of the thread. Normal priority is 0, 1 is
+ the next lower, etc. -1 is the next higher, etc. but boosting
+ the priority may not be permitted and will be silenty ignored.
+ */
+ void setPriority(int n);
+
+ //! Force pollSocket() to return
+ /*!
+ Forces a currently blocked pollSocket() in the thread to return
+ immediately.
+ */
+ void unblockPollSocket();
+
+ //@}
+ //! @name accessors
+ //@{
+
+ //! Get current thread's handle
+ /*!
+ Return a Thread object representing the calling thread.
+ */
+ static Thread getCurrentThread();
+
+ //! Test for cancellation
+ /*!
+ testCancel() does nothing but is a cancellation point. Call
+ this to make a function itself a cancellation point. If the
+ thread was cancelled and cancellation is enabled this will
+ cause the thread to unwind the stack and terminate.
+
+ (cancellation point)
+ */
+ static void testCancel();
+
+ //! Wait for thread to terminate
+ /*!
+ Waits for the thread to terminate (by exit() or cancel() or
+ by returning from the thread job) for up to \c timeout seconds,
+ returning true if the thread terminated and false otherwise.
+ This returns immediately with false if called by a thread on
+ itself and immediately with true if the thread has already
+ terminated. This will wait forever if \c timeout < 0.0.
+
+ (cancellation point)
+ */
+ bool wait(double timeout = -1.0) const;
+
+ //! Get the exit result
+ /*!
+ Returns the exit result. This does an implicit wait(). It returns
+ NULL immediately if called by a thread on itself or on a thread that
+ was cancelled.
+
+ (cancellation point)
+ */
+ void* getResult() const;
+
+ //! Get the thread id
+ /*!
+ Returns an integer id for this thread. This id must not be used to
+ check if two Thread objects refer to the same thread. Use
+ operator==() for that.
+ */
+ IArchMultithread::ThreadID
+ getID() const;
+
+ //! Compare thread handles
+ /*!
+ Returns true if two Thread objects refer to the same thread.
+ */
+ bool operator==(const Thread&) const;
+
+ //! Compare thread handles
+ /*!
+ Returns true if two Thread objects do not refer to the same thread.
+ */
+ bool operator!=(const Thread&) const;
+
+ //@}
+
+private:
+ Thread(ArchThread);
+
+ static void* threadFunc(void*);
+
+private:
+ ArchThread m_thread;
+};
diff --git a/src/lib/mt/XMT.cpp b/src/lib/mt/XMT.cpp
new file mode 100644
index 0000000..9aa5852
--- /dev/null
+++ b/src/lib/mt/XMT.cpp
@@ -0,0 +1,29 @@
+/*
+ * barrier -- mouse and keyboard sharing utility
+ * Copyright (C) 2012-2016 Symless Ltd.
+ * Copyright (C) 2002 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file LICENSE that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "XMT.h"
+
+//
+// XMTThreadUnavailable
+//
+
+String
+XMTThreadUnavailable::getWhat() const throw()
+{
+ return format("XMTThreadUnavailable", "cannot create thread");
+}
diff --git a/src/lib/mt/XMT.h b/src/lib/mt/XMT.h
new file mode 100644
index 0000000..9e48fd9
--- /dev/null
+++ b/src/lib/mt/XMT.h
@@ -0,0 +1,30 @@
+/*
+ * barrier -- mouse and keyboard sharing utility
+ * Copyright (C) 2012-2016 Symless Ltd.
+ * Copyright (C) 2002 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file LICENSE that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "base/XBase.h"
+
+//! Generic multithreading exception
+XBASE_SUBCLASS(XMT, XBase);
+
+//! Thread creation exception
+/*!
+Thrown when a thread cannot be created.
+*/
+XBASE_SUBCLASS_WHAT(XMTThreadUnavailable, XMT);
diff --git a/src/lib/mt/XThread.h b/src/lib/mt/XThread.h
new file mode 100644
index 0000000..acc32e3
--- /dev/null
+++ b/src/lib/mt/XThread.h
@@ -0,0 +1,37 @@
+/*
+ * barrier -- mouse and keyboard sharing utility
+ * Copyright (C) 2012-2016 Symless Ltd.
+ * Copyright (C) 2002 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file LICENSE that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "arch/XArch.h"
+
+//! Thread exception to exit
+/*!
+Thrown by Thread::exit() to exit a thread. Clients of Thread
+must not throw this type but must rethrow it if caught (by
+XThreadExit, XThread, or ...).
+*/
+class XThreadExit : public XThread {
+public:
+ //! \c result is the result of the thread
+ XThreadExit(void* result) : m_result(result) { }
+ ~XThreadExit() { }
+
+public:
+ void* m_result;
+};