diff options
Diffstat (limited to 'usr/src/lib/libc/port/gen/waitpid.c')
-rw-r--r-- | usr/src/lib/libc/port/gen/waitpid.c | 159 |
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)); +} |