2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 /* Copyright (c) 1995, 1997 Apple Computer, Inc. All Rights Reserved */
27 * Copyright (c) 1982, 1986, 1991, 1993
28 * The Regents of the University of California. All rights reserved.
29 * (c) UNIX System Laboratories, Inc.
30 * All or some portions of this file are derived from material licensed
31 * to the University of California by American Telephone and Telegraph
32 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
33 * the permission of UNIX System Laboratories, Inc.
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
38 * 1. Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 * notice, this list of conditions and the following disclaimer in the
42 * documentation and/or other materials provided with the distribution.
43 * 3. All advertising materials mentioning features or use of this software
44 * must display the following acknowledgement:
45 * This product includes software developed by the University of
46 * California, Berkeley and its contributors.
47 * 4. Neither the name of the University nor the names of its contributors
48 * may be used to endorse or promote products derived from this software
49 * without specific prior written permission.
51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * @(#)kern_resource.c 8.5 (Berkeley) 1/21/94
66 #include <sys/param.h>
67 #include <sys/systm.h>
68 #include <sys/sysctl.h>
69 #include <sys/kernel.h>
71 #include <sys/resourcevar.h>
72 #include <sys/malloc.h>
74 #include <machine/spl.h>
76 #include <sys/mount.h>
78 #include <machine/vmparam.h>
80 #include <mach/mach_types.h>
81 #include <mach/time_value.h>
82 #include <mach/task_info.h>
84 #include <vm/vm_map.h>
86 int donice
__P((struct proc
*curp
, struct proc
*chgp
, int n
));
87 int dosetrlimit
__P((struct proc
*p
, u_int which
, struct rlimit
*limp
));
89 rlim_t maxdmap
= MAXDSIZ
; /* XXX */
90 rlim_t maxsmap
= MAXSSIZ
; /* XXX */
93 * Limits on the number of open files per process, and the number
94 * of child processes per process.
96 * Note: would be in kern/subr_param.c in FreeBSD.
98 int maxprocperuid
= CHILD_MAX
; /* max # of procs per user */
99 int maxfilesperproc
= OPEN_MAX
; /* per-proc open files limit */
101 SYSCTL_INT( _kern
, KERN_MAXPROCPERUID
, maxprocperuid
, CTLFLAG_RW
,
102 &maxprocperuid
, 0, "Maximum processes allowed per userid" );
104 SYSCTL_INT( _kern
, KERN_MAXFILESPERPROC
, maxfilesperproc
, CTLFLAG_RW
,
105 &maxfilesperproc
, 0, "Maximum files allowed open per process" );
109 * Resource controls and accounting.
111 struct getpriority_args
{
116 getpriority(curp
, uap
, retval
)
118 register struct getpriority_args
*uap
;
121 register struct proc
*p
;
122 register int low
= PRIO_MAX
+ 1;
124 switch (uap
->which
) {
137 register struct pgrp
*pg
;
141 else if ((pg
= pgfind(uap
->who
)) == NULL
)
143 for (p
= pg
->pg_members
.lh_first
; p
!= 0; p
= p
->p_pglist
.le_next
) {
152 uap
->who
= curp
->p_ucred
->cr_uid
;
153 for (p
= allproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
)
154 if (p
->p_ucred
->cr_uid
== uap
->who
&&
162 if (low
== PRIO_MAX
+ 1)
168 struct setpriority_args
{
175 setpriority(curp
, uap
, retval
)
177 register struct setpriority_args
*uap
;
180 register struct proc
*p
;
181 int found
= 0, error
= 0;
183 switch (uap
->which
) {
192 error
= donice(curp
, p
, uap
->prio
);
197 register struct pgrp
*pg
;
201 else if ((pg
= pgfind(uap
->who
)) == NULL
)
203 for (p
= pg
->pg_members
.lh_first
; p
!= 0;
204 p
= p
->p_pglist
.le_next
) {
205 error
= donice(curp
, p
, uap
->prio
);
213 uap
->who
= curp
->p_ucred
->cr_uid
;
214 for (p
= allproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
)
215 if (p
->p_ucred
->cr_uid
== uap
->who
) {
216 error
= donice(curp
, p
, uap
->prio
);
230 donice(curp
, chgp
, n
)
231 register struct proc
*curp
, *chgp
;
234 register struct pcred
*pcred
= curp
->p_cred
;
236 if (pcred
->pc_ucred
->cr_uid
&& pcred
->p_ruid
&&
237 pcred
->pc_ucred
->cr_uid
!= chgp
->p_ucred
->cr_uid
&&
238 pcred
->p_ruid
!= chgp
->p_ucred
->cr_uid
)
244 if (n
< chgp
->p_nice
&& suser(pcred
->pc_ucred
, &curp
->p_acflag
))
247 (void)resetpriority(chgp
);
252 struct osetrlimit_args
{
254 struct ogetrlimit
* rlp
;
258 osetrlimit(p
, uap
, retval
)
260 struct osetrlimit_args
*uap
;
267 if (error
= copyin((caddr_t
)uap
->rlp
, (caddr_t
)&olim
,
268 sizeof (struct orlimit
)))
270 lim
.rlim_cur
= olim
.rlim_cur
;
271 lim
.rlim_max
= olim
.rlim_max
;
272 return (dosetrlimit(p
, uap
->which
, &lim
));
275 struct ogetrlimit_args
{
277 struct ogetrlimit
* rlp
;
281 ogetrlimit(p
, uap
, retval
)
283 struct ogetrlimit_args
*uap
;
288 if (uap
->which
>= RLIM_NLIMITS
)
290 olim
.rlim_cur
= p
->p_rlimit
[uap
->which
].rlim_cur
;
291 if (olim
.rlim_cur
== -1)
292 olim
.rlim_cur
= 0x7fffffff;
293 olim
.rlim_max
= p
->p_rlimit
[uap
->which
].rlim_max
;
294 if (olim
.rlim_max
== -1)
295 olim
.rlim_max
= 0x7fffffff;
296 return (copyout((caddr_t
)&olim
, (caddr_t
)uap
->rlp
,
299 #endif /* COMPAT_43 */
301 struct setrlimit_args
{
307 setrlimit(p
, uap
, retval
)
309 register struct setrlimit_args
*uap
;
315 if (error
= copyin((caddr_t
)uap
->rlp
, (caddr_t
)&alim
,
316 sizeof (struct rlimit
)))
318 return (dosetrlimit(p
, uap
->which
, &alim
));
322 dosetrlimit(p
, which
, limp
)
327 register struct rlimit
*alimp
;
328 extern rlim_t maxdmap
, maxsmap
;
331 if (which
>= RLIM_NLIMITS
)
333 alimp
= &p
->p_rlimit
[which
];
334 if (limp
->rlim_cur
> alimp
->rlim_max
||
335 limp
->rlim_max
> alimp
->rlim_max
)
336 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
338 if (limp
->rlim_cur
> limp
->rlim_max
)
339 limp
->rlim_cur
= limp
->rlim_max
;
340 if (p
->p_limit
->p_refcnt
> 1 &&
341 (p
->p_limit
->p_lflags
& PL_SHAREMOD
) == 0) {
342 p
->p_limit
->p_refcnt
--;
343 p
->p_limit
= limcopy(p
->p_limit
);
344 alimp
= &p
->p_rlimit
[which
];
350 if (limp
->rlim_cur
> maxdmap
)
351 limp
->rlim_cur
= maxdmap
;
352 if (limp
->rlim_max
> maxdmap
)
353 limp
->rlim_max
= maxdmap
;
357 if (limp
->rlim_cur
> maxsmap
)
358 limp
->rlim_cur
= maxsmap
;
359 if (limp
->rlim_max
> maxsmap
)
360 limp
->rlim_max
= maxsmap
;
362 * Stack is allocated to the max at exec time with only
363 * "rlim_cur" bytes accessible. If stack limit is going
364 * up make more accessible, if going down make inaccessible.
366 if (limp
->rlim_cur
!= alimp
->rlim_cur
) {
371 if (limp
->rlim_cur
> alimp
->rlim_cur
) {
373 size
= round_page_64(limp
->rlim_cur
);
374 size
-= round_page_64(alimp
->rlim_cur
);
377 /* go to top of current stack */
378 addr
= trunc_page((unsigned int)(p
->user_stack
+ alimp
->rlim_cur
));
379 #else STACK_GROWTH_UP
380 addr
= trunc_page_32((unsigned int)(p
->user_stack
- alimp
->rlim_cur
));
382 #endif /* STACK_GROWTH_UP */
383 if (vm_allocate(current_map(),
384 &addr
, size
, FALSE
) != KERN_SUCCESS
)
394 * Only root can set the maxfiles limits, as it is systemwide resource
397 if (limp
->rlim_cur
> maxfiles
)
398 limp
->rlim_cur
= maxfiles
;
399 if (limp
->rlim_max
> maxfiles
)
400 limp
->rlim_max
= maxfiles
;
403 if (limp
->rlim_cur
> maxfilesperproc
)
404 limp
->rlim_cur
= maxfilesperproc
;
405 if (limp
->rlim_max
> maxfilesperproc
)
406 limp
->rlim_max
= maxfilesperproc
;
412 * Only root can set to the maxproc limits, as it is
413 * systemwide resource; all others are limited to
414 * maxprocperuid (presumably less than maxproc).
417 if (limp
->rlim_cur
> maxproc
)
418 limp
->rlim_cur
= maxproc
;
419 if (limp
->rlim_max
> maxproc
)
420 limp
->rlim_max
= maxproc
;
423 if (limp
->rlim_cur
> maxprocperuid
)
424 limp
->rlim_cur
= maxprocperuid
;
425 if (limp
->rlim_max
> maxprocperuid
)
426 limp
->rlim_max
= maxprocperuid
;
435 struct getrlimit_args
{
441 getrlimit(p
, uap
, retval
)
443 register struct getrlimit_args
*uap
;
447 if (uap
->which
>= RLIM_NLIMITS
)
449 return (copyout((caddr_t
)&p
->p_rlimit
[uap
->which
],
450 (caddr_t
)uap
->rlp
, sizeof (struct rlimit
)));
454 * Transform the running time and tick information in proc p into user,
455 * system, and interrupt time usage.
458 calcru(p
, up
, sp
, ip
)
459 register struct proc
*p
;
460 register struct timeval
*up
;
461 register struct timeval
*sp
;
462 register struct timeval
*ip
;
473 task_basic_info_data_t tinfo
;
474 task_thread_times_info_data_t ttimesinfo
;
475 int task_info_stuff
, task_ttimes_stuff
;
476 struct timeval ut
,st
;
478 task_info_stuff
= TASK_BASIC_INFO_COUNT
;
479 task_info(task
, TASK_BASIC_INFO
,
480 &tinfo
, &task_info_stuff
);
481 ut
.tv_sec
= tinfo
.user_time
.seconds
;
482 ut
.tv_usec
= tinfo
.user_time
.microseconds
;
483 st
.tv_sec
= tinfo
.system_time
.seconds
;
484 st
.tv_usec
= tinfo
.system_time
.microseconds
;
485 timeradd(&ut
, up
, up
);
486 timeradd(&st
, sp
, sp
);
488 task_ttimes_stuff
= TASK_THREAD_TIMES_INFO_COUNT
;
489 task_info(task
, TASK_THREAD_TIMES_INFO
,
490 &ttimesinfo
, &task_ttimes_stuff
);
492 ut
.tv_sec
= ttimesinfo
.user_time
.seconds
;
493 ut
.tv_usec
= ttimesinfo
.user_time
.microseconds
;
494 st
.tv_sec
= ttimesinfo
.system_time
.seconds
;
495 st
.tv_usec
= ttimesinfo
.system_time
.microseconds
;
496 timeradd(&ut
, up
, up
);
497 timeradd(&st
, sp
, sp
);
501 struct getrusage_args
{
503 struct rusage
* rusage
;
507 getrusage(p
, uap
, retval
)
508 register struct proc
*p
;
509 register struct getrusage_args
*uap
;
512 struct rusage
*rup
, rubuf
;
517 rup
= &p
->p_stats
->p_ru
;
518 calcru(p
, &rup
->ru_utime
, &rup
->ru_stime
, NULL
);
522 case RUSAGE_CHILDREN
:
523 rup
= &p
->p_stats
->p_cru
;
530 return (copyout((caddr_t
)&rubuf
, (caddr_t
)uap
->rusage
,
531 sizeof (struct rusage
)));
536 register struct rusage
*ru
, *ru2
;
538 register long *ip
, *ip2
;
541 timeradd(&ru
->ru_utime
, &ru2
->ru_utime
, &ru
->ru_utime
);
542 timeradd(&ru
->ru_stime
, &ru2
->ru_stime
, &ru
->ru_stime
);
543 if (ru
->ru_maxrss
< ru2
->ru_maxrss
)
544 ru
->ru_maxrss
= ru2
->ru_maxrss
;
545 ip
= &ru
->ru_first
; ip2
= &ru2
->ru_first
;
546 for (i
= &ru
->ru_last
- &ru
->ru_first
; i
>= 0; i
--)
551 * Make a copy of the plimit structure.
552 * We share these structures copy-on-write after fork,
553 * and copy when a limit is changed.
559 register struct plimit
*copy
;
561 MALLOC_ZONE(copy
, struct plimit
*,
562 sizeof(struct plimit
), M_SUBPROC
, M_WAITOK
);
563 bcopy(lim
->pl_rlimit
, copy
->pl_rlimit
,
564 sizeof(struct rlimit
) * RLIM_NLIMITS
);