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