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 }