home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tcl2-73c.zip / tcl7.3 / compat / waitpid.c < prev   
C/C++ Source or Header  |  1993-07-01  |  6KB  |  187 lines

  1. /* 
  2.  * waitpid.c --
  3.  *
  4.  *    This procedure emulates the POSIX waitpid kernel call on
  5.  *    BSD systems that don't have waitpid but do have wait3.
  6.  *    This code is based on a prototype version written by
  7.  *    Mark Diekhans and Karl Lehenbauer.
  8.  *
  9.  * Copyright (c) 1993 The Regents of the University of California.
  10.  * All rights reserved.
  11.  *
  12.  * Permission is hereby granted, without written agreement and without
  13.  * license or royalty fees, to use, copy, modify, and distribute this
  14.  * software and its documentation for any purpose, provided that the
  15.  * above copyright notice and the following two paragraphs appear in
  16.  * all copies of this software.
  17.  * 
  18.  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
  19.  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
  20.  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
  21.  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22.  *
  23.  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  24.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  25.  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  26.  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
  27.  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  28.  */
  29.  
  30. #ifndef lint
  31. static char rcsid[] = "$Header: /user6/ouster/tcl/compat/RCS/waitpid.c,v 1.5 93/07/01 15:25:18 ouster Exp $ SPRITE (Berkeley)";
  32. #endif /* not lint */
  33.  
  34. #include "tclInt.h"
  35. #include "tclUnix.h"
  36.  
  37. /*
  38.  * A linked list of the following structures is used to keep track
  39.  * of processes for which we received notification from the kernel,
  40.  * but the application hasn't waited for them yet (this can happen
  41.  * because wait may not return the process we really want).  We
  42.  * save the information here until the application finally does
  43.  * wait for the process.
  44.  */
  45.  
  46. typedef struct WaitInfo {
  47.     int pid;                /* Pid of process that exited. */
  48.     WAIT_STATUS_TYPE status;        /* Status returned when child exited
  49.                      * or suspended. */
  50.     struct WaitInfo *nextPtr;        /* Next in list of exited processes. */
  51. } WaitInfo;
  52.  
  53. static WaitInfo *deadList = NULL;    /* First in list of all dead
  54.                      * processes. */
  55.  
  56. /*
  57.  *----------------------------------------------------------------------
  58.  *
  59.  * waitpid --
  60.  *
  61.  *    This procedure emulates the functionality of the POSIX
  62.  *    waitpid kernel call, using the BSD wait3 kernel call.
  63.  *    Note:  it doesn't emulate absolutely all of the waitpid
  64.  *    functionality, in that it doesn't support pid's of 0
  65.  *    or < -1.
  66.  *
  67.  * Results:
  68.  *    -1 is returned if there is an error in the wait kernel call.
  69.  *    Otherwise the pid of an exited or suspended process is
  70.  *    returned and *statusPtr is set to the status value of the
  71.  *    process.
  72.  *
  73.  * Side effects:
  74.  *    None.
  75.  *
  76.  *----------------------------------------------------------------------
  77.  */
  78.  
  79. #ifdef waitpid
  80. #   undef waitpid
  81. #endif
  82.  
  83. int
  84. waitpid(pid, statusPtr, options)
  85.     int pid;            /* The pid to wait on.  Must be -1 or
  86.                  * greater than zero. */
  87.     int *statusPtr;        /* Where to store wait status for the
  88.                  * process. */
  89.     int options;        /* OR'ed combination of WNOHANG and
  90.                  * WUNTRACED. */
  91. {
  92.     register WaitInfo *waitPtr, *prevPtr;
  93.     int result;
  94.     WAIT_STATUS_TYPE status;
  95.  
  96.     if ((pid < -1) || (pid == 0)) {
  97.     errno = EINVAL;
  98.     return -1;
  99.     }
  100.  
  101.     /*
  102.      * See if there's a suitable process that has already stopped or
  103.      * exited. If so, remove it from the list of exited processes and
  104.      * return its information.
  105.      */
  106.  
  107.     for (waitPtr = deadList, prevPtr = NULL; waitPtr != NULL;
  108.         prevPtr = waitPtr, waitPtr = waitPtr->nextPtr) {
  109.     if ((pid != waitPtr->pid) && (pid != -1)) {
  110.         continue;
  111.     }
  112.     if (!(options & WUNTRACED) && (WIFSTOPPED(waitPtr->status))) {
  113.         continue;
  114.     }
  115.     result = waitPtr->pid;
  116.     *statusPtr = *((int *) &waitPtr->status);
  117.     if (prevPtr == NULL) {
  118.         deadList = waitPtr->nextPtr;
  119.     } else {
  120.         prevPtr->nextPtr = waitPtr->nextPtr;
  121.     }
  122.     ckfree((char *) waitPtr);
  123.     return result;
  124.     }
  125.  
  126.     /*
  127.      * Wait for any process to stop or exit.  If it's an acceptable one
  128.      * then return it to the caller;  otherwise store information about it
  129.      * in the list of exited processes and try again.  On systems that
  130.      * have only wait but not wait3, there are several situations we can't
  131.      * handle, but we do the best we can (e.g. can still handle some
  132.      * combinations of options by invoking wait instead of wait3).
  133.      */
  134.  
  135.     while (1) {
  136. #if NO_WAIT3
  137.     if (options & WNOHANG) {
  138.         return 0;
  139.     }
  140.     if (options != 0) {
  141.         errno = EINVAL;
  142.         return -1;
  143.     }
  144.     result = wait(&status);
  145. #else
  146.     result = wait3(&status, options, 0);
  147. #endif
  148.     if ((result == -1) && (errno == EINTR)) {
  149.         continue;
  150.     }
  151.     if (result <= 0) {
  152.         return result;
  153.     }
  154.  
  155.     if ((pid != result) && (pid != -1)) {
  156.         goto saveInfo;
  157.     }
  158.     if (!(options & WUNTRACED) && (WIFSTOPPED(status))) {
  159.         goto saveInfo;
  160.     }
  161.     *statusPtr = *((int *) &status);
  162.     return result;
  163.  
  164.     /*
  165.      * Can't return this info to caller.  Save it in the list of
  166.      * stopped or exited processes.  Tricky point: first check for
  167.      * an existing entry for the process and overwrite it if it
  168.      * exists (e.g. a previously stopped process might now be dead).
  169.      */
  170.  
  171.     saveInfo:
  172.     for (waitPtr = deadList; waitPtr != NULL; waitPtr = waitPtr->nextPtr) {
  173.         if (waitPtr->pid == result) {
  174.         waitPtr->status = status;
  175.         goto waitAgain;
  176.         }
  177.     }
  178.     waitPtr = (WaitInfo *) ckalloc(sizeof(WaitInfo));
  179.     waitPtr->pid = result;
  180.     waitPtr->status = status;
  181.     waitPtr->nextPtr = deadList;
  182.     deadList = waitPtr;
  183.  
  184.     waitAgain: continue;
  185.     }
  186. }
  187.