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