xref: /illumos-gate/usr/src/lib/libc/port/gen/waitpid.c (revision 7257d1b4)
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
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
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
111 wait(int *stat_loc)
112 {
113 	return (waitpid(-1, stat_loc, 0));
114 }
115 
116 pid_t
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
188 wait3(int *stat_loc, int options, struct rusage *rp)
189 {
190 	return (wait4(0, stat_loc, options, rp));
191 }
192