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 26482 2014-04-23 20:13:33Z rubidium $ */
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
20 #include "../safeguards.h"
21
25 class ThreadObject_Win32 : public ThreadObject {
26 private:
27 HANDLE thread;
28 uint id;
29 OTTDThreadFunc proc;
30 void *param;
31 bool self_destruct;
32
33 public:
37 ThreadObject_Win32(OTTDThreadFunc proc, void *param, bool self_destruct) :
38 thread(NULL),
39 id(0),
40 proc(proc),
41 param(param),
42 self_destruct(self_destruct)
43 {
44 this->thread = (HANDLE)_beginthreadex(NULL, 0, &stThreadProc, this, CREATE_SUSPENDED, &this->id);
45 if (this->thread == NULL) return;
46 ResumeThread(this->thread);
47 }
48
49 /* virtual */ ~ThreadObject_Win32()
50 {
51 if (this->thread != NULL) {
52 CloseHandle(this->thread);
53 this->thread = NULL;
54 }
55 }
56
57 /* virtual */ bool Exit()
58 {
59 assert(GetCurrentThreadId() == this->id);
60 /* For now we terminate by throwing an error, gives much cleaner cleanup */
61 throw OTTDThreadExitSignal();
62 }
63
64 /* virtual */ void Join()
65 {
66 /* You cannot join yourself */
67 assert(GetCurrentThreadId() != this->id);
68 WaitForSingleObject(this->thread, INFINITE);
69 }
70
71 private:
76 static uint CALLBACK stThreadProc(void *thr)
77 {
78 ((ThreadObject_Win32 *)thr)->ThreadProc();
79 return 0;
80 }
81
86 void ThreadProc()
87 {
88 try {
89 this->proc(this->param);
90 } catch (OTTDThreadExitSignal) {
91 } catch (...) {
92 NOT_REACHED();
93 }
94
95 if (self_destruct) delete this;
96 }
97 };
98
99 /* static */ bool ThreadObject::New(OTTDThreadFunc proc, void *param, ThreadObject **thread)
100 {
101 ThreadObject *to = new ThreadObject_Win32(proc, param, thread == NULL);
102 if (thread != NULL) *thread = to;
103 return true;
104 }
105
109 class ThreadMutex_Win32 : public ThreadMutex {
110 private:
111 CRITICAL_SECTION critical_section;
112 HANDLE event;
113 uint recursive_count;
114
115 public:
116 ThreadMutex_Win32() : recursive_count(0)
117 {
118 InitializeCriticalSection(&this->critical_section);
119 this->event = CreateEvent(NULL, FALSE, FALSE, NULL);
120 }
121
122 /* virtual */ ~ThreadMutex_Win32()
123 {
124 DeleteCriticalSection(&this->critical_section);
125 CloseHandle(this->event);
126 }
127
128 /* virtual */ void BeginCritical(bool allow_recursive = false)
129 {
130 /* windows mutex is recursive by itself */
131 EnterCriticalSection(&this->critical_section);
132 this->recursive_count++;
133 if (!allow_recursive && this->recursive_count != 1) NOT_REACHED();
134 }
135
136 /* virtual */ void EndCritical(bool allow_recursive = false)
137 {
138 if (!allow_recursive && this->recursive_count != 1) NOT_REACHED();
139 this->recursive_count--;
140 LeaveCriticalSection(&this->critical_section);
141 }
142
143 /* virtual */ void WaitForSignal()
144 {
145 assert(this->recursive_count == 1); // Do we need to call Begin/EndCritical multiple times otherwise?
146 this->EndCritical();
147 WaitForSingleObject(this->event, INFINITE);
148 this->BeginCritical();
149 }
150
151 /* virtual */ void SendSignal()
152 {
153 SetEvent(this->event);
154 }
155 };
156
157 /* static */ ThreadMutex *ThreadMutex::New()
158 {
159 return new ThreadMutex_Win32();
160 }