(svn r27985) -Codechange: Convert VA2 switches into ones with non-overlapping ranges...
[openttd.git] / src / thread / thread_win32.cpp
bloba01ea8e108082b6553934ca6b655df5bb65513ff
1 /* $Id$ */
3 /*
4 * This file is part of OpenTTD.
5 * OpenTTD 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, version 2.
6 * OpenTTD 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.
7 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8 */
10 /** @file thread_win32.cpp Win32 thread implementation of Threads. */
12 #include "../stdafx.h"
13 #include "thread.h"
14 #include "../debug.h"
15 #include "../core/alloc_func.hpp"
16 #include <stdlib.h>
17 #include <windows.h>
18 #include <process.h>
19 #include "../os/windows/win32.h"
21 #include "../safeguards.h"
23 /**
24 * Win32 thread version for ThreadObject.
26 class ThreadObject_Win32 : public ThreadObject {
27 private:
28 HANDLE thread; ///< System thread identifier.
29 uint id; ///< Thread identifier.
30 OTTDThreadFunc proc; ///< External thread procedure.
31 void *param; ///< Parameter for the external thread procedure.
32 bool self_destruct; ///< Free ourselves when done?
33 const char *name; ///< Thread name.
35 public:
36 /**
37 * Create a win32 thread and start it, calling proc(param).
39 ThreadObject_Win32(OTTDThreadFunc proc, void *param, bool self_destruct, const char *name) :
40 thread(NULL),
41 id(0),
42 proc(proc),
43 param(param),
44 self_destruct(self_destruct),
45 name(name)
47 this->thread = (HANDLE)_beginthreadex(NULL, 0, &stThreadProc, this, CREATE_SUSPENDED, &this->id);
48 if (this->thread == NULL) return;
49 ResumeThread(this->thread);
52 /* virtual */ ~ThreadObject_Win32()
54 if (this->thread != NULL) {
55 CloseHandle(this->thread);
56 this->thread = NULL;
60 /* virtual */ bool Exit()
62 assert(GetCurrentThreadId() == this->id);
63 /* For now we terminate by throwing an error, gives much cleaner cleanup */
64 throw OTTDThreadExitSignal();
67 /* virtual */ void Join()
69 /* You cannot join yourself */
70 assert(GetCurrentThreadId() != this->id);
71 WaitForSingleObject(this->thread, INFINITE);
74 private:
75 /**
76 * On thread creation, this function is called, which calls the real startup
77 * function. This to get back into the correct instance again.
79 static uint CALLBACK stThreadProc(void *thr)
81 ((ThreadObject_Win32 *)thr)->ThreadProc();
82 return 0;
85 /**
86 * A new thread is created, and this function is called. Call the custom
87 * function of the creator of the thread.
89 void ThreadProc()
91 #ifdef _MSC_VER
92 /* Set thread name for debuggers. Has to be done from the thread due to a race condition in older MS debuggers. */
93 SetWin32ThreadName(-1, this->name);
94 #endif
95 try {
96 this->proc(this->param);
97 } catch (OTTDThreadExitSignal) {
98 } catch (...) {
99 NOT_REACHED();
102 if (self_destruct) delete this;
106 /* static */ bool ThreadObject::New(OTTDThreadFunc proc, void *param, ThreadObject **thread, const char *name)
108 ThreadObject *to = new ThreadObject_Win32(proc, param, thread == NULL, name);
109 if (thread != NULL) *thread = to;
110 return true;
114 * Win32 thread version of ThreadMutex.
116 class ThreadMutex_Win32 : public ThreadMutex {
117 private:
118 CRITICAL_SECTION critical_section; ///< The critical section we would enter.
119 HANDLE event; ///< Event for signalling.
120 uint recursive_count; ///< Recursive lock count.
122 public:
123 ThreadMutex_Win32() : recursive_count(0)
125 InitializeCriticalSection(&this->critical_section);
126 this->event = CreateEvent(NULL, FALSE, FALSE, NULL);
129 /* virtual */ ~ThreadMutex_Win32()
131 DeleteCriticalSection(&this->critical_section);
132 CloseHandle(this->event);
135 /* virtual */ void BeginCritical(bool allow_recursive = false)
137 /* windows mutex is recursive by itself */
138 EnterCriticalSection(&this->critical_section);
139 this->recursive_count++;
140 if (!allow_recursive && this->recursive_count != 1) NOT_REACHED();
143 /* virtual */ void EndCritical(bool allow_recursive = false)
145 if (!allow_recursive && this->recursive_count != 1) NOT_REACHED();
146 this->recursive_count--;
147 LeaveCriticalSection(&this->critical_section);
150 /* virtual */ void WaitForSignal()
152 assert(this->recursive_count == 1); // Do we need to call Begin/EndCritical multiple times otherwise?
153 this->EndCritical();
154 WaitForSingleObject(this->event, INFINITE);
155 this->BeginCritical();
158 /* virtual */ void SendSignal()
160 SetEvent(this->event);
164 /* static */ ThreadMutex *ThreadMutex::New()
166 return new ThreadMutex_Win32();