/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This software 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 software; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ // -=- Threading_win32.h // Win32 Threading interface implementation #ifndef __RFB_THREADING_IMPL_WIN32 #define __RFB_THREADING_IMPL_WIN32 #define __RFB_THREADING_IMPL WIN32 #include #include #include //#include namespace rfb { class Condition; class Mutex { public: Mutex() { InitializeCriticalSection(&crit); } ~Mutex() { DeleteCriticalSection(&crit); } friend class Lock; friend class Condition; protected: void enter() {EnterCriticalSection(&crit);} void exit() {LeaveCriticalSection(&crit);} CRITICAL_SECTION crit; }; class Lock { public: Lock(Mutex& m) : mutex(m) {m.enter();} ~Lock() {mutex.exit();} protected: Mutex& mutex; }; enum ThreadState {ThreadCreated, ThreadStarted, ThreadStopped, ThreadJoined, ThreadNative}; class Thread { public: Thread(const char* name_=0); virtual ~Thread(); virtual void run(); virtual void start(); virtual Thread* join(); const char* getName() const; ThreadState getState() const; // Determines whether the thread should delete itself when run() returns // If you set this, you must NEVER call join()! void setDeleteAfterRun() {deleteAfterRun = true;}; unsigned long getThreadId() const; static Thread* self(); friend class Condition; protected: Thread(HANDLE thread_, DWORD thread_id_); static DWORD WINAPI threadProc(LPVOID lpParameter); win32::Handle thread; DWORD thread_id; CharArray name; ThreadState state; Condition* sig; Mutex mutex; win32::Handle cond_event; Thread* cond_next; bool deleteAfterRun; }; class Condition { public: Condition(Mutex& m) : mutex(m), waiting(0) { } ~Condition() { } // Wake up the specified number of threads that are waiting // on this Condition, or all of them if -1 is specified. void signal(int howMany=1) { Lock l(cond_lock); while (waiting && howMany!=0) { SetEvent(waiting->cond_event); waiting = waiting->cond_next; if (howMany>0) --howMany; } } // NB: Must hold "mutex" to call wait() // Wait until either the Condition is signalled or the timeout // expires. void wait(DWORD timeout=INFINITE) { Thread* self = Thread::self(); ResetEvent(self->cond_event); { Lock l(cond_lock); self->cond_next = waiting; waiting = self; } mutex.exit(); DWORD result = WaitForSingleObject(self->cond_event, timeout); mutex.enter(); if (result == WAIT_TIMEOUT) { Lock l(cond_lock); // Remove this thread from the Condition for (Thread** removeFrom = &waiting; *removeFrom; removeFrom = &(*removeFrom)->cond_next) { if (*removeFrom == self) { *removeFrom = self->cond_next; break; } } } else if (result == WAIT_FAILED) { throw rdr::SystemException("failed to wait on Condition", GetLastError()); } } protected: Mutex& mutex; Mutex cond_lock; Thread* waiting; }; }; #endif // __RFB_THREADING_IMPL