/* @(#)wait3.c 1.1 95/03/22 Copyr 1995 J. Schilling */ #ifndef lint static char sccsid[] = "@(#)wait3.c 1.1 95/03/22 Copyr 1995 J. Schilling"; #endif lint /* * Compatibility function for BSD wait3(). * * J"org Schilling (joerg@schily.isdn.cs.tu-berlin.de js@cs.tu-berlin.de) * * Tries to get rusage information from /proc filesystem. * NOTE: since non root processes are not allowed to open suid procs * we cannot get complete rusage information in this case. * * Theory of Operation: * * On stock SVR4 there is no way to get resource usage information. * We may only get times information from siginfo struct: * * wait3() * { * call waitid(,,,); * if (child is found) { * compute times from siginfo and fill in rusage * } * } * * Solaris (at least 2.3) has PIOCUSAGE which is guaranteed * to work even on zombies: * * wait3() * { * call waitid(P_ALL,,,options|WNOWAIT); * if (child is found) { * compute times from siginfo and fill in rusage * if (can get /proc PIOCUSAGE info) * fill in rest of rusage from /proc * selective call waitid(P_PID, pid,,); * } * * /proc ioctl's that work on zombies: * PIOCPSINFO, PIOCGETPR, PIOCUSAGE, PIOCLUSAGE * */ #include #ifdef WNOWAIT /* We are on SVR4 */ #include #include #include #include #include #include #include #include "resource.h" /* local version of BSD /usr/include/sys/resource.h */ static int wait_prusage(siginfo_t *, int, struct rusage *); static int wait_status(int, int); static void wait_times(siginfo_t *, struct rusage *); wait3(status, options, rusage) int *status; int options; struct rusage *rusage; { siginfo_t info; if (rusage) memset((void *)rusage, 0, sizeof(struct rusage)); memset((void *)&info, 0, sizeof(siginfo_t)); /* * BSD wait3() only supports WNOHANG & WUNTRACED * * You may want to modify the next two lines to meet your requirements: * 1) options &= (WNOHANG|WUNTRACED); * 2a) options |= (WEXITED|WSTOPPED|WTRAPPED); * 2b) options |= (WEXITED|WSTOPPED|WTRAPPED|WCONTINUED); * * If you want BSD compatibility use 1) and 2a) * If you want maximum SYSV compatibility remove both lines. */ options &= (WNOHANG|WUNTRACED); options |= (WEXITED|WSTOPPED|WTRAPPED); if (waitid(P_ALL, 0, &info, options|WNOWAIT) < 0) return (-1); (void) wait_prusage(&info, options, rusage); if (status) *status = wait_status(info.si_code, info.si_status); return (info.si_pid); } static int wait_prusage(info, options, rusage) siginfo_t *info; int options; struct rusage *rusage; { #ifdef PIOCUSAGE int f; char cproc[32]; prusage_t prusage; #endif struct tms tms_stop; siginfo_t info2; if ((options & WNOHANG) && (info->si_pid == 0)) return (0); /* no children */ if (rusage == 0) goto norusage; wait_times(info, rusage); #ifdef PIOCUSAGE sprintf(cproc, "/proc/%d", info->si_pid); if ((f = open(cproc, 0)) < 0) goto norusage; if (ioctl(f, PIOCUSAGE, &prusage) < 0) { close(f); goto norusage; } close(f); #ifdef COMMENT Missing fields: rusage->ru_maxrss = XXX; rusage->ru_ixrss = XXX; rusage->ru_idrss = XXX; rusage->ru_isrss = XXX; #endif rusage->ru_minflt = prusage.pr_minf; rusage->ru_majflt = prusage.pr_majf; rusage->ru_nswap = prusage.pr_nswap; rusage->ru_inblock = prusage.pr_inblk; rusage->ru_oublock = prusage.pr_oublk; rusage->ru_msgsnd = prusage.pr_msnd; rusage->ru_msgrcv = prusage.pr_mrcv; rusage->ru_nsignals = prusage.pr_sigs; rusage->ru_nvcsw = prusage.pr_vctx; rusage->ru_nivcsw = prusage.pr_ictx; #endif norusage: return (waitid(P_PID, info->si_pid, &info2, options)); } /* * Convert the status code to old style wait status */ static int wait_status(code, status) int code; int status; { register int stat = (status & 0377); switch (code) { case CLD_EXITED: stat <<= 8; break; case CLD_KILLED: break; case CLD_DUMPED: stat |= WCOREFLG; break; case CLD_TRAPPED: case CLD_STOPPED: stat <<= 8; stat |= WSTOPFLG; break; case CLD_CONTINUED: stat = WCONTFLG; break; } return (stat); } /* * Convert the siginfo times to rusage timeval */ static void wait_times(info, rusage) siginfo_t *info; struct rusage *rusage; { int hz = HZ; /* HZ is mapped into sysconf(_SC_CLK_TCK) */ rusage->ru_utime.tv_sec = info->si_utime / hz; rusage->ru_utime.tv_usec = (info->si_utime % hz) * 1000000 / hz; rusage->ru_stime.tv_sec = info->si_stime / hz; rusage->ru_stime.tv_usec = (info->si_stime % hz) * 1000000 / hz; } #endif /* WNOWAIT */ /* @(#)resource.h 2.10 89/02/21 SMI; from UCB 4.1 83/02/10 */ /* * Missing parts for wait3() taken from SunOS 4.1 */ #ifndef _resource_h #define _resource_h /* * Get rest of definitions from system include files */ #include /* * Resource utilization information. */ #define RUSAGE_SELF 0 #define RUSAGE_CHILDREN -1 struct rusage { struct timeval ru_utime; /* user time used */ struct timeval ru_stime; /* system time used */ long ru_maxrss; #define ru_first ru_ixrss long ru_ixrss; /* XXX: 0 */ long ru_idrss; /* XXX: sum of rm_asrss */ long ru_isrss; /* XXX: 0 */ long ru_minflt; /* any page faults not requiring I/O */ long ru_majflt; /* any page faults requiring I/O */ long ru_nswap; /* swaps */ long ru_inblock; /* block input operations */ long ru_oublock; /* block output operations */ long ru_msgsnd; /* messages sent */ long ru_msgrcv; /* messages received */ long ru_nsignals; /* signals received */ long ru_nvcsw; /* voluntary context switches */ long ru_nivcsw; /* involuntary " */ #define ru_last ru_nivcsw }; #endif /* _resource_h */