tron@2285: /* $Id$ */ tron@2285: belugas@6422: /** @file thread.cpp */ belugas@6422: tron@2285: #include "stdafx.h" tron@2285: #include "thread.h" rubidium@8130: #include "core/alloc_func.hpp" tron@2285: #include tron@2285: truelight@6557: #if defined(__AMIGA__) || defined(PSP) || defined(NO_THREADS) truelight@4324: OTTDThread *OTTDCreateThread(OTTDThreadFunc function, void *arg) { return NULL; } truelight@4324: void *OTTDJoinThread(OTTDThread *t) { return NULL; } rubidium@6247: void OTTDExitThread() { NOT_REACHED(); }; tron@2285: tron@2285: #elif defined(__OS2__) tron@2285: tron@2285: #define INCL_DOS tron@2285: #include tron@2285: #include tron@2285: truelight@4298: struct OTTDThread { tron@2285: TID thread; truelight@4298: OTTDThreadFunc func; tron@2286: void* arg; tron@2286: void* ret; tron@2285: }; tron@2285: tron@2286: static void Proxy(void* arg) tron@2286: { rubidium@5587: OTTDThread* t = (OTTDThread*)arg; tron@2286: t->ret = t->func(t->arg); tron@2286: } tron@2286: truelight@4298: OTTDThread* OTTDCreateThread(OTTDThreadFunc function, void* arg) tron@2285: { KUDr@5609: OTTDThread* t = MallocT(1); tron@2285: tron@2285: if (t == NULL) return NULL; tron@2285: tron@2286: t->func = function; tron@2286: t->arg = arg; tron@2286: t->thread = _beginthread(Proxy, NULL, 32768, t); rubidium@5587: if (t->thread != (TID)-1) { tron@2285: return t; tron@2285: } else { tron@2285: free(t); tron@2285: return NULL; tron@2285: } tron@2285: } tron@2285: truelight@4298: void* OTTDJoinThread(OTTDThread* t) tron@2285: { tron@2286: void* ret; tron@2286: tron@2286: if (t == NULL) return NULL; tron@2285: tron@2285: DosWaitThread(&t->thread, DCWW_WAIT); tron@2286: ret = t->ret; tron@2285: free(t); tron@2286: return ret; tron@2285: } tron@2285: rubidium@6247: void OTTDExitThread() truelight@4300: { truelight@4300: _endthread(); truelight@4300: } tron@2285: truelight@6557: #elif defined(UNIX) && !defined(MORPHOS) tron@2285: tron@2285: #include tron@2285: truelight@4298: struct OTTDThread { tron@2285: pthread_t thread; tron@2285: }; tron@2285: truelight@4298: OTTDThread* OTTDCreateThread(OTTDThreadFunc function, void* arg) tron@2285: { KUDr@5609: OTTDThread* t = MallocT(1); tron@2285: tron@2285: if (t == NULL) return NULL; tron@2285: tron@2286: if (pthread_create(&t->thread, NULL, function, arg) == 0) { tron@2285: return t; tron@2285: } else { tron@2285: free(t); tron@2285: return NULL; tron@2285: } tron@2285: } tron@2285: truelight@4298: void* OTTDJoinThread(OTTDThread* t) tron@2285: { tron@2286: void* ret; tron@2285: tron@2286: if (t == NULL) return NULL; tron@2286: tron@2286: pthread_join(t->thread, &ret); tron@2285: free(t); tron@2286: return ret; tron@2285: } tron@2285: rubidium@6247: void OTTDExitThread() truelight@4300: { truelight@4300: pthread_exit(NULL); truelight@4300: } tron@2285: tron@2285: #elif defined(WIN32) tron@2285: tron@2285: #include tron@2285: truelight@4298: struct OTTDThread { tron@2285: HANDLE thread; truelight@4298: OTTDThreadFunc func; tron@2286: void* arg; tron@2286: void* ret; tron@2285: }; tron@2285: tron@2286: static DWORD WINAPI Proxy(LPVOID arg) tron@2286: { rubidium@5587: OTTDThread* t = (OTTDThread*)arg; tron@2286: t->ret = t->func(t->arg); tron@2286: return 0; tron@2286: } tron@2286: truelight@4298: OTTDThread* OTTDCreateThread(OTTDThreadFunc function, void* arg) tron@2285: { KUDr@5609: OTTDThread* t = MallocT(1); tron@2285: DWORD dwThreadId; tron@2285: tron@2285: if (t == NULL) return NULL; tron@2285: tron@2286: t->func = function; tron@2286: t->arg = arg; tron@2287: t->thread = CreateThread(NULL, 0, Proxy, t, 0, &dwThreadId); tron@2285: tron@2285: if (t->thread != NULL) { tron@2285: return t; tron@2285: } else { tron@2285: free(t); tron@2285: return NULL; tron@2285: } tron@2285: } tron@2285: truelight@4298: void* OTTDJoinThread(OTTDThread* t) tron@2285: { tron@2286: void* ret; tron@2286: tron@2286: if (t == NULL) return NULL; tron@2285: tron@2285: WaitForSingleObject(t->thread, INFINITE); tron@2285: CloseHandle(t->thread); tron@2286: ret = t->ret; tron@2285: free(t); tron@2286: return ret; tron@2285: } truelight@4300: rubidium@6247: void OTTDExitThread() truelight@4300: { truelight@4300: ExitThread(0); truelight@4300: } truelight@6557: truelight@6557: truelight@6557: #elif defined(MORPHOS) truelight@6557: truelight@6557: #include truelight@6557: #include truelight@6557: #include truelight@6557: truelight@6557: #include truelight@6557: #include truelight@6557: truelight@6557: #include truelight@6557: truelight@6557: /* NOTE: this code heavily depends on latest libnix updates. So make truelight@6557: * sure you link with new stuff which supports semaphore locking of truelight@6557: * the IO resources, else it will just go foobar. */ truelight@6557: truelight@6557: struct OTTDThreadStartupMessage { truelight@6557: struct Message msg; ///< standard exec.library message (MUST be the first thing in the message struct!) truelight@6557: OTTDThreadFunc func; ///< function the thread will execute truelight@6557: void *arg; ///< functions arguments for the thread function truelight@6557: void *ret; ///< return value of the thread function truelight@6557: jmp_buf jumpstore; ///< storage for the setjump state truelight@6557: }; truelight@6557: truelight@6557: struct OTTDThread { truelight@6557: struct MsgPort *replyport; truelight@6557: struct OTTDThreadStartupMessage msg; truelight@6557: }; truelight@6557: truelight@6557: truelight@6557: /** truelight@6557: * Default OpenTTD STDIO/ERR debug output is not very useful for this, so we truelight@6557: * utilize serial/ramdebug instead. truelight@6557: */ truelight@6557: #ifndef NO_DEBUG_MESSAGES truelight@6557: void KPutStr(CONST_STRPTR format) truelight@6557: { truelight@6557: RawDoFmt(format, NULL, (void (*)())RAWFMTFUNC_SERIAL, NULL); truelight@6557: } truelight@6557: #else truelight@6557: #define KPutStr(x) tron@2285: #endif truelight@6557: truelight@6557: static void Proxy(void) truelight@6557: { truelight@6557: struct Task *child = FindTask(NULL); truelight@6557: struct OTTDThreadStartupMessage *msg; truelight@6557: truelight@6557: /* Make sure, we don't block the parent. */ truelight@6557: SetTaskPri(child, -5); truelight@6557: truelight@6557: KPutStr("[Child] Progressing...\n"); truelight@6557: truelight@6557: if (NewGetTaskAttrs(NULL, &msg, sizeof(struct OTTDThreadStartupMessage *), TASKINFOTYPE_STARTUPMSG, TAG_DONE) && msg != NULL) { truelight@6557: /* Make use of setjmp() here, so this point can be reached again from inside truelight@6557: * OTTDExitThread() which can be called from anythere inside msg->func. truelight@6557: * It's a bit ugly and in worst case it leaks some memory. */ truelight@6557: if (setjmp(msg->jumpstore) == 0) { truelight@6557: msg->ret = msg->func(msg->arg); truelight@6557: } else { truelight@6557: KPutStr("[Child] Returned to main()\n"); truelight@6557: } truelight@6557: } truelight@6557: truelight@6557: /* Quit the child, exec.library will reply the startup msg internally. */ truelight@6557: KPutStr("[Child] Done.\n"); truelight@6557: } truelight@6557: truelight@6557: OTTDThread* OTTDCreateThread(OTTDThreadFunc function, void *arg) truelight@6557: { truelight@6557: OTTDThread *t; truelight@6557: struct Task *parent; truelight@6557: truelight@6557: KPutStr("[OpenTTD] Create thread...\n"); truelight@6557: truelight@6557: t = (struct OTTDThread *)AllocVecTaskPooled(sizeof(struct OTTDThread)); truelight@6557: if (t == NULL) return NULL; truelight@6557: truelight@6557: parent = FindTask(NULL); truelight@6557: truelight@6557: /* Make sure main thread runs with sane priority */ truelight@6557: SetTaskPri(parent, 0); truelight@6557: truelight@6557: /* Things we'll pass down to the child by utilizing NP_StartupMsg */ truelight@6557: t->msg.func = function; truelight@6557: t->msg.arg = arg; truelight@6557: t->msg.ret = NULL; truelight@6557: truelight@6557: t->replyport = CreateMsgPort(); truelight@6557: truelight@6557: if (t->replyport != NULL) { truelight@6557: struct Process *child; truelight@6557: truelight@6557: t->msg.msg.mn_Node.ln_Type = NT_MESSAGE; truelight@6557: t->msg.msg.mn_ReplyPort = t->replyport; truelight@6557: t->msg.msg.mn_Length = sizeof(struct OTTDThreadStartupMessage); truelight@6557: truelight@6557: child = CreateNewProcTags( truelight@6557: NP_CodeType, CODETYPE_PPC, truelight@6557: NP_Entry, Proxy, truelight@6557: NP_StartupMsg, (ULONG)&t->msg, truelight@6557: NP_Priority, 5UL, truelight@6557: NP_Name, (ULONG)"OpenTTD Thread", truelight@6557: NP_PPCStackSize, 131072UL, truelight@6557: TAG_DONE); truelight@6557: truelight@6557: if (child != NULL) { truelight@6557: KPutStr("[OpenTTD] Child process launched.\n"); truelight@6557: return t; truelight@6557: } truelight@6557: DeleteMsgPort(t->replyport); truelight@6557: } truelight@6557: FreeVecTaskPooled(t); truelight@6557: truelight@6557: return NULL; truelight@6557: } truelight@6557: truelight@6557: void* OTTDJoinThread(OTTDThread *t) truelight@6557: { truelight@6557: struct OTTDThreadStartupMessage *reply; truelight@6557: void *ret; truelight@6557: truelight@6557: KPutStr("[OpenTTD] Join threads...\n"); truelight@6557: truelight@6557: if (t == NULL) return NULL; truelight@6557: truelight@6557: KPutStr("[OpenTTD] Wait for child to quit...\n"); truelight@6557: WaitPort(t->replyport); truelight@6557: truelight@6557: reply = (struct OTTDThreadStartupMessage *)GetMsg(t->replyport); truelight@6557: ret = reply->ret; truelight@6557: truelight@6557: DeleteMsgPort(t->replyport); truelight@6557: FreeVecTaskPooled(t); truelight@6557: truelight@6557: return ret; truelight@6557: } truelight@6557: truelight@6557: void OTTDExitThread() truelight@6557: { truelight@6557: struct OTTDThreadStartupMessage *msg; truelight@6557: truelight@6557: KPutStr("[Child] Aborting...\n"); truelight@6557: truelight@6557: if (NewGetTaskAttrs(NULL, &msg, sizeof(struct OTTDThreadStartupMessage *), TASKINFOTYPE_STARTUPMSG, TAG_DONE) && msg != NULL) { truelight@6557: KPutStr("[Child] Jumping back...\n"); truelight@6557: longjmp(msg->jumpstore, 0xBEAFCAFE); truelight@6557: } truelight@6557: truelight@6557: NOT_REACHED(); truelight@6557: } truelight@6557: truelight@6557: #endif