A wait3() implementation with rusage / patch for SVR4 bug in csh(1)

A wait3() implementation with rusage / patch for SVR4 bug in csh(1)

Post by Joerg Schilli » Fri, 24 Mar 1995 06:38:35



This is an alternative to the wait3() implementation from /usr/ucblib.
Opposed to the implementation found in /usr/ucblib it gives you most of the
rusage fields from BSD 4.x.

The missing fields are:
        rusage->ru_maxrss
        rusage->ru_ixrss
        rusage->ru_idrss
        rusage->ru_isrss

NOTES:
        1)      Due to a lazy implementation the wait3() function found
                in /usr/ucblib and in csh(1) gives you only full seconds
                in the ru_utime and ru_stime fields, usecs are always zeroed.
                On current hardware commands typically run in less than
                a second. This causes csh to print normally only zeroes in the
                time command or if timing is enabled.
                The following implementation gives you a resolution of a
                clock tick as on SunOS 4.x.

        2)      If the process beeing waited for is setuid and the parent is
                not run by root, the /proc entry for the child may not be
                opened. In these cases only time information is available.
                This seemes to be a design flaw of the /proc filesystem we have
                to live with.

People with source access may replace the file wait3.c found in .../cmd/csh
with the following and edit getrusage.c to correct the timing computations
(look into my implentation of wait3() too see how or use the
patch script below) to get better timing information.

I hope Sun will use this for csh on Solaris 2.5 ...

/* @(#)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 (jo...@schily.isdn.cs.tu-berlin.de j...@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 <wait.h>
#ifdef  WNOWAIT         /* We are on SVR4 */

#include <sys/types.h>
#include <sys/time.h>
#include <sys/times.h>
#include <sys/siginfo.h>
#include <sys/procset.h>
#include <sys/param.h>
#include <sys/procfs.h>
#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 <sys/resource.h>

/*
 * 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 */

*** getrusage.c Wed Mar 22 18:34:59 1995
--- getrusage.c.bak     Wed Mar 22 18:34:59 1995
***************
*** 61,80 ****

                case RUSAGE_SELF:
                        rusage->ru_utime.tv_sec = tms.tms_utime / HZ;
!                       rusage->ru_utime.tv_usec = (tms.tms_utime % HZ) *
!                               1000000 / HZ;
                        rusage->ru_stime.tv_sec = tms.tms_stime / HZ;
!                       rusage->ru_stime.tv_usec = (tms.tms_stime % HZ) *
!                               1000000 / HZ;
                        return 0;

                case RUSAGE_CHILDREN:
                        rusage->ru_utime.tv_sec = tms.tms_cutime / HZ;
!                       rusage->ru_utime.tv_usec = (tms.tms_cutime % HZ) *
!                               1000000 / HZ;
                        rusage->ru_stime.tv_sec = tms.tms_cstime / HZ;
!                       rusage->ru_stime.tv_usec = (tms.tms_cstime % HZ) *
!                               1000000 / HZ;
                        return 0;

                default:
--- 61,80 ----

                case RUSAGE_SELF:
                        rusage->ru_utime.tv_sec = tms.tms_utime / HZ;
!                       rusage->ru_utime.tv_usec = (tms.tms_utime % HZ) /
!                               HZ * 1000000;
                        rusage->ru_stime.tv_sec = tms.tms_stime / HZ;
!                       rusage->ru_stime.tv_usec = (tms.tms_stime % HZ) /
!                               HZ * 1000000;
                        return 0;

                case RUSAGE_CHILDREN:
                        rusage->ru_utime.tv_sec = tms.tms_cutime / HZ;
!                       rusage->ru_utime.tv_usec = (tms.tms_cutime % HZ) /
!                               HZ * 1000000;
                        rusage->ru_stime.tv_sec = tms.tms_cstime / HZ;
!                       rusage->ru_stime.tv_usec = (tms.tms_cstime % HZ) /
!                               HZ * 1000000;
                        return 0;

                default:

--
Private:J?rg Schilling Seestr. 110 D-13353 Berlin      (030)452 55 85
EMail:  jo...@schily.isdn.cs.tu-berlin.de
        j...@cs.tu-berlin.de
If you don't have iso-8859-1 chars my name is           J"org Schilling