# 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