thread.cpp

Go to the documentation of this file.
00001 /* $Id: thread.cpp 11691 2007-12-25 09:48:53Z rubidium $ */
00002 
00005 #include "stdafx.h"
00006 #include "thread.h"
00007 #include "core/alloc_func.hpp"
00008 #include <stdlib.h>
00009 
00010 #if defined(__AMIGA__) || defined(PSP) || defined(NO_THREADS)
00011 OTTDThread *OTTDCreateThread(OTTDThreadFunc function, void *arg) { return NULL; }
00012 void *OTTDJoinThread(OTTDThread *t) { return NULL; }
00013 void OTTDExitThread() { NOT_REACHED(); };
00014 
00015 #elif defined(__OS2__)
00016 
00017 #define INCL_DOS
00018 #include <os2.h>
00019 #include <process.h>
00020 
00021 struct OTTDThread {
00022   TID thread;
00023   OTTDThreadFunc func;
00024   void* arg;
00025   void* ret;
00026 };
00027 
00028 static void Proxy(void* arg)
00029 {
00030   OTTDThread* t = (OTTDThread*)arg;
00031   t->ret = t->func(t->arg);
00032 }
00033 
00034 OTTDThread* OTTDCreateThread(OTTDThreadFunc function, void* arg)
00035 {
00036   OTTDThread* t = MallocT<OTTDThread>(1);
00037 
00038   if (t == NULL) return NULL;
00039 
00040   t->func = function;
00041   t->arg  = arg;
00042   t->thread = _beginthread(Proxy, NULL, 32768, t);
00043   if (t->thread != (TID)-1) {
00044     return t;
00045   } else {
00046     free(t);
00047     return NULL;
00048   }
00049 }
00050 
00051 void* OTTDJoinThread(OTTDThread* t)
00052 {
00053   void* ret;
00054 
00055   if (t == NULL) return NULL;
00056 
00057   DosWaitThread(&t->thread, DCWW_WAIT);
00058   ret = t->ret;
00059   free(t);
00060   return ret;
00061 }
00062 
00063 void OTTDExitThread()
00064 {
00065   _endthread();
00066 }
00067 
00068 #elif defined(UNIX) && !defined(MORPHOS)
00069 
00070 #include <pthread.h>
00071 
00072 struct OTTDThread {
00073   pthread_t thread;
00074 };
00075 
00076 OTTDThread* OTTDCreateThread(OTTDThreadFunc function, void* arg)
00077 {
00078   OTTDThread* t = MallocT<OTTDThread>(1);
00079 
00080   if (t == NULL) return NULL;
00081 
00082   if (pthread_create(&t->thread, NULL, function, arg) == 0) {
00083     return t;
00084   } else {
00085     free(t);
00086     return NULL;
00087   }
00088 }
00089 
00090 void* OTTDJoinThread(OTTDThread* t)
00091 {
00092   void* ret;
00093 
00094   if (t == NULL) return NULL;
00095 
00096   pthread_join(t->thread, &ret);
00097   free(t);
00098   return ret;
00099 }
00100 
00101 void OTTDExitThread()
00102 {
00103   pthread_exit(NULL);
00104 }
00105 
00106 #elif defined(WIN32)
00107 
00108 #include <windows.h>
00109 
00110 struct OTTDThread {
00111   HANDLE thread;
00112   OTTDThreadFunc func;
00113   void* arg;
00114   void* ret;
00115 };
00116 
00117 static DWORD WINAPI Proxy(LPVOID arg)
00118 {
00119   OTTDThread* t = (OTTDThread*)arg;
00120   t->ret = t->func(t->arg);
00121   return 0;
00122 }
00123 
00124 OTTDThread* OTTDCreateThread(OTTDThreadFunc function, void* arg)
00125 {
00126   OTTDThread* t = MallocT<OTTDThread>(1);
00127   DWORD dwThreadId;
00128 
00129   if (t == NULL) return NULL;
00130 
00131   t->func = function;
00132   t->arg  = arg;
00133   t->thread = CreateThread(NULL, 0, Proxy, t, 0, &dwThreadId);
00134 
00135   if (t->thread != NULL) {
00136     return t;
00137   } else {
00138     free(t);
00139     return NULL;
00140   }
00141 }
00142 
00143 void* OTTDJoinThread(OTTDThread* t)
00144 {
00145   void* ret;
00146 
00147   if (t == NULL) return NULL;
00148 
00149   WaitForSingleObject(t->thread, INFINITE);
00150   CloseHandle(t->thread);
00151   ret = t->ret;
00152   free(t);
00153   return ret;
00154 }
00155 
00156 void OTTDExitThread()
00157 {
00158   ExitThread(0);
00159 }
00160 
00161 
00162 #elif defined(MORPHOS)
00163 
00164 #include <exec/types.h>
00165 #include <exec/rawfmt.h>
00166 #include <dos/dostags.h>
00167 
00168 #include <proto/dos.h>
00169 #include <proto/exec.h>
00170 
00171 #include <setjmp.h>
00172 
00173 /* NOTE: this code heavily depends on latest libnix updates. So make
00174  *        sure you link with new stuff which supports semaphore locking of
00175  *        the IO resources, else it will just go foobar. */
00176 
00177 struct OTTDThreadStartupMessage {
00178   struct Message msg;  
00179   OTTDThreadFunc func; 
00180   void *arg;           
00181   void *ret;           
00182   jmp_buf jumpstore;   
00183 };
00184 
00185 struct OTTDThread {
00186   struct MsgPort *replyport;
00187   struct OTTDThreadStartupMessage msg;
00188 };
00189 
00190 
00195 #ifndef NO_DEBUG_MESSAGES
00196 void KPutStr(CONST_STRPTR format)
00197 {
00198   RawDoFmt(format, NULL, (void (*)())RAWFMTFUNC_SERIAL, NULL);
00199 }
00200 #else
00201 #define KPutStr(x)
00202 #endif
00203 
00204 static void Proxy(void)
00205 {
00206   struct Task *child = FindTask(NULL);
00207   struct OTTDThreadStartupMessage *msg;
00208 
00209   /* Make sure, we don't block the parent. */
00210   SetTaskPri(child, -5);
00211 
00212   KPutStr("[Child] Progressing...\n");
00213 
00214   if (NewGetTaskAttrs(NULL, &msg, sizeof(struct OTTDThreadStartupMessage *), TASKINFOTYPE_STARTUPMSG, TAG_DONE) && msg != NULL) {
00215     /* Make use of setjmp() here, so this point can be reached again from inside
00216      *  OTTDExitThread() which can be called from anythere inside msg->func.
00217      *  It's a bit ugly and in worst case it leaks some memory. */
00218     if (setjmp(msg->jumpstore) == 0) {
00219       msg->ret = msg->func(msg->arg);
00220     } else {
00221       KPutStr("[Child] Returned to main()\n");
00222     }
00223   }
00224 
00225   /*  Quit the child, exec.library will reply the startup msg internally. */
00226   KPutStr("[Child] Done.\n");
00227 }
00228 
00229 OTTDThread* OTTDCreateThread(OTTDThreadFunc function, void *arg)
00230 {
00231   OTTDThread *t;
00232   struct Task *parent;
00233 
00234   KPutStr("[OpenTTD] Create thread...\n");
00235 
00236   t = (struct OTTDThread *)AllocVecTaskPooled(sizeof(struct OTTDThread));
00237   if (t == NULL) return NULL;
00238 
00239   parent = FindTask(NULL);
00240 
00241   /* Make sure main thread runs with sane priority */
00242   SetTaskPri(parent, 0);
00243 
00244   /* Things we'll pass down to the child by utilizing NP_StartupMsg */
00245   t->msg.func = function;
00246   t->msg.arg  = arg;
00247   t->msg.ret  = NULL;
00248 
00249   t->replyport = CreateMsgPort();
00250 
00251   if (t->replyport != NULL) {
00252     struct Process *child;
00253 
00254     t->msg.msg.mn_Node.ln_Type = NT_MESSAGE;
00255     t->msg.msg.mn_ReplyPort    = t->replyport;
00256     t->msg.msg.mn_Length       = sizeof(struct OTTDThreadStartupMessage);
00257 
00258     child = CreateNewProcTags(
00259       NP_CodeType,     CODETYPE_PPC,
00260       NP_Entry,        Proxy,
00261       NP_StartupMsg,   (ULONG)&t->msg,
00262       NP_Priority,     5UL,
00263       NP_Name,         (ULONG)"OpenTTD Thread",
00264       NP_PPCStackSize, 131072UL,
00265       TAG_DONE);
00266 
00267     if (child != NULL) {
00268       KPutStr("[OpenTTD] Child process launched.\n");
00269       return t;
00270     }
00271     DeleteMsgPort(t->replyport);
00272   }
00273   FreeVecTaskPooled(t);
00274 
00275   return NULL;
00276 }
00277 
00278 void* OTTDJoinThread(OTTDThread *t)
00279 {
00280   struct OTTDThreadStartupMessage *reply;
00281   void *ret;
00282 
00283   KPutStr("[OpenTTD] Join threads...\n");
00284 
00285   if (t == NULL) return NULL;
00286 
00287   KPutStr("[OpenTTD] Wait for child to quit...\n");
00288   WaitPort(t->replyport);
00289 
00290   reply = (struct OTTDThreadStartupMessage *)GetMsg(t->replyport);
00291   ret   = reply->ret;
00292 
00293   DeleteMsgPort(t->replyport);
00294   FreeVecTaskPooled(t);
00295 
00296   return ret;
00297 }
00298 
00299 void OTTDExitThread()
00300 {
00301   struct OTTDThreadStartupMessage *msg;
00302 
00303   KPutStr("[Child] Aborting...\n");
00304 
00305   if (NewGetTaskAttrs(NULL, &msg, sizeof(struct OTTDThreadStartupMessage *), TASKINFOTYPE_STARTUPMSG, TAG_DONE) && msg != NULL) {
00306     KPutStr("[Child] Jumping back...\n");
00307     longjmp(msg->jumpstore, 0xBEAFCAFE);
00308   }
00309 
00310   NOT_REACHED();
00311 }
00312 
00313 #endif

Generated on Wed Oct 1 17:03:24 2008 for openttd by  doxygen 1.5.6