OpenTTD
thread_pthread.cpp
Go to the documentation of this file.
1 /* $Id$ */
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 <pthread.h>
15 #include <errno.h>
16 
17 #if defined(__APPLE__)
18 #include "../os/macosx/macos.h"
19 #endif
20 
21 #include "../safeguards.h"
22 
27 private:
28  pthread_t thread;
30  void *param;
32  const char *name;
33 
34 public:
38  ThreadObject_pthread(OTTDThreadFunc proc, void *param, bool self_destruct, const char *name) :
39  thread(0),
40  proc(proc),
41  param(param),
42  self_destruct(self_destruct),
43  name(name)
44  {
45  pthread_create(&this->thread, NULL, &stThreadProc, this);
46  }
47 
48  /* virtual */ bool Exit()
49  {
50  assert(pthread_self() == this->thread);
51  /* For now we terminate by throwing an error, gives much cleaner cleanup */
52  throw OTTDThreadExitSignal();
53  }
54 
55  /* virtual */ void Join()
56  {
57  /* You cannot join yourself */
58  assert(pthread_self() != this->thread);
59  pthread_join(this->thread, NULL);
60  this->thread = 0;
61  }
62 private:
67  static void *stThreadProc(void *thr)
68  {
70 #if defined(__GLIBC__)
71 #if __GLIBC_PREREQ(2, 12)
72  if (self->name) {
73  pthread_setname_np(pthread_self(), self->name);
74  }
75 #endif
76 #endif
77 #if defined(__APPLE__)
78  MacOSSetThreadName(self->name);
79 #endif
80  self->ThreadProc();
81  pthread_exit(NULL);
82  }
83 
88  void ThreadProc()
89  {
90  /* Call the proc of the creator to continue this thread */
91  try {
92  this->proc(this->param);
93  } catch (OTTDThreadExitSignal) {
94  } catch (...) {
95  NOT_REACHED();
96  }
97 
98  if (self_destruct) {
99  pthread_detach(pthread_self());
100  delete this;
101  }
102  }
103 };
104 
105 /* static */ bool ThreadObject::New(OTTDThreadFunc proc, void *param, ThreadObject **thread, const char *name)
106 {
107  ThreadObject *to = new ThreadObject_pthread(proc, param, thread == NULL, name);
108  if (thread != NULL) *thread = to;
109  return true;
110 }
111 
116 private:
117  pthread_mutex_t mutex;
118  pthread_cond_t condition;
119  pthread_mutexattr_t attr;
120  pthread_t owner;
122 
123 public:
124  ThreadMutex_pthread() : owner(0), recursive_count(0)
125  {
126  pthread_mutexattr_init(&this->attr);
127  pthread_mutexattr_settype(&this->attr, PTHREAD_MUTEX_ERRORCHECK);
128  pthread_mutex_init(&this->mutex, &this->attr);
129  pthread_cond_init(&this->condition, NULL);
130  }
131 
132  /* virtual */ ~ThreadMutex_pthread()
133  {
134  int err = pthread_cond_destroy(&this->condition);
135  assert(err != EBUSY);
136  err = pthread_mutex_destroy(&this->mutex);
137  assert(err != EBUSY);
138  }
139 
140  bool IsOwnedByCurrentThread() const
141  {
142  return this->owner == pthread_self();
143  }
144 
145  /* virtual */ void BeginCritical(bool allow_recursive = false)
146  {
147  /* pthread mutex is not recursive by itself */
148  if (this->IsOwnedByCurrentThread()) {
149  if (!allow_recursive) NOT_REACHED();
150  } else {
151  int err = pthread_mutex_lock(&this->mutex);
152  assert(err == 0);
153  assert(this->recursive_count == 0);
154  this->owner = pthread_self();
155  }
156  this->recursive_count++;
157  }
158 
159  /* virtual */ void EndCritical(bool allow_recursive = false)
160  {
161  assert(this->IsOwnedByCurrentThread());
162  if (!allow_recursive && this->recursive_count != 1) NOT_REACHED();
163  this->recursive_count--;
164  if (this->recursive_count != 0) return;
165  this->owner = 0;
166  int err = pthread_mutex_unlock(&this->mutex);
167  assert(err == 0);
168  }
169 
170  /* virtual */ void WaitForSignal()
171  {
172  uint old_recursive_count = this->recursive_count;
173  this->recursive_count = 0;
174  this->owner = 0;
175  int err = pthread_cond_wait(&this->condition, &this->mutex);
176  assert(err == 0);
177  this->owner = pthread_self();
178  this->recursive_count = old_recursive_count;
179  }
180 
181  /* virtual */ void SendSignal()
182  {
183  int err = pthread_cond_signal(&this->condition);
184  assert(err == 0);
185  }
186 };
187 
188 /* static */ ThreadMutex *ThreadMutex::New()
189 {
190  return new ThreadMutex_pthread();
191 }
void Join()
Join this thread.
void(* OTTDThreadFunc)(void *)
Definition of all thread entry functions.
Definition: thread.h:16
void ThreadProc()
A new thread is created, and this function is called.
POSIX pthread version for ThreadObject.
void SendSignal()
Send a signal and wake the &#39;thread&#39; that was waiting for it.
Cross-platform Mutex.
Definition: thread.h:56
pthread_mutexattr_t attr
Attributes set for the mutex.
pthread_t thread
System thread identifier.
Base of all threads.
pthread_t owner
Owning thread of the mutex.
static ThreadMutex * New()
Create a new mutex.
Definition: thread_none.cpp:32
bool self_destruct
Free ourselves when done?
OTTDThreadFunc proc
External thread procedure.
pthread_mutex_t mutex
The actual mutex.
uint recursive_count
Recursive lock count.
void EndCritical(bool allow_recursive=false)
End of the critical section.
POSIX pthread version of ThreadMutex.
void WaitForSignal()
Wait for a signal to be send.
pthread_cond_t condition
Data for conditional waiting.
ThreadObject_pthread(OTTDThreadFunc proc, void *param, bool self_destruct, const char *name)
Create a pthread and start it, calling proc(param).
void BeginCritical(bool allow_recursive=false)
Begin the critical section.
const char * name
Name for the thread.
static void * stThreadProc(void *thr)
On thread creation, this function is called, which calls the real startup function.
void * param
Parameter for the external thread procedure.
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...
bool Exit()
Exit this thread.