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