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:
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:
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 }