xref: /plan9/sys/src/ape/lib/ap/plan9/wait.c (revision 282e677fa45fb578cdb8bc2c412ac084c367776e)
1 #include "lib.h"
2 #include <stdlib.h>
3 #include <sys/wait.h>
4 #include <sys/stat.h>
5 #include <unistd.h>
6 #include <errno.h>
7 #include <stdio.h>
8 #include "sys9.h"
9 
10 /*
11 **	PID cache
12 */
13 typedef struct wdesc wdesc;
14 struct wdesc {
15 	pid_t w_pid;
16 	Waitmsg *w_msg;
17 	wdesc *w_next;
18 };
19 static wdesc *wd = 0;
20 
21 static Waitmsg *
22 lookpid (pid_t pid) {
23 	wdesc **wp0 = &wd, *wp;
24 	Waitmsg *msg;
25 
26 	if (pid == -1) {
27 		if (wd == 0)
28 			return 0;
29 		pid = wd->w_pid;
30 	}
31 	for (wp = wd; wp; wp = wp->w_next) {
32 		if (wp->w_pid == pid) {
33 			msg = wp->w_msg;
34 			*wp0 = wp->w_next;
35 			free (wp);
36 			return msg;
37 		}
38 		wp0 = &(wp->w_next);
39 	}
40 	return 0;
41 }
42 
43 static void
44 addpid (Waitmsg *msg) {
45 	wdesc *wp = malloc (sizeof (wdesc));
46 
47 	wp->w_msg = msg;
48 	wp->w_pid = msg->pid;
49 	wp->w_next = wd;
50 	wd = wp;
51 }
52 
53 pid_t
54 wait (int *status) {
55 	return wait4(-1, status, 0, 0);
56 }
57 
58 pid_t
59 waitpid (pid_t wpid, int *status, int options) {
60 	return wait4(wpid, status, options, 0);
61 }
62 
63 pid_t
64 wait3 (int *status, int options, Waitmsg *waitmsg) {
65 	return wait4(-1, status, options, waitmsg);
66 }
67 
68 pid_t
69 wait4 (pid_t wpid, int *status, int options, Waitmsg *waitmsg) {
70 	Waitmsg *w;
71 
72 	if (options & WNOHANG) {
73 		char pname[128];
74 		int i;
75 		struct stat buf;
76 
77 		snprintf (pname, sizeof (pname), "/proc/%d/wait", getpid());
78 		i = stat (pname, &buf);
79 		if (i >= 0 && buf.st_size == 0)
80 			return 0;
81 	}
82 	if (w = lookpid (wpid)) {
83 		waitmsg = w;
84 		wpid = w->pid;
85 		return wpid;
86 	}
87 	w = _WAIT();
88 	while (w) {
89 		if (wpid <= 0) {
90 			waitmsg = w;
91 			wpid = w->pid;
92 			return wpid;
93 		}
94 		if (w->pid == wpid) {
95 			if (status) {
96 				int r = 0;
97 				int t = 0;
98 				char *bp, *ep;
99 
100 				if (w->msg[0]) {
101 					/* message is 'prog pid:string' */
102 					bp = w->msg;
103 					while (*bp) {
104 						if (*bp++ == ':')
105 							break;
106 					}
107 					if (*bp == 0)
108 						bp = w->msg;
109 					r = strtol (bp, &ep, 10);
110 					if (*ep == 0) {
111 						if (r < 0 || r >= 256)
112 							r = 1;
113 					} else {
114 						t = _stringsig (bp);
115 						if (t == 0)
116 							r = 1;
117 					}
118 				}
119 				*status = (r << 8) | t;
120 			}
121 			waitmsg = w;
122 			wpid = w->pid;
123 			return wpid;
124 		} else {
125 			addpid (w);
126 		}
127 		w = _WAIT();
128 	}
129 	if (w == 0) {
130 		_syserrno ();
131 	}
132 }
133