# thread_pthread.cpp

Go to the documentation of this file.

    00001 /* $Id: thread_pthread.cpp 26349 2014-02-16 21:37:05Z frosch $ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * 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.
    00006  * 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.
    00007  * 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/>.
    00008  */
    00009
    00012 #include "../stdafx.h"
    00013 #include "thread.h"
    00014 #include <pthread.h>
    00015 #include <errno.h>
    00016
    00020 class ThreadObject_pthread : public ThreadObject {
    00021 private:
    00022   pthread_t thread;
    00023   OTTDThreadFunc proc;
    00024   void *param;
    00025   bool self_destruct;
    00026
    00027 public:
    00031   ThreadObject_pthread(OTTDThreadFunc proc, void *param, bool self_destruct) :
    00032     thread(0),
    00033     proc(proc),
    00034     param(param),
    00035     self_destruct(self_destruct)
    00036   {
    00037     pthread_create(&this->thread, NULL, &stThreadProc, this);
    00038   }
    00039
    00040   /* virtual */ bool Exit()
    00041   {
    00042     assert(pthread_self() == this->thread);
    00043     /* For now we terminate by throwing an error, gives much cleaner cleanup */
    00044     throw OTTDThreadExitSignal();
    00045   }
    00046
    00047   /* virtual */ void Join()
    00048   {
    00049     /* You cannot join yourself */
    00050     assert(pthread_self() != this->thread);
    00051     pthread_join(this->thread, NULL);
    00052     this->thread = 0;
    00053   }
    00054 private:
    00059   static void *stThreadProc(void *thr)
    00060   {
    00061     ((ThreadObject_pthread *)thr)->ThreadProc();
    00062     pthread_exit(NULL);
    00063   }
    00064
    00069   void ThreadProc()
    00070   {
    00071     /* Call the proc of the creator to continue this thread */
    00072     try {
    00073       this->proc(this->param);
    00074     } catch (OTTDThreadExitSignal) {
    00075     } catch (...) {
    00076       NOT_REACHED();
    00077     }
    00078
    00079     if (self_destruct) {
    00080       pthread_detach(pthread_self());
    00081       delete this;
    00082     }
    00083   }
    00084 };
    00085
    00086 /* static */ bool ThreadObject::New(OTTDThreadFunc proc, void *param, ThreadObject **thread)
    00087 {
    00088   ThreadObject *to = new ThreadObject_pthread(proc, param, thread == NULL);
    00089   if (thread != NULL) *thread = to;
    00090   return true;
    00091 }
    00092
    00096 class ThreadMutex_pthread : public ThreadMutex {
    00097 private:
    00098   pthread_mutex_t mutex;
    00099   pthread_cond_t condition;
    00100   pthread_mutexattr_t attr;
    00101   pthread_t owner;
    00102   uint recursive_count;
    00103
    00104 public:
    00105   ThreadMutex_pthread() : owner(0), recursive_count(0)
    00106   {
    00107     pthread_mutexattr_init(&this->attr);
    00108     pthread_mutexattr_settype(&this->attr, PTHREAD_MUTEX_ERRORCHECK);
    00109     pthread_mutex_init(&this->mutex, &this->attr);
    00110     pthread_cond_init(&this->condition, NULL);
    00111   }
    00112
    00113   /* virtual */ ~ThreadMutex_pthread()
    00114   {
    00115     int err = pthread_cond_destroy(&this->condition);
    00116     assert(err != EBUSY);
    00117     err = pthread_mutex_destroy(&this->mutex);
    00118     assert(err != EBUSY);
    00119   }
    00120
    00121   bool IsOwnedByCurrentThread() const
    00122   {
    00123     return this->owner == pthread_self();
    00124   }
    00125
    00126   /* virtual */ void BeginCritical(bool allow_recursive = false)
    00127   {
    00128     /* pthread mutex is not recursive by itself */
    00129     if (this->IsOwnedByCurrentThread()) {
    00130       if (!allow_recursive) NOT_REACHED();
    00131     } else {
    00132       int err = pthread_mutex_lock(&this->mutex);
    00133       assert(err == 0);
    00134       assert(this->recursive_count == 0);
    00135       this->owner = pthread_self();
    00136     }
    00137     this->recursive_count++;
    00138   }
    00139
    00140   /* virtual */ void EndCritical(bool allow_recursive = false)
    00141   {
    00142     assert(this->IsOwnedByCurrentThread());
    00143     if (!allow_recursive && this->recursive_count != 1) NOT_REACHED();
    00144     this->recursive_count--;
    00145     if (this->recursive_count != 0) return;
    00146     this->owner = 0;
    00147     int err = pthread_mutex_unlock(&this->mutex);
    00148     assert(err == 0);
    00149   }
    00150
    00151   /* virtual */ void WaitForSignal()
    00152   {
    00153     uint old_recursive_count = this->recursive_count;
    00154     this->recursive_count = 0;
    00155     this->owner = 0;
    00156     int err = pthread_cond_wait(&this->condition, &this->mutex);
    00157     assert(err == 0);
    00158     this->owner = pthread_self();
    00159     this->recursive_count = old_recursive_count;
    00160   }
    00161
    00162   /* virtual */ void SendSignal()
    00163   {
    00164     int err = pthread_cond_signal(&this->condition);
    00165     assert(err == 0);
    00166   }
    00167 };
    00168
    00169 /* static */ ThreadMutex *ThreadMutex::New()
    00170 {
    00171   return new ThreadMutex_pthread();
    00172 }