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/>.
10 /** @file thread_pthread.cpp POSIX pthread implementation of Threads. */
12 #include "../stdafx.h"
17 #include "../safeguards.h"
20 * POSIX pthread version for ThreadObject.
22 class ThreadObject_pthread
: public ThreadObject
{
24 pthread_t thread
; ///< System thread identifier.
25 OTTDThreadFunc proc
; ///< External thread procedure.
26 void *param
; ///< Parameter for the external thread procedure.
27 bool self_destruct
; ///< Free ourselves when done?
28 const char *name
; ///< Name for the thread
32 * Create a pthread and start it, calling proc(param).
34 ThreadObject_pthread(OTTDThreadFunc proc
, void *param
, bool self_destruct
, const char *name
) :
38 self_destruct(self_destruct
),
41 pthread_create(&this->thread
, NULL
, &stThreadProc
, this);
44 /* virtual */ bool Exit()
46 assert(pthread_self() == this->thread
);
47 /* For now we terminate by throwing an error, gives much cleaner cleanup */
48 throw OTTDThreadExitSignal();
51 /* virtual */ void Join()
53 /* You cannot join yourself */
54 assert(pthread_self() != this->thread
);
55 pthread_join(this->thread
, NULL
);
60 * On thread creation, this function is called, which calls the real startup
61 * function. This to get back into the correct instance again.
63 static void *stThreadProc(void *thr
)
65 ThreadObject_pthread
*self
= (ThreadObject_pthread
*) thr
;
66 #if defined(__GLIBC__)
67 #if __GLIBC_PREREQ(2, 12)
69 pthread_setname_np(pthread_self(), self
->name
);
78 * A new thread is created, and this function is called. Call the custom
79 * function of the creator of the thread.
83 /* Call the proc of the creator to continue this thread */
85 this->proc(this->param
);
86 } catch (OTTDThreadExitSignal
) {
92 pthread_detach(pthread_self());
98 /* static */ bool ThreadObject::New(OTTDThreadFunc proc
, void *param
, ThreadObject
**thread
, const char *name
)
100 ThreadObject
*to
= new ThreadObject_pthread(proc
, param
, thread
== NULL
, name
);
101 if (thread
!= NULL
) *thread
= to
;
106 * POSIX pthread version of ThreadMutex.
108 class ThreadMutex_pthread
: public ThreadMutex
{
110 pthread_mutex_t mutex
; ///< The actual mutex.
111 pthread_cond_t condition
; ///< Data for conditional waiting.
112 pthread_mutexattr_t attr
; ///< Attributes set for the mutex.
113 pthread_t owner
; ///< Owning thread of the mutex.
114 uint recursive_count
; ///< Recursive lock count.
117 ThreadMutex_pthread() : owner(0), recursive_count(0)
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
);
125 /* virtual */ ~ThreadMutex_pthread()
127 int err
= pthread_cond_destroy(&this->condition
);
128 assert(err
!= EBUSY
);
129 err
= pthread_mutex_destroy(&this->mutex
);
130 assert(err
!= EBUSY
);
133 bool IsOwnedByCurrentThread() const
135 return this->owner
== pthread_self();
138 /* virtual */ void BeginCritical(bool allow_recursive
= false)
140 /* pthread mutex is not recursive by itself */
141 if (this->IsOwnedByCurrentThread()) {
142 if (!allow_recursive
) NOT_REACHED();
144 int err
= pthread_mutex_lock(&this->mutex
);
146 assert(this->recursive_count
== 0);
147 this->owner
= pthread_self();
149 this->recursive_count
++;
152 /* virtual */ void EndCritical(bool allow_recursive
= false)
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;
159 int err
= pthread_mutex_unlock(&this->mutex
);
163 /* virtual */ void WaitForSignal()
165 uint old_recursive_count
= this->recursive_count
;
166 this->recursive_count
= 0;
168 int err
= pthread_cond_wait(&this->condition
, &this->mutex
);
170 this->owner
= pthread_self();
171 this->recursive_count
= old_recursive_count
;
174 /* virtual */ void SendSignal()
176 int err
= pthread_cond_signal(&this->condition
);
181 /* static */ ThreadMutex
*ThreadMutex::New()
183 return new ThreadMutex_pthread();