OpenTTD

- Main Page
- Related Pages
- Modules
- Namespaces
- Data Structures
- Files

- File List
- Globals

thread_win32.cpp
Go to the documentation of this file.
1 /* $Id: thread_win32.cpp 27673 2016-10-30 18:22:55Z michi_cc $ */
2
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 */
9
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"
20
21 #include "../safeguards.h"
22
26 class ThreadObject_Win32 : public ThreadObject {
27 private:
28 HANDLE thread;
29 uint id;
30 OTTDThreadFunc proc;
31 void *param;
32 bool self_destruct;
33 const char *name;
34
35 public:
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)
46 {
47 this->thread = (HANDLE)_beginthreadex(NULL, 0, &stThreadProc, this, CREATE_SUSPENDED, &this->id);
48 if (this->thread == NULL) return;
49 ResumeThread(this->thread);
50 }
51
52 /* virtual */ ~ThreadObject_Win32()
53 {
54 if (this->thread != NULL) {
55 CloseHandle(this->thread);
56 this->thread = NULL;
57 }
58 }
59
60 /* virtual */ bool Exit()
61 {
62 assert(GetCurrentThreadId() == this->id);
63 /* For now we terminate by throwing an error, gives much cleaner cleanup */
64 throw OTTDThreadExitSignal();
65 }
66
67 /* virtual */ void Join()
68 {
69 /* You cannot join yourself */
70 assert(GetCurrentThreadId() != this->id);
71 WaitForSingleObject(this->thread, INFINITE);
72 }
73
74 private:
79 static uint CALLBACK stThreadProc(void *thr)
80 {
81 ((ThreadObject_Win32 *)thr)->ThreadProc();
82 return 0;
83 }
84
89 void ThreadProc()
90 {
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();
100 }
101
102 if (self_destruct) delete this;
103 }
104 };
105
106 /* static */ bool ThreadObject::New(OTTDThreadFunc proc, void *param, ThreadObject **thread, const char *name)
107 {
108 ThreadObject *to = new ThreadObject_Win32(proc, param, thread == NULL, name);
109 if (thread != NULL) *thread = to;
110 return true;
111 }
112
116 class ThreadMutex_Win32 : public ThreadMutex {
117 private:
118 CRITICAL_SECTION critical_section;
119 HANDLE event;
120 uint recursive_count;
121
122 public:
123 ThreadMutex_Win32() : recursive_count(0)
124 {
125 InitializeCriticalSection(&this->critical_section);
126 this->event = CreateEvent(NULL, FALSE, FALSE, NULL);
127 }
128
129 /* virtual */ ~ThreadMutex_Win32()
130 {
131 DeleteCriticalSection(&this->critical_section);
132 CloseHandle(this->event);
133 }
134
135 /* virtual */ void BeginCritical(bool allow_recursive = false)
136 {
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();
141 }
142
143 /* virtual */ void EndCritical(bool allow_recursive = false)
144 {
145 if (!allow_recursive && this->recursive_count != 1) NOT_REACHED();
146 this->recursive_count--;
147 LeaveCriticalSection(&this->critical_section);
148 }
149
150 /* virtual */ void WaitForSignal()
151 {
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();
156 }
157
158 /* virtual */ void SendSignal()
159 {
160 SetEvent(this->event);
161 }
162 };
163
164 /* static */ ThreadMutex *ThreadMutex::New()
165 {
166 return new ThreadMutex_Win32();
167 }