Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/external/source/vncdll/winvnc/omnithread/omnithread.h
Views: 11784
// Package : omnithread1// omnithread.h Created : 7/94 tjr2//3// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.4//5// This file is part of the omnithread library6//7// The omnithread library is free software; you can redistribute it and/or8// modify it under the terms of the GNU Library General Public9// License as published by the Free Software Foundation; either10// version 2 of the License, or (at your option) any later version.11//12// This library is distributed in the hope that it will be useful,13// but WITHOUT ANY WARRANTY; without even the implied warranty of14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU15// Library General Public License for more details.16//17// You should have received a copy of the GNU Library General Public18// License along with this library; if not, write to the Free19// Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA20// 02111-1307, USA21//2223//24// Interface to OMNI thread abstraction.25//26// This file declares classes for threads and synchronisation objects27// (mutexes, condition variables and counting semaphores).28//29// Wherever a seemingly arbitrary choice has had to be made as to the interface30// provided, the intention here has been to be as POSIX-like as possible. This31// is why there is no semaphore timed wait, for example.32//3334#ifndef __omnithread_h_35#define __omnithread_h_3637#ifndef NULL38#define NULL (void*)039#endif4041class omni_mutex;42class omni_condition;43class omni_semaphore;44class omni_thread;4546//47// OMNI_THREAD_EXPOSE can be defined as public or protected to expose the48// implementation class - this may be useful for debugging. Hopefully this49// won't change the underlying structure which the compiler generates so that50// this can work without recompiling the library.51//5253#ifndef OMNI_THREAD_EXPOSE54#define OMNI_THREAD_EXPOSE private55#endif565758//59// Include implementation-specific header file.60//61// This must define 4 CPP macros of the form OMNI_x_IMPLEMENTATION for mutex,62// condition variable, semaphore and thread. Each should define any63// implementation-specific members of the corresponding classes.64//656667#if defined(__arm__) && defined(__atmos__)68#include <omnithread/posix.h>6970#elif defined(__alpha__) && defined(__osf1__)71#include <omnithread/posix.h>7273#elif defined(__powerpc__) && defined(__aix__)74#include <omnithread/posix.h>7576#elif defined(__hpux__)77#include <omnithread/posix.h>7879#elif defined(__WIN32__)80#include "nt.h"8182#ifdef _MSC_VER8384// Using MSVC++ to compile. If compiling library as a DLL,85// define _OMNITHREAD_DLL. If compiling as a statuc library, define86// _WINSTATIC87// If compiling an application that is to be statically linked to omnithread,88// define _WINSTATIC (if the application is to be dynamically linked,89// there is no need to define any of these macros).9091#if defined (_OMNITHREAD_DLL) && defined(_WINSTATIC)92#error "Both _OMNITHREAD_DLL and _WINSTATIC are defined."93#elif defined(_OMNITHREAD_DLL)94#define _OMNITHREAD_NTDLL_ __declspec(dllexport)95#elif !defined(_WINSTATIC)96#define _OMNITHREAD_NTDLL_ __declspec(dllimport)97#elif defined(_WINSTATIC)98#define _OMNITHREAD_NTDLL_99#endif100// _OMNITHREAD_DLL && _WINSTATIC101102#else103104// Not using MSVC++ to compile105#define _OMNITHREAD_NTDLL_106107#endif108// _MSC_VER109110#elif defined(__sunos__) && (__OSVERSION__ == 5)111#ifdef UsePthread112#include <omnithread/posix.h>113#else114#include <omnithread/solaris.h>115#endif116117#elif defined(__linux__)118#include <omnithread/posix.h>119120#elif defined(__nextstep__)121#include <omnithread/mach.h>122123#elif defined(__VMS)124#include <omnithread/posix.h>125126#elif defined(__SINIX__)127#include <omnithread/posix.h>128129#elif defined(__osr5__)130#include <omnithread/posix.h>131132#elif defined(__irix__)133#include <omnithread/posix.h>134135#else136#error "No implementation header file"137#endif138139#if !defined(__WIN32__)140#define _OMNITHREAD_NTDLL_141#endif142143#if (!defined(OMNI_MUTEX_IMPLEMENTATION) || \144!defined(OMNI_CONDITION_IMPLEMENTATION) || \145!defined(OMNI_SEMAPHORE_IMPLEMENTATION) || \146!defined(OMNI_THREAD_IMPLEMENTATION))147#error "Implementation header file incomplete"148#endif149150151//152// This exception is thrown in the event of a fatal error.153//154155class _OMNITHREAD_NTDLL_ omni_thread_fatal {156public:157int error;158omni_thread_fatal(int e = 0) : error(e) {}159};160161162//163// This exception is thrown when an operation is invoked with invalid164// arguments.165//166167class _OMNITHREAD_NTDLL_ omni_thread_invalid {};168169170///////////////////////////////////////////////////////////////////////////171//172// Mutex173//174///////////////////////////////////////////////////////////////////////////175176class _OMNITHREAD_NTDLL_ omni_mutex {177178public:179omni_mutex(void);180~omni_mutex(void);181182void lock(void);183void unlock(void);184void acquire(void) { lock(); }185void release(void) { unlock(); }186// the names lock and unlock are preferred over acquire and release187// since we are attempting to be as POSIX-like as possible.188189friend class omni_condition;190191private:192// dummy copy constructor and operator= to prevent copying193omni_mutex(const omni_mutex&);194omni_mutex& operator=(const omni_mutex&);195196OMNI_THREAD_EXPOSE:197OMNI_MUTEX_IMPLEMENTATION198};199200//201// As an alternative to:202// {203// mutex.lock();204// .....205// mutex.unlock();206// }207//208// you can use a single instance of the omni_mutex_lock class:209//210// {211// omni_mutex_lock l(mutex);212// ....213// }214//215// This has the advantage that mutex.unlock() will be called automatically216// when an exception is thrown.217//218219class _OMNITHREAD_NTDLL_ omni_mutex_lock {220omni_mutex& mutex;221public:222omni_mutex_lock(omni_mutex& m) : mutex(m) { mutex.lock(); }223~omni_mutex_lock(void) { mutex.unlock(); }224private:225// dummy copy constructor and operator= to prevent copying226omni_mutex_lock(const omni_mutex_lock&);227omni_mutex_lock& operator=(const omni_mutex_lock&);228};229230231///////////////////////////////////////////////////////////////////////////232//233// Condition variable234//235///////////////////////////////////////////////////////////////////////////236237class _OMNITHREAD_NTDLL_ omni_condition {238239omni_mutex* mutex;240241public:242omni_condition(omni_mutex* m);243// constructor must be given a pointer to an existing mutex. The244// condition variable is then linked to the mutex, so that there is an245// implicit unlock and lock around wait() and timed_wait().246247~omni_condition(void);248249void wait(void);250// wait for the condition variable to be signalled. The mutex is251// implicitly released before waiting and locked again after waking up.252// If wait() is called by multiple threads, a signal may wake up more253// than one thread. See POSIX threads documentation for details.254255int timedwait(unsigned long secs, unsigned long nanosecs = 0);256// timedwait() is given an absolute time to wait until. To wait for a257// relative time from now, use omni_thread::get_time. See POSIX threads258// documentation for why absolute times are better than relative.259// Returns 1 (true) if successfully signalled, 0 (false) if time260// expired.261262void signal(void);263// if one or more threads have called wait(), signal wakes up at least264// one of them, possibly more. See POSIX threads documentation for265// details.266267void broadcast(void);268// broadcast is like signal but wakes all threads which have called269// wait().270271private:272// dummy copy constructor and operator= to prevent copying273omni_condition(const omni_condition&);274omni_condition& operator=(const omni_condition&);275276OMNI_THREAD_EXPOSE:277OMNI_CONDITION_IMPLEMENTATION278};279280281///////////////////////////////////////////////////////////////////////////282//283// Counting semaphore284//285///////////////////////////////////////////////////////////////////////////286287class _OMNITHREAD_NTDLL_ omni_semaphore {288289public:290omni_semaphore(unsigned int initial = 1);291~omni_semaphore(void);292293void wait(void);294// if semaphore value is > 0 then decrement it and carry on. If it's295// already 0 then block.296297int trywait(void);298// if semaphore value is > 0 then decrement it and return 1 (true).299// If it's already 0 then return 0 (false).300301void post(void);302// if any threads are blocked in wait(), wake one of them up. Otherwise303// increment the value of the semaphore.304305private:306// dummy copy constructor and operator= to prevent copying307omni_semaphore(const omni_semaphore&);308omni_semaphore& operator=(const omni_semaphore&);309310OMNI_THREAD_EXPOSE:311OMNI_SEMAPHORE_IMPLEMENTATION312};313314//315// A helper class for semaphores, similar to omni_mutex_lock above.316//317318class _OMNITHREAD_NTDLL_ omni_semaphore_lock {319omni_semaphore& sem;320public:321omni_semaphore_lock(omni_semaphore& s) : sem(s) { sem.wait(); }322~omni_semaphore_lock(void) { sem.post(); }323private:324// dummy copy constructor and operator= to prevent copying325omni_semaphore_lock(const omni_semaphore_lock&);326omni_semaphore_lock& operator=(const omni_semaphore_lock&);327};328329330///////////////////////////////////////////////////////////////////////////331//332// Thread333//334///////////////////////////////////////////////////////////////////////////335336class _OMNITHREAD_NTDLL_ omni_thread {337338public:339340enum priority_t {341PRIORITY_LOW,342PRIORITY_NORMAL,343PRIORITY_HIGH344};345346enum state_t {347STATE_NEW, // thread object exists but thread hasn't348// started yet.349STATE_RUNNING, // thread is running.350STATE_TERMINATED // thread has terminated but storage has not351// been reclaimed (i.e. waiting to be joined).352};353354//355// Constructors set up the thread object but the thread won't start until356// start() is called. The create method can be used to construct and start357// a thread in a single call.358//359360omni_thread(void (*fn)(void*), void* arg = NULL,361priority_t pri = PRIORITY_NORMAL);362omni_thread(void* (*fn)(void*), void* arg = NULL,363priority_t pri = PRIORITY_NORMAL);364// these constructors create a thread which will run the given function365// when start() is called. The thread will be detached if given a366// function with void return type, undetached if given a function367// returning void*. If a thread is detached, storage for the thread is368// reclaimed automatically on termination. Only an undetached thread369// can be joined.370371void start(void);372// start() causes a thread created with one of the constructors to373// start executing the appropriate function.374375protected:376377omni_thread(void* arg = NULL, priority_t pri = PRIORITY_NORMAL);378// this constructor is used in a derived class. The thread will379// execute the run() or run_undetached() member functions depending on380// whether start() or start_undetached() is called respectively.381382void start_undetached(void);383// can be used with the above constructor in a derived class to cause384// the thread to be undetached. In this case the thread executes the385// run_undetached member function.386387virtual ~omni_thread(void);388// destructor cannot be called by user (except via a derived class).389// Use exit() or cancel() instead. This also means a thread object must390// be allocated with new - it cannot be statically or automatically391// allocated. The destructor of a class that inherits from omni_thread392// shouldn't be public either (otherwise the thread object can be393// destroyed while the underlying thread is still running).394395public:396397void join(void**);398// join causes the calling thread to wait for another's completion,399// putting the return value in the variable of type void* whose address400// is given (unless passed a null pointer). Only undetached threads401// may be joined. Storage for the thread will be reclaimed.402403void set_priority(priority_t);404// set the priority of the thread.405406static omni_thread* create(void (*fn)(void*), void* arg = NULL,407priority_t pri = PRIORITY_NORMAL);408static omni_thread* create(void* (*fn)(void*), void* arg = NULL,409priority_t pri = PRIORITY_NORMAL);410// create spawns a new thread executing the given function with the411// given argument at the given priority. Returns a pointer to the412// thread object. It simply constructs a new thread object then calls413// start.414415static void exit(void* return_value = NULL);416// causes the calling thread to terminate.417418static omni_thread* self(void);419// returns the calling thread's omni_thread object.420// If the calling thread is not the main thread and421// is not created using this library, returns 0.422423static void yield(void);424// allows another thread to run.425426static void sleep(unsigned long secs, unsigned long nanosecs = 0);427// sleeps for the given time.428429static void get_time(unsigned long* abs_sec, unsigned long* abs_nsec,430unsigned long rel_sec = 0, unsigned long rel_nsec=0);431// calculates an absolute time in seconds and nanoseconds, suitable for432// use in timed_waits on condition variables, which is the current time433// plus the given relative offset.434435private:436437virtual void run(void* arg) {}438virtual void* run_undetached(void* arg) { return NULL; }439// can be overridden in a derived class. When constructed using the440// the constructor omni_thread(void*, priority_t), these functions are441// called by start() and start_undetached() respectively.442443void common_constructor(void* arg, priority_t pri, int det);444// implements the common parts of the constructors.445446omni_mutex mutex;447// used to protect any members which can change after construction,448// i.e. the following 2 members:449450state_t _state;451priority_t _priority;452453static omni_mutex* next_id_mutex;454static int next_id;455int _id;456457void (*fn_void)(void*);458void* (*fn_ret)(void*);459void* thread_arg;460int detached;461462public:463464priority_t priority(void) {465466// return this thread's priority.467468omni_mutex_lock l(mutex);469return _priority;470}471472state_t state(void) {473474// return thread state (invalid, new, running or terminated).475476omni_mutex_lock l(mutex);477return _state;478}479480int id(void) { return _id; }481// return unique thread id within the current process.482483484// This class plus the instance of it declared below allows us to execute485// some initialisation code before main() is called.486487class _OMNITHREAD_NTDLL_ init_t {488static int count;489public:490init_t(void);491};492493friend class init_t;494495OMNI_THREAD_EXPOSE:496OMNI_THREAD_IMPLEMENTATION497};498499static omni_thread::init_t omni_thread_init;500501#endif502503504