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 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
22 class ThreadObject_pthread : public ThreadObject {
23 private:
24 pthread_t thread;
25 OTTDThreadFunc proc;
26 void *param;
27 bool self_destruct;
28
29 public:
33 ThreadObject_pthread(OTTDThreadFunc proc, void *param, bool self_destruct) :
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
98 class ThreadMutex_pthread : public ThreadMutex {
99 private:
100 pthread_mutex_t mutex;
101 pthread_cond_t condition;
102 pthread_mutexattr_t attr;
103 pthread_t owner;
104 uint recursive_count;
105
106 public:
107 ThreadMutex_pthread() : owner(0), recursive_count(0)
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 }