ovr_sdk

diff LibOVR/Src/Kernel/OVR_Threads.h @ 0:1b39a1b46319

initial 0.4.4
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 14 Jan 2015 06:51:16 +0200
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/LibOVR/Src/Kernel/OVR_Threads.h	Wed Jan 14 06:51:16 2015 +0200
     1.3 @@ -0,0 +1,434 @@
     1.4 +/************************************************************************************
     1.5 +
     1.6 +PublicHeader:   None
     1.7 +Filename    :   OVR_Threads.h
     1.8 +Content     :   Contains thread-related (safe) functionality
     1.9 +Created     :   September 19, 2012
    1.10 +Notes       : 
    1.11 +
    1.12 +Copyright   :   Copyright 2014 Oculus VR, LLC All Rights reserved.
    1.13 +
    1.14 +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); 
    1.15 +you may not use the Oculus VR Rift SDK except in compliance with the License, 
    1.16 +which is provided at the time of installation or download, or which 
    1.17 +otherwise accompanies this software in either electronic or hard copy form.
    1.18 +
    1.19 +You may obtain a copy of the License at
    1.20 +
    1.21 +http://www.oculusvr.com/licenses/LICENSE-3.2 
    1.22 +
    1.23 +Unless required by applicable law or agreed to in writing, the Oculus VR SDK 
    1.24 +distributed under the License is distributed on an "AS IS" BASIS,
    1.25 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    1.26 +See the License for the specific language governing permissions and
    1.27 +limitations under the License.
    1.28 +
    1.29 +************************************************************************************/
    1.30 +#ifndef OVR_Threads_h
    1.31 +#define OVR_Threads_h
    1.32 +
    1.33 +#include "OVR_Types.h"
    1.34 +#include "OVR_Atomic.h"
    1.35 +#include "OVR_RefCount.h"
    1.36 +#include "OVR_Array.h"
    1.37 +
    1.38 +// Defines the infinite wait delay timeout
    1.39 +#define OVR_WAIT_INFINITE 0xFFFFFFFF
    1.40 +
    1.41 +// To be defined in the project configuration options
    1.42 +#ifdef OVR_ENABLE_THREADS
    1.43 +
    1.44 +
    1.45 +namespace OVR {
    1.46 +
    1.47 +//-----------------------------------------------------------------------------------
    1.48 +// ****** Declared classes
    1.49 +
    1.50 +// Declared with thread support only
    1.51 +class   Mutex;
    1.52 +class   WaitCondition;
    1.53 +class   Event;
    1.54 +// Implementation forward declarations
    1.55 +class MutexImpl;
    1.56 +class WaitConditionImpl;
    1.57 +
    1.58 +
    1.59 +
    1.60 +//-----------------------------------------------------------------------------------
    1.61 +// ***** Mutex
    1.62 +
    1.63 +// Mutex class represents a system Mutex synchronization object that provides access 
    1.64 +// serialization between different threads, allowing one thread mutually exclusive access 
    1.65 +// to a resource. Mutex is more heavy-weight then Lock, but supports WaitCondition.
    1.66 +
    1.67 +class Mutex
    1.68 +{
    1.69 +    friend class WaitConditionImpl;    
    1.70 +    friend class MutexImpl;
    1.71 +
    1.72 +    MutexImpl  *pImpl; 
    1.73 +
    1.74 +public:
    1.75 +    // Constructor/destructor
    1.76 +    Mutex(bool recursive = 1);
    1.77 +    ~Mutex();
    1.78 +
    1.79 +    // Locking functions
    1.80 +    void  DoLock();
    1.81 +    bool  TryLock();
    1.82 +    void  Unlock();
    1.83 +
    1.84 +    // Returns 1 if the mutes is currently locked by another thread
    1.85 +    // Returns 0 if the mutex is not locked by another thread, and can therefore be acquired. 
    1.86 +    bool  IsLockedByAnotherThread();
    1.87 +    
    1.88 +    // Locker class; Used for automatic locking of a mutex withing scope    
    1.89 +    class Locker
    1.90 +    {
    1.91 +    public:
    1.92 +        Mutex *pMutex;
    1.93 +        Locker(Mutex *pmutex)
    1.94 +            { pMutex = pmutex; pMutex->DoLock(); }
    1.95 +        ~Locker()
    1.96 +            { pMutex->Unlock(); }
    1.97 +    };
    1.98 +};
    1.99 +
   1.100 +
   1.101 +//-----------------------------------------------------------------------------------
   1.102 +// ***** WaitCondition
   1.103 +
   1.104 +/*
   1.105 +    WaitCondition is a synchronization primitive that can be used to implement what is known as a monitor.
   1.106 +    Dependent threads wait on a wait condition by calling Wait(), and get woken up by other threads that
   1.107 +    call Notify() or NotifyAll().
   1.108 +
   1.109 +    The unique feature of this class is that it provides an atomic way of first releasing a Mutex, and then 
   1.110 +    starting a wait on a wait condition. If both the mutex and the wait condition are associated with the same
   1.111 +    resource, this ensures that any condition checked for while the mutex was locked does not change before
   1.112 +    the wait on the condition is actually initiated.
   1.113 +*/
   1.114 +
   1.115 +class WaitCondition
   1.116 +{
   1.117 +    friend class WaitConditionImpl;
   1.118 +    // Internal implementation structure
   1.119 +    WaitConditionImpl *pImpl;
   1.120 +
   1.121 +public:
   1.122 +    // Constructor/destructor
   1.123 +    WaitCondition();
   1.124 +    ~WaitCondition();
   1.125 +
   1.126 +    // Release mutex and wait for condition. The mutex is re-aquired after the wait.
   1.127 +    // Delay is specified in milliseconds (1/1000 of a second).
   1.128 +    bool    Wait(Mutex *pmutex, unsigned delay = OVR_WAIT_INFINITE);
   1.129 +
   1.130 +    // Notify a condition, releasing at one object waiting
   1.131 +    void    Notify();
   1.132 +    // Notify a condition, releasing all objects waiting
   1.133 +    void    NotifyAll();
   1.134 +};
   1.135 +
   1.136 +
   1.137 +//-----------------------------------------------------------------------------------
   1.138 +// ***** Event
   1.139 +
   1.140 +// Event is a wait-able synchronization object similar to Windows event.
   1.141 +// Event can be waited on until it's signaled by another thread calling
   1.142 +// either SetEvent or PulseEvent.
   1.143 +
   1.144 +class Event
   1.145 +{
   1.146 +    // Event state, its mutex and the wait condition
   1.147 +    volatile bool   State;
   1.148 +    volatile bool   Temporary;  
   1.149 +    mutable Mutex   StateMutex;
   1.150 +    WaitCondition   StateWaitCondition;
   1.151 +
   1.152 +    void updateState(bool newState, bool newTemp, bool mustNotify);
   1.153 +
   1.154 +public:    
   1.155 +    Event(bool setInitially = 0) : State(setInitially), Temporary(false) { }
   1.156 +    ~Event() { }
   1.157 +
   1.158 +    // Wait on an event condition until it is set
   1.159 +    // Delay is specified in milliseconds (1/1000 of a second).
   1.160 +    bool  Wait(unsigned delay = OVR_WAIT_INFINITE);
   1.161 +    
   1.162 +    // Set an event, releasing objects waiting on it
   1.163 +    void  SetEvent()
   1.164 +    { updateState(true, false, true); }
   1.165 +
   1.166 +    // Reset an event, un-signaling it
   1.167 +    void  ResetEvent()
   1.168 +    { updateState(false, false, false); }
   1.169 +
   1.170 +    // Set and then reset an event once a waiter is released.
   1.171 +    // If threads are already waiting, they will be notified and released
   1.172 +    // If threads are not waiting, the event is set until the first thread comes in
   1.173 +    void  PulseEvent()
   1.174 +    { updateState(true, true, true); }
   1.175 +};
   1.176 +
   1.177 +
   1.178 +//-----------------------------------------------------------------------------------
   1.179 +// ***** Thread class
   1.180 +
   1.181 +// ThreadHandle is a handle to a thread, which on some platforms (e.g. Windows) is 
   1.182 +// different from ThreadId. On Unix platforms, a ThreadHandle is the same as a 
   1.183 +// ThreadId and is pthread_t.
   1.184 +typedef void* ThreadHandle;
   1.185 +
   1.186 +// ThreadId uniquely identifies a thread; returned by Windows GetCurrentThreadId(), 
   1.187 +// Unix pthread_self() and Thread::GetThreadId.
   1.188 +typedef void* ThreadId;
   1.189 +
   1.190 +
   1.191 +// *** Thread flags
   1.192 +
   1.193 +// Indicates that the thread is has been started, i.e. Start method has been called, and threads
   1.194 +// OnExit() method has not yet been called/returned.
   1.195 +#define OVR_THREAD_STARTED               0x01
   1.196 +// This flag is set once the thread has ran, and finished.
   1.197 +#define OVR_THREAD_FINISHED              0x02
   1.198 +// This flag is set temporarily if this thread was started suspended. It is used internally.
   1.199 +#define OVR_THREAD_START_SUSPENDED       0x08
   1.200 +// This flag is used to ask a thread to exit. Message driven threads will usually check this flag
   1.201 +// and finish once it is set.
   1.202 +#define OVR_THREAD_EXIT                  0x10
   1.203 +
   1.204 +
   1.205 +class Thread : public RefCountBase<Thread>
   1.206 +{ // NOTE: Waitable must be the first base since it implements RefCountImpl.    
   1.207 +public:
   1.208 +    // *** Callback functions, can be used instead of overriding Run
   1.209 +
   1.210 +    // Run function prototypes.    
   1.211 +    // Thread function and user handle passed to it, executed by the default
   1.212 +    // Thread::Run implementation if not null.
   1.213 +    typedef int (*ThreadFn)(Thread *pthread, void* h);
   1.214 +    
   1.215 +    // Thread ThreadFunction1 is executed if not 0, otherwise ThreadFunction2 is tried
   1.216 +    ThreadFn    ThreadFunction;    
   1.217 +    // User handle passes to a thread
   1.218 +    void*       UserHandle;
   1.219 +
   1.220 +    // Thread state to start a thread with
   1.221 +    enum ThreadState
   1.222 +    {
   1.223 +        NotRunning  = 0,
   1.224 +        Running     = 1,
   1.225 +        Suspended   = 2
   1.226 +    };
   1.227 +
   1.228 +    // Thread priority
   1.229 +    enum ThreadPriority
   1.230 +    {
   1.231 +        CriticalPriority,
   1.232 +        HighestPriority,
   1.233 +        AboveNormalPriority,
   1.234 +        NormalPriority,
   1.235 +        BelowNormalPriority,
   1.236 +        LowestPriority,
   1.237 +        IdlePriority,
   1.238 +    };
   1.239 +
   1.240 +    // Thread constructor parameters
   1.241 +    struct CreateParams
   1.242 +    {
   1.243 +        CreateParams(ThreadFn func = 0, void* hand = 0, size_t ssize = 128 * 1024, 
   1.244 +                     int proc = -1, ThreadState state = NotRunning, ThreadPriority prior = NormalPriority)
   1.245 +                     : threadFunction(func), userHandle(hand), stackSize(ssize), 
   1.246 +                       processor(proc), initialState(state), priority(prior) {}
   1.247 +        ThreadFn       threadFunction;   // Thread function
   1.248 +        void*          userHandle;       // User handle passes to a thread
   1.249 +        size_t         stackSize;        // Thread stack size
   1.250 +        int            processor;        // Thread hardware processor
   1.251 +        ThreadState    initialState;     // 
   1.252 +        ThreadPriority priority;         // Thread priority
   1.253 +    };
   1.254 +
   1.255 +
   1.256 +    // *** Constructors
   1.257 +
   1.258 +    // A default constructor always creates a thread in NotRunning state, because
   1.259 +    // the derived class has not yet been initialized. The derived class can call Start explicitly.
   1.260 +    // "processor" parameter specifies which hardware processor this thread will be run on. 
   1.261 +    // -1 means OS decides this. Implemented only on Win32
   1.262 +    Thread(size_t stackSize = 128 * 1024, int processor = -1);
   1.263 +    // Constructors that initialize the thread with a pointer to function.
   1.264 +    // An option to start a thread is available, but it should not be used if classes are derived from Thread.
   1.265 +    // "processor" parameter specifies which hardware processor this thread will be run on. 
   1.266 +    // -1 means OS decides this. Implemented only on Win32
   1.267 +    Thread(ThreadFn threadFunction, void*  userHandle = 0, size_t stackSize = 128 * 1024,
   1.268 +           int processor = -1, ThreadState initialState = NotRunning);
   1.269 +    // Constructors that initialize the thread with a create parameters structure.
   1.270 +    explicit Thread(const CreateParams& params);
   1.271 +
   1.272 +    // Destructor.
   1.273 +    virtual ~Thread();
   1.274 +
   1.275 +    // Waits for all Threads to finish; should be called only from the root
   1.276 +    // application thread. Once this function returns, we know that all other
   1.277 +    // thread's references to Thread object have been released.
   1.278 +    static  void OVR_CDECL FinishAllThreads();
   1.279 +
   1.280 +
   1.281 +    // *** Overridable Run function for thread processing
   1.282 +
   1.283 +    // - returning from this method will end the execution of the thread
   1.284 +    // - return value is usually 0 for success 
   1.285 +    virtual int   Run();
   1.286 +    // Called after return/exit function
   1.287 +    virtual void  OnExit();
   1.288 +
   1.289 +
   1.290 +    // *** Thread management
   1.291 +
   1.292 +    // Starts the thread if its not already running
   1.293 +    // - internally sets up the threading and calls Run()
   1.294 +    // - initial state can either be Running or Suspended, NotRunning will just fail and do nothing
   1.295 +    // - returns the exit code
   1.296 +    virtual bool  Start(ThreadState initialState = Running);
   1.297 +
   1.298 +    // Quits with an exit code
   1.299 +    virtual void  Exit(int exitCode=0);
   1.300 +
   1.301 +    // Suspend the thread until resumed
   1.302 +    // Returns 1 for success, 0 for failure.
   1.303 +    bool  Suspend();
   1.304 +    // Resumes currently suspended thread
   1.305 +    // Returns 1 for success, 0 for failure.
   1.306 +    bool  Resume();
   1.307 +
   1.308 +    // Static function to return a pointer to the current thread
   1.309 +    //static Thread* GetThread();
   1.310 +
   1.311 +
   1.312 +    // *** Thread status query functions
   1.313 +
   1.314 +    bool          GetExitFlag() const;
   1.315 +    void          SetExitFlag(bool exitFlag);
   1.316 +
   1.317 +    // Determines whether the thread was running and is now finished
   1.318 +    bool          IsFinished() const;
   1.319 +    // Determines if the thread is currently suspended
   1.320 +    bool          IsSuspended() const;
   1.321 +    // Returns current thread state
   1.322 +    ThreadState   GetThreadState() const;
   1.323 +
   1.324 +    // Wait for thread to finish for a maxmimum number of milliseconds
   1.325 +    // For maxWaitMs = 0 it simply polls and then returns if the thread is not finished
   1.326 +    // For maxWaitMs < 0 it will wait forever
   1.327 +    bool          Join(int maxWaitMs = -1) const;
   1.328 +
   1.329 +    // Returns the number of available CPUs on the system 
   1.330 +    static int    GetCPUCount();
   1.331 +
   1.332 +    // Returns the thread exit code. Exit code is initialized to 0,
   1.333 +    // and set to the return value if Run function after the thread is finished.
   1.334 +    inline int    GetExitCode() const { return ExitCode; }
   1.335 +    // Returns an OS handle 
   1.336 +#if defined(OVR_OS_MS)
   1.337 +    void*          GetOSHandle() const { return ThreadHandle; }
   1.338 +#else
   1.339 +    pthread_t      GetOSHandle() const { return ThreadHandle; }
   1.340 +#endif
   1.341 +
   1.342 +#if defined(OVR_OS_MS)
   1.343 +    ThreadId       GetThreadId() const { return IdValue; }
   1.344 +#else
   1.345 +    ThreadId       GetThreadId() const { return (ThreadId)GetOSHandle(); }
   1.346 +#endif
   1.347 +
   1.348 +    // Returns the platform-specific equivalent const that corresponds to the given ThreadPriority. 
   1.349 +    static int            GetOSPriority(ThreadPriority);
   1.350 +    static ThreadPriority GetOVRPriority(int osPriority); // May return a value outside the ThreadPriority enum range in unusual cases.
   1.351 +
   1.352 +    // Gets this instance's priority.
   1.353 +    ThreadPriority GetPriority();
   1.354 +
   1.355 +    // Gets the current thread's priority.
   1.356 +    static ThreadPriority GetCurrentPriority();
   1.357 +
   1.358 +    // Sets this instance's thread's priority.
   1.359 +    // Some platforms (e.g. Unix) don't let you set thread priorities unless you have root privileges/
   1.360 +    bool SetPriority(ThreadPriority);
   1.361 +
   1.362 +    // Sets the current thread's priority.
   1.363 +    static bool SetCurrentPriority(ThreadPriority);
   1.364 +
   1.365 +    // *** Sleep
   1.366 +
   1.367 +    // Sleep secs seconds
   1.368 +    static bool    Sleep(unsigned secs);
   1.369 +    // Sleep msecs milliseconds
   1.370 +    static bool    MSleep(unsigned msecs);
   1.371 +
   1.372 +
   1.373 +    // *** Debugging functionality
   1.374 +    virtual void    SetThreadName(const char* name);
   1.375 +    static void     SetThreadName(const char* name, ThreadId threadId);
   1.376 +    static void     SetCurrentThreadName(const char* name);
   1.377 +
   1.378 +    static void     GetThreadName(char* name, size_t nameCapacity, ThreadId threadId);
   1.379 +    static void     GetCurrentThreadName(char* name, size_t nameCapacity);
   1.380 +
   1.381 +private:
   1.382 +#if defined(OVR_OS_WIN32)
   1.383 +    friend unsigned WINAPI Thread_Win32StartFn(void *phandle);
   1.384 +#elif defined(OVR_OS_MS) // Any other Microsoft OS...
   1.385 +    friend DWORD WINAPI Thread_Win32StartFn(void *phandle);
   1.386 +#else
   1.387 +    friend void *Thread_PthreadStartFn(void * phandle);
   1.388 +
   1.389 +    static int            InitAttr;
   1.390 +    static pthread_attr_t Attr;
   1.391 +#endif
   1.392 +
   1.393 +protected:    
   1.394 +    // Thread state flags
   1.395 +    AtomicInt<uint32_t>   ThreadFlags;
   1.396 +    AtomicInt<int32_t>   SuspendCount;
   1.397 +    size_t              StackSize;
   1.398 +
   1.399 +    // Hardware processor which this thread is running on.
   1.400 +    int            Processor;
   1.401 +    ThreadPriority Priority;
   1.402 +
   1.403 +#if defined(OVR_OS_MS)
   1.404 +    void*               ThreadHandle;
   1.405 +    volatile ThreadId   IdValue;
   1.406 +
   1.407 +    // System-specific cleanup function called from destructor
   1.408 +    void                CleanupSystemThread();
   1.409 +
   1.410 +#else
   1.411 +    pthread_t           ThreadHandle;
   1.412 +#endif
   1.413 +
   1.414 +    // Exit code of the thread, as returned by Run.
   1.415 +    int                 ExitCode;
   1.416 +
   1.417 +    // Internal run function.
   1.418 +    int                 PRun();    
   1.419 +    // Finishes the thread and releases internal reference to it.
   1.420 +    void                FinishAndRelease();
   1.421 +
   1.422 +    void                Init(const CreateParams& params);
   1.423 +
   1.424 +    // Protected copy constructor
   1.425 +    Thread(const Thread &source) : RefCountBase<Thread>() { OVR_UNUSED(source); }
   1.426 +
   1.427 +};
   1.428 +
   1.429 +// Returns the unique Id of a thread it is called on, intended for
   1.430 +// comparison purposes.
   1.431 +ThreadId GetCurrentThreadId();
   1.432 +
   1.433 +
   1.434 +} // OVR
   1.435 +
   1.436 +#endif // OVR_ENABLE_THREADS
   1.437 +#endif // OVR_Threads_h