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"
21 * Win32 thread version for ThreadObject.
23 class ThreadObject_Win32
: public ThreadObject
{
25 HANDLE thread
; ///< System thread identifier.
26 uint id
; ///< Thread identifier.
27 OTTDThreadFunc proc
; ///< External thread procedure.
28 void *param
; ///< Parameter for the external thread procedure.
29 bool self_destruct
; ///< Free ourselves when done?
33 * Create a win32 thread and start it, calling proc(param).
35 ThreadObject_Win32(OTTDThreadFunc proc
, void *param
, bool self_destruct
) :
40 self_destruct(self_destruct
)
42 this->thread
= (HANDLE
)_beginthreadex(NULL
, 0, &stThreadProc
, this, CREATE_SUSPENDED
, &this->id
);
43 if (this->thread
== NULL
) return;
44 ResumeThread(this->thread
);
47 /* virtual */ ~ThreadObject_Win32()
49 if (this->thread
!= NULL
) {
50 CloseHandle(this->thread
);
55 /* virtual */ bool Exit()
57 assert(GetCurrentThreadId() == this->id
);
58 /* For now we terminate by throwing an error, gives much cleaner cleanup */
59 throw OTTDThreadExitSignal();
62 /* virtual */ void Join()
64 /* You cannot join yourself */
65 assert(GetCurrentThreadId() != this->id
);
66 WaitForSingleObject(this->thread
, INFINITE
);
71 * On thread creation, this function is called, which calls the real startup
72 * function. This to get back into the correct instance again.
74 static uint CALLBACK
stThreadProc(void *thr
)
76 ((ThreadObject_Win32
*)thr
)->ThreadProc();
81 * A new thread is created, and this function is called. Call the custom
82 * function of the creator of the thread.
87 this->proc(this->param
);
88 } catch (OTTDThreadExitSignal
) {
93 if (self_destruct
) delete this;
97 /* static */ bool ThreadObject::New(OTTDThreadFunc proc
, void *param
, ThreadObject
**thread
)
99 ThreadObject
*to
= new ThreadObject_Win32(proc
, param
, thread
== NULL
);
100 if (thread
!= NULL
) *thread
= to
;
105 * Win32 thread version of ThreadMutex.
107 class ThreadMutex_Win32
: public ThreadMutex
{
109 CRITICAL_SECTION critical_section
; ///< The critical section we would enter.
110 HANDLE event
; ///< Event for signalling.
111 uint recursive_count
; ///< Recursive lock count.
114 ThreadMutex_Win32() : recursive_count(0)
116 InitializeCriticalSection(&this->critical_section
);
117 this->event
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
120 /* virtual */ ~ThreadMutex_Win32()
122 DeleteCriticalSection(&this->critical_section
);
123 CloseHandle(this->event
);
126 /* virtual */ void BeginCritical(bool allow_recursive
= false)
128 /* windows mutex is recursive by itself */
129 EnterCriticalSection(&this->critical_section
);
130 this->recursive_count
++;
131 if (!allow_recursive
&& this->recursive_count
!= 1) NOT_REACHED();
134 /* virtual */ void EndCritical(bool allow_recursive
= false)
136 if (!allow_recursive
&& this->recursive_count
!= 1) NOT_REACHED();
137 this->recursive_count
--;
138 LeaveCriticalSection(&this->critical_section
);
141 /* virtual */ void WaitForSignal()
143 assert(this->recursive_count
== 1); // Do we need to call Begin/EndCritical multiple times otherwise?
145 WaitForSingleObject(this->event
, INFINITE
);
146 this->BeginCritical();
149 /* virtual */ void SendSignal()
151 SetEvent(this->event
);
155 /* static */ ThreadMutex
*ThreadMutex::New()
157 return new ThreadMutex_Win32();