blob: c41ac38b7544247a38551afbf65805a680acbd6f [file] [log] [blame]
Constantin Kaplinsky0a1eca12006-04-16 07:28:14 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18
19// -=- Threading.cxx
20// Win32 Threading interface implementation
21
22#include <malloc.h>
23
24#include <rdr/Exception.h>
25#include <rfb/LogWriter.h>
26#include <rfb/util.h>
27#include <rfb_win32/Threading.h>
28
29using namespace rfb;
30
31static LogWriter vlog("Threading");
32
33static DWORD threadStorage = TlsAlloc();
34
35
36inline void logAction(Thread* t, const char* action) {
37 vlog.debug("%-16.16s %s(%lx)", action, t->getName(), t);
38}
39
40inline void logError(Thread* t, const char* err) {
41 vlog.error("%-16.16s %s(%lx):%s", "failed", t->getName(), t, err);
42}
43
44
45DWORD WINAPI
46Thread::threadProc(LPVOID lpParameter) {
47 Thread* thread = (Thread*) lpParameter;
48 TlsSetValue(threadStorage, thread);
49 logAction(thread, "started");
50 try {
51 thread->run();
52 logAction(thread, "stopped");
53 } catch (rdr::Exception& e) {
54 logError(thread, e.str());
55 }
56 bool deleteThread = false;
57 {
58 Lock l(thread->mutex);
59 thread->state = ThreadStopped;
60 thread->sig->signal();
61 deleteThread = thread->deleteAfterRun;
62 }
63 if (deleteThread)
64 delete thread;
65 return 0;
66}
67
68Thread::Thread(const char* name_) : name(strDup(name_ ? name_ : "Unnamed")), sig(0), deleteAfterRun(false) {
69 sig = new Condition(mutex);
70 cond_event.h = CreateEvent(NULL, TRUE, FALSE, NULL);
71 thread.h = CreateThread(NULL, 0, threadProc, this, CREATE_SUSPENDED, &thread_id);
72 state = ThreadCreated;
73 logAction(this, "created");
74}
75
76Thread::Thread(HANDLE thread_, DWORD thread_id_) : name(strDup("Native")), sig(0), deleteAfterRun(false),
77 thread(thread_), thread_id(thread_id_) {
78 cond_event.h = CreateEvent(NULL, TRUE, FALSE, NULL);
79 state = ThreadNative;
80 logAction(this, "created");
81}
82
83Thread::~Thread() {
84 logAction(this, "destroying");
85 if (!deleteAfterRun && state != ThreadNative)
86 this->join();
87 if (sig)
88 delete sig;
89 logAction(this, "destroyed");
90}
91
92void
93Thread::run() {
94}
95
96void
97Thread::start() {
98 Lock l(mutex);
99 if (state == ThreadCreated) {
100 state = ThreadStarted;
101 sig->signal();
102 ResumeThread(thread);
103 }
104}
105
106Thread*
107Thread::join() {
108 if (deleteAfterRun)
109 throw rdr::Exception("attempt to join() with deleteAfterRun thread");
110 Lock l(mutex);
111 if (state == ThreadJoined) {
112 logAction(this, "already joined");
113 } else {
114 logAction(this, "joining");
115 while (state == ThreadStarted) {
116 sig->wait();
117 logAction(this, "checking");
118 }
119 state = ThreadJoined;
120 logAction(this, "joined");
121 }
122 return this;
123}
124
125const char*
126Thread::getName() const {
127 return name.buf;
128}
129
130ThreadState
131Thread::getState() const {
132 return state;
133}
134
135unsigned long
136Thread::getThreadId() const {
137 return thread_id;
138}
139
140
141Thread*
142Thread::self() {
143 Thread* thread = (Thread*) TlsGetValue(threadStorage);
144 if (!thread) {
145 // *** memory leak - could use GetExitCodeThread to lazily detect when
146 // to clean up native thread objects
147 thread = new Thread(GetCurrentThread(), GetCurrentThreadId());
148 TlsSetValue(threadStorage, thread);
149 }
150 return thread;
151}