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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Implement fast getrusage call
31  */
32 
33 #include <sys/types.h>
34 #include <sys/systm.h>
35 #include <sys/time.h>
36 #include <sys/errno.h>
37 #include <sys/resource.h>
38 
39 static int
40 getrusage(void *user_rusage)
41 {
42 	struct rusage r;
43 	kthread_t *t = curthread;
44 	proc_t *p = ttoproc(t);
45 	hrtime_t snsecs, unsecs;
46 	klwp_t *lwp;
47 
48 	r.ru_maxrss =	0;	/* always 0 */
49 	r.ru_ixrss =	0;	/* always 0 */
50 	r.ru_idrss =	0;	/* always 0 */
51 	r.ru_isrss =	0;	/* always 0 */
52 
53 	r.ru_utime.tv_sec = 0;
54 	r.ru_utime.tv_usec = 0;
55 	r.ru_stime.tv_sec = 0;
56 	r.ru_stime.tv_usec = 0;
57 
58 	mutex_enter(&p->p_lock);
59 
60 	if (p->p_defunct > 0) {
61 		r.ru_majflt	= p->p_ru.majflt;
62 		r.ru_minflt	= p->p_ru.minflt;
63 		r.ru_nswap	= p->p_ru.nswap;
64 		r.ru_inblock	= p->p_ru.inblock;
65 		r.ru_oublock	= p->p_ru.oublock;
66 		r.ru_msgsnd	= p->p_ru.msgsnd;
67 		r.ru_msgrcv	= p->p_ru.msgrcv;
68 		r.ru_nsignals	= p->p_ru.nsignals;
69 		r.ru_nvcsw	= p->p_ru.nvcsw;
70 		r.ru_nivcsw	= p->p_ru.nivcsw;
71 	}
72 
73 	unsecs = mstate_aggr_state(p, LMS_USER);
74 	snsecs = mstate_aggr_state(p, LMS_SYSTEM);
75 
76 	do {
77 		if (t->t_proc_flag & TP_LWPEXIT)
78 			continue;
79 
80 		lwp = ttolwp(t);
81 
82 		r.ru_majflt	+= lwp->lwp_ru.majflt;
83 		r.ru_minflt	+= lwp->lwp_ru.minflt;
84 		r.ru_nswap	+= lwp->lwp_ru.nswap;
85 		r.ru_inblock	+= lwp->lwp_ru.inblock;
86 		r.ru_oublock	+= lwp->lwp_ru.oublock;
87 		r.ru_msgsnd	+= lwp->lwp_ru.msgsnd;
88 		r.ru_msgrcv	+= lwp->lwp_ru.msgrcv;
89 		r.ru_nsignals	+= lwp->lwp_ru.nsignals;
90 		r.ru_nvcsw	+= lwp->lwp_ru.nvcsw;
91 		r.ru_nivcsw	+= lwp->lwp_ru.nivcsw;
92 
93 	} while ((t = t->t_forw) != curthread);
94 
95 	mutex_exit(&p->p_lock);
96 
97 	hrt2tv(unsecs, &r.ru_utime);
98 	hrt2tv(snsecs, &r.ru_stime);
99 
100 #ifdef _SYSCALL32_IMPL
101 	if (get_udatamodel() == DATAMODEL_ILP32) {
102 		struct rusage32 r32;
103 
104 		r32.ru_maxrss =	0;	/* always 0 */
105 		r32.ru_ixrss =	0;	/* always 0 */
106 		r32.ru_idrss =	0;	/* always 0 */
107 		r32.ru_isrss =	0;	/* always 0 */
108 
109 		r32.ru_utime.tv_sec  = r.ru_utime.tv_sec;
110 		r32.ru_utime.tv_usec = r.ru_utime.tv_usec;
111 		r32.ru_stime.tv_sec  = r.ru_stime.tv_sec;
112 		r32.ru_stime.tv_usec = r.ru_stime.tv_usec;
113 
114 		r32.ru_majflt	= (int32_t)r.ru_majflt;
115 		r32.ru_minflt	= (int32_t)r.ru_minflt;
116 		r32.ru_nswap	= (int32_t)r.ru_nswap;
117 		r32.ru_inblock	= (int32_t)r.ru_inblock;
118 		r32.ru_oublock	= (int32_t)r.ru_oublock;
119 		r32.ru_msgsnd	= (int32_t)r.ru_msgsnd;
120 		r32.ru_msgrcv	= (int32_t)r.ru_msgrcv;
121 		r32.ru_nsignals	= (int32_t)r.ru_nsignals;
122 		r32.ru_nvcsw	= (int32_t)r.ru_nvcsw;
123 		r32.ru_nivcsw	= (int32_t)r.ru_nivcsw;
124 		if (copyout(&r32, user_rusage, sizeof (r32)) != 0)
125 			return (set_errno(EFAULT));
126 	} else
127 #endif /* _SYSCALL32_IMPL */
128 
129 		if (copyout(&r, user_rusage, sizeof (r)) != 0)
130 			return (set_errno(EFAULT));
131 
132 	return (0);
133 }
134 
135 static int
136 getrusage_chld(void *user_rusage)
137 {
138 	struct rusage r;
139 	kthread_t *t = curthread;
140 	proc_t *p = ttoproc(t);
141 
142 	hrtime_t snsecs, unsecs;
143 
144 	r.ru_maxrss =	0;	/* always 0 */
145 	r.ru_ixrss =	0;	/* always 0 */
146 	r.ru_idrss =	0;	/* always 0 */
147 	r.ru_isrss =	0;	/* always 0 */
148 
149 	mutex_enter(&p->p_lock);
150 
151 	unsecs = p->p_cacct[LMS_USER];
152 	snsecs = p->p_cacct[LMS_SYSTEM] + p->p_cacct[LMS_TRAP];
153 	r.ru_utime.tv_sec = 0;
154 	r.ru_utime.tv_usec = 0;
155 	r.ru_stime.tv_sec = 0;
156 	r.ru_stime.tv_usec = 0;
157 
158 	r.ru_majflt	= p->p_cru.majflt;
159 	r.ru_minflt	= p->p_cru.minflt;
160 	r.ru_nswap	= p->p_cru.nswap;
161 	r.ru_inblock	= p->p_cru.inblock;
162 	r.ru_oublock	= p->p_cru.oublock;
163 	r.ru_msgsnd	= p->p_cru.msgsnd;
164 	r.ru_msgrcv	= p->p_cru.msgrcv;
165 	r.ru_nsignals	= p->p_cru.nsignals;
166 	r.ru_nvcsw	= p->p_cru.nvcsw;
167 	r.ru_nivcsw	= p->p_cru.nivcsw;
168 
169 	mutex_exit(&p->p_lock);
170 
171 	hrt2tv(unsecs, &r.ru_utime);
172 	hrt2tv(snsecs, &r.ru_stime);
173 #ifdef _SYSCALL32_IMPL
174 	if (get_udatamodel() == DATAMODEL_ILP32) {
175 		struct rusage32 r32;
176 
177 		r32.ru_maxrss =	0;	/* always 0 */
178 		r32.ru_ixrss =	0;	/* always 0 */
179 		r32.ru_idrss =	0;	/* always 0 */
180 		r32.ru_isrss =	0;	/* always 0 */
181 
182 		r32.ru_utime.tv_sec  = r.ru_utime.tv_sec;
183 		r32.ru_utime.tv_usec = r.ru_utime.tv_usec;
184 		r32.ru_stime.tv_sec  = r.ru_stime.tv_sec;
185 		r32.ru_stime.tv_usec = r.ru_stime.tv_usec;
186 
187 		r32.ru_majflt	= (int32_t)r.ru_majflt;
188 		r32.ru_minflt	= (int32_t)r.ru_minflt;
189 		r32.ru_nswap	= (int32_t)r.ru_nswap;
190 		r32.ru_inblock	= (int32_t)r.ru_inblock;
191 		r32.ru_oublock	= (int32_t)r.ru_oublock;
192 		r32.ru_msgsnd	= (int32_t)r.ru_msgsnd;
193 		r32.ru_msgrcv	= (int32_t)r.ru_msgrcv;
194 		r32.ru_nsignals	= (int32_t)r.ru_nsignals;
195 		r32.ru_nvcsw	= (int32_t)r.ru_nvcsw;
196 		r32.ru_nivcsw	= (int32_t)r.ru_nivcsw;
197 		if (copyout(&r32, user_rusage, sizeof (r32)) != 0)
198 			return (set_errno(EFAULT));
199 	} else
200 #endif /* _SYSCALL32_IMPL */
201 
202 		if (copyout(&r, user_rusage, sizeof (r)) != 0)
203 			return (set_errno(EFAULT));
204 
205 	return (0);
206 }
207 
208 static int
209 getrusage_lwp(void *user_rusage)
210 {
211 	struct rusage r;
212 	kthread_t *t = curthread;
213 	klwp_t *lwp;
214 	hrtime_t snsecs, unsecs;
215 	struct mstate *ms;
216 
217 	r.ru_maxrss =	0;	/* always 0 */
218 	r.ru_ixrss =	0;	/* always 0 */
219 	r.ru_idrss =	0;	/* always 0 */
220 	r.ru_isrss =	0;	/* always 0 */
221 	r.ru_utime.tv_sec = 0;
222 	r.ru_utime.tv_usec = 0;
223 	r.ru_stime.tv_sec = 0;
224 	r.ru_stime.tv_usec = 0;
225 
226 	lwp = ttolwp(t);
227 	ms = &lwp->lwp_mstate;
228 	unsecs = ms->ms_acct[LMS_USER];
229 	snsecs = ms->ms_acct[LMS_SYSTEM] + ms->ms_acct[LMS_TRAP];
230 	scalehrtime(&unsecs);
231 	scalehrtime(&snsecs);
232 	r.ru_majflt	= lwp->lwp_ru.majflt;
233 	r.ru_minflt	= lwp->lwp_ru.minflt;
234 	r.ru_nswap	= lwp->lwp_ru.nswap;
235 	r.ru_inblock	= lwp->lwp_ru.inblock;
236 	r.ru_oublock	= lwp->lwp_ru.oublock;
237 	r.ru_msgsnd	= lwp->lwp_ru.msgsnd;
238 	r.ru_msgrcv	= lwp->lwp_ru.msgrcv;
239 	r.ru_nsignals	= lwp->lwp_ru.nsignals;
240 	r.ru_nvcsw	= lwp->lwp_ru.nvcsw;
241 	r.ru_nivcsw	= lwp->lwp_ru.nivcsw;
242 
243 	hrt2tv(unsecs, &r.ru_utime);
244 	hrt2tv(snsecs, &r.ru_stime);
245 #ifdef _SYSCALL32_IMPL
246 	if (get_udatamodel() == DATAMODEL_ILP32) {
247 		struct rusage32 r32;
248 
249 		r32.ru_maxrss =	0;	/* always 0 */
250 		r32.ru_ixrss =	0;	/* always 0 */
251 		r32.ru_idrss =	0;	/* always 0 */
252 		r32.ru_isrss =	0;	/* always 0 */
253 
254 		r32.ru_utime.tv_sec  = r.ru_utime.tv_sec;
255 		r32.ru_utime.tv_usec = r.ru_utime.tv_usec;
256 		r32.ru_stime.tv_sec  = r.ru_stime.tv_sec;
257 		r32.ru_stime.tv_usec = r.ru_stime.tv_usec;
258 
259 		r32.ru_majflt	= (int32_t)r.ru_majflt;
260 		r32.ru_minflt	= (int32_t)r.ru_minflt;
261 		r32.ru_nswap	= (int32_t)r.ru_nswap;
262 		r32.ru_inblock	= (int32_t)r.ru_inblock;
263 		r32.ru_oublock	= (int32_t)r.ru_oublock;
264 		r32.ru_msgsnd	= (int32_t)r.ru_msgsnd;
265 		r32.ru_msgrcv	= (int32_t)r.ru_msgrcv;
266 		r32.ru_nsignals	= (int32_t)r.ru_nsignals;
267 		r32.ru_nvcsw	= (int32_t)r.ru_nvcsw;
268 		r32.ru_nivcsw	= (int32_t)r.ru_nivcsw;
269 		if (copyout(&r32, user_rusage, sizeof (r32)) != 0)
270 			return (set_errno(EFAULT));
271 	} else
272 #endif /* _SYSCALL32_IMPL */
273 
274 		if (copyout(&r, user_rusage, sizeof (r)) != 0)
275 			return (set_errno(EFAULT));
276 
277 	return (0);
278 }
279 
280 int
281 rusagesys(int code, void * arg)
282 {
283 	switch (code) {
284 
285 	case _RUSAGESYS_GETRUSAGE:
286 		return (getrusage(arg));
287 	case _RUSAGESYS_GETRUSAGE_CHLD:
288 		return (getrusage_chld(arg));
289 	case _RUSAGESYS_GETRUSAGE_LWP:
290 		return (getrusage_lwp(arg));
291 	default:
292 		return (set_errno(EINVAL));
293 	}
294 }
295