home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 200-299 / ff236.lzh / Proc / proc.c < prev    next >
C/C++ Source or Header  |  1989-08-09  |  9KB  |  283 lines

  1. /*  :ts=8 bk=0
  2.  *
  3.  * proc.c:    Illustration of how to create a full-fledged DOS process
  4.  *        without needing to LoadSeg() it first.  Based on an idea
  5.  *        presented at BADGE (don't remember the name of the guy
  6.  *        who thought it up).
  7.  *
  8.  * Leo L. Schwab                8903.01
  9.  */
  10. #include <exec/types.h>
  11. #include <libraries/dosextens.h>
  12.  
  13. extern void    *AllocMem(), *CreatePort(), *GetMsg(), *FindTask();
  14.  
  15. extern LONG    Open(), Output(), CreateProc();
  16.  
  17.  
  18. /*
  19.  * Cursor manipulation strings.
  20.  */
  21. char    fwdcursor[] = "\033[C";
  22. char    backcursor = '\b';
  23.  
  24. /*
  25.  * Buried deep in the AmigaDOS Technical Reference Manual, the structure of
  26.  * of memory lists and SegLists are described.  A SegList consists of a BPTR
  27.  * to the next element in the list (NULL-terminated), followed by code.
  28.  * The pointers point to the NextSeg field.  The size of the node in bytes
  29.  * is stored in the longword just before NextSeg field.  However, the
  30.  * size is only of real interest to UnLoadSeg(), which you won't be calling
  31.  * in this case.  So we don't need it.
  32.  *
  33.  * So the PhonySegList structure consists merely of a NextSeg field, which
  34.  * is initialized to NULL (CreateProc() ignores this field, anyway), followed
  35.  * by code to execute, which CreateProc() will jump to.  The code we give it
  36.  * to execute is an absolute jump to the real entry point, which you
  37.  * initialize appropriately.
  38.  */
  39. struct PhonySegList {
  40.     BPTR    psl_NextSeg;        /*  BPTR to next element in list  */
  41.     UWORD    psl_JMP;        /*  A 68000 JMP abs.l instruction  */
  42.     LONG    (*psl_EntryPoint)();    /*  The address of the function  */
  43. };
  44.  
  45. /*
  46.  * This is NOT the structure that will actually get passed to CreateProc().
  47.  * AmigaDOS demands that everything, including SegLists, be on longword
  48.  * boundaries.  Short of compiler-dependent switches, the only way to
  49.  * guarantee correct alignment is to AllocMem() a PhonySegList structure,
  50.  * and copy this template into it.  You should also remember to initialize
  51.  * the psl_EntryPoint field (the argument to the JMP instruction) in the
  52.  * allocated structure, for obvious reasons.
  53.  */
  54. struct PhonySegList template = {
  55.     NULL,                /*  No next element.          */
  56.     0x4EF9,                /*  JMP abs.l              */
  57.     NULL                /*  Argument for JMP instruction  */
  58. };
  59.  
  60.  
  61. /*
  62.  * This is the routine that will be CreateProc()ed.  Due to the global nature
  63.  * of library base variables, any library routines this routine calls will
  64.  * be using library base variables that, strictly speaking, belong to the
  65.  * "parent" process.  Despite the fact that it will work, this is
  66.  * nevertheless a dangerous practice.  In an ideal world, you would want to
  67.  * convince the linker to resolve all library base pointer references to 
  68.  * your co-process's own copies.  Lattice, on the other hand, due to its
  69.  * #pragmas, may not have this problem (can someone confirm this?).
  70.  */
  71. LONG
  72. coprocess ()
  73. {
  74.     register int    i, n;
  75.     struct Process    *me;
  76.     struct Message    *startupmsg;
  77.     LONG        doswin;
  78.     char        buf[256];
  79.  
  80. #ifdef    AZTEC_C
  81. #ifndef    _LARGE_DATA
  82.     /*
  83.      * This gets to be a bloody nuisance.
  84.      */
  85.     geta4 ();
  86. #endif
  87. #endif
  88.     /*
  89.      * Startup messages are important.  Not only can they provide
  90.      * configuration information for the newly-created process (what
  91.      * directory you're in, what size to make your window, etc.), but
  92.      * they also serve to inform the program that started you that
  93.      * you have finished executing.  This is important, because the
  94.      * parent program will want to know when it's okay to free the
  95.      * resources it allocated to start you.  In this example, we
  96.      * grab the message so that we can reply it.  The act of replying
  97.      * the startup message will inform the parent that we're done.
  98.      */
  99.     me = FindTask (NULL);
  100.     WaitPort (&me -> pr_MsgPort);
  101.     startupmsg = GetMsg (&me -> pr_MsgPort);
  102.  
  103.     /*
  104.      * Recall that, because a global DOSBase pointer has been initialized
  105.      * by the parent, and because the stubs will reference it at the link
  106.      * stage, we don't need to open dos.library here.
  107.      */
  108.     if (!(doswin = Open ("CON:0/0/320/100/Sub-Process", MODE_NEWFILE)))
  109.         goto xit;
  110.  
  111.     /*
  112.      * Say hello.
  113.      */
  114.     Write (doswin, "This is the child speaking.\n", 28L);
  115.  
  116.     /*
  117.      * Print the value of FindTask(NULL) to prove we're a separate
  118.      * task, and print some values in the Process structure to prove
  119.      * we're a real process.
  120.      *
  121.      * (Another caveat:  The stdio functions in this example (like
  122.      * sprintf()) are being shared by both processes.  Some stdio
  123.      * routines utilize a set of global variables, access to which is
  124.      * not arbitrated.  Therefore, it is possible for the processes to
  125.      * collide when calling stdio functions, causing Bad Things to
  126.      * happen.  Be aware of this when doing your own multiprogramming.
  127.      * (I'm pretty sure sprintf() is safe.))
  128.      */
  129.     sprintf (buf, "I'm at 0x%lx\n", me);
  130.     Write (doswin, buf, (LONG) strlen (buf));
  131.  
  132.     sprintf (buf, "My stack size appears to be\n%ld bytes.\n",
  133.          me -> pr_StackSize);
  134.     Write (doswin, buf, (LONG) strlen (buf));
  135.  
  136.     sprintf (buf, "pr_StackBase is 0x%lx\n", me -> pr_StackBase);
  137.     Write (doswin, buf, (LONG) strlen (buf));
  138.  
  139.     /*
  140.      * Make the cursor in the window zot back and forth, which will
  141.      * happen concurrently with the same action in the CLI window,
  142.      * proving beyond a shadow of a doubt that there really are two
  143.      * separate programs running.
  144.      */
  145.     for (n = 20;  n--; ) {
  146.         for (i = 35;  i--; )
  147.             Write (doswin, fwdcursor, sizeof (fwdcursor) - 1L);
  148.         for (i = 35;  i--; )
  149.             Write (doswin, &backcursor, 1L);
  150.     }
  151.  
  152.     /*
  153.      * We've proved our existence.  We now reply our startup message,
  154.      * and exit.  Note the use of Forbid() without a corresponding
  155.      * Permit().  This prevents this process from being switched out
  156.      * before exiting completely.  When this process is totally gone,
  157.      * Exec will notice, and do the equivalent of a Permit() internally.
  158.      */
  159.     Close (doswin);            /*  Get ridda da window.  */
  160. xit:
  161.     Forbid ();
  162.     ReplyMsg (startupmsg);
  163.     return (0);
  164. }
  165.  
  166.  
  167. /*
  168.  * Here is the main program.  Its job will be to create the support
  169.  * structures to fire off the sub-process, print out some relevant
  170.  * information, then while away the time until the child exits.
  171.  */
  172. main ()
  173. {
  174.     register int        i;
  175.     struct Process        *me;
  176.     struct MsgPort        *replyport = NULL;
  177.     struct Message        startupmsg;
  178.     struct PhonySegList    *fakelist = NULL;
  179.     LONG            child,
  180.                 priority,
  181.                 term;
  182.  
  183.     /*
  184.      * Get a handle on the current output stream so that we can Write()
  185.      * to it.  Note that this implies this program really ought to be
  186.      * run from a CLI.
  187.      */
  188.     if (!(term = Output ()))
  189.         goto xit;
  190.  
  191.     /*
  192.      * Create a message port for the startup message to be replied to.
  193.      */
  194.     if (!(replyport = CreatePort (NULL, NULL)))
  195.         goto xit;
  196.  
  197.     /*
  198.      * Allocate a PhonySegList structure.
  199.      */
  200.     if (!(fakelist = AllocMem ((LONG) sizeof (*fakelist), NULL)))
  201.         goto xit;
  202.  
  203.     /*
  204.      * Copy the template into the allocated memory, and set the entry
  205.      * point to the sub-process.
  206.      */
  207.     CopyMem (&template, fakelist, (LONG) sizeof (template));
  208.     fakelist -> psl_EntryPoint = coprocess;
  209.  
  210.     /*
  211.      * Initialize the startup message.  There's nothing really amazing
  212.      * happening here.  Its sole purpose in life is to be replied.
  213.      */
  214.     startupmsg.mn_Node.ln_Type    = NT_MESSAGE;
  215.     startupmsg.mn_Node.ln_Pri    = 0;
  216.     startupmsg.mn_ReplyPort        = replyport;
  217.  
  218.     /*
  219.      * Find ourselves.  Discover what priority we're running at, so that
  220.      * we can start the sub-process at the same priority.
  221.      */
  222.     me = FindTask (NULL);
  223.     priority = me -> pr_Task.tc_Node.ln_Pri;
  224.  
  225.     /*
  226.      * Print some information about ourselves.
  227.      */
  228.     puts ("This is the parent speaking.");
  229.     printf ("I'm at 0x%lx\n", me);
  230.     printf ("My stack size appears to be\n%ld bytes.\n",
  231.          me -> pr_StackSize);
  232.     printf ("pr_StackBase is 0x%lx\n", me -> pr_StackBase);
  233.  
  234.     /*
  235.      * Now, create and start the sub-process.  The current release of
  236.      * AmigaDOS CreateProc() does nothing special with SegLists.
  237.      * All it uses it for is to find the first bit of code to execute.
  238.      * By passing it 'fakelist', we're essentially feeding it a JMP
  239.      * instruction which jumps to the real start of our sub-process.
  240.      * (Note that we have to convert 'fakelist' into a BPTR.)
  241.      * Thus, we get a full-fledged DOS process, which we can do things
  242.      * with, and we didn't have to LoadSeg() it.
  243.      */
  244.     if (!(child = CreateProc ("Sub-Process",
  245.                   priority,
  246.                   (LONG) fakelist >> 2,
  247.                   2048L)))
  248.         goto xit;
  249.  
  250.     /* 
  251.      * Send the startup message.  This will get the sub-process doing
  252.      * its thing.
  253.      * (Note that CreateProc() returns a pointer, not to the process
  254.      * structure, but to the pr_MsgPort structure *within* the process
  255.      * structure.)
  256.      */
  257.     PutMsg (child, &startupmsg);
  258.  
  259.     /*
  260.      * Make our cursor fly back and forth, which hopefully will happen
  261.      * concurrently with the sub-process's activity.  We continue to
  262.      * do this until the sub-process replies its message, making
  263.      * GetMsg() return a non-NULL value.  Since we "know" what's arriving
  264.      * at the replyport, we can safely throw the result from GetMsg()
  265.      * away.
  266.      */
  267.     while (!GetMsg (replyport)) {
  268.         for (i = 64;  i--; )
  269.             Write (term, fwdcursor, sizeof (fwdcursor) - 1L);
  270.         for (i = 64;  i--; )
  271.             Write (term, &backcursor, 1L);
  272.     }
  273.  
  274.     /*
  275.      * At this point, the sub-process has completely exited.  We may
  276.      * now safely deallocate all the support structures, and exit.
  277.      */
  278.     puts ("Child terminated.");
  279. xit:
  280.     if (fakelist)    FreeMem (fakelist, (LONG) sizeof (*fakelist));
  281.     if (replyport)    DeletePort (replyport);
  282. }
  283.