diff options
Diffstat (limited to 'src/lib/mt')
| -rw-r--r-- | src/lib/mt/CMakeLists.txt | 24 | ||||
| -rw-r--r-- | src/lib/mt/CondVar.cpp | 91 | ||||
| -rw-r--r-- | src/lib/mt/CondVar.h | 225 | ||||
| -rw-r--r-- | src/lib/mt/Lock.cpp | 42 | ||||
| -rw-r--r-- | src/lib/mt/Lock.h | 49 | ||||
| -rw-r--r-- | src/lib/mt/Mutex.cpp | 58 | ||||
| -rw-r--r-- | src/lib/mt/Mutex.h | 79 | ||||
| -rw-r--r-- | src/lib/mt/Thread.cpp | 187 | ||||
| -rw-r--r-- | src/lib/mt/Thread.h | 210 | ||||
| -rw-r--r-- | src/lib/mt/XMT.cpp | 29 | ||||
| -rw-r--r-- | src/lib/mt/XMT.h | 30 | ||||
| -rw-r--r-- | src/lib/mt/XThread.h | 37 |
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; +}; |
