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
37static int
38getrusage(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
122static int
123getrusage_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
184static int
185getrusage_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
246int
247rusagesys(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}
264