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