OpenTTD

- Main Page
- Related Pages
- Modules
- Namespaces
- Data Structures
- Files

- File List
- Globals

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
22 class ThreadObject_pthread : public ThreadObject {
23 private:
24 pthread_t thread;
25 OTTDThreadFunc proc;
26 void *param;
27 bool self_destruct;
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 {
65 ThreadObject_pthread *self = (ThreadObject_pthread *) thr;
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
108 class ThreadMutex_pthread : public ThreadMutex {
109 private:
110 pthread_mutex_t mutex;
111 pthread_cond_t condition;
112 pthread_mutexattr_t attr;
113 pthread_t owner;
114 uint recursive_count;
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 }