1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1988 AT&T */
28 /* All Rights Reserved */
29
30 #pragma ident "%Z%%M% %I% %E% SMI"
31
32 /*
33 * All of the wait*() functions are cancellation points.
34 */
35 #pragma weak _waitpid = waitpid
36 #pragma weak _wait = wait
37
38 #include "lint.h"
39 #include <unistd.h>
40 #include <string.h>
41 #include <errno.h>
42 #include <wait.h>
43 #include <sys/types.h>
44 #include <sys/siginfo.h>
45 #include <sys/times.h>
46 #include <sys/resource.h>
47
48 /*
49 * Convert the siginfo_t code and status fields to an old style wait status.
50 */
51 static int
wstat(int code,int status)52 wstat(int code, int status)
53 {
54 int stat = (status & 0377);
55
56 switch (code) {
57 case CLD_EXITED:
58 stat <<= 8;
59 break;
60 case CLD_DUMPED:
61 stat |= WCOREFLG;
62 break;
63 case CLD_KILLED:
64 break;
65 case CLD_TRAPPED:
66 case CLD_STOPPED:
67 stat <<= 8;
68 stat |= WSTOPFLG;
69 break;
70 case CLD_CONTINUED:
71 stat = WCONTFLG;
72 break;
73 }
74 return (stat);
75 }
76
77 pid_t
waitpid(pid_t pid,int * stat_loc,int options)78 waitpid(pid_t pid, int *stat_loc, int options)
79 {
80 idtype_t idtype;
81 id_t id;
82 siginfo_t info;
83 int error;
84
85 if (pid > 0) {
86 idtype = P_PID;
87 id = pid;
88 } else if (pid < -1) {
89 idtype = P_PGID;
90 id = -pid;
91 } else if (pid == -1) {
92 idtype = P_ALL;
93 id = 0;
94 } else {
95 idtype = P_PGID;
96 id = getpgid(0);
97 }
98
99 options |= (WEXITED|WTRAPPED);
100
101 if ((error = waitid(idtype, id, &info, options)) < 0)
102 return (error);
103
104 if (stat_loc)
105 *stat_loc = wstat(info.si_code, info.si_status);
106
107 return (info.si_pid);
108 }
109
110 pid_t
wait(int * stat_loc)111 wait(int *stat_loc)
112 {
113 return (waitpid(-1, stat_loc, 0));
114 }
115
116 pid_t
wait4(pid_t pid,int * stat_loc,int options,struct rusage * rp)117 wait4(pid_t pid, int *stat_loc, int options, struct rusage *rp)
118 {
119 struct tms before_tms;
120 struct tms after_tms;
121 siginfo_t info;
122 int error;
123 int noptions;
124 idtype_t idtype;
125
126 if (rp)
127 (void) memset(rp, 0, sizeof (struct rusage));
128 (void) memset(&info, 0, sizeof (siginfo_t));
129
130 if (times(&before_tms) == (clock_t)-1)
131 return (-1); /* errno is set by times() */
132
133 /*
134 * SunOS's wait4() previously supported only WNOHANG &
135 * WUNTRACED. XPG4v2 mandates that wait3() (which calls
136 * wait4()) also support WCONTINUED.
137 */
138 if (options & ~(WNOHANG|WUNTRACED|WCONTINUED)) {
139 errno = EINVAL;
140 return (-1);
141 }
142 noptions = options | WEXITED | WTRAPPED;
143
144 /*
145 * Emulate undocumented 4.x semantics for 1186845
146 */
147 if (pid < 0) {
148 pid = -pid;
149 idtype = P_PGID;
150 } else if (pid == 0) {
151 idtype = P_ALL;
152 } else {
153 idtype = P_PID;
154 }
155
156 error = waitid(idtype, pid, &info, noptions);
157 if (error == 0) {
158 clock_t diffu; /* difference in usertime (ticks) */
159 clock_t diffs; /* difference in systemtime (ticks) */
160 clock_t hz;
161
162 if ((options & WNOHANG) && info.si_pid == 0)
163 return (0); /* no child found */
164
165 if (rp) {
166 if (times(&after_tms) == (clock_t)-1)
167 return (-1); /* errno set by times() */
168 /*
169 * The system/user time is an approximation only !!!
170 */
171 diffu = after_tms.tms_cutime - before_tms.tms_cutime;
172 diffs = after_tms.tms_cstime - before_tms.tms_cstime;
173 hz = CLK_TCK;
174 rp->ru_utime.tv_sec = diffu / hz;
175 rp->ru_utime.tv_usec = (diffu % hz) * (1000000 / hz);
176 rp->ru_stime.tv_sec = diffs / hz;
177 rp->ru_stime.tv_usec = (diffs % hz) * (1000000 / hz);
178 }
179 if (stat_loc)
180 *stat_loc = wstat(info.si_code, info.si_status);
181 return (info.si_pid);
182 } else {
183 return (-1); /* error number is set by waitid() */
184 }
185 }
186
187 pid_t
wait3(int * stat_loc,int options,struct rusage * rp)188 wait3(int *stat_loc, int options, struct rusage *rp)
189 {
190 return (wait4(0, stat_loc, options, rp));
191 }
192