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 /*
31 * All of the wait*() functions are cancellation points.
32 */
33 #pragma weak _waitpid = waitpid
34 #pragma weak _wait = wait
35
36 #include "lint.h"
37 #include <unistd.h>
38 #include <string.h>
39 #include <errno.h>
40 #include <wait.h>
41 #include <sys/types.h>
42 #include <sys/siginfo.h>
43 #include <sys/times.h>
44 #include <sys/resource.h>
45
46 /*
47 * Convert the siginfo_t code and status fields to an old style wait status.
48 */
49 static int
wstat(int code,int status)50 wstat(int code, int status)
51 {
52 int stat = (status & 0377);
53
54 switch (code) {
55 case CLD_EXITED:
56 stat <<= 8;
57 break;
58 case CLD_DUMPED:
59 stat |= WCOREFLG;
60 break;
61 case CLD_KILLED:
62 break;
63 case CLD_TRAPPED:
64 case CLD_STOPPED:
65 stat <<= 8;
66 stat |= WSTOPFLG;
67 break;
68 case CLD_CONTINUED:
69 stat = WCONTFLG;
70 break;
71 }
72 return (stat);
73 }
74
75 pid_t
waitpid(pid_t pid,int * stat_loc,int options)76 waitpid(pid_t pid, int *stat_loc, int options)
77 {
78 idtype_t idtype;
79 id_t id;
80 siginfo_t info;
81 int error;
82
83 if (pid > 0) {
84 idtype = P_PID;
85 id = pid;
86 } else if (pid < -1) {
87 idtype = P_PGID;
88 id = -pid;
89 } else if (pid == -1) {
90 idtype = P_ALL;
91 id = 0;
92 } else {
93 idtype = P_PGID;
94 id = getpgid(0);
95 }
96
97 options |= (WEXITED|WTRAPPED);
98
99 if ((error = waitid(idtype, id, &info, options)) < 0)
100 return (error);
101
102 if (stat_loc)
103 *stat_loc = wstat(info.si_code, info.si_status);
104
105 return (info.si_pid);
106 }
107
108 pid_t
wait(int * stat_loc)109 wait(int *stat_loc)
110 {
111 return (waitpid(-1, stat_loc, 0));
112 }
113
114 pid_t
wait4(pid_t pid,int * stat_loc,int options,struct rusage * rp)115 wait4(pid_t pid, int *stat_loc, int options, struct rusage *rp)
116 {
117 struct tms before_tms;
118 struct tms after_tms;
119 siginfo_t info;
120 int error;
121 int noptions;
122 idtype_t idtype;
123
124 if (rp)
125 (void) memset(rp, 0, sizeof (struct rusage));
126 (void) memset(&info, 0, sizeof (siginfo_t));
127
128 if (times(&before_tms) == (clock_t)-1)
129 return (-1); /* errno is set by times() */
130
131 /*
132 * SunOS's wait4() previously supported only WNOHANG &
133 * WUNTRACED. XPG4v2 mandates that wait3() (which calls
134 * wait4()) also support WCONTINUED.
135 */
136 if (options & ~(WNOHANG|WUNTRACED|WCONTINUED)) {
137 errno = EINVAL;
138 return (-1);
139 }
140 noptions = options | WEXITED | WTRAPPED;
141
142 /*
143 * Emulate undocumented 4.x semantics for 1186845
144 */
145 if (pid < 0) {
146 pid = -pid;
147 idtype = P_PGID;
148 } else if (pid == 0) {
149 idtype = P_ALL;
150 } else {
151 idtype = P_PID;
152 }
153
154 error = waitid(idtype, pid, &info, noptions);
155 if (error == 0) {
156 clock_t diffu; /* difference in usertime (ticks) */
157 clock_t diffs; /* difference in systemtime (ticks) */
158 clock_t hz;
159
160 if ((options & WNOHANG) && info.si_pid == 0)
161 return (0); /* no child found */
162
163 if (rp) {
164 if (times(&after_tms) == (clock_t)-1)
165 return (-1); /* errno set by times() */
166 /*
167 * The system/user time is an approximation only !!!
168 */
169 diffu = after_tms.tms_cutime - before_tms.tms_cutime;
170 diffs = after_tms.tms_cstime - before_tms.tms_cstime;
171 hz = CLK_TCK;
172 rp->ru_utime.tv_sec = diffu / hz;
173 rp->ru_utime.tv_usec = (diffu % hz) * (1000000 / hz);
174 rp->ru_stime.tv_sec = diffs / hz;
175 rp->ru_stime.tv_usec = (diffs % hz) * (1000000 / hz);
176 }
177 if (stat_loc)
178 *stat_loc = wstat(info.si_code, info.si_status);
179 return (info.si_pid);
180 } else {
181 return (-1); /* error number is set by waitid() */
182 }
183 }
184
185 pid_t
wait3(int * stat_loc,int options,struct rusage * rp)186 wait3(int *stat_loc, int options, struct rusage *rp)
187 {
188 return (wait4(0, stat_loc, options, rp));
189 }
190