xref: /plan9/sys/src/ape/lib/ap/plan9/wait.c (revision 9c74240406852a66155a96c0daa6f8bf6e19c93e)
1 #include "lib.h"
2 #include <stdlib.h>
3 #include <sys/wait.h>
4 #include <sys/time.h>
5 #include <sys/resource.h>
6 #include <sys/stat.h>
7 #include <unistd.h>
8 #include <string.h>
9 #include <errno.h>
10 #include <stdio.h>
11 #include "sys9.h"
12 #include "dir.h"
13 
14 /*
15  * status not yet collected for processes that have exited
16  */
17 typedef struct Waited Waited;
18 struct Waited {
19 	Waitmsg*	msg;
20 	Waited*	next;
21 };
22 static Waited *wd;
23 
24 static Waitmsg *
lookpid(int pid)25 lookpid(int pid)
26 {
27 	Waited **wl, *w;
28 	Waitmsg *msg;
29 
30 	for(wl = &wd; (w = *wl) != nil; wl = &w->next)
31 		if(pid <= 0 || w->msg->pid == pid){
32 			msg = w->msg;
33 			*wl = w->next;
34 			free(w);
35 			return msg;
36 		}
37 	return 0;
38 }
39 
40 static void
addpid(Waitmsg * msg)41 addpid(Waitmsg *msg)
42 {
43 	Waited *w;
44 
45 	w = malloc(sizeof(*w));
46 	if(w == nil){
47 		/* lost it; what can we do? */
48 		free(msg);
49 		return;
50 	}
51 	w->msg = msg;
52 	w->next = wd;
53 	wd = w;
54 }
55 
56 static int
waitstatus(Waitmsg * w)57 waitstatus(Waitmsg *w)
58 {
59 	int r, t;
60 	char *bp, *ep;
61 
62 	r = 0;
63 	t = 0;
64 	if(w->msg[0]){
65 		/* message is 'prog pid:string' */
66 		bp = w->msg;
67 		while(*bp){
68 			if(*bp++ == ':')
69 				break;
70 		}
71 		if(*bp == 0)
72 			bp = w->msg;
73 		r = strtol(bp, &ep, 10);
74 		if(*ep == 0){
75 			if(r < 0 || r >= 256)
76 				r = 1;
77 		}else{
78 			t = _stringsig(bp);
79 			if(t == 0)
80 				r = 1;
81 		}
82 	}
83 	return (r<<8) | t;
84 }
85 
86 static void
waitresource(struct rusage * ru,Waitmsg * w)87 waitresource(struct rusage *ru, Waitmsg *w)
88 {
89 	memset(ru, 0, sizeof(*ru));
90 	ru->ru_utime.tv_sec = w->time[0]/1000;
91 	ru->ru_utime.tv_usec = (w->time[0]%1000)*1000;
92 	ru->ru_stime.tv_sec = w->time[1]/1000;
93 	ru->ru_stime.tv_usec = (w->time[1]%1000)*1000;
94 }
95 
96 pid_t
wait(int * status)97 wait(int *status)
98 {
99 	return wait4(-1, status, 0, nil);
100 }
101 
102 pid_t
waitpid(pid_t wpid,int * status,int options)103 waitpid(pid_t wpid, int *status, int options)
104 {
105 	return wait4(wpid, status, options, nil);
106 }
107 
108 pid_t
wait3(int * status,int options,struct rusage * res)109 wait3(int *status, int options, struct rusage *res)
110 {
111 	return wait4(-1, status, options, res);
112 }
113 
114 pid_t
wait4(pid_t wpid,int * status,int options,struct rusage * res)115 wait4(pid_t wpid, int *status, int options, struct rusage *res)
116 {
117 	char pname[50];
118 	Dir *d;
119 	Waitmsg *w;
120 
121 	w = lookpid(wpid);
122 	if(w == nil){
123 		if(options & WNOHANG){
124 			snprintf(pname, sizeof(pname), "/proc/%d/wait", getpid());
125 			d = _dirstat(pname);
126 			if(d != nil && d->length == 0){
127 				free(d);
128 				return 0;
129 			}
130 			free(d);
131 		}
132 		for(;;){
133 			w = _WAIT();
134 			if(w == nil){
135 				_syserrno();
136 				return -1;
137 			}
138 			if(wpid <= 0 || w->pid == wpid)
139 				break;
140 			addpid(w);
141 		}
142 	}
143 	if(res != nil)
144 		waitresource(res, w);
145 	if(status != nil)
146 		*status = waitstatus(w);
147 	wpid = w->pid;
148 	free(w);
149 	return wpid;
150 }
151