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