thread_win32.cpp

Go to the documentation of this file.
00001 /* $Id: thread_win32.cpp 26353 2014-02-18 17:58:46Z 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 "../debug.h"
00015 #include "../core/alloc_func.hpp"
00016 #include <stdlib.h>
00017 #include <windows.h>
00018 #include <process.h>
00019 
00023 class ThreadObject_Win32 : public ThreadObject {
00024 private:
00025   HANDLE thread;       
00026   uint id;             
00027   OTTDThreadFunc proc; 
00028   void *param;         
00029   bool self_destruct;  
00030 
00031 public:
00035   ThreadObject_Win32(OTTDThreadFunc proc, void *param, bool self_destruct) :
00036     thread(NULL),
00037     id(0),
00038     proc(proc),
00039     param(param),
00040     self_destruct(self_destruct)
00041   {
00042     this->thread = (HANDLE)_beginthreadex(NULL, 0, &stThreadProc, this, CREATE_SUSPENDED, &this->id);
00043     if (this->thread == NULL) return;
00044     ResumeThread(this->thread);
00045   }
00046 
00047   /* virtual */ ~ThreadObject_Win32()
00048   {
00049     if (this->thread != NULL) {
00050       CloseHandle(this->thread);
00051       this->thread = NULL;
00052     }
00053   }
00054 
00055   /* virtual */ bool Exit()
00056   {
00057     assert(GetCurrentThreadId() == this->id);
00058     /* For now we terminate by throwing an error, gives much cleaner cleanup */
00059     throw OTTDThreadExitSignal();
00060   }
00061 
00062   /* virtual */ void Join()
00063   {
00064     /* You cannot join yourself */
00065     assert(GetCurrentThreadId() != this->id);
00066     WaitForSingleObject(this->thread, INFINITE);
00067   }
00068 
00069 private:
00074   static uint CALLBACK stThreadProc(void *thr)
00075   {
00076     ((ThreadObject_Win32 *)thr)->ThreadProc();
00077     return 0;
00078   }
00079 
00084   void ThreadProc()
00085   {
00086     try {
00087       this->proc(this->param);
00088     } catch (OTTDThreadExitSignal) {
00089     } catch (...) {
00090       NOT_REACHED();
00091     }
00092 
00093     if (self_destruct) delete this;
00094   }
00095 };
00096 
00097 /* static */ bool ThreadObject::New(OTTDThreadFunc proc, void *param, ThreadObject **thread)
00098 {
00099   ThreadObject *to = new ThreadObject_Win32(proc, param, thread == NULL);
00100   if (thread != NULL) *thread = to;
00101   return true;
00102 }
00103 
00107 class ThreadMutex_Win32 : public ThreadMutex {
00108 private:
00109   CRITICAL_SECTION critical_section; 
00110   HANDLE event;                      
00111   uint recursive_count;     
00112 
00113 public:
00114   ThreadMutex_Win32() : recursive_count(0)
00115   {
00116     InitializeCriticalSection(&this->critical_section);
00117     this->event = CreateEvent(NULL, FALSE, FALSE, NULL);
00118   }
00119 
00120   /* virtual */ ~ThreadMutex_Win32()
00121   {
00122     DeleteCriticalSection(&this->critical_section);
00123     CloseHandle(this->event);
00124   }
00125 
00126   /* virtual */ void BeginCritical(bool allow_recursive = false)
00127   {
00128     /* windows mutex is recursive by itself */
00129     EnterCriticalSection(&this->critical_section);
00130     this->recursive_count++;
00131     if (!allow_recursive && this->recursive_count != 1) NOT_REACHED();
00132   }
00133 
00134   /* virtual */ void EndCritical(bool allow_recursive = false)
00135   {
00136     if (!allow_recursive && this->recursive_count != 1) NOT_REACHED();
00137     this->recursive_count--;
00138     LeaveCriticalSection(&this->critical_section);
00139   }
00140 
00141   /* virtual */ void WaitForSignal()
00142   {
00143     assert(this->recursive_count == 1); // Do we need to call Begin/EndCritical multiple times otherwise?
00144     this->EndCritical();
00145     WaitForSingleObject(this->event, INFINITE);
00146     this->BeginCritical();
00147   }
00148 
00149   /* virtual */ void SendSignal()
00150   {
00151     SetEvent(this->event);
00152   }
00153 };
00154 
00155 /* static */ ThreadMutex *ThreadMutex::New()
00156 {
00157   return new ThreadMutex_Win32();
00158 }