1 /*************************************************************************
2 *
3 * (c) 1997 California Institute of Technology
4 * Department of Computer Science
5 * Pasadena, CA 91125.
6 * All Rights Reserved
7 *
8 * $Header$
9 *
10 *************************************************************************/
11 #include <stdio.h>
12 #include <string.h>
13 #ifndef SYSV
14 #include <sys/wait.h>
15 #endif /* SYSV */
16 #include <errno.h>
17
18 #include "utils/utils.h"
19 #include "utils/malloc.h"
20
21
22 /*------------------------------------------------------------------------
23 * Internal list management
24 *------------------------------------------------------------------------*/
25
26 struct Wait_List {
27 int pid;
28 int status;
29 int pending;
30 struct Wait_List *next;
31 };
32
33 static struct Wait_List *wl = NULL;
34
35 static
36 void
make_finished(pid,status)37 make_finished (pid, status)
38 int pid;
39 int *status;
40 {
41 struct Wait_List *l;
42
43 l = wl;
44 while (l) {
45 if (l->pid == pid) {
46 l->pending = 0;
47 l->status = *status;
48 return;
49 }
50 l = l->next;
51 }
52 return;
53 }
54
55 static
56 void
add_pending_to_list(pid)57 add_pending_to_list (pid)
58 int pid;
59 {
60 struct Wait_List *l;
61
62 l = (struct Wait_List *) mallocMagic((unsigned)(sizeof(struct Wait_List)));
63 l->next = wl;
64 l->pid = pid;
65 l->status = -1;
66 l->pending = 1;
67 wl = l;
68 return;
69 }
70
71 static
72 int
find_pid(pid,status)73 find_pid (pid,status)
74 int pid;
75 int *status;
76 {
77 struct Wait_List *l;
78 l = wl;
79 while (l) {
80 if (l->pid == pid) {
81 *status = l->status;
82 return l->pending;
83 }
84 l = l->next;
85 }
86 return -1;
87 }
88
89 static
90 int
get_next(status)91 get_next (status)
92 int *status;
93 {
94 struct Wait_List *l, *prev;
95 int pid;
96
97 prev = NULL;
98 l = wl;
99 while (l) {
100 if (!l->pending) {
101 pid = l->pid;
102 *status = l->status;
103 if (prev)
104 prev->next = l->next;
105 else
106 wl = l->next;
107 freeMagic(l);
108 return pid;
109 }
110 prev = l;
111 l = l->next;
112 }
113 return -1;
114 }
115
116 static
117 void
delete_from_list(pid)118 delete_from_list (pid)
119 int pid;
120 {
121 struct Wait_List *l, *prev;
122
123 prev = NULL;
124 l = wl;
125 while (l) {
126 if (l->pid == pid) {
127 if (prev)
128 prev->next = l->next;
129 else
130 wl = l->next;
131 freeMagic(l);
132 return;
133 }
134 prev = l;
135 l = l->next;
136 }
137 }
138
139
140
141 /*------------------------------------------------------------------------
142 *
143 * Wait --
144 *
145 * Wait for a process to terminate. Returns the pid that you waited
146 * for, along with the exit status in *status.
147 *
148 * Returns -1 on an attempt to wait for a pid which wasn't ever
149 * forked.
150 *
151 * If you want to wait for a particular pid, use WaitPid instead
152 * of Wait.
153 *
154 * Results:
155 * The pid that finished, along with the status.
156 *
157 * Side effects:
158 * None.
159 *
160 *------------------------------------------------------------------------
161 */
162
163 int
Wait(status)164 Wait (status)
165 int *status;
166 {
167 int pid;
168 int p_status = 0;
169
170 pid = get_next(&p_status);
171 if (pid != -1) {
172 if (status)
173 *status = p_status;
174 return pid;
175 }
176 if (wl) {
177 do {
178 pid = wait(&p_status);
179 } while (pid < 0 && errno == EINTR);
180 delete_from_list (pid);
181 if (status)
182 *status = p_status;
183 return pid;
184 }
185 else
186 /* nothing to wait for */
187 return -1;
188 }
189
190
191 /*------------------------------------------------------------------------
192 *
193 * WaitPid --
194 *
195 * Wait for a particular process to terminate.
196 *
197 * Returns -1 on an attempt to wait for a pid which wasn't ever
198 * forked.
199 *
200 * If you want to wait for a particular pid, use WaitPid instead
201 * of Wait.
202 *
203 * Results:
204 * The pid that finished, along with the status.
205 *
206 * Side effects:
207 * None.
208 *
209 *------------------------------------------------------------------------
210 */
211
212 int
WaitPid(pid,status)213 WaitPid (pid,status)
214 int pid;
215 int *status;
216 {
217 int stat;
218 int n_pid, n_status;
219
220 stat = find_pid (pid,&n_status);
221 if (stat == -1)
222 return -1;
223 if (stat == 0) {
224 delete_from_list (pid);
225 if (status)
226 *status = n_status;
227 return 1;
228 }
229 do {
230 do {
231 n_pid = wait(&n_status);
232 } while (n_pid < 0 && errno == EINTR);
233 make_finished (n_pid, &n_status);
234 } while (n_pid != pid && n_pid != -1);
235 if (n_pid == -1) return -1;
236 delete_from_list (pid);
237 if (status)
238 *status = n_status;
239 return 1;
240 }
241
242
243 /*------------------------------------------------------------------------
244 *
245 * ForkChildAdd --
246 *
247 * Fork, along with updating the wait list structure.
248 *
249 * Results:
250 * The pid that finished, along with the status.
251 *
252 * Side effects:
253 * None.
254 *
255 *------------------------------------------------------------------------
256 */
257
258 void
ForkChildAdd(pid)259 ForkChildAdd (pid)
260 int pid;
261 {
262 add_pending_to_list (pid);
263 }
264
265