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 }