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/>.
10 /** @file thread_win32.cpp Win32 thread implementation of Threads. */
12 #include "../stdafx.h"
15 #include "../core/alloc_func.hpp"
19 #include "../os/windows/win32.h"
21 #include "../safeguards.h"
24 * Win32 thread version for ThreadObject.
26 class ThreadObject_Win32
: public ThreadObject
{
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.
37 * Create a win32 thread and start it, calling proc(param).
39 ThreadObject_Win32(OTTDThreadFunc proc
, void *param
, bool self_destruct
, const char *name
) :
44 self_destruct(self_destruct
),
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
);
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
);
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();
86 * A new thread is created, and this function is called. Call the custom
87 * function of the creator of the thread.
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
);
96 this->proc(this->param
);
97 } catch (OTTDThreadExitSignal
) {
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
;
114 * Win32 thread version of ThreadMutex.
116 class ThreadMutex_Win32
: public ThreadMutex
{
118 CRITICAL_SECTION critical_section
; ///< The critical section we would enter.
119 HANDLE event
; ///< Event for signalling.
120 uint recursive_count
; ///< Recursive lock count.
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?
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();