OpenTTD
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 
26 private:
27  HANDLE thread;
28  uint id;
30  void *param;
32 
33 public:
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 
110 private:
111  CRITICAL_SECTION critical_section;
112  HANDLE event;
114 
115 public:
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 }