thread_morphos.cpp

Go to the documentation of this file.
00001 /* $Id: thread_morphos.cpp 15158 2009-01-20 03:12:46Z rubidium $ */
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     /* Make sure main thread runs with sane priority */
00078     SetTaskPri(parent, 0);
00079 
00080     /* Things we'll pass down to the child by utilizing NP_StartupMsg */
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   /* virtual */ ~ThreadObject_MorphOS()
00114   {
00115   }
00116 
00117   /* virtual */ bool Exit()
00118   {
00119     struct OTTDThreadStartupMessage *msg;
00120 
00121     /* You can only exit yourself */
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       /* For now we terminate by throwing an error, gives much cleaner cleanup */
00128       throw OTTDThreadExitSignal();
00129     }
00130 
00131     return true;
00132   }
00133 
00134   /* virtual */ void Join()
00135   {
00136     struct OTTDThreadStartupMessage *reply;
00137 
00138     /* You cannot join yourself */
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   /* virtual */ 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     /* Make sure, we don't block the parent. */
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     /*  Quit the child, exec.library will reply the startup msg internally. */
00181     KPutStr("[Child] Done.\n");
00182 
00183     if (self_destruct) delete this;
00184   }
00185 };
00186 
00187 /* static */ 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 }

Generated on Wed Jun 3 19:05:15 2009 for OpenTTD by  doxygen 1.5.6