OpenTTD
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 
27 private:
28  HANDLE thread;
29  uint id;
31  void *param;
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 
117 private:
118  CRITICAL_SECTION critical_section;
119  HANDLE event;
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 }
HANDLE thread
System thread identifier.
void(* OTTDThreadFunc)(void *)
Definition of all thread entry functions.
Definition: thread.h:16
void * param
Parameter for the external thread procedure.
Cross-platform Mutex.
Definition: thread.h:56
void SendSignal()
Send a signal and wake the &#39;thread&#39; that was waiting for it.
void ThreadProc()
A new thread is created, and this function is called.
const char * name
Thread name.
ThreadObject_Win32(OTTDThreadFunc proc, void *param, bool self_destruct, const char *name)
Create a win32 thread and start it, calling proc(param).
Base of all threads.
static ThreadMutex * New()
Create a new mutex.
Definition: thread_none.cpp:32
CRITICAL_SECTION critical_section
The critical section we would enter.
OTTDThreadFunc proc
External thread procedure.
void EndCritical(bool allow_recursive=false)
End of the critical section.
uint id
Thread identifier.
bool Exit()
Exit this thread.
HANDLE event
Event for signalling.
Win32 thread version for ThreadObject.
Win32 thread version of ThreadMutex.
static uint CALLBACK stThreadProc(void *thr)
On thread creation, this function is called, which calls the real startup function.
bool self_destruct
Free ourselves when done?
A Thread Object which works on all our supported OSes.
Definition: thread.h:24
Signal used for signalling we knowingly want to end the thread.
Definition: thread.h:19
static bool New(OTTDThreadFunc proc, void *param, ThreadObject **thread=NULL, const char *name=NULL)
Create a thread; proc will be called as first function inside the thread, with optional params...
void BeginCritical(bool allow_recursive=false)
Begin the critical section.
void WaitForSignal()
Wait for a signal to be send.
void Join()
Join this thread.
uint recursive_count
Recursive lock count.