/* :ts=4 ipcsubproc.c IPC sub-process, launched and controlled from the outside. This program should be pure and re-entrant, so that it can be launched several times from the same seglist, if needed. Use no globals, use no static data. Variables should be put to struct localdata. If this structure grows very large, allocate it from global memory pool (AllocVec) instead of stack. Written by Harry "Piru" Sintonen . This source code is Public Domain. */ #include #include #include #include #include "ipc.h" #ifdef __MORPHOS__ /* Tell MorphOS this is a native MOS application and not PUP */ const LONG __amigappc__ = 1; const LONG __abox__ = 1; #endif struct localdata { struct ExecBase *ld_SysBase; struct IntuitionBase *ld_IntuitionBase; }; #define SysBase ld->ld_SysBase #define IntuitionBase ld->ld_IntuitionBase BOOL init(struct localdata *ld); void cleanup(struct localdata *ld); /* The first function of the first objectfile is started. There is no * argument parsing or any startup routine, so everything needs to be * done "by hand". */ void entry(void) { struct localdata _ld, *ld = &_ld; struct Process *Self; struct MsgPort *ipcport; struct IPCMsg *ipcmsg; BOOL result = FALSE; memset(ld, 0, sizeof(*ld)); SysBase = *((struct ExecBase **) 4); Self = (struct Process *) FindTask(NULL); /* Wait for the startup message */ WaitPort(&Self->pr_MsgPort); ipcmsg = (APTR) GetMsg(&Self->pr_MsgPort); ipcport = CreateMsgPort(); if (ipcport) { result = init(ld); } if (result) { /* success, return the port address for further ipc messages */ ipcmsg->ipc_port = ipcport; ReplyMsg((APTR) ipcmsg); } else { /* oops, something failed */ cleanup(ld); /* failed, indicate with NULL port */ ipcmsg->ipc_port = NULL; /* Forbid to make sure the process won't get unloaded while * we still execute it. */ Forbid(); ReplyMsg((APTR) ipcmsg); /* We're done! */ return; } /* The main loop */ for (;;) { WaitPort(ipcport); while ((ipcmsg = (APTR) GetMsg(ipcport))) { ipcmsg->ipc_result = IPCE_NOACTION; switch (ipcmsg->ipc_action) { case IPCA_STARTUP: /* IPCA_STARTUP should never be used at this point. * If it is, do nothing. Will return IPCE_NOACTION result. */ break; case IPCA_BEEP: DisplayBeep(ipcmsg->ipc_screen); ipcmsg->ipc_result = IPCE_OK; break; case IPCA_QUIT: cleanup(ld); ipcmsg->ipc_result = IPCE_OK; /* Forbid to make sure the process won't get unloaded while * we still execute it. This also ensures that all pending * messages get properly replied with IPCE_ABORTED result. */ Forbid(); ReplyMsg((APTR) ipcmsg); /* Reply all pending messages with IPCE_ABORTED result */ while ((ipcmsg = (APTR) GetMsg(ipcport))) { ipcmsg->ipc_result = IPCE_ABORTED; ReplyMsg((APTR) ipcmsg); } /* Now ipcport is empty, and it's safe to delete it */ DeleteMsgPort(ipcport); /* We're done! */ return; } ReplyMsg((APTR) ipcmsg); } } } BOOL init(struct localdata *ld) { IntuitionBase = (APTR) OpenLibrary("intuition.library", 37); if (!IntuitionBase) return FALSE; return TRUE; } void cleanup(struct localdata *ld) { if (IntuitionBase) { CloseLibrary((APTR) IntuitionBase); IntuitionBase = NULL; } }