OpenTTD
thread_pthread.cpp
Go to the documentation of this file.
1 /* $Id: thread_pthread.cpp 27670 2016-10-30 17:29:33Z frosch $ */
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 #include "../safeguards.h"
18 
23 private:
24  pthread_t thread;
26  void *param;
28  const char *name;
29 
30 public:
34  ThreadObject_pthread(OTTDThreadFunc proc, void *param, bool self_destruct, const char *name) :
35  thread(0),
36  proc(proc),
37  param(param),
38  self_destruct(self_destruct),
39  name(name)
40  {
41  pthread_create(&this->thread, NULL, &stThreadProc, this);
42  }
43 
44  /* virtual */ bool Exit()
45  {
46  assert(pthread_self() == this->thread);
47  /* For now we terminate by throwing an error, gives much cleaner cleanup */
48  throw OTTDThreadExitSignal();
49  }
50 
51  /* virtual */ void Join()
52  {
53  /* You cannot join yourself */
54  assert(pthread_self() != this->thread);
55  pthread_join(this->thread, NULL);
56  this->thread = 0;
57  }
58 private:
63  static void *stThreadProc(void *thr)
64  {
66 #if defined(__GLIBC__)
67 #if __GLIBC_PREREQ(2, 12)
68  if (self->name) {
69  pthread_setname_np(pthread_self(), self->name);
70  }
71 #endif
72 #endif
73  self->ThreadProc();
74  pthread_exit(NULL);
75  }
76 
81  void ThreadProc()
82  {
83  /* Call the proc of the creator to continue this thread */
84  try {
85  this->proc(this->param);
86  } catch (OTTDThreadExitSignal) {
87  } catch (...) {
88  NOT_REACHED();
89  }
90 
91  if (self_destruct) {
92  pthread_detach(pthread_self());
93  delete this;
94  }
95  }
96 };
97 
98 /* static */ bool ThreadObject::New(OTTDThreadFunc proc, void *param, ThreadObject **thread, const char *name)
99 {
100  ThreadObject *to = new ThreadObject_pthread(proc, param, thread == NULL, name);
101  if (thread != NULL) *thread = to;
102  return true;
103 }
104 
109 private:
110  pthread_mutex_t mutex;
111  pthread_cond_t condition;
112  pthread_mutexattr_t attr;
113  pthread_t owner;
115 
116 public:
117  ThreadMutex_pthread() : owner(0), recursive_count(0)
118  {
119  pthread_mutexattr_init(&this->attr);
120  pthread_mutexattr_settype(&this->attr, PTHREAD_MUTEX_ERRORCHECK);
121  pthread_mutex_init(&this->mutex, &this->attr);
122  pthread_cond_init(&this->condition, NULL);
123  }
124 
125  /* virtual */ ~ThreadMutex_pthread()
126  {
127  int err = pthread_cond_destroy(&this->condition);
128  assert(err != EBUSY);
129  err = pthread_mutex_destroy(&this->mutex);
130  assert(err != EBUSY);
131  }
132 
133  bool IsOwnedByCurrentThread() const
134  {
135  return this->owner == pthread_self();
136  }
137 
138  /* virtual */ void BeginCritical(bool allow_recursive = false)
139  {
140  /* pthread mutex is not recursive by itself */
141  if (this->IsOwnedByCurrentThread()) {
142  if (!allow_recursive) NOT_REACHED();
143  } else {
144  int err = pthread_mutex_lock(&this->mutex);
145  assert(err == 0);
146  assert(this->recursive_count == 0);
147  this->owner = pthread_self();
148  }
149  this->recursive_count++;
150  }
151 
152  /* virtual */ void EndCritical(bool allow_recursive = false)
153  {
154  assert(this->IsOwnedByCurrentThread());
155  if (!allow_recursive && this->recursive_count != 1) NOT_REACHED();
156  this->recursive_count--;
157  if (this->recursive_count != 0) return;
158  this->owner = 0;
159  int err = pthread_mutex_unlock(&this->mutex);
160  assert(err == 0);
161  }
162 
163  /* virtual */ void WaitForSignal()
164  {
165  uint old_recursive_count = this->recursive_count;
166  this->recursive_count = 0;
167  this->owner = 0;
168  int err = pthread_cond_wait(&this->condition, &this->mutex);
169  assert(err == 0);
170  this->owner = pthread_self();
171  this->recursive_count = old_recursive_count;
172  }
173 
174  /* virtual */ void SendSignal()
175  {
176  int err = pthread_cond_signal(&this->condition);
177  assert(err == 0);
178  }
179 };
180 
181 /* static */ ThreadMutex *ThreadMutex::New()
182 {
183  return new ThreadMutex_pthread();
184 }
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.