xref: /illumos-gate/usr/src/uts/common/syscall/rusagesys.c (revision 45d2468cd430f160914c353c714144054804373a)
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 
37 static int
38 getrusage(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 
122 static int
123 getrusage_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 
184 static int
185 getrusage_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 
246 int
247 rusagesys(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