thread_morphos.cpp

Go to the documentation of this file.
00001 /* $Id: thread_morphos.cpp 17339 2009-09-01 10:07:22Z rubidium $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
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     /* Make sure main thread runs with sane priority */
00085     SetTaskPri(parent, 0);
00086 
00087     /* Things we'll pass down to the child by utilizing NP_StartupMsg */
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   /* virtual */ ~ThreadObject_MorphOS()
00121   {
00122   }
00123 
00124   /* virtual */ bool Exit()
00125   {
00126     struct OTTDThreadStartupMessage *msg;
00127 
00128     /* You can only exit yourself */
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       /* For now we terminate by throwing an error, gives much cleaner cleanup */
00135       throw OTTDThreadExitSignal();
00136     }
00137 
00138     return true;
00139   }
00140 
00141   /* virtual */ void Join()
00142   {
00143     struct OTTDThreadStartupMessage *reply;
00144 
00145     /* You cannot join yourself */
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   /* virtual */ 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     /* Make sure, we don't block the parent. */
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     /*  Quit the child, exec.library will reply the startup msg internally. */
00188     KPutStr("[Child] Done.\n");
00189 
00190     if (self_destruct) delete this;
00191   }
00192 };
00193 
00194 /* static */ 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 }

Generated on Sat Jul 17 18:43:25 2010 for OpenTTD by  doxygen 1.6.1