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  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * Implement fast getrusage call
  28  */
  29 
  30 #include <sys/types.h>
  31 #include <sys/systm.h>
  32 #include <sys/time.h>
  33 #include <sys/errno.h>
  34 #include <sys/resource.h>
  35 #include <sys/vm_usage.h>
  36 
  37 static int
  38 getrusage(void *user_rusage)
  39 {
  40         struct rusage r;
  41         kthread_t *t = curthread;
  42         proc_t *p = ttoproc(t);
  43         hrtime_t snsecs, unsecs;
  44         klwp_t *lwp;
  45 
  46         bzero(&r, sizeof (struct rusage));
  47 
  48         mutex_enter(&p->p_lock);
  49 
  50         if (p->p_defunct > 0) {
  51                 r.ru_majflt     = p->p_ru.majflt;
  52                 r.ru_minflt     = p->p_ru.minflt;
  53                 r.ru_nswap      = p->p_ru.nswap;
  54                 r.ru_inblock    = p->p_ru.inblock;
  55                 r.ru_oublock    = p->p_ru.oublock;
  56                 r.ru_msgsnd     = p->p_ru.msgsnd;
  57                 r.ru_msgrcv     = p->p_ru.msgrcv;
  58                 r.ru_nsignals   = p->p_ru.nsignals;
  59                 r.ru_nvcsw      = p->p_ru.nvcsw;
  60                 r.ru_nivcsw     = p->p_ru.nivcsw;
  61         }
  62 
  63         unsecs = mstate_aggr_state(p, LMS_USER);
  64         snsecs = mstate_aggr_state(p, LMS_SYSTEM);
  65 
  66         do {
  67                 if (t->t_proc_flag & TP_LWPEXIT)
  68                         continue;
  69 
  70                 lwp = ttolwp(t);
  71 
  72                 r.ru_majflt     += lwp->lwp_ru.majflt;
  73                 r.ru_minflt     += lwp->lwp_ru.minflt;
  74                 r.ru_nswap      += lwp->lwp_ru.nswap;
  75                 r.ru_inblock    += lwp->lwp_ru.inblock;
  76                 r.ru_oublock    += lwp->lwp_ru.oublock;
  77                 r.ru_msgsnd     += lwp->lwp_ru.msgsnd;
  78                 r.ru_msgrcv     += lwp->lwp_ru.msgrcv;
  79                 r.ru_nsignals   += lwp->lwp_ru.nsignals;
  80                 r.ru_nvcsw      += lwp->lwp_ru.nvcsw;
  81                 r.ru_nivcsw     += lwp->lwp_ru.nivcsw;
  82 
  83         } while ((t = t->t_forw) != curthread);
  84 
  85         mutex_exit(&p->p_lock);
  86 
  87         hrt2tv(unsecs, &r.ru_utime);
  88         hrt2tv(snsecs, &r.ru_stime);
  89 
  90 #ifdef _SYSCALL32_IMPL
  91         if (get_udatamodel() == DATAMODEL_ILP32) {
  92                 struct rusage32 r32;
  93 
  94                 bzero(&r32, sizeof (struct rusage32));
  95 
  96                 r32.ru_utime.tv_sec  = r.ru_utime.tv_sec;
  97                 r32.ru_utime.tv_usec = r.ru_utime.tv_usec;
  98                 r32.ru_stime.tv_sec  = r.ru_stime.tv_sec;
  99                 r32.ru_stime.tv_usec = r.ru_stime.tv_usec;
 100 
 101                 r32.ru_majflt   = (int32_t)r.ru_majflt;
 102                 r32.ru_minflt   = (int32_t)r.ru_minflt;
 103                 r32.ru_nswap    = (int32_t)r.ru_nswap;
 104                 r32.ru_inblock  = (int32_t)r.ru_inblock;
 105                 r32.ru_oublock  = (int32_t)r.ru_oublock;
 106                 r32.ru_msgsnd   = (int32_t)r.ru_msgsnd;
 107                 r32.ru_msgrcv   = (int32_t)r.ru_msgrcv;
 108                 r32.ru_nsignals = (int32_t)r.ru_nsignals;
 109                 r32.ru_nvcsw    = (int32_t)r.ru_nvcsw;
 110                 r32.ru_nivcsw   = (int32_t)r.ru_nivcsw;
 111                 if (copyout(&r32, user_rusage, sizeof (r32)) != 0)
 112                         return (set_errno(EFAULT));
 113         } else
 114 #endif /* _SYSCALL32_IMPL */
 115 
 116                 if (copyout(&r, user_rusage, sizeof (r)) != 0)
 117                         return (set_errno(EFAULT));
 118 
 119         return (0);
 120 }
 121 
 122 static int
 123 getrusage_chld(void *user_rusage)
 124 {
 125         struct rusage r;
 126         kthread_t *t = curthread;
 127         proc_t *p = ttoproc(t);
 128         hrtime_t snsecs, unsecs;
 129 
 130         bzero(&r, sizeof (struct rusage));
 131 
 132         mutex_enter(&p->p_lock);
 133 
 134         unsecs = p->p_cacct[LMS_USER];
 135         snsecs = p->p_cacct[LMS_SYSTEM] + p->p_cacct[LMS_TRAP];
 136 
 137         r.ru_majflt     = p->p_cru.majflt;
 138         r.ru_minflt     = p->p_cru.minflt;
 139         r.ru_nswap      = p->p_cru.nswap;
 140         r.ru_inblock    = p->p_cru.inblock;
 141         r.ru_oublock    = p->p_cru.oublock;
 142         r.ru_msgsnd     = p->p_cru.msgsnd;
 143         r.ru_msgrcv     = p->p_cru.msgrcv;
 144         r.ru_nsignals   = p->p_cru.nsignals;
 145         r.ru_nvcsw      = p->p_cru.nvcsw;
 146         r.ru_nivcsw     = p->p_cru.nivcsw;
 147 
 148         mutex_exit(&p->p_lock);
 149 
 150         hrt2tv(unsecs, &r.ru_utime);
 151         hrt2tv(snsecs, &r.ru_stime);
 152 #ifdef _SYSCALL32_IMPL
 153         if (get_udatamodel() == DATAMODEL_ILP32) {
 154                 struct rusage32 r32;
 155 
 156                 bzero(&r32, sizeof (struct rusage32));
 157 
 158                 r32.ru_utime.tv_sec  = r.ru_utime.tv_sec;
 159                 r32.ru_utime.tv_usec = r.ru_utime.tv_usec;
 160                 r32.ru_stime.tv_sec  = r.ru_stime.tv_sec;
 161                 r32.ru_stime.tv_usec = r.ru_stime.tv_usec;
 162 
 163                 r32.ru_majflt   = (int32_t)r.ru_majflt;
 164                 r32.ru_minflt   = (int32_t)r.ru_minflt;
 165                 r32.ru_nswap    = (int32_t)r.ru_nswap;
 166                 r32.ru_inblock  = (int32_t)r.ru_inblock;
 167                 r32.ru_oublock  = (int32_t)r.ru_oublock;
 168                 r32.ru_msgsnd   = (int32_t)r.ru_msgsnd;
 169                 r32.ru_msgrcv   = (int32_t)r.ru_msgrcv;
 170                 r32.ru_nsignals = (int32_t)r.ru_nsignals;
 171                 r32.ru_nvcsw    = (int32_t)r.ru_nvcsw;
 172                 r32.ru_nivcsw   = (int32_t)r.ru_nivcsw;
 173                 if (copyout(&r32, user_rusage, sizeof (r32)) != 0)
 174                         return (set_errno(EFAULT));
 175         } else
 176 #endif /* _SYSCALL32_IMPL */
 177 
 178                 if (copyout(&r, user_rusage, sizeof (r)) != 0)
 179                         return (set_errno(EFAULT));
 180 
 181         return (0);
 182 }
 183 
 184 static int
 185 getrusage_lwp(void *user_rusage)
 186 {
 187         struct rusage r;
 188         kthread_t *t = curthread;
 189         klwp_t *lwp;
 190         hrtime_t snsecs, unsecs;
 191         struct mstate *ms;
 192 
 193         bzero(&r, sizeof (struct rusage));
 194 
 195         lwp = ttolwp(t);
 196         ms = &lwp->lwp_mstate;
 197         unsecs = ms->ms_acct[LMS_USER];
 198         snsecs = ms->ms_acct[LMS_SYSTEM] + ms->ms_acct[LMS_TRAP];
 199         scalehrtime(&unsecs);
 200         scalehrtime(&snsecs);
 201         r.ru_majflt     = lwp->lwp_ru.majflt;
 202         r.ru_minflt     = lwp->lwp_ru.minflt;
 203         r.ru_nswap      = lwp->lwp_ru.nswap;
 204         r.ru_inblock    = lwp->lwp_ru.inblock;
 205         r.ru_oublock    = lwp->lwp_ru.oublock;
 206         r.ru_msgsnd     = lwp->lwp_ru.msgsnd;
 207         r.ru_msgrcv     = lwp->lwp_ru.msgrcv;
 208         r.ru_nsignals   = lwp->lwp_ru.nsignals;
 209         r.ru_nvcsw      = lwp->lwp_ru.nvcsw;
 210         r.ru_nivcsw     = lwp->lwp_ru.nivcsw;
 211 
 212         hrt2tv(unsecs, &r.ru_utime);
 213         hrt2tv(snsecs, &r.ru_stime);
 214 #ifdef _SYSCALL32_IMPL
 215         if (get_udatamodel() == DATAMODEL_ILP32) {
 216                 struct rusage32 r32;
 217 
 218                 bzero(&r32, sizeof (struct rusage32));
 219 
 220                 r32.ru_utime.tv_sec  = r.ru_utime.tv_sec;
 221                 r32.ru_utime.tv_usec = r.ru_utime.tv_usec;
 222                 r32.ru_stime.tv_sec  = r.ru_stime.tv_sec;
 223                 r32.ru_stime.tv_usec = r.ru_stime.tv_usec;
 224 
 225                 r32.ru_majflt   = (int32_t)r.ru_majflt;
 226                 r32.ru_minflt   = (int32_t)r.ru_minflt;
 227                 r32.ru_nswap    = (int32_t)r.ru_nswap;
 228                 r32.ru_inblock  = (int32_t)r.ru_inblock;
 229                 r32.ru_oublock  = (int32_t)r.ru_oublock;
 230                 r32.ru_msgsnd   = (int32_t)r.ru_msgsnd;
 231                 r32.ru_msgrcv   = (int32_t)r.ru_msgrcv;
 232                 r32.ru_nsignals = (int32_t)r.ru_nsignals;
 233                 r32.ru_nvcsw    = (int32_t)r.ru_nvcsw;
 234                 r32.ru_nivcsw   = (int32_t)r.ru_nivcsw;
 235                 if (copyout(&r32, user_rusage, sizeof (r32)) != 0)
 236                         return (set_errno(EFAULT));
 237         } else
 238 #endif /* _SYSCALL32_IMPL */
 239 
 240                 if (copyout(&r, user_rusage, sizeof (r)) != 0)
 241                         return (set_errno(EFAULT));
 242 
 243         return (0);
 244 }
 245 
 246 int
 247 rusagesys(int code, void *arg1, void *arg2, void *arg3, void *arg4)
 248 {
 249         switch (code) {
 250 
 251         case _RUSAGESYS_GETRUSAGE:
 252                 return (getrusage(arg1));
 253         case _RUSAGESYS_GETRUSAGE_CHLD:
 254                 return (getrusage_chld(arg1));
 255         case _RUSAGESYS_GETRUSAGE_LWP:
 256                 return (getrusage_lwp(arg1));
 257         case _RUSAGESYS_GETVMUSAGE:
 258                 return (vm_getusage((uint_t)(uintptr_t)arg1, (time_t)arg2,
 259                     (vmusage_t *)arg3, (size_t *)arg4, 0));
 260         default:
 261                 return (set_errno(EINVAL));
 262         }
 263 }