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