summaryrefslogtreecommitdiff
path: root/usr/src/lib/libc/port/gen/waitpid.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libc/port/gen/waitpid.c')
-rw-r--r--usr/src/lib/libc/port/gen/waitpid.c159
1 files changed, 127 insertions, 32 deletions
diff --git a/usr/src/lib/libc/port/gen/waitpid.c b/usr/src/lib/libc/port/gen/waitpid.c
index 993e046097..3a7d66330e 100644
--- a/usr/src/lib/libc/port/gen/waitpid.c
+++ b/usr/src/lib/libc/port/gen/waitpid.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -19,8 +18,9 @@
*
* CDDL HEADER END
*/
+
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -29,14 +29,55 @@
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
+/*
+ * All of these functions are cancellation points.
+ */
+#pragma weak waitpid = _waitpid
+#pragma weak wait = _wait
+#pragma weak wait4 = _wait4
+#pragma weak wait3 = _wait3
#include "synonyms.h"
-#include <sys/types.h>
#include <unistd.h>
+#include <string.h>
+#include <errno.h>
#include <wait.h>
+#include <sys/types.h>
+#include <sys/siginfo.h>
+#include <sys/times.h>
+#include <sys/resource.h>
+
+/*
+ * Convert the siginfo_t code and status fields to an old style wait status.
+ */
+static int
+wstat(int code, int status)
+{
+ int stat = (status & 0377);
+
+ switch (code) {
+ case CLD_EXITED:
+ stat <<= 8;
+ break;
+ case CLD_DUMPED:
+ stat |= WCOREFLG;
+ break;
+ case CLD_KILLED:
+ break;
+ case CLD_TRAPPED:
+ case CLD_STOPPED:
+ stat <<= 8;
+ stat |= WSTOPFLG;
+ break;
+ case CLD_CONTINUED:
+ stat = WCONTFLG;
+ break;
+ }
+ return (stat);
+}
pid_t
-_waitpid(pid_t pid, int *stat_loc, int options)
+waitpid(pid_t pid, int *stat_loc, int options)
{
idtype_t idtype;
id_t id;
@@ -62,37 +103,91 @@ _waitpid(pid_t pid, int *stat_loc, int options)
if ((error = waitid(idtype, id, &info, options)) < 0)
return (error);
- if (stat_loc) {
-
- int stat = (info.si_status & 0377);
-
- switch (info.si_code) {
- case CLD_EXITED:
- stat <<= 8;
- break;
- case CLD_DUMPED:
- stat |= WCOREFLG;
- break;
- case CLD_KILLED:
- break;
- case CLD_TRAPPED:
- case CLD_STOPPED:
- stat <<= 8;
- stat |= WSTOPFLG;
- break;
- case CLD_CONTINUED:
- stat = WCONTFLG;
- break;
- }
-
- *stat_loc = stat;
- }
+ if (stat_loc)
+ *stat_loc = wstat(info.si_code, info.si_status);
return (info.si_pid);
}
pid_t
-_wait(int *stat_loc)
+wait(int *stat_loc)
{
return (waitpid(-1, stat_loc, 0));
}
+
+pid_t
+wait4(pid_t pid, int *stat_loc, int options, struct rusage *rp)
+{
+ struct tms before_tms;
+ struct tms after_tms;
+ siginfo_t info;
+ int error;
+ int noptions;
+ idtype_t idtype;
+
+ if (rp)
+ (void) memset(rp, 0, sizeof (struct rusage));
+ (void) memset(&info, 0, sizeof (siginfo_t));
+
+ if (times(&before_tms) == (clock_t)-1)
+ return (-1); /* errno is set by times() */
+
+ /*
+ * SunOS's wait4() previously supported only WNOHANG &
+ * WUNTRACED. XPG4v2 mandates that wait3() (which calls
+ * wait4()) also support WCONTINUED.
+ */
+ if (options & ~(WNOHANG|WUNTRACED|WCONTINUED)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ noptions = options | WEXITED | WTRAPPED;
+
+ /*
+ * Emulate undocumented 4.x semantics for 1186845
+ */
+ if (pid < 0) {
+ pid = -pid;
+ idtype = P_PGID;
+ } else if (pid == 0) {
+ idtype = P_ALL;
+ } else {
+ idtype = P_PID;
+ }
+
+ error = waitid(idtype, pid, &info, noptions);
+ if (error == 0) {
+ clock_t diffu; /* difference in usertime (ticks) */
+ clock_t diffs; /* difference in systemtime (ticks) */
+ clock_t hz;
+
+ if ((options & WNOHANG) && info.si_pid == 0)
+ return (0); /* no child found */
+
+ if (rp) {
+ if (times(&after_tms) == (clock_t)-1)
+ return (-1); /* errno set by times() */
+ /*
+ * The system/user time is an approximation only !!!
+ */
+ diffu = after_tms.tms_cutime - before_tms.tms_cutime;
+ diffs = after_tms.tms_cstime - before_tms.tms_cstime;
+ hz = CLK_TCK;
+ rp->ru_utime.tv_sec = diffu / hz;
+ rp->ru_utime.tv_usec = (diffu % hz) * (1000000 / hz);
+ rp->ru_stime.tv_sec = diffs / hz;
+ rp->ru_stime.tv_usec = (diffs % hz) * (1000000 / hz);
+ }
+ if (stat_loc)
+ *stat_loc = wstat(info.si_code, info.si_status);
+ return (info.si_pid);
+ } else {
+ return (-1); /* error number is set by waitid() */
+ }
+}
+
+pid_t
+wait3(int *stat_loc, int options, struct rusage *rp)
+{
+ return (wait4(0, stat_loc, options, rp));
+}