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