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