home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 3 / CDPDIII.bin / pd / programming / gnuc / library / rcs / vfork.c,v < prev    next >
Encoding:
Text File  |  1992-09-14  |  24.0 KB  |  940 lines

  1. head    1.6;
  2. access;
  3. symbols
  4.     version39-41:1.4;
  5. locks;
  6. comment    @ *  @;
  7.  
  8.  
  9. 1.6
  10. date    92.09.14.01.48.11;    author mwild;    state Exp;
  11. branches;
  12. next    1.5;
  13.  
  14. 1.5
  15. date    92.08.09.21.01.43;    author amiga;    state Exp;
  16. branches;
  17. next    1.4;
  18.  
  19. 1.4
  20. date    92.07.04.19.24.12;    author mwild;    state Exp;
  21. branches;
  22. next    1.3;
  23.  
  24. 1.3
  25. date    92.05.18.12.26.25;    author mwild;    state Exp;
  26. branches;
  27. next    1.2;
  28.  
  29. 1.2
  30. date    92.05.18.01.02.31;    author mwild;    state Exp;
  31. branches;
  32. next    1.1;
  33.  
  34. 1.1
  35. date    92.05.14.19.55.40;    author mwild;    state Exp;
  36. branches;
  37. next    ;
  38.  
  39.  
  40. desc
  41. @provide vfork(),wait4()
  42. @
  43.  
  44.  
  45. 1.6
  46. log
  47. @move kmalloc() out of Forbid() (since the allocator is now Semaphore-based).
  48. move errno assignment after sigsetmask (thanks Niklas!)
  49. remove dead code
  50. @
  51. text
  52. @/*
  53.  *  This file is part of ixemul.library for the Amiga.
  54.  *  Copyright (C) 1991, 1992  Markus M. Wild
  55.  *
  56.  *  This library is free software; you can redistribute it and/or
  57.  *  modify it under the terms of the GNU Library General Public
  58.  *  License as published by the Free Software Foundation; either
  59.  *  version 2 of the License, or (at your option) any later version.
  60.  *
  61.  *  This library is distributed in the hope that it will be useful,
  62.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  63.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  64.  *  Library General Public License for more details.
  65.  *
  66.  *  You should have received a copy of the GNU Library General Public
  67.  *  License along with this library; if not, write to the Free
  68.  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  69.  *
  70.  *  $Id: vfork.c,v 1.5 1992/08/09 21:01:43 amiga Exp $
  71.  *
  72.  *  $Log: vfork.c,v $
  73.  *  Revision 1.5  1992/08/09  21:01:43  amiga
  74.  *  change to 2.x header files
  75.  *  duplicate calling stack frame in vfork_resume() instead of just doing rts.
  76.  *  temporary abort calling 1.3 vfork, until that's fixed again (when???).
  77.  *
  78.  *  Revision 1.4  1992/07/04  19:24:12  mwild
  79.  *  get passing of environment right.
  80.  *  change ix_sleep() calls to new semantics.
  81.  *
  82.  * Revision 1.3  1992/05/18  12:26:25  mwild
  83.  * fixed bad typo that didn't close files before sending wait message.
  84.  * Set childs Input()/Output() to NIL:, we only keep the files in our
  85.  * own filetable.
  86.  *
  87.  * Revision 1.2  1992/05/18  01:02:31  mwild
  88.  * add temporary Delay(100) before CloseLibrary() in the child after
  89.  * vfork(), there seem to arrive some late packets (don't know why..)
  90.  * pass NIL: filehandles as Input()/Output() to the child, so that the
  91.  * real I/O-handles only depend on ix-filetable for usage-count
  92.  *
  93.  * Revision 1.1  1992/05/14  19:55:40  mwild
  94.  * Initial revision
  95.  *
  96.  */
  97.  
  98. #define KERNEL
  99. #include "ixemul.h"
  100.  
  101. /* #undef DEBUG */
  102. #ifdef DEBUG
  103. #define DP(a) kprintf a
  104. #else
  105. #define DP(a)
  106. #endif
  107.  
  108. #include <sys/syscall.h>
  109. #include <sys/resource.h>
  110. #include <sys/wait.h>
  111. #include <stddef.h>
  112. #include <setjmp.h>
  113.  
  114. extern int _dos20;
  115.  
  116. void volatile vfork_longjmp (jmp_buf, int);
  117.  
  118. #include <utility/tagitem.h>
  119. #include <dos/dostags.h>
  120.  
  121. /* ARP stuff for 1.3 */
  122. struct    ProcessControlBlock {
  123.   u_int     pcb_StackSize;    /* Stacksize for new process            */
  124.   char        pcb_Pri;    /* Priority of new task                */
  125.   u_char    pcb_Control;    /* Control bits, see defines below        */
  126.   void *    pcb_TrapCode;    /* Optional Trap Code                */
  127.   BPTR        pcb_Input;
  128.   BPTR        pcb_Output;    /* Optional stdin, stdout            */
  129.   void *    pcb_Console;    /* really a union */
  130.   void *    pcb_LoadedCode;    /* If not null, will not load/unload code    */
  131.   struct    ZombieMsg    *pcb_LastGasp;    /* ReplyMsg() to be filled in by exit        */
  132.   struct    MsgPort        *pcb_WBProcess;    /* Valid only when PRB_NOCLI            */
  133. };
  134.  
  135. #define    PRB_SAVEIO    0L    /* Don't free/check file handles on exit    */
  136. #define    PRB_CLOSESPLAT    1L    /* Close Splat file, must request explicitly    */
  137. #define    PRB_NOCLI    2L    /* Don't create a CLI process            */
  138. /*    PRB_INTERACTIVE    3L       This is now obsolete...            */
  139. #define    PRB_CODE    4L    /* Dangerous yet enticing            */
  140. #define    PRB_STDIO    5L    /* Do the stdio thing, splat = CON:Filename     */
  141.  
  142. #define    PRF_SAVEIO    (1L << PRB_SAVEIO)
  143. #define    PRF_CLOSESPLAT    (1L << PRB_CLOSESPLAT)
  144. #define    PRF_NOCLI    (1L << PRB_NOCLI)
  145. #define    PRF_CODE    (1L << PRB_CODE)
  146. #define    PRF_STDIO    (1L << PRB_STDIO)
  147.  
  148. #undef BASE_NAME
  149. #define BASE_EXT_DECL
  150. #define BASE_NAME    ix.ix_arp_base
  151. #define BASE_PAR_DECL
  152. #define BASE_PAR_DECL0
  153. __inline static LONG ASyncRun(BASE_PAR_DECL const char* name, const char* command, struct ProcessControlBlock* pcb)
  154. {
  155.     BASE_EXT_DECL
  156.     register LONG res __asm("d0");
  157.     register void *a6 __asm ("a6");
  158.     register const char* a0 __asm("a0");
  159.     register const char* a1 __asm("a1");
  160.     register struct ProcessControlBlock* a2 __asm("a2");
  161.  
  162.     a6 = BASE_NAME;
  163.     a0 = name;
  164.     a1 = command;
  165.     a2 = pcb;
  166.     __asm volatile ("
  167.     jsr a6@@(-0x222)"
  168.     : "=r" (res)
  169.     : "r" (a6), "r" (a0), "r" (a1), "r" (a2)
  170.     : "d0", "d1", "a0", "a1", "a2");
  171.     *(char *)a2=*(char *)a2;
  172.     return res;
  173. }
  174.  
  175. __inline static struct    Process* FindCLI(BASE_PAR_DECL LONG clinum)
  176. {
  177.     BASE_EXT_DECL
  178.     register struct    Process* res __asm("d0");
  179.     register void *a6 __asm ("a6");
  180.     register LONG d0 __asm("d0");
  181.  
  182.     a6 = BASE_NAME;
  183.     d0 = clinum;
  184.     __asm volatile ("
  185.     jsr a6@@(-0x1a4)"
  186.     : "=r" (res)
  187.     : "r" (a6), "r" (d0)
  188.     : "d0", "d1", "a0", "a1");
  189.     return res;
  190. }
  191.  
  192.  
  193. /* having it in a struct makes parameter passing easier */
  194.  
  195. struct reg_parms {
  196.   jmp_buf jb;
  197. };
  198.  
  199. struct vfork_msg {
  200.   struct Message     vm_msg;
  201.   struct Process    *vm_self;    /* for validation purposes (1.3, grrr) */
  202.   struct Process     *vm_pptr;
  203.   struct reg_parms     *vm_regs;    /* parents context to restore */
  204.   int             vm_rc;        /* 0 if the child started normally, else errno */
  205. };
  206.  
  207. struct death_msg {
  208.   struct MinNode    dm_node;
  209.   struct Process    *dm_child;
  210.   int            dm_pgrp;
  211.   int            dm_status;
  212.   struct rusage        dm_rusage;
  213. };
  214.  
  215. /* this is the new process generated by vfork () ! */
  216. static void
  217. launcher ()
  218. {
  219.   void *ixb = OpenLibrary ("ixemul.library", IX_VERSION);
  220.   struct Process *me = (struct Process *) FindTask (0);
  221.   struct vfork_msg *vm;
  222.   int omask;
  223.  
  224.   /* the launcher() generated by Arp's ASyncRun seems to get a weird
  225.      message. Verify that the message at least looks right.. (damn 1.3 support..) */
  226.   vm = 0;
  227.   do
  228.     {
  229.       if (! vm) 
  230.         WaitPort (& me->pr_MsgPort);
  231.       vm = (struct vfork_msg *) GetMsg (& me->pr_MsgPort);
  232.     }
  233.   while (vm->vm_self != me);
  234.       
  235.  
  236.   if (ixb)
  237.     {
  238.       /* get parents user area */
  239.       volatile struct user *pu = (struct user *) (vm->vm_pptr->pr_Task.tc_TrapData);
  240.       /* `my' user area. This way we don't have to recalculate it too often */
  241.       volatile struct user *mu = &u;
  242.       /* reaping the dup function of execve() ;-)) */
  243.       extern char **dupvec (char **);
  244.       int fd, rc;
  245.  
  246.       /* link ourselves into the parents process lists. Guarantee single
  247.        * threaded access to those lists by locking out any other users of
  248.        * the library (nicer than to just call Forbid()) */
  249.       ix_lock_base ();
  250.       
  251.       /* our older sybling is the last recently created child of the parent */
  252.       mu->p_osptr = pu->p_cptr;
  253.       /* we have no younger sybling */
  254.       mu->p_ysptr = 0;
  255.       /* if we have an older sybling, point its `younger sybling' field at us */
  256.       if (mu->p_osptr)
  257.         {
  258.           struct user *ou = (struct user *) (mu->p_osptr->pr_Task.tc_TrapData);
  259.       ou->p_ysptr = me;
  260.     }
  261.       /* set the parents `last recently created child' field at us */
  262.       pu->p_cptr = me;
  263.  
  264.       /* inherit the process group of our parent */
  265.       mu->p_pgrp = pu->p_pgrp;
  266.       mu->p_pptr = vm->vm_pptr;
  267.       
  268.       /* inherit these global variables. */
  269.       mu->u_environ = (char ***) malloc (4);
  270.       * mu->u_environ = dupvec (* pu->u_environ);
  271.       mu->u_errno   = pu->u_errno;
  272.       
  273.       /* and inherit several other things as well, upto not including u_md */
  274.       bcopy (& pu->u_signal[0], & mu->u_signal[0],
  275.          offsetof (struct user, u_md) - offsetof (struct user, u_signal[0]));
  276.  
  277.       /* some things have been copied that should be reset */      
  278.       bzero (& mu->u_ru, sizeof (struct rusage));
  279.       bzero (& mu->u_cru, sizeof (struct rusage));
  280.       bzero (& mu->u_timer[0], sizeof (struct itimerval)); /* just the REAL timer! */
  281.       syscall (SYS_gettimeofday, & mu->u_start, 0);
  282.       omask = vm->vm_rc;    /* signal mask to restore at the end */
  283.  
  284.       /* and adjust the open count of each of the copied filedescriptors */
  285.       for (fd = 0; fd < NOFILE; fd++)
  286.         if (mu->u_ofile[fd])
  287.           mu->u_ofile[fd]->f_count++;
  288.  
  289.       /* copying finished, allow other processes to vfork() as well ;-)) */
  290.       ix_unlock_base ();
  291.       
  292.       /* remember the message we have to reply when either _exit() or 
  293.        * execve() is called */
  294.       mu->p_vfork_msg = vm;
  295.       
  296.       vm->vm_rc = 0;
  297.  
  298.       mu->u_save_sp = (void *) get_sp ();
  299.  
  300.       /* we get here when the user does an _exit() 
  301.        * (so as well after execve() terminates !) */
  302.       if (rc = setjmp (mu->u_jmp_buf))
  303.         {
  304.       struct death_msg *dm = 0;
  305.       int i;
  306.  
  307.       /* reset `mu' in here, setjmp() might have clobbered it */
  308.       mu = &u;
  309.  
  310.       /* although this is done in CloseLibrary(), files should 
  311.          really be closed *before* a death-message is sent to
  312.          the parent. */
  313.       for (i = 0; i < NOFILE; i++) 
  314.         if (u.u_ofile[i]) syscall (SYS_close, i);
  315.  
  316. /* DP(("vforked: _exit in progress, rc = %ld.\n", rc)); */
  317.  
  318.       /* this whole thing only happens if our parent is still alive ! */
  319.       if (mu->p_pptr && mu->p_pptr != (struct Process *) 1)
  320.         {
  321.           rc --;
  322.  
  323. /*DP(("vforked: parent alive, zombie-sig = %ld, vfork_msg = $%lx.\n",
  324.     pu->p_zombie_sig, mu->p_vfork_msg));*/
  325.  
  326.           pu = (struct user *) (mu->p_pptr->pr_Task.tc_TrapData);
  327.  
  328.           /* send the parent a death message with our return code */
  329.           dm = (struct death_msg *) kmalloc (sizeof (struct death_msg));
  330.  
  331.           Forbid ();
  332.           if (dm)
  333.         {
  334.           dm->dm_status = (rc >= 128) ? W_EXITCODE (0, rc & 0x7f) 
  335.                       : W_EXITCODE (rc, 0);
  336.           dm->dm_rusage = mu->u_ru;
  337.           ruadd (&dm->dm_rusage, &mu->u_cru);
  338.           dm->dm_child = (struct Process *) FindTask (0);
  339.           dm->dm_pgrp  = mu->p_pgrp;
  340. DP(("vfork-exit: Adding child $%lx to $%lx\n", dm->dm_child, mu->p_pptr));
  341.           AddTail ((struct List *) &pu->p_zombies, (struct Node *) dm);
  342.         }
  343.  
  344.           _psignal (mu->p_pptr, SIGCHLD);
  345.           /* have to wakeup the parent `by hand' to make sure it gets
  346.              out of its sleep, since it might have SIGCHLD masked out or
  347.              ignored at the moment */
  348.           if (pu->p_stat == SSLEEP && pu->p_wchan == (caddr_t) pu)
  349.         ix_wakeup (pu);
  350.  
  351.           if (mu->p_vfork_msg)
  352.             ReplyMsg ((struct Message *) mu->p_vfork_msg);
  353.  
  354. /*DP(("vforked: unlinking from parent process chains\n"));*/
  355.           /* unlink us from the parents process chains */
  356.  
  357.           if (mu->p_ysptr)
  358.             {
  359.               struct user *yu = (struct user *) (mu->p_ysptr->pr_Task.tc_TrapData);
  360.               yu->p_osptr = mu->p_osptr;
  361.             }
  362.  
  363.           if (mu->p_osptr)
  364.             {
  365.              struct user *ou = (struct user *) (mu->p_osptr->pr_Task.tc_TrapData);
  366.              ou->p_ysptr = mu->p_ysptr;
  367.             }
  368.  
  369.           if (pu->p_cptr == me)
  370.             pu->p_cptr = mu->p_osptr;
  371.         }
  372.       else
  373.         {
  374.           Forbid ();
  375. DP(("vforked: couldn't send death_msg\n"));
  376.         }
  377.  
  378.       /* this seems to be necessary for process synchronisation, or
  379.          else it is possible that the same process address is
  380.          reused before the parent noticed the death of this child,
  381.          and this would rather confuse it (or ksh at least ;-)) */
  382.       if (dm)
  383.         ix_sleep (dm, "vfork-dm");
  384. DP(("vforked: now closing library\n"));
  385.  
  386.       /* temporary `fix'.. there seem to be some packets arriving
  387.          too late.. */
  388.       Delay (100);
  389.  
  390.       CloseLibrary (ixb);
  391.  
  392. DP(("vforked: falling off the edge of the world.\n"));
  393.       /* just fall off the edge of the world, this is a process */
  394.       return;
  395.         }
  396.  
  397.       syscall (SYS_sigsetmask, omask);
  398.  
  399. DP(("vforked: jumping back\n"));
  400.  
  401.       /* jump into nevereverland ;-) */
  402.       vfork_longjmp (vm->vm_regs->jb, 0);
  403.       /* NOTREACHED */
  404.     }
  405.  
  406.   vm->vm_rc = ENOMEM; /* can't imagine any other reason why the OpenLib should fail */
  407.   ReplyMsg ((struct Message *) vm);
  408.   /* fall off the edge of the world ;-) */
  409. }
  410.  
  411.  
  412. /*
  413.  * this is an implementation extension to the `real' vfork(). Normally you
  414.  * can only cause the parent to resume by calling _exit() or execve() from
  415.  * the child. Since I can't provide a real fork() on the Amiga, this function
  416.  * is a third possibility to make the parent resume. You have then two
  417.  * concurrent processes sharing the same frame and global data... Please be
  418.  * EXTREMLY careful what you may do and what not. vfork() itself is a hack,
  419.  * this is an even greater one...
  420.  */
  421. static void
  422. _vfork_resume (u_int *copy_from_sp)
  423. {
  424.   struct vfork_msg **vm = &u.p_vfork_msg;
  425.  
  426.   if (*vm)
  427.     {
  428.       u_int *sp = (u_int *)u.u_save_sp;
  429.       u_int *copy_till_sp = (u_int *)get_sp ();
  430.  
  431.       /* copy the stack frame */
  432.       copy_from_sp++;
  433.       do
  434.     *--sp = *--copy_from_sp;
  435.       while (copy_from_sp > copy_till_sp);
  436.  
  437.       set_sp (sp);
  438.  
  439.       ReplyMsg ((struct Message *) *vm);
  440.       *vm = 0;
  441.  
  442.       /* optimizers *want* to be fooled, right ? ;-)) */
  443.       /* asm volatile ("rts" : "=g" (u.p_vfork_msg) : "0" (u.p_vfork_msg)); */
  444.     }
  445. }
  446.  
  447.  
  448. asm ("
  449.     .globl _vfork
  450.     .globl _vfork_resume
  451. _vfork:
  452.     | store a setjmp () compatible frame on the stack to pass to _vfork ()
  453.     lea    sp@@(-18*4),sp        | _JBLEN (17) longs on the stack
  454.     pea    sp@@
  455.     jbsr    _setjmp
  456.     lea    sp@@(4),sp
  457.     | now patch sp and pc, since they differ
  458.     addl    #20*4,sp@@(8)        | account for buffer space
  459.     movel    sp@@(18*4),sp@@(20)    | insert real PC (return addr on stack)
  460.     bsr    __vfork
  461.     lea    sp@@(18*4),sp
  462.     rts
  463.  
  464.  
  465.     | the following is longjmp(), with the subtle difference that this
  466.     | thing doesn't insist in returning something non-zero... 
  467. _vfork_longjmp:
  468.     movel    sp@@(4),a0    /* save area pointer */
  469.     tstl    a0@@(8)        /* ensure non-zero SP */
  470.     jeq    Lbotch        /* oops! */
  471.     movel    sp@@(8),d0    /* grab return value */
  472.     moveml    a0@@(28),d2-d7/a2-a4/a6    /* restore non-scratch regs */
  473.     movel    a0,sp@@-        /* let sigreturn */
  474.     jbsr    _sigreturn    /*   finish for us */
  475.  
  476. Lbotch:
  477.     jsr    _longjmperror
  478.     stop    #0
  479.  
  480. _vfork_resume:
  481.     pea    sp@@        | pass the sp containing the return address
  482.     bsr    __vfork_resume
  483.     lea    sp@@(4),sp
  484.     rts
  485. ");
  486.  
  487. static int
  488. _vfork (struct reg_parms rp)
  489. {
  490.   struct Process *me = (struct Process *) FindTask(0);
  491.   struct CommandLineInterface *CLI = BTOCPTR (me->pr_CLI);
  492.   u_int stack_size = CLI ? CLI->cli_DefaultStack * 4 : me->pr_StackSize;
  493.   BPTR input, output;
  494.   /* those *have* to be in registers to survive the stack deallocation */
  495.   register struct vfork_msg *vm asm ("a2");
  496.   register int omask asm ("d2");
  497.   register struct Process *child asm ("a3");
  498.  
  499.   if (! _dos20)
  500.     {
  501.       ix_panic ("vfork currently broken in 1.3. Want to fix?");
  502.       return -1;
  503.     }
  504.  
  505.   vm = (struct vfork_msg *) kmalloc (sizeof (struct vfork_msg));
  506.   if (! vm)
  507.     {
  508.       errno = ENOMEM;
  509.       return -1;
  510.     }
  511.  
  512.   vm->vm_msg.mn_ReplyPort = u.u_sync_mp;
  513.   vm->vm_msg.mn_Node.ln_Type = NT_MESSAGE;
  514.   vm->vm_msg.mn_Length = sizeof (struct vfork_msg);
  515.   vm->vm_pptr = me;
  516.   vm->vm_regs = & rp;
  517.  
  518.   /* we have to block all signals as long as the child uses our resources.
  519.    * but since the child needs to start with the signal mask BEFORE this
  520.    * general blocking, we have to pass it the old signal mask. This is a
  521.    * way to do it */
  522.   vm->vm_rc   = 
  523.   omask      = syscall (SYS_sigsetmask, ~0);
  524.  
  525.   /* save the passed frame in our user structure, since the child will
  526.      deallocate it from the stack when it `returns' to user code */
  527.   bcopy (&rp, &u.u_vfork_frame, sizeof (rp));
  528.  
  529. #if 0
  530.   /* NOTE: would like to pass our real filehandles like this to the
  531.            child. But then the files stay open even if the child
  532.            process closes them. That way, the parent is not able to
  533.            get rid of them as long as the child runs, this is not
  534.            acceptable */
  535.   if (u.u_ofile[0] && u.u_ofile[0]->f_type == DTYPE_FILE)
  536.     input = CTOBPTR (u.u_ofile[0]->f_fh);
  537.   else  
  538.     input = Input();
  539.   
  540.   if (u.u_ofile[1] && u.u_ofile[1]->f_type == DTYPE_FILE)
  541.     output = CTOBPTR (u.u_ofile[1]->f_fh);
  542.   else  
  543.     output = Output();
  544. #else
  545.   if (! _dos20)
  546.     {
  547.       /* use Open(), so that we can safely ask the child to close the 
  548.          files on termination */
  549.       input = Open ("nil:", MODE_OLDFILE);
  550.       output = Open ("nil:", MODE_OLDFILE);
  551.   
  552.       if (!input || !output)
  553.         ix_panic ("Couldn't open NIL: for I/O ?!?!");
  554.     }
  555. #endif
  556.  
  557.   if (_dos20)
  558.     {
  559.       struct TagItem tags [] = {
  560.         { NP_Entry, (ULONG) launcher, },
  561. #if 0
  562. /* NIL: filehandles are the default according to the man page */
  563.         { NP_Input, (ULONG) input, },
  564.         { NP_Output, (ULONG) output, },
  565.         { NP_CloseInput, (ULONG) -1, },        /* do close (nil:) */
  566.         { NP_CloseOutput, (ULONG) -1, },    /* do close (nil:) */
  567. #endif
  568.         { NP_Cli, (ULONG) (CLI ? -1 : 0), },    /* same thing we are */
  569.         { NP_Name, (ULONG) "vfork()'d process", },    /* to be overridden by execve() */
  570.         { NP_StackSize, stack_size, },        /* same size we use */
  571.         { TAG_END, 0, }
  572.       };
  573.       
  574.       child = CreateNewProc (tags);
  575.     }
  576.   else
  577.     {
  578.       struct ProcessControlBlock pcb = {
  579.     stack_size,                /* pcb_StackSize */
  580.     0,                    /* pcb_Pri */
  581.     CLI ? PRF_CODE : PRF_NOCLI|PRF_CODE,
  582.     0,                    /* pcb_TrapCode */
  583.     input, output,                /* pcb_Input, pcb_Output */
  584.     0,                    /* pcb_Console */
  585.     launcher,                /* pcb_LoadedCode */
  586.     0,                    /* pcb_LastGasp */
  587.     0,                    /* pcb_WBProcess */
  588.       };
  589.       int cli_num;    
  590.       
  591.       cli_num = ASyncRun ("vfork()'d process", 0, &pcb);
  592.       if (cli_num > 0)
  593.         child = FindCLI (cli_num);
  594.       else if (cli_num == 0)
  595.         child = (struct Process *)((int)pcb.pcb_WBProcess - 
  596.                    offsetof(struct Process, pr_MsgPort));
  597.       else
  598.     child = 0;
  599.     }
  600.  
  601.   if (! child)
  602.     {
  603.       /* do I have to close input/output here? Or does the startup close
  604.          them no matter whether it succeeds or not ? */
  605.       kfree (vm);
  606.       syscall (SYS_sigsetmask, omask);
  607.       errno = EPROCLIM;
  608.       return -1;
  609.     }
  610.  
  611.   /* As soon as this message is dispatched, the child will `return' and 
  612.      deallocate the stack we're running on. So afterwards, *only* use
  613.      register variables and then longjmp () back.
  614.      Since we don't have a stack until after the longjmp(), temporarily
  615.      switch to our mini-stack */
  616.   set_sp ((u_int) &u.u_mini_stack[sizeof (u.u_mini_stack) / sizeof (long)]);
  617.  
  618.   vm->vm_self = child;
  619.   PutMsg (& child->pr_MsgPort, (struct Message *) vm);
  620.   /* wait until the child does execve() or _exit() */
  621.   WaitPort (u.u_sync_mp);
  622.   GetMsg (u.u_sync_mp);
  623.   syscall (SYS_sigsetmask, omask);
  624.  
  625.   if (vm->vm_rc)
  626.     {
  627.       errno = (int) vm->vm_rc;
  628.       child = (struct Process *) -1;
  629.     }
  630.       
  631.   /* this is the parent return, so we pass the id of the new child */
  632.   kfree (vm);
  633.   /* could use longjmp() here, but since we already *have* the local one.. */
  634.   vfork_longjmp (u.u_vfork_frame, (int) child);
  635. }
  636.  
  637.   
  638. ruadd(ru, ru2)
  639.     register struct rusage *ru, *ru2;
  640. {
  641.     register long *ip, *ip2;
  642.     register int i;
  643.  
  644.     timevaladd(&ru->ru_utime, &ru2->ru_utime);
  645.     timevaladd(&ru->ru_stime, &ru2->ru_stime);
  646.     if (ru->ru_maxrss < ru2->ru_maxrss)
  647.         ru->ru_maxrss = ru2->ru_maxrss;
  648.     ip = &ru->ru_first; ip2 = &ru2->ru_first;
  649.     for (i = &ru->ru_last - &ru->ru_first; i > 0; i--)
  650.         *ip++ += *ip2++;
  651. }
  652.  
  653.  
  654. /* This function is in desperate need of redesign !!!! */
  655.  
  656. int
  657. wait4 (int pid, int *status, int options, struct rusage *rusage)
  658. {
  659.   struct Process * me = (struct Process *) FindTask (0);
  660.   struct user * mu = (struct user *) me->pr_Task.tc_TrapData;
  661.   int omask;
  662.  
  663.   for (;;)
  664.     {
  665.       int err = 0, omask;
  666.       struct death_msg *dm, *ndm;
  667.       int got_node;
  668.  
  669.       got_node = 0;
  670.       Forbid ();
  671.       
  672.       for (dm  = (struct death_msg *) mu->p_zombies.mlh_Head;
  673.          ndm = (struct death_msg *) dm->dm_node.mln_Succ;
  674.          dm  = ndm)
  675.       if (pid == -1 ||
  676.           (pid == 0 && dm->dm_pgrp == mu->p_pgrp) ||
  677.         (pid < -1 && dm->dm_pgrp == - pid) ||
  678.         (pid == (int) dm->dm_child))
  679.       {
  680.         got_node = 1;
  681.         Remove ((struct Node *) dm);
  682.         break;
  683.       }
  684.  
  685.       if (!got_node && !mu->p_cptr)
  686.     err = ECHILD;
  687.  
  688.       if (got_node)
  689.         {
  690.       struct Process *child;
  691.  
  692. DP(("wait4: unlinking child $%lx\n", dm->dm_child));
  693.       ix_wakeup (dm);
  694.       Permit ();
  695.  
  696.           if (status)
  697.             *status = dm->dm_status;
  698.           if (rusage)
  699.             *rusage = dm->dm_rusage;
  700.  
  701.       child = dm->dm_child;
  702.  
  703.       kfree (dm);
  704.  
  705.           return (int) child;
  706.     }
  707.  
  708.       if (!got_node && err)
  709.     {
  710.       Permit ();
  711.       errno = err;
  712.       return -1;
  713.     }
  714.  
  715.       if (options & WNOHANG)
  716.     {
  717.       Permit ();
  718.       return 0;
  719.     }
  720.  
  721. DP(("wait4: waiting for SIGCHLD\n"));
  722.       ix_sleep (mu, "wait4");
  723.       if (mu->p_sig)
  724.     err = EINTR;
  725.  
  726.       Permit ();
  727.       if (CURSIG (mu))
  728.         setrun (me);
  729.     }
  730. }
  731. @
  732.  
  733.  
  734. 1.5
  735. log
  736. @change to 2.x header files
  737. duplicate calling stack frame in vfork_resume() instead of just doing rts.
  738. temporary abort calling 1.3 vfork, until that's fixed again (when???).
  739. @
  740. text
  741. @d19 1
  742. a19 1
  743.  *  $Id: vfork.c,v 1.4 1992/07/04 19:24:12 mwild Exp $
  744. d22 5
  745. a264 2
  746.       ix_lock_base ();
  747.  
  748. a276 2
  749.           Forbid ();
  750.  
  751. d279 2
  752. a282 1
  753.           /* don't need to fill out dm_message, it won't be ReplyMsg'd */
  754. a292 5
  755. #if 0
  756.           /* once for Exec */
  757.           Signal ((struct Task *) mu->p_pptr, 1 << pu->p_zombie_sig);
  758.           /* and once for my signals ;-) */
  759. #endif
  760. a326 3
  761. /*DP(("vforked: unlocking base and closing library\n"));*/
  762.       ix_unlock_base ();
  763.  
  764. a553 1
  765.       errno = EPROCLIM;
  766. d556 1
  767. a617 1
  768.       ix_lock_base ();
  769. a635 5
  770. #if 0
  771.       else if (!ndm && !(options & WNOHANG))
  772.     /* it's important to do this while ixbase is locked ! */
  773.         SetSignal (0, 1 << mu->p_zombie_sig);
  774. #endif
  775. a636 2
  776.       ix_unlock_base ();
  777.             
  778. a669 3
  779. #if 0
  780.       Wait ((1 << mu->p_zombie_sig) | (1 << mu->u_sleep_sig) | SIGBREAKF_CTRL_C);
  781. #else
  782. d674 1
  783. a674 1
  784. #endif
  785. @
  786.  
  787.  
  788. 1.4
  789. log
  790. @get passing of environment right.
  791. change ix_sleep() calls to new semantics.
  792. @
  793. text
  794. @d19 1
  795. a19 1
  796.  *  $Id: vfork.c,v 1.3 1992/05/18 12:26:25 mwild Exp $
  797. d22 4
  798. d62 2
  799. a63 22
  800. #include "gcc:include20/utility/tagitem.h"
  801. #include "gcc:include20/dos/dostags.h"
  802. #define BASE_EXT_DECL
  803. #define BASE_PAR_DECL    
  804. #define BASE_PAR_DECL0    
  805. #define BASE_NAME    ix.ix_dos_base
  806. __inline static struct Process* CreateNewProc(BASE_PAR_DECL struct TagItem* tags)
  807. {
  808.     BASE_EXT_DECL
  809.     register struct Process* res __asm("d0");
  810.     register void *a6 __asm ("a6");
  811.     register struct TagItem* d1 __asm("d1");
  812.  
  813.     a6 = BASE_NAME;
  814.     d1 = tags;
  815.     __asm volatile ("
  816.     jsr a6@@(-0x1f2)"
  817.     : "=r" (res)
  818.     : "r" (a6), "r" (d1)
  819.     : "d0", "d1", "a0", "a1");
  820.     return res;
  821. }
  822. d93 1
  823. d95 2
  824. d145 1
  825. d168 11
  826. a178 2
  827.   WaitPort (& me->pr_MsgPort);
  828.   vm = (struct vfork_msg *) GetMsg (& me->pr_MsgPort);
  829. d213 1
  830. a213 1
  831.       mu->u_environ = malloc (4);
  832. d242 1
  833. a242 1
  834.       mu->u_save_sp = get_sp ();
  835. d377 1
  836. a377 1
  837. _vfork_resume (u_int jmp_to)
  838. d379 3
  839. a381 1
  840.   if (u.p_vfork_msg)
  841. d383 8
  842. a390 3
  843.       /* make room on the new stack for the return address */
  844.       ((u_int *)u.u_save_sp) --;
  845.       *((u_int *)u.u_save_sp) = jmp_to;
  846. d392 1
  847. a392 1
  848.       set_sp ((u_int) u.u_save_sp);
  849. d394 2
  850. a395 2
  851.       ReplyMsg ((struct Message *) u.p_vfork_msg);
  852.       u.p_vfork_msg = 0;
  853. d398 1
  854. a398 1
  855.       asm volatile ("rts" : "=g" (u.p_vfork_msg) : "0" (u.p_vfork_msg));
  856. d436 1
  857. a436 1
  858.     movel    sp@@,sp@@-    | pass the return address on the stack
  859. d454 6
  860. d534 1
  861. a534 1
  862.     stack_size,                /* pcb_StackSize XXXX FIX ME !!! */
  863. d573 1
  864. @
  865.  
  866.  
  867. 1.3
  868. log
  869. @fixed bad typo that didn't close files before sending wait message.
  870. Set childs Input()/Output() to NIL:, we only keep the files in our
  871. own filetable.
  872. @
  873. text
  874. @d19 1
  875. a19 1
  876.  *  $Id: vfork.c,v 1.2 1992/05/18 01:02:31 mwild Exp $
  877. d22 5
  878. d189 2
  879. d216 2
  880. a217 1
  881.       mu->u_environ = pu->u_environ;
  882. d341 1
  883. a341 1
  884.         ix_sleep (dm);
  885. d677 1
  886. a677 1
  887.       ix_sleep (mu);
  888. @
  889.  
  890.  
  891. 1.2
  892. log
  893. @add temporary Delay(100) before CloseLibrary() in the child after
  894. vfork(), there seem to arrive some late packets (don't know why..)
  895. pass NIL: filehandles as Input()/Output() to the child, so that the
  896. real I/O-handles only depend on ix-filetable for usage-count
  897. @
  898. text
  899. @d19 1
  900. a19 1
  901.  *  $Id: vfork.c,v 1.1 1992/05/14 19:55:40 mwild Exp $
  902. d22 6
  903. d253 1
  904. a253 1
  905.         if (u.u_ofile[fd]) syscall (SYS_close, fd);
  906. d482 10
  907. a491 4
  908.   /* use Open(), so that we can safely ask the child to close the 
  909.      files on termination */
  910.   input = Open ("nil:", MODE_OLDFILE);
  911.   output = Open ("nil:", MODE_NEWFILE);
  912. d498 2
  913. d504 1
  914. @
  915.  
  916.  
  917. 1.1
  918. log
  919. @Initial revision
  920. @
  921. text
  922. @d19 1
  923. a19 1
  924.  *  $Id$
  925. d21 4
  926. a24 1
  927.  *  $Log$
  928. d330 4
  929. d460 6
  930. d475 6
  931. d488 2
  932. a489 2
  933.         { NP_CloseInput, 0, },            /* don't close */
  934.         { NP_CloseOutput, 0, },            /* don't close */
  935. d503 1
  936. a503 1
  937.     CLI ? PRF_SAVEIO|PRF_CODE : PRF_SAVEIO|PRF_NOCLI|PRF_CODE,
  938. d525 2
  939. @
  940.