00001
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
00174
00175
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
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
00216
00217
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
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
00242 SetTaskPri(parent, 0);
00243
00244
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