Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/tcl8.5.2/compat/waitpid.c @ 37

Last change on this file since 37 was 25, checked in by landauf, 16 years ago

added tcl to libs

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