thread_morphos.cpp
Go to the documentation of this file.00001
00002
00005 #include "stdafx.h"
00006 #include "thread.h"
00007 #include "debug.h"
00008 #include "core/alloc_func.hpp"
00009 #include <stdlib.h>
00010 #include <unistd.h>
00011
00012 #include <exec/types.h>
00013 #include <exec/rawfmt.h>
00014 #include <dos/dostags.h>
00015
00016 #include <proto/dos.h>
00017 #include <proto/exec.h>
00018
00022 #undef Exit
00023 #undef Wait
00024
00025
00033 struct OTTDThreadStartupMessage {
00034 struct Message msg;
00035 OTTDThreadFunc func;
00036 void *arg;
00037 };
00038
00039
00044 #ifndef NO_DEBUG_MESSAGES
00045 void KPutStr(CONST_STRPTR format)
00046 {
00047 RawDoFmt(format, NULL, (void (*)())RAWFMTFUNC_SERIAL, NULL);
00048 }
00049 #else
00050 #define KPutStr(x)
00051 #endif
00052
00053
00057 class ThreadObject_MorphOS : public ThreadObject {
00058 private:
00059 APTR m_thr;
00060 struct MsgPort *m_replyport;
00061 struct OTTDThreadStartupMessage m_msg;
00062 bool self_destruct;
00063
00064 public:
00068 ThreadObject_MorphOS(OTTDThreadFunc proc, void *param, self_destruct) :
00069 m_thr(0), self_destruct(self_destruct)
00070 {
00071 struct Task *parent;
00072
00073 KPutStr("[OpenTTD] Create thread...\n");
00074
00075 parent = FindTask(NULL);
00076
00077
00078 SetTaskPri(parent, 0);
00079
00080
00081 m_msg.func = proc;
00082 m_msg.arg = param;
00083
00084 m_replyport = CreateMsgPort();
00085
00086 if (m_replyport != NULL) {
00087 struct Process *child;
00088
00089 m_msg.msg.mn_Node.ln_Type = NT_MESSAGE;
00090 m_msg.msg.mn_ReplyPort = m_replyport;
00091 m_msg.msg.mn_Length = sizeof(struct OTTDThreadStartupMessage);
00092
00093 child = CreateNewProcTags(
00094 NP_CodeType, CODETYPE_PPC,
00095 NP_Entry, ThreadObject_MorphOS::Proxy,
00096 NP_StartupMsg, (IPTR)&m_msg,
00097 NP_Priority, 5UL,
00098 NP_Name, (IPTR)"OpenTTD Thread",
00099 NP_PPCStackSize, 131072UL,
00100 TAG_DONE);
00101
00102 m_thr = (APTR) child;
00103
00104 if (child != NULL) {
00105 KPutStr("[OpenTTD] Child process launched.\n");
00106 } else {
00107 KPutStr("[OpenTTD] Couldn't create child process. (constructors never fail, yeah!)\n");
00108 DeleteMsgPort(m_replyport);
00109 }
00110 }
00111 }
00112
00113 ~ThreadObject_MorphOS()
00114 {
00115 }
00116
00117 bool Exit()
00118 {
00119 struct OTTDThreadStartupMessage *msg;
00120
00121
00122 assert(IsCurrent());
00123
00124 KPutStr("[Child] Aborting...\n");
00125
00126 if (NewGetTaskAttrs(NULL, &msg, sizeof(struct OTTDThreadStartupMessage *), TASKINFOTYPE_STARTUPMSG, TAG_DONE) && msg != NULL) {
00127
00128 throw OTTDThreadExitSignal();
00129 }
00130
00131 return true;
00132 }
00133
00134 void Join()
00135 {
00136 struct OTTDThreadStartupMessage *reply;
00137
00138
00139 assert(!IsCurrent());
00140
00141 KPutStr("[OpenTTD] Join threads...\n");
00142 KPutStr("[OpenTTD] Wait for child to quit...\n");
00143 WaitPort(m_replyport);
00144
00145 GetMsg(m_replyport);
00146 DeleteMsgPort(m_replyport);
00147 m_thr = 0;
00148 }
00149
00150 bool IsCurrent()
00151 {
00152 return FindTask(NULL) == m_thr;
00153 }
00154
00155 private:
00160 static void Proxy(void)
00161 {
00162 struct Task *child = FindTask(NULL);
00163 struct OTTDThreadStartupMessage *msg;
00164
00165
00166 SetTaskPri(child, -5);
00167
00168 KPutStr("[Child] Progressing...\n");
00169
00170 if (NewGetTaskAttrs(NULL, &msg, sizeof(struct OTTDThreadStartupMessage *), TASKINFOTYPE_STARTUPMSG, TAG_DONE) && msg != NULL) {
00171 try {
00172 msg->func(msg->arg);
00173 } catch(OTTDThreadExitSignal e) {
00174 KPutStr("[Child] Returned to main()\n");
00175 } catch(...) {
00176 NOT_REACHED();
00177 }
00178 }
00179
00180
00181 KPutStr("[Child] Done.\n");
00182
00183 if (self_destruct) delete this;
00184 }
00185 };
00186
00187 bool ThreadObject::New(OTTDThreadFunc proc, void *param, ThreadObject **thread)
00188 {
00189 ThreadObject *to = new ThreadObject_MorphOS(proc, param, thread == NULL);
00190 if (thread != NULL) *thread = to;
00191 return true;
00192 }