os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/compat/waitpid.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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  * Copyright (c) 1994 Sun Microsystems, Inc.
    11  *
    12  * See the file "license.terms" for information on usage and redistribution
    13  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
    14  *
    15  * RCS: @(#) $Id: waitpid.c,v 1.3 2000/01/11 22:08:50 hobbs Exp $
    16  */
    17 
    18 #include "tclInt.h"
    19 #include "tclPort.h"
    20 
    21 #ifndef pid_t
    22 #define pid_t int
    23 #endif
    24 
    25 /*
    26  * A linked list of the following structures is used to keep track
    27  * of processes for which we received notification from the kernel,
    28  * but the application hasn't waited for them yet (this can happen
    29  * because wait may not return the process we really want).  We
    30  * save the information here until the application finally does
    31  * wait for the process.
    32  */
    33 
    34 typedef struct WaitInfo {
    35     pid_t pid;				/* Pid of process that exited. */
    36     WAIT_STATUS_TYPE status;		/* Status returned when child exited
    37 					 * or suspended. */
    38     struct WaitInfo *nextPtr;		/* Next in list of exited processes. */
    39 } WaitInfo;
    40 
    41 static WaitInfo *deadList = NULL;	/* First in list of all dead
    42 					 * processes. */
    43 
    44 /*
    45  *----------------------------------------------------------------------
    46  *
    47  * waitpid --
    48  *
    49  *	This procedure emulates the functionality of the POSIX
    50  *	waitpid kernel call, using the BSD wait3 kernel call.
    51  *	Note:  it doesn't emulate absolutely all of the waitpid
    52  *	functionality, in that it doesn't support pid's of 0
    53  *	or < -1.
    54  *
    55  * Results:
    56  *	-1 is returned if there is an error in the wait kernel call.
    57  *	Otherwise the pid of an exited or suspended process is
    58  *	returned and *statusPtr is set to the status value of the
    59  *	process.
    60  *
    61  * Side effects:
    62  *	None.
    63  *
    64  *----------------------------------------------------------------------
    65  */
    66 
    67 #ifdef waitpid
    68 #   undef waitpid
    69 #endif
    70 
    71 pid_t
    72 waitpid(pid, statusPtr, options)
    73     pid_t pid;			/* The pid to wait on.  Must be -1 or
    74 				 * greater than zero. */
    75     int *statusPtr;		/* Where to store wait status for the
    76 				 * process. */
    77     int options;		/* OR'ed combination of WNOHANG and
    78 				 * WUNTRACED. */
    79 {
    80     register WaitInfo *waitPtr, *prevPtr;
    81     pid_t result;
    82     WAIT_STATUS_TYPE status;
    83 
    84     if ((pid < -1) || (pid == 0)) {
    85 	errno = EINVAL;
    86 	return -1;
    87     }
    88 
    89     /*
    90      * See if there's a suitable process that has already stopped or
    91      * exited. If so, remove it from the list of exited processes and
    92      * return its information.
    93      */
    94 
    95     for (waitPtr = deadList, prevPtr = NULL; waitPtr != NULL;
    96 	    prevPtr = waitPtr, waitPtr = waitPtr->nextPtr) {
    97 	if ((pid != waitPtr->pid) && (pid != -1)) {
    98 	    continue;
    99 	}
   100 	if (!(options & WUNTRACED) && (WIFSTOPPED(waitPtr->status))) {
   101 	    continue;
   102 	}
   103 	result = waitPtr->pid;
   104 	*statusPtr = *((int *) &waitPtr->status);
   105 	if (prevPtr == NULL) {
   106 	    deadList = waitPtr->nextPtr;
   107 	} else {
   108 	    prevPtr->nextPtr = waitPtr->nextPtr;
   109 	}
   110 	ckfree((char *) waitPtr);
   111 	return result;
   112     }
   113 
   114     /*
   115      * Wait for any process to stop or exit.  If it's an acceptable one
   116      * then return it to the caller;  otherwise store information about it
   117      * in the list of exited processes and try again.  On systems that
   118      * have only wait but not wait3, there are several situations we can't
   119      * handle, but we do the best we can (e.g. can still handle some
   120      * combinations of options by invoking wait instead of wait3).
   121      */
   122 
   123     while (1) {
   124 #if NO_WAIT3
   125 	if (options & WNOHANG) {
   126 	    return 0;
   127 	}
   128 	if (options != 0) {
   129 	    errno = EINVAL;
   130 	    return -1;
   131 	}
   132 	result = wait(&status);
   133 #else
   134 	result = wait3(&status, options, 0);
   135 #endif
   136 	if ((result == -1) && (errno == EINTR)) {
   137 	    continue;
   138 	}
   139 	if (result <= 0) {
   140 	    return result;
   141 	}
   142 
   143 	if ((pid != result) && (pid != -1)) {
   144 	    goto saveInfo;
   145 	}
   146 	if (!(options & WUNTRACED) && (WIFSTOPPED(status))) {
   147 	    goto saveInfo;
   148 	}
   149 	*statusPtr = *((int *) &status);
   150 	return result;
   151 
   152 	/*
   153 	 * Can't return this info to caller.  Save it in the list of
   154 	 * stopped or exited processes.  Tricky point: first check for
   155 	 * an existing entry for the process and overwrite it if it
   156 	 * exists (e.g. a previously stopped process might now be dead).
   157 	 */
   158 
   159 	saveInfo:
   160 	for (waitPtr = deadList; waitPtr != NULL; waitPtr = waitPtr->nextPtr) {
   161 	    if (waitPtr->pid == result) {
   162 		waitPtr->status = status;
   163 		goto waitAgain;
   164 	    }
   165 	}
   166 	waitPtr = (WaitInfo *) ckalloc(sizeof(WaitInfo));
   167 	waitPtr->pid = result;
   168 	waitPtr->status = status;
   169 	waitPtr->nextPtr = deadList;
   170 	deadList = waitPtr;
   171 
   172 	waitAgain: continue;
   173     }
   174 }