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