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