blob: c41ac38b7544247a38551afbf65805a680acbd6f [file] [log] [blame]
/* 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.cxx
// Win32 Threading interface implementation
#include <malloc.h>
#include <rdr/Exception.h>
#include <rfb/LogWriter.h>
#include <rfb/util.h>
#include <rfb_win32/Threading.h>
using namespace rfb;
static LogWriter vlog("Threading");
static DWORD threadStorage = TlsAlloc();
inline void logAction(Thread* t, const char* action) {
vlog.debug("%-16.16s %s(%lx)", action, t->getName(), t);
}
inline void logError(Thread* t, const char* err) {
vlog.error("%-16.16s %s(%lx):%s", "failed", t->getName(), t, err);
}
DWORD WINAPI
Thread::threadProc(LPVOID lpParameter) {
Thread* thread = (Thread*) lpParameter;
TlsSetValue(threadStorage, thread);
logAction(thread, "started");
try {
thread->run();
logAction(thread, "stopped");
} catch (rdr::Exception& e) {
logError(thread, e.str());
}
bool deleteThread = false;
{
Lock l(thread->mutex);
thread->state = ThreadStopped;
thread->sig->signal();
deleteThread = thread->deleteAfterRun;
}
if (deleteThread)
delete thread;
return 0;
}
Thread::Thread(const char* name_) : name(strDup(name_ ? name_ : "Unnamed")), sig(0), deleteAfterRun(false) {
sig = new Condition(mutex);
cond_event.h = CreateEvent(NULL, TRUE, FALSE, NULL);
thread.h = CreateThread(NULL, 0, threadProc, this, CREATE_SUSPENDED, &thread_id);
state = ThreadCreated;
logAction(this, "created");
}
Thread::Thread(HANDLE thread_, DWORD thread_id_) : name(strDup("Native")), sig(0), deleteAfterRun(false),
thread(thread_), thread_id(thread_id_) {
cond_event.h = CreateEvent(NULL, TRUE, FALSE, NULL);
state = ThreadNative;
logAction(this, "created");
}
Thread::~Thread() {
logAction(this, "destroying");
if (!deleteAfterRun && state != ThreadNative)
this->join();
if (sig)
delete sig;
logAction(this, "destroyed");
}
void
Thread::run() {
}
void
Thread::start() {
Lock l(mutex);
if (state == ThreadCreated) {
state = ThreadStarted;
sig->signal();
ResumeThread(thread);
}
}
Thread*
Thread::join() {
if (deleteAfterRun)
throw rdr::Exception("attempt to join() with deleteAfterRun thread");
Lock l(mutex);
if (state == ThreadJoined) {
logAction(this, "already joined");
} else {
logAction(this, "joining");
while (state == ThreadStarted) {
sig->wait();
logAction(this, "checking");
}
state = ThreadJoined;
logAction(this, "joined");
}
return this;
}
const char*
Thread::getName() const {
return name.buf;
}
ThreadState
Thread::getState() const {
return state;
}
unsigned long
Thread::getThreadId() const {
return thread_id;
}
Thread*
Thread::self() {
Thread* thread = (Thread*) TlsGetValue(threadStorage);
if (!thread) {
// *** memory leak - could use GetExitCodeThread to lazily detect when
// to clean up native thread objects
thread = new Thread(GetCurrentThread(), GetCurrentThreadId());
TlsSetValue(threadStorage, thread);
}
return thread;
}