src/thread.cpp
branchNewGRF_ports
changeset 6719 4cc327ad39d5
parent 6573 7624f942237f
child 6872 1c4a4a609f85
equal deleted inserted replaced
6718:5a8b295aa345 6719:4cc327ad39d5
     1 /* $Id$ */
     1 /* $Id$ */
       
     2 
       
     3 /** @file thread.cpp */
     2 
     4 
     3 #include "stdafx.h"
     5 #include "stdafx.h"
     4 #include "thread.h"
     6 #include "thread.h"
     5 #include <stdlib.h>
     7 #include <stdlib.h>
     6 #include "helpers.hpp"
     8 #include "helpers.hpp"
     7 
     9 
     8 #if defined(__AMIGA__) || defined(__MORPHOS__) || defined(PSP) || defined(NO_THREADS)
    10 #if defined(__AMIGA__) || defined(PSP) || defined(NO_THREADS)
     9 OTTDThread *OTTDCreateThread(OTTDThreadFunc function, void *arg) { return NULL; }
    11 OTTDThread *OTTDCreateThread(OTTDThreadFunc function, void *arg) { return NULL; }
    10 void *OTTDJoinThread(OTTDThread *t) { return NULL; }
    12 void *OTTDJoinThread(OTTDThread *t) { return NULL; }
    11 void OTTDExitThread() { NOT_REACHED(); };
    13 void OTTDExitThread() { NOT_REACHED(); };
    12 
    14 
    13 #elif defined(__OS2__)
    15 #elif defined(__OS2__)
    61 void OTTDExitThread()
    63 void OTTDExitThread()
    62 {
    64 {
    63 	_endthread();
    65 	_endthread();
    64 }
    66 }
    65 
    67 
    66 #elif defined(UNIX)
    68 #elif defined(UNIX) && !defined(MORPHOS)
    67 
    69 
    68 #include <pthread.h>
    70 #include <pthread.h>
    69 
    71 
    70 struct OTTDThread {
    72 struct OTTDThread {
    71 	pthread_t thread;
    73 	pthread_t thread;
   153 
   155 
   154 void OTTDExitThread()
   156 void OTTDExitThread()
   155 {
   157 {
   156 	ExitThread(0);
   158 	ExitThread(0);
   157 }
   159 }
       
   160 
       
   161 
       
   162 #elif defined(MORPHOS)
       
   163 
       
   164 #include <exec/types.h>
       
   165 #include <exec/rawfmt.h>
       
   166 #include <dos/dostags.h>
       
   167 
       
   168 #include <proto/dos.h>
       
   169 #include <proto/exec.h>
       
   170 
       
   171 #include <setjmp.h>
       
   172 
       
   173 /* NOTE: this code heavily depends on latest libnix updates. So make
       
   174  *        sure you link with new stuff which supports semaphore locking of
       
   175  *        the IO resources, else it will just go foobar. */
       
   176 
       
   177 struct OTTDThreadStartupMessage {
       
   178 	struct Message msg;  ///< standard exec.library message (MUST be the first thing in the message struct!)
       
   179 	OTTDThreadFunc func; ///< function the thread will execute
       
   180 	void *arg;           ///< functions arguments for the thread function
       
   181 	void *ret;           ///< return value of the thread function
       
   182 	jmp_buf jumpstore;   ///< storage for the setjump state
       
   183 };
       
   184 
       
   185 struct OTTDThread {
       
   186 	struct MsgPort *replyport;
       
   187 	struct OTTDThreadStartupMessage msg;
       
   188 };
       
   189 
       
   190 
       
   191 /**
       
   192  *  Default OpenTTD STDIO/ERR debug output is not very useful for this, so we
       
   193  *  utilize serial/ramdebug instead.
       
   194  */
       
   195 #ifndef NO_DEBUG_MESSAGES
       
   196 void KPutStr(CONST_STRPTR format)
       
   197 {
       
   198 	RawDoFmt(format, NULL, (void (*)())RAWFMTFUNC_SERIAL, NULL);
       
   199 }
       
   200 #else
       
   201 #define KPutStr(x)
   158 #endif
   202 #endif
       
   203 
       
   204 static void Proxy(void)
       
   205 {
       
   206 	struct Task *child = FindTask(NULL);
       
   207 	struct OTTDThreadStartupMessage *msg;
       
   208 
       
   209 	/* Make sure, we don't block the parent. */
       
   210 	SetTaskPri(child, -5);
       
   211 
       
   212 	KPutStr("[Child] Progressing...\n");
       
   213 
       
   214 	if (NewGetTaskAttrs(NULL, &msg, sizeof(struct OTTDThreadStartupMessage *), TASKINFOTYPE_STARTUPMSG, TAG_DONE) && msg != NULL) {
       
   215 		/* Make use of setjmp() here, so this point can be reached again from inside
       
   216 		 *  OTTDExitThread() which can be called from anythere inside msg->func.
       
   217 		 *  It's a bit ugly and in worst case it leaks some memory. */
       
   218 		if (setjmp(msg->jumpstore) == 0) {
       
   219 			msg->ret = msg->func(msg->arg);
       
   220 		} else {
       
   221 			KPutStr("[Child] Returned to main()\n");
       
   222 		}
       
   223 	}
       
   224 
       
   225 	/*  Quit the child, exec.library will reply the startup msg internally. */
       
   226 	KPutStr("[Child] Done.\n");
       
   227 }
       
   228 
       
   229 OTTDThread* OTTDCreateThread(OTTDThreadFunc function, void *arg)
       
   230 {
       
   231 	OTTDThread *t;
       
   232 	struct Task *parent;
       
   233 
       
   234 	KPutStr("[OpenTTD] Create thread...\n");
       
   235 
       
   236 	t = (struct OTTDThread *)AllocVecTaskPooled(sizeof(struct OTTDThread));
       
   237 	if (t == NULL) return NULL;
       
   238 
       
   239 	parent = FindTask(NULL);
       
   240 
       
   241 	/* Make sure main thread runs with sane priority */
       
   242 	SetTaskPri(parent, 0);
       
   243 
       
   244 	/* Things we'll pass down to the child by utilizing NP_StartupMsg */
       
   245 	t->msg.func = function;
       
   246 	t->msg.arg  = arg;
       
   247 	t->msg.ret  = NULL;
       
   248 
       
   249 	t->replyport = CreateMsgPort();
       
   250 
       
   251 	if (t->replyport != NULL) {
       
   252 		struct Process *child;
       
   253 
       
   254 		t->msg.msg.mn_Node.ln_Type = NT_MESSAGE;
       
   255 		t->msg.msg.mn_ReplyPort    = t->replyport;
       
   256 		t->msg.msg.mn_Length       = sizeof(struct OTTDThreadStartupMessage);
       
   257 
       
   258 		child = CreateNewProcTags(
       
   259 			NP_CodeType,     CODETYPE_PPC,
       
   260 			NP_Entry,        Proxy,
       
   261 			NP_StartupMsg,   (ULONG)&t->msg,
       
   262 			NP_Priority,     5UL,
       
   263 			NP_Name,         (ULONG)"OpenTTD Thread",
       
   264 			NP_PPCStackSize, 131072UL,
       
   265 			TAG_DONE);
       
   266 
       
   267 		if (child != NULL) {
       
   268 			KPutStr("[OpenTTD] Child process launched.\n");
       
   269 			return t;
       
   270 		}
       
   271 		DeleteMsgPort(t->replyport);
       
   272 	}
       
   273 	FreeVecTaskPooled(t);
       
   274 
       
   275 	return NULL;
       
   276 }
       
   277 
       
   278 void* OTTDJoinThread(OTTDThread *t)
       
   279 {
       
   280 	struct OTTDThreadStartupMessage *reply;
       
   281 	void *ret;
       
   282 
       
   283 	KPutStr("[OpenTTD] Join threads...\n");
       
   284 
       
   285 	if (t == NULL) return NULL;
       
   286 
       
   287 	KPutStr("[OpenTTD] Wait for child to quit...\n");
       
   288 	WaitPort(t->replyport);
       
   289 
       
   290 	reply = (struct OTTDThreadStartupMessage *)GetMsg(t->replyport);
       
   291 	ret   = reply->ret;
       
   292 
       
   293 	DeleteMsgPort(t->replyport);
       
   294 	FreeVecTaskPooled(t);
       
   295 
       
   296 	return ret;
       
   297 }
       
   298 
       
   299 void OTTDExitThread()
       
   300 {
       
   301 	struct OTTDThreadStartupMessage *msg;
       
   302 
       
   303 	KPutStr("[Child] Aborting...\n");
       
   304 
       
   305 	if (NewGetTaskAttrs(NULL, &msg, sizeof(struct OTTDThreadStartupMessage *), TASKINFOTYPE_STARTUPMSG, TAG_DONE) && msg != NULL) {
       
   306 		KPutStr("[Child] Jumping back...\n");
       
   307 		longjmp(msg->jumpstore, 0xBEAFCAFE);
       
   308 	}
       
   309 
       
   310 	NOT_REACHED();
       
   311 }
       
   312 
       
   313 #endif