2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
30 * Copyright (c) 1982, 1986, 1989, 1991, 1993
31 * The Regents of the University of California. All rights reserved.
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. All advertising materials mentioning features or use of this software
42 * must display the following acknowledgement:
43 * This product includes software developed by the University of
44 * California, Berkeley and its contributors.
45 * 4. Neither the name of the University nor the names of its contributors
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * @(#)kern_proc.c 8.4 (Berkeley) 1/4/94
64 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
65 * support for mandatory and extensible security protections. This notice
66 * is included in support of clause 2.2 (b) of the Apple Public License,
70 * 04-Aug-97 Umesh Vaishampayan (umeshv@apple.com)
71 * Added current_proc_EXTERNAL() function for the use of kernel
74 * 05-Jun-95 Mac Gillon (mgillon) at NeXT
75 * New version based on 3.3NS and 4.4
79 #include <sys/param.h>
80 #include <sys/systm.h>
81 #include <sys/kernel.h>
82 #include <sys/proc_internal.h>
85 #include <sys/file_internal.h>
87 #include <sys/malloc.h>
90 #include <sys/ioctl.h>
92 #include <sys/signalvar.h>
93 #include <sys/syslog.h>
94 #include <sys/sysctl.h>
95 #include <sys/sysproto.h>
96 #include <sys/kauth.h>
97 #include <sys/codesign.h>
98 #include <sys/kernel_types.h>
100 #include <kern/kalloc.h>
101 #include <kern/task.h>
102 #include <kern/assert.h>
103 #include <vm/vm_protos.h>
104 #include <vm/vm_map.h> /* vm_map_switch_protect() */
105 #include <mach/task.h>
106 #include <mach/message.h>
108 #if CONFIG_MEMORYSTATUS
109 #include <sys/kern_memorystatus.h>
113 #include <security/mac_framework.h>
116 #include <libkern/crypto/sha1.h>
119 * Structure associated with user cacheing.
122 LIST_ENTRY(uidinfo
) ui_hash
;
126 #define UIHASH(uid) (&uihashtbl[(uid) & uihash])
127 LIST_HEAD(uihashhead
, uidinfo
) *uihashtbl
;
128 u_long uihash
; /* size of hash table - 1 */
131 * Other process lists
133 struct pidhashhead
*pidhashtbl
;
135 struct pgrphashhead
*pgrphashtbl
;
137 struct sesshashhead
*sesshashtbl
;
140 struct proclist allproc
;
141 struct proclist zombproc
;
142 extern struct tty cons
;
148 static pid_t lastlcid
= 1;
149 static int alllctx_cnt
;
151 #define LCID_MAX 8192 /* Does this really need to be large? */
152 static int maxlcid
= LCID_MAX
;
154 LIST_HEAD(lctxlist
, lctx
);
155 static struct lctxlist alllctx
;
157 lck_mtx_t alllctx_lock
;
158 lck_grp_t
* lctx_lck_grp
;
159 lck_grp_attr_t
* lctx_lck_grp_attr
;
160 lck_attr_t
* lctx_lck_attr
;
162 static void lctxinit(void);
168 #define __PROC_INTERNAL_DEBUG 1
170 /* Name to give to core files */
171 __XNU_PRIVATE_EXTERN
char corefilename
[MAXPATHLEN
+1] = {"/cores/core.%P"};
173 static void orphanpg(struct pgrp
*pg
);
174 void proc_name_kdp(task_t t
, char * buf
, int size
);
175 char *proc_name_address(void *p
);
177 static void pgrp_add(struct pgrp
* pgrp
, proc_t parent
, proc_t child
);
178 static void pgrp_remove(proc_t p
);
179 static void pgrp_replace(proc_t p
, struct pgrp
*pgrp
);
180 static void pgdelete_dropref(struct pgrp
*pgrp
);
181 extern void pg_rele_dropref(struct pgrp
* pgrp
);
182 static int csops_internal(pid_t pid
, int ops
, user_addr_t uaddr
, user_size_t usersize
, user_addr_t uaddittoken
);
183 static boolean_t
proc_parent_is_currentproc(proc_t p
);
185 struct fixjob_iterargs
{
187 struct session
* mysession
;
191 int fixjob_callback(proc_t
, void *);
194 * Initialize global process hashing structures.
200 LIST_INIT(&zombproc
);
201 pidhashtbl
= hashinit(maxproc
/ 4, M_PROC
, &pidhash
);
202 pgrphashtbl
= hashinit(maxproc
/ 4, M_PROC
, &pgrphash
);
203 sesshashtbl
= hashinit(maxproc
/ 4, M_PROC
, &sesshash
);
204 uihashtbl
= hashinit(maxproc
/ 16, M_PROC
, &uihash
);
211 * Change the count associated with number of processes
212 * a given user is using. This routine protects the uihash
216 chgproccnt(uid_t uid
, int diff
)
219 struct uidinfo
*newuip
= NULL
;
220 struct uihashhead
*uipp
;
226 for (uip
= uipp
->lh_first
; uip
!= 0; uip
= uip
->ui_hash
.le_next
)
227 if (uip
->ui_uid
== uid
)
230 uip
->ui_proccnt
+= diff
;
231 if (uip
->ui_proccnt
> 0) {
232 retval
= uip
->ui_proccnt
;
236 if (uip
->ui_proccnt
< 0)
237 panic("chgproccnt: procs < 0");
238 LIST_REMOVE(uip
, ui_hash
);
241 FREE_ZONE(uip
, sizeof(*uip
), M_PROC
);
250 panic("chgproccnt: lost user");
252 if (newuip
!= NULL
) {
255 LIST_INSERT_HEAD(uipp
, uip
, ui_hash
);
257 uip
->ui_proccnt
= diff
;
263 MALLOC_ZONE(newuip
, struct uidinfo
*, sizeof(*uip
), M_PROC
, M_WAITOK
);
265 panic("chgproccnt: M_PROC zone depleted");
269 FREE_ZONE(newuip
, sizeof(*uip
), M_PROC
);
274 * Is p an inferior of the current process?
282 for (; p
!= current_proc(); p
= p
->p_pptr
)
292 * Is p an inferior of t ?
295 isinferior(proc_t p
, proc_t t
)
301 /* if p==t they are not inferior */
306 for (; p
!= t
; p
= p
->p_pptr
) {
309 /* Detect here if we're in a cycle */
310 if ((p
->p_pid
== 0) || (p
->p_pptr
== start
) || (nchecked
>= nprocs
))
320 proc_isinferior(int pid1
, int pid2
)
322 proc_t p
= PROC_NULL
;
323 proc_t t
= PROC_NULL
;
326 if (((p
= proc_find(pid1
)) != (proc_t
)0 ) && ((t
= proc_find(pid2
)) != (proc_t
)0))
327 retval
= isinferior(p
, t
);
340 return(proc_findinternal(pid
, 0));
344 proc_findinternal(int pid
, int locked
)
346 proc_t p
= PROC_NULL
;
352 p
= pfind_locked(pid
);
353 if ((p
== PROC_NULL
) || (p
!= proc_ref_locked(p
)))
364 proc_findthread(thread_t thread
)
366 proc_t p
= PROC_NULL
;
370 uth
= get_bsdthread_info(thread
);
371 if (uth
&& (uth
->uu_flag
& UT_VFORK
))
374 p
= (proc_t
)(get_bsdthreadtask_info(thread
));
375 p
= proc_ref_locked(p
);
398 if (p
!= proc_ref_locked(p
))
406 proc_ref_locked(proc_t p
)
410 /* if process still in creation return failure */
411 if ((p
== PROC_NULL
) || ((p
->p_listflag
& P_LIST_INCREATE
) != 0))
413 /* do not return process marked for termination */
414 if ((p
->p_stat
!= SZOMB
) && ((p
->p_listflag
& P_LIST_EXITED
) == 0) && ((p
->p_listflag
& (P_LIST_DRAINWAIT
| P_LIST_DRAIN
| P_LIST_DEAD
)) == 0))
423 proc_rele_locked(proc_t p
)
426 if (p
->p_refcount
> 0) {
428 if ((p
->p_refcount
== 0) && ((p
->p_listflag
& P_LIST_DRAINWAIT
) == P_LIST_DRAINWAIT
)) {
429 p
->p_listflag
&= ~P_LIST_DRAINWAIT
;
430 wakeup(&p
->p_refcount
);
433 panic("proc_rele_locked -ve ref\n");
438 proc_find_zombref(int pid
)
445 p
= pfind_locked(pid
);
447 /* should we bail? */
448 if ((p
== PROC_NULL
) /* not found */
449 || ((p
->p_listflag
& P_LIST_INCREATE
) != 0) /* not created yet */
450 || ((p
->p_listflag
& P_LIST_EXITED
) == 0)) { /* not started exit */
456 /* If someone else is controlling the (unreaped) zombie - wait */
457 if ((p
->p_listflag
& P_LIST_WAITING
) != 0) {
458 (void)msleep(&p
->p_stat
, proc_list_mlock
, PWAIT
, "waitcoll", 0);
461 p
->p_listflag
|= P_LIST_WAITING
;
469 proc_drop_zombref(proc_t p
)
472 if ((p
->p_listflag
& P_LIST_WAITING
) == P_LIST_WAITING
) {
473 p
->p_listflag
&= ~P_LIST_WAITING
;
481 proc_refdrain(proc_t p
)
486 p
->p_listflag
|= P_LIST_DRAIN
;
487 while (p
->p_refcount
) {
488 p
->p_listflag
|= P_LIST_DRAINWAIT
;
489 msleep(&p
->p_refcount
, proc_list_mlock
, 0, "proc_refdrain", 0) ;
491 p
->p_listflag
&= ~P_LIST_DRAIN
;
492 p
->p_listflag
|= P_LIST_DEAD
;
500 proc_parentholdref(proc_t p
)
502 proc_t parent
= PROC_NULL
;
510 if ((pp
== PROC_NULL
) || (pp
->p_stat
== SZOMB
) || ((pp
->p_listflag
& (P_LIST_CHILDDRSTART
| P_LIST_CHILDDRAINED
)) == (P_LIST_CHILDDRSTART
| P_LIST_CHILDDRAINED
))) {
515 if ((pp
->p_listflag
& (P_LIST_CHILDDRSTART
| P_LIST_CHILDDRAINED
)) == P_LIST_CHILDDRSTART
) {
516 pp
->p_listflag
|= P_LIST_CHILDDRWAIT
;
517 msleep(&pp
->p_childrencnt
, proc_list_mlock
, 0, "proc_parent", 0);
526 if ((pp
->p_listflag
& (P_LIST_CHILDDRSTART
| P_LIST_CHILDDRAINED
)) == 0) {
537 proc_parentdropref(proc_t p
, int listlocked
)
542 if (p
->p_parentref
> 0) {
544 if ((p
->p_parentref
== 0) && ((p
->p_listflag
& P_LIST_PARENTREFWAIT
) == P_LIST_PARENTREFWAIT
)) {
545 p
->p_listflag
&= ~P_LIST_PARENTREFWAIT
;
546 wakeup(&p
->p_parentref
);
549 panic("proc_parentdropref -ve ref\n");
557 proc_childdrainstart(proc_t p
)
559 #if __PROC_INTERNAL_DEBUG
560 if ((p
->p_listflag
& P_LIST_CHILDDRSTART
) == P_LIST_CHILDDRSTART
)
561 panic("proc_childdrainstart: childdrain already started\n");
563 p
->p_listflag
|= P_LIST_CHILDDRSTART
;
564 /* wait for all that hold parentrefs to drop */
565 while (p
->p_parentref
> 0) {
566 p
->p_listflag
|= P_LIST_PARENTREFWAIT
;
567 msleep(&p
->p_parentref
, proc_list_mlock
, 0, "proc_childdrainstart", 0) ;
573 proc_childdrainend(proc_t p
)
575 #if __PROC_INTERNAL_DEBUG
576 if (p
->p_childrencnt
> 0)
577 panic("exiting: children stil hanging around\n");
579 p
->p_listflag
|= P_LIST_CHILDDRAINED
;
580 if ((p
->p_listflag
& (P_LIST_CHILDLKWAIT
|P_LIST_CHILDDRWAIT
)) != 0) {
581 p
->p_listflag
&= ~(P_LIST_CHILDLKWAIT
|P_LIST_CHILDDRWAIT
);
582 wakeup(&p
->p_childrencnt
);
587 proc_checkdeadrefs(__unused proc_t p
)
589 #if __PROC_INTERNAL_DEBUG
590 if ((p
->p_listflag
& P_LIST_INHASH
) != 0)
591 panic("proc being freed and still in hash %p: %u\n", p
, p
->p_listflag
);
592 if (p
->p_childrencnt
!= 0)
593 panic("proc being freed and pending children cnt %p:%d\n", p
, p
->p_childrencnt
);
594 if (p
->p_refcount
!= 0)
595 panic("proc being freed and pending refcount %p:%d\n", p
, p
->p_refcount
);
596 if (p
->p_parentref
!= 0)
597 panic("proc being freed and pending parentrefs %p:%d\n", p
, p
->p_parentref
);
616 return (current_proc()->p_pid
);
622 return (current_proc()->p_ppid
);
627 dtrace_current_proc_vforking(void)
629 thread_t th
= current_thread();
630 struct uthread
*ut
= get_bsdthread_info(th
);
633 ((ut
->uu_flag
& (UT_VFORK
|UT_VFORKING
)) == (UT_VFORK
|UT_VFORKING
))) {
635 * Handle the narrow window where we're in the vfork syscall,
636 * but we're not quite ready to claim (in particular, to DTrace)
637 * that we're running as the child.
639 return (get_bsdtask_info(get_threadtask(th
)));
641 return (current_proc());
645 dtrace_proc_selfpid(void)
647 return (dtrace_current_proc_vforking()->p_pid
);
651 dtrace_proc_selfppid(void)
653 return (dtrace_current_proc_vforking()->p_ppid
);
657 dtrace_proc_selfruid(void)
659 return (dtrace_current_proc_vforking()->p_ruid
);
661 #endif /* CONFIG_DTRACE */
664 proc_parent(proc_t p
)
672 parent
= proc_ref_locked(pp
);
673 if ((parent
== PROC_NULL
) && (pp
!= PROC_NULL
) && (pp
->p_stat
!= SZOMB
) && ((pp
->p_listflag
& P_LIST_EXITED
) != 0) && ((pp
->p_listflag
& P_LIST_CHILDDRAINED
)== 0)){
674 pp
->p_listflag
|= P_LIST_CHILDLKWAIT
;
675 msleep(&pp
->p_childrencnt
, proc_list_mlock
, 0, "proc_parent", 0);
683 proc_parent_is_currentproc(proc_t p
)
685 boolean_t ret
= FALSE
;
688 if (p
->p_pptr
== current_proc())
696 proc_name(int pid
, char * buf
, int size
)
700 if ((p
= proc_find(pid
)) != PROC_NULL
) {
701 strlcpy(buf
, &p
->p_comm
[0], size
);
707 proc_name_kdp(task_t t
, char * buf
, int size
)
709 proc_t p
= get_bsdtask_info(t
);
712 strlcpy(buf
, &p
->p_comm
[0], size
);
716 proc_name_address(void *p
)
718 return &((proc_t
)p
)->p_comm
[0];
722 proc_selfname(char * buf
, int size
)
726 if ((p
= current_proc())!= (proc_t
)0) {
727 strlcpy(buf
, &p
->p_comm
[0], size
);
732 proc_signal(int pid
, int signum
)
736 if ((p
= proc_find(pid
)) != PROC_NULL
) {
743 proc_issignal(int pid
, sigset_t mask
)
748 if ((p
= proc_find(pid
)) != PROC_NULL
) {
749 error
= proc_pendingsignals(p
, mask
);
757 proc_noremotehang(proc_t p
)
762 retval
= p
->p_flag
& P_NOREMOTEHANG
;
763 return(retval
? 1: 0);
768 proc_exiting(proc_t p
)
773 retval
= p
->p_lflag
& P_LEXIT
;
774 return(retval
? 1: 0);
778 proc_forcequota(proc_t p
)
783 retval
= p
->p_flag
& P_FORCEQUOTA
;
784 return(retval
? 1: 0);
794 retval
= p
->p_flag
& P_TBE
;
795 return(retval
? 1: 0);
802 kauth_cred_t my_cred
;
805 my_cred
= kauth_cred_proc_ref(p
);
806 error
= suser(my_cred
, &p
->p_acflag
);
807 kauth_cred_unref(&my_cred
);
812 proc_task(proc_t proc
)
814 return (task_t
)proc
->task
;
818 * Obtain the first thread in a process
820 * XXX This is a bad thing to do; it exists predominantly to support the
821 * XXX use of proc_t's in places that should really be using
822 * XXX thread_t's instead. This maintains historical behaviour, but really
823 * XXX needs an audit of the context (proxy vs. not) to clean up.
826 proc_thread(proc_t proc
)
828 uthread_t uth
= TAILQ_FIRST(&proc
->p_uthlist
);
831 return(uth
->uu_context
.vc_thread
);
845 thread_t th
= current_thread();
847 return((struct uthread
*)get_bsdthread_info(th
));
852 proc_is64bit(proc_t p
)
854 return(IS_64BIT_PROCESS(p
));
858 proc_pidversion(proc_t p
)
860 return(p
->p_idversion
);
864 proc_uniqueid(proc_t p
)
866 return(p
->p_uniqueid
);
870 proc_puniqueid(proc_t p
)
872 return(p
->p_puniqueid
);
876 proc_was_throttled(proc_t p
)
878 return (p
->was_throttled
);
882 proc_did_throttle(proc_t p
)
884 return (p
->did_throttle
);
888 proc_getcdhash(proc_t p
, unsigned char *cdhash
)
890 return vn_getcdhash(p
->p_textvp
, p
->p_textoff
, cdhash
);
894 proc_getexecutableuuid(proc_t p
, unsigned char *uuidbuf
, unsigned long size
)
896 if (size
>= sizeof(p
->p_uuid
)) {
897 memcpy(uuidbuf
, p
->p_uuid
, sizeof(p
->p_uuid
));
903 bsd_set_dependency_capable(task_t task
)
905 proc_t p
= get_bsdtask_info(task
);
908 OSBitOrAtomic(P_DEPENDENCY_CAPABLE
, &p
->p_flag
);
914 IS_64BIT_PROCESS(proc_t p
)
916 if (p
&& (p
->p_flag
& P_LP64
))
923 * Locate a process by number
926 pfind_locked(pid_t pid
)
936 for (p
= PIDHASH(pid
)->lh_first
; p
!= 0; p
= p
->p_hash
.le_next
) {
937 if (p
->p_pid
== pid
) {
939 for (q
= p
->p_hash
.le_next
; q
!= 0; q
= q
->p_hash
.le_next
) {
940 if ((p
!=q
) && (q
->p_pid
== pid
))
941 panic("two procs with same pid %p:%p:%d:%d\n", p
, q
, p
->p_pid
, q
->p_pid
);
951 * Locate a zombie by PID
953 __private_extern__ proc_t
961 for (p
= zombproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
)
971 * Locate a process group by number
980 pgrp
= pgfind_internal(pgid
);
981 if ((pgrp
== NULL
) || ((pgrp
->pg_listflags
& PGRP_FLAG_TERMINATE
) != 0))
992 pgfind_internal(pid_t pgid
)
996 for (pgrp
= PGRPHASH(pgid
)->lh_first
; pgrp
!= 0; pgrp
= pgrp
->pg_hash
.le_next
)
997 if (pgrp
->pg_id
== pgid
)
1003 pg_rele(struct pgrp
* pgrp
)
1005 if(pgrp
== PGRP_NULL
)
1007 pg_rele_dropref(pgrp
);
1011 pg_rele_dropref(struct pgrp
* pgrp
)
1014 if ((pgrp
->pg_refcount
== 1) && ((pgrp
->pg_listflags
& PGRP_FLAG_TERMINATE
) == PGRP_FLAG_TERMINATE
)) {
1016 pgdelete_dropref(pgrp
);
1020 pgrp
->pg_refcount
--;
1025 session_find_internal(pid_t sessid
)
1027 struct session
*sess
;
1029 for (sess
= SESSHASH(sessid
)->lh_first
; sess
!= 0; sess
= sess
->s_hash
.le_next
)
1030 if (sess
->s_sid
== sessid
)
1037 * Make a new process ready to become a useful member of society by making it
1038 * visible in all the right places and initialize its own lists to empty.
1040 * Parameters: parent The parent of the process to insert
1041 * child The child process to insert
1045 * Notes: Insert a child process into the parents process group, assign
1046 * the child the parent process pointer and PPID of the parent,
1047 * place it on the parents p_children list as a sibling,
1048 * initialize its own child list, place it in the allproc list,
1049 * insert it in the proper hash bucket, and initialize its
1053 pinsertchild(proc_t parent
, proc_t child
)
1057 LIST_INIT(&child
->p_children
);
1058 TAILQ_INIT(&child
->p_evlist
);
1059 child
->p_pptr
= parent
;
1060 child
->p_ppid
= parent
->p_pid
;
1061 child
->p_puniqueid
= parent
->p_uniqueid
;
1063 pg
= proc_pgrp(parent
);
1064 pgrp_add(pg
, parent
, child
);
1069 #if CONFIG_MEMORYSTATUS
1070 memorystatus_add(child
, TRUE
);
1073 parent
->p_childrencnt
++;
1074 LIST_INSERT_HEAD(&parent
->p_children
, child
, p_sibling
);
1076 LIST_INSERT_HEAD(&allproc
, child
, p_list
);
1077 /* mark the completion of proc creation */
1078 child
->p_listflag
&= ~P_LIST_INCREATE
;
1084 * Move p to a new or existing process group (and session)
1086 * Returns: 0 Success
1087 * ESRCH No such process
1090 enterpgrp(proc_t p
, pid_t pgid
, int mksess
)
1093 struct pgrp
*mypgrp
;
1094 struct session
* procsp
;
1096 pgrp
= pgfind(pgid
);
1097 mypgrp
= proc_pgrp(p
);
1098 procsp
= proc_session(p
);
1101 if (pgrp
!= NULL
&& mksess
) /* firewalls */
1102 panic("enterpgrp: setsid into non-empty pgrp");
1103 if (SESS_LEADER(p
, procsp
))
1104 panic("enterpgrp: session leader attempted setpgrp");
1106 if (pgrp
== PGRP_NULL
) {
1107 pid_t savepid
= p
->p_pid
;
1108 proc_t np
= PROC_NULL
;
1113 if (p
->p_pid
!= pgid
)
1114 panic("enterpgrp: new pgrp and pid != pgid");
1116 MALLOC_ZONE(pgrp
, struct pgrp
*, sizeof(struct pgrp
), M_PGRP
,
1119 panic("enterpgrp: M_PGRP zone depleted");
1120 if ((np
= proc_find(savepid
)) == NULL
|| np
!= p
) {
1121 if (np
!= PROC_NULL
)
1123 if (mypgrp
!= PGRP_NULL
)
1125 if (procsp
!= SESSION_NULL
)
1126 session_rele(procsp
);
1127 FREE_ZONE(pgrp
, sizeof(struct pgrp
), M_PGRP
);
1132 struct session
*sess
;
1137 MALLOC_ZONE(sess
, struct session
*,
1138 sizeof(struct session
), M_SESSION
, M_WAITOK
);
1140 panic("enterpgrp: M_SESSION zone depleted");
1142 sess
->s_sid
= p
->p_pid
;
1144 sess
->s_ttyvp
= NULL
;
1145 sess
->s_ttyp
= TTY_NULL
;
1147 sess
->s_listflags
= 0;
1148 sess
->s_ttypgrpid
= NO_PID
;
1149 #if CONFIG_FINE_LOCK_GROUPS
1150 lck_mtx_init(&sess
->s_mlock
, proc_mlock_grp
, proc_lck_attr
);
1152 lck_mtx_init(&sess
->s_mlock
, proc_lck_grp
, proc_lck_attr
);
1154 bcopy(procsp
->s_login
, sess
->s_login
,
1155 sizeof(sess
->s_login
));
1156 OSBitAndAtomic(~((uint32_t)P_CONTROLT
), &p
->p_flag
);
1158 LIST_INSERT_HEAD(SESSHASH(sess
->s_sid
), sess
, s_hash
);
1160 pgrp
->pg_session
= sess
;
1162 if (p
!= current_proc())
1163 panic("enterpgrp: mksession and p != curproc");
1167 pgrp
->pg_session
= procsp
;
1169 if ((pgrp
->pg_session
->s_listflags
& (S_LIST_TERM
| S_LIST_DEAD
)) != 0)
1170 panic("enterpgrp: providing ref to terminating session ");
1171 pgrp
->pg_session
->s_count
++;
1175 #if CONFIG_FINE_LOCK_GROUPS
1176 lck_mtx_init(&pgrp
->pg_mlock
, proc_mlock_grp
, proc_lck_attr
);
1178 lck_mtx_init(&pgrp
->pg_mlock
, proc_lck_grp
, proc_lck_attr
);
1180 LIST_INIT(&pgrp
->pg_members
);
1181 pgrp
->pg_membercnt
= 0;
1184 pgrp
->pg_refcount
= 1;
1185 pgrp
->pg_listflags
= 0;
1186 LIST_INSERT_HEAD(PGRPHASH(pgid
), pgrp
, pg_hash
);
1188 } else if (pgrp
== mypgrp
) {
1192 if (procsp
!= SESSION_NULL
)
1193 session_rele(procsp
);
1197 if (procsp
!= SESSION_NULL
)
1198 session_rele(procsp
);
1200 * Adjust eligibility of affected pgrps to participate in job control.
1201 * Increment eligibility counts before decrementing, otherwise we
1202 * could reach 0 spuriously during the first call.
1204 fixjobc(p
, pgrp
, 1);
1205 fixjobc(p
, mypgrp
, 0);
1207 if(mypgrp
!= PGRP_NULL
)
1209 pgrp_replace(p
, pgrp
);
1216 * remove process from process group
1227 * delete a process group
1230 pgdelete_dropref(struct pgrp
*pgrp
)
1234 struct session
*sessp
;
1238 if (pgrp
->pg_membercnt
!= 0) {
1244 pgrp
->pg_refcount
--;
1245 if ((emptypgrp
== 0) || (pgrp
->pg_membercnt
!= 0)) {
1250 pgrp
->pg_listflags
|= PGRP_FLAG_TERMINATE
;
1252 if (pgrp
->pg_refcount
> 0) {
1257 pgrp
->pg_listflags
|= PGRP_FLAG_DEAD
;
1258 LIST_REMOVE(pgrp
, pg_hash
);
1262 ttyp
= SESSION_TP(pgrp
->pg_session
);
1263 if (ttyp
!= TTY_NULL
) {
1264 if (ttyp
->t_pgrp
== pgrp
) {
1266 /* Re-check after acquiring the lock */
1267 if (ttyp
->t_pgrp
== pgrp
) {
1268 ttyp
->t_pgrp
= NULL
;
1269 pgrp
->pg_session
->s_ttypgrpid
= NO_PID
;
1277 sessp
= pgrp
->pg_session
;
1278 if ((sessp
->s_listflags
& (S_LIST_TERM
| S_LIST_DEAD
)) != 0)
1279 panic("pg_deleteref: manipulating refs of already terminating session");
1280 if (--sessp
->s_count
== 0) {
1281 if ((sessp
->s_listflags
& (S_LIST_TERM
| S_LIST_DEAD
)) != 0)
1282 panic("pg_deleteref: terminating already terminated session");
1283 sessp
->s_listflags
|= S_LIST_TERM
;
1284 ttyp
= SESSION_TP(sessp
);
1285 LIST_REMOVE(sessp
, s_hash
);
1287 if (ttyp
!= TTY_NULL
) {
1289 if (ttyp
->t_session
== sessp
)
1290 ttyp
->t_session
= NULL
;
1294 sessp
->s_listflags
|= S_LIST_DEAD
;
1295 if (sessp
->s_count
!= 0)
1296 panic("pg_deleteref: freeing session in use");
1298 #if CONFIG_FINE_LOCK_GROUPS
1299 lck_mtx_destroy(&sessp
->s_mlock
, proc_mlock_grp
);
1301 lck_mtx_destroy(&sessp
->s_mlock
, proc_lck_grp
);
1303 FREE_ZONE(sessp
, sizeof(struct session
), M_SESSION
);
1306 #if CONFIG_FINE_LOCK_GROUPS
1307 lck_mtx_destroy(&pgrp
->pg_mlock
, proc_mlock_grp
);
1309 lck_mtx_destroy(&pgrp
->pg_mlock
, proc_lck_grp
);
1311 FREE_ZONE(pgrp
, sizeof(*pgrp
), M_PGRP
);
1316 * Adjust pgrp jobc counters when specified process changes process group.
1317 * We count the number of processes in each process group that "qualify"
1318 * the group for terminal job control (those with a parent in a different
1319 * process group of the same session). If that count reaches zero, the
1320 * process group becomes orphaned. Check both the specified process'
1321 * process group and that of its children.
1322 * entering == 0 => p is leaving specified group.
1323 * entering == 1 => p is entering specified group.
1326 fixjob_callback(proc_t p
, void * arg
)
1328 struct fixjob_iterargs
*fp
;
1329 struct pgrp
* pg
, *hispg
;
1330 struct session
* mysession
, *hissess
;
1333 fp
= (struct fixjob_iterargs
*)arg
;
1335 mysession
= fp
->mysession
;
1336 entering
= fp
->entering
;
1338 hispg
= proc_pgrp(p
);
1339 hissess
= proc_session(p
);
1341 if ((hispg
!= pg
) &&
1342 (hissess
== mysession
)) {
1347 } else if (--hispg
->pg_jobc
== 0) {
1353 if (hissess
!= SESSION_NULL
)
1354 session_rele(hissess
);
1355 if (hispg
!= PGRP_NULL
)
1358 return(PROC_RETURNED
);
1362 fixjobc(proc_t p
, struct pgrp
*pgrp
, int entering
)
1364 struct pgrp
*hispgrp
= PGRP_NULL
;
1365 struct session
*hissess
= SESSION_NULL
;
1366 struct session
*mysession
= pgrp
->pg_session
;
1368 struct fixjob_iterargs fjarg
;
1369 boolean_t proc_parent_self
;
1372 * Check if p's parent is current proc, if yes then no need to take
1373 * a ref; calling proc_parent with current proc as parent may
1374 * deadlock if current proc is exiting.
1376 proc_parent_self
= proc_parent_is_currentproc(p
);
1377 if (proc_parent_self
)
1378 parent
= current_proc();
1380 parent
= proc_parent(p
);
1382 if (parent
!= PROC_NULL
) {
1383 hispgrp
= proc_pgrp(parent
);
1384 hissess
= proc_session(parent
);
1385 if (!proc_parent_self
)
1391 * Check p's parent to see whether p qualifies its own process
1392 * group; if so, adjust count for p's process group.
1394 if ((hispgrp
!= pgrp
) &&
1395 (hissess
== mysession
)) {
1400 }else if (--pgrp
->pg_jobc
== 0) {
1407 if (hissess
!= SESSION_NULL
)
1408 session_rele(hissess
);
1409 if (hispgrp
!= PGRP_NULL
)
1413 * Check this process' children to see whether they qualify
1414 * their process groups; if so, adjust counts for children's
1418 fjarg
.mysession
= mysession
;
1419 fjarg
.entering
= entering
;
1420 proc_childrenwalk(p
, fixjob_callback
, &fjarg
);
1424 * A process group has become orphaned;
1425 * if there are any stopped processes in the group,
1426 * hang-up all process in that group.
1429 orphanpg(struct pgrp
* pgrp
)
1433 int count
, pidcount
, i
, alloc_count
;
1435 if (pgrp
== PGRP_NULL
)
1439 for (p
= pgrp
->pg_members
.lh_first
; p
!= 0; p
= p
->p_pglist
.le_next
) {
1440 if (p
->p_stat
== SSTOP
) {
1441 for (p
= pgrp
->pg_members
.lh_first
; p
!= 0;
1442 p
= p
->p_pglist
.le_next
)
1444 break; /* ??? stops after finding one.. */
1450 if (count
> hard_maxproc
)
1451 count
= hard_maxproc
;
1452 alloc_count
= count
* sizeof(pid_t
);
1453 pid_list
= (pid_t
*)kalloc(alloc_count
);
1454 bzero(pid_list
, alloc_count
);
1458 for (p
= pgrp
->pg_members
.lh_first
; p
!= 0;
1459 p
= p
->p_pglist
.le_next
) {
1460 if (p
->p_stat
== SSTOP
) {
1461 for (p
= pgrp
->pg_members
.lh_first
; p
!= 0;
1462 p
= p
->p_pglist
.le_next
) {
1463 pid_list
[pidcount
] = p
->p_pid
;
1465 if (pidcount
>= count
)
1468 break; /* ??? stops after finding one.. */
1477 for (i
= 0; i
< pidcount
; i
++) {
1478 /* No handling or proc0 */
1479 if (pid_list
[i
] == 0)
1481 p
= proc_find(pid_list
[i
]);
1483 proc_transwait(p
, 0);
1486 psignal(p
, SIGCONT
);
1491 kfree(pid_list
, alloc_count
);
1497 /* XXX should be __private_extern__ */
1499 proc_is_classic(proc_t p
)
1501 return (p
->p_flag
& P_TRANSLATED
) ? 1 : 0;
1504 /* XXX Why does this function exist? Need to kill it off... */
1506 current_proc_EXTERNAL(void)
1508 return (current_proc());
1512 proc_is_forcing_hfs_case_sensitivity(proc_t p
)
1514 return (p
->p_vfs_iopolicy
& P_VFS_IOPOLICY_FORCE_HFS_CASE_SENSITIVITY
) ? 1 : 0;
1518 * proc_core_name(name, uid, pid)
1519 * Expand the name described in corefilename, using name, uid, and pid.
1520 * corefilename is a printf-like string, with three format specifiers:
1521 * %N name of process ("name")
1522 * %P process id (pid)
1524 * For example, "%N.core" is the default; they can be disabled completely
1525 * by using "/dev/null", or all core files can be stored in "/cores/%U/%N-%P".
1526 * This is controlled by the sysctl variable kern.corefile (see above).
1528 __private_extern__
int
1529 proc_core_name(const char *name
, uid_t uid
, pid_t pid
, char *cf_name
,
1532 const char *format
, *appendstr
;
1533 char id_buf
[11]; /* Buffer for pid/uid -- max 4B */
1536 if (cf_name
== NULL
)
1539 format
= corefilename
;
1540 for (i
= 0, n
= 0; n
< cf_name_len
&& format
[i
]; i
++) {
1541 switch (format
[i
]) {
1542 case '%': /* Format character */
1544 switch (format
[i
]) {
1548 case 'N': /* process name */
1551 case 'P': /* process id */
1552 snprintf(id_buf
, sizeof(id_buf
), "%u", pid
);
1555 case 'U': /* user id */
1556 snprintf(id_buf
, sizeof(id_buf
), "%u", uid
);
1562 "Unknown format character %c in `%s'\n",
1565 l
= strlen(appendstr
);
1566 if ((n
+ l
) >= cf_name_len
)
1568 bcopy(appendstr
, cf_name
+ n
, l
);
1572 cf_name
[n
++] = format
[i
];
1575 if (format
[i
] != '\0')
1579 log(LOG_ERR
, "pid %ld (%s), uid (%u): corename is too long\n",
1580 (long)pid
, name
, (uint32_t)uid
);
1589 LIST_INIT(&alllctx
);
1592 /* allocate lctx lock group attribute and group */
1593 lctx_lck_grp_attr
= lck_grp_attr_alloc_init();
1594 lck_grp_attr_setstat(lctx_lck_grp_attr
);
1596 lctx_lck_grp
= lck_grp_alloc_init("lctx", lctx_lck_grp_attr
);
1597 /* Allocate lctx lock attribute */
1598 lctx_lck_attr
= lck_attr_alloc_init();
1600 lck_mtx_init(&alllctx_lock
, lctx_lck_grp
, lctx_lck_attr
);
1604 * Locate login context by number.
1612 LIST_FOREACH(l
, &alllctx
, lc_list
) {
1613 if (l
->lc_id
== lcid
) {
1625 if (lastlcid > maxlcid) \
1635 /* Not very efficient but this isn't a common operation. */
1636 while ((l
= lcfind(lastlcid
)) != NULL
) {
1643 MALLOC(l
, struct lctx
*, sizeof(struct lctx
), M_LCTX
, M_WAITOK
|M_ZERO
);
1645 LIST_INIT(&l
->lc_members
);
1646 lck_mtx_init(&l
->lc_mtx
, lctx_lck_grp
, lctx_lck_attr
);
1648 l
->lc_label
= mac_lctx_label_alloc();
1651 LIST_INSERT_HEAD(&alllctx
, l
, lc_list
);
1659 * Call with proc protected (either by being invisible
1660 * or by having the all-login-context lock held) and
1663 * Will unlock lctx on return.
1666 enterlctx (proc_t p
, struct lctx
*l
, __unused
int create
)
1672 LIST_INSERT_HEAD(&l
->lc_members
, p
, p_lclist
);
1677 mac_lctx_notify_create(p
, l
);
1679 mac_lctx_notify_join(p
, l
);
1687 * Remove process from login context (if any). Called with p protected by
1691 leavelctx (proc_t p
)
1695 if (p
->p_lctx
== NULL
) {
1699 LCTX_LOCK(p
->p_lctx
);
1702 LIST_REMOVE(p
, p_lclist
);
1705 mac_lctx_notify_leave(p
, l
);
1707 if (LIST_EMPTY(&l
->lc_members
)) {
1708 LIST_REMOVE(l
, lc_list
);
1711 lck_mtx_destroy(&l
->lc_mtx
, lctx_lck_grp
);
1713 mac_lctx_label_free(l
->lc_label
);
1724 sysctl_kern_lctx SYSCTL_HANDLER_ARGS
1726 int *name
= (int*) arg1
;
1727 u_int namelen
= arg2
;
1728 struct kinfo_lctx kil
;
1734 switch (oidp
->oid_number
) {
1737 /* Request for size. */
1739 error
= SYSCTL_OUT(req
, 0,
1740 sizeof(struct kinfo_lctx
) * (alllctx_cnt
+ 1));
1745 case KERN_LCTX_LCID
:
1747 if (req
->oldlen
< sizeof(struct kinfo_lctx
))
1752 /* No login context */
1753 l
= lcfind((pid_t
)name
[0]);
1759 return (SYSCTL_OUT(req
, (caddr_t
)&kil
, sizeof(kil
)));
1765 /* Provided buffer is too small. */
1766 if (req
->oldlen
< (sizeof(struct kinfo_lctx
) * alllctx_cnt
)) {
1771 LIST_FOREACH(l
, &alllctx
, lc_list
) {
1776 error
= SYSCTL_OUT(req
, (caddr_t
)&kil
, sizeof(kil
));
1786 SYSCTL_NODE(_kern
, KERN_LCTX
, lctx
, CTLFLAG_RW
|CTLFLAG_LOCKED
, 0, "Login Context");
1788 SYSCTL_PROC(_kern_lctx
, KERN_LCTX_ALL
, all
, CTLFLAG_RD
|CTLTYPE_STRUCT
| CTLFLAG_LOCKED
,
1789 0, 0, sysctl_kern_lctx
, "S,lctx",
1790 "Return entire login context table");
1791 SYSCTL_NODE(_kern_lctx
, KERN_LCTX_LCID
, lcid
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
1792 sysctl_kern_lctx
, "Login Context Table");
1793 SYSCTL_INT(_kern_lctx
, OID_AUTO
, last
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &lastlcid
, 0, "");
1794 SYSCTL_INT(_kern_lctx
, OID_AUTO
, count
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &alllctx_cnt
, 0, "");
1795 SYSCTL_INT(_kern_lctx
, OID_AUTO
, max
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &maxlcid
, 0, "");
1799 /* Code Signing related routines */
1802 csops(__unused proc_t p
, struct csops_args
*uap
, __unused
int32_t *retval
)
1804 return(csops_internal(uap
->pid
, uap
->ops
, uap
->useraddr
,
1805 uap
->usersize
, USER_ADDR_NULL
));
1809 csops_audittoken(__unused proc_t p
, struct csops_audittoken_args
*uap
, __unused
int32_t *retval
)
1811 if (uap
->uaudittoken
== USER_ADDR_NULL
)
1813 return(csops_internal(uap
->pid
, uap
->ops
, uap
->useraddr
,
1814 uap
->usersize
, uap
->uaudittoken
));
1818 csops_copy_token(void *start
, size_t length
, user_size_t usize
, user_addr_t uaddr
)
1820 char fakeheader
[8] = { 0 };
1823 if (usize
< sizeof(fakeheader
))
1826 /* if no blob, fill in zero header */
1827 if (NULL
== start
) {
1829 length
= sizeof(fakeheader
);
1830 } else if (usize
< length
) {
1831 /* ... if input too short, copy out length of entitlement */
1832 uint32_t length32
= htonl((uint32_t)length
);
1833 memcpy(&fakeheader
[4], &length32
, sizeof(length32
));
1835 error
= copyout(fakeheader
, uaddr
, sizeof(fakeheader
));
1837 return ERANGE
; /* input buffer to short, ERANGE signals that */
1840 return copyout(start
, uaddr
, length
);
1844 csops_internal(pid_t pid
, int ops
, user_addr_t uaddr
, user_size_t usersize
, user_addr_t uaudittoken
)
1846 size_t usize
= (size_t)CAST_DOWN(size_t, usersize
);
1852 unsigned char cdhash
[SHA1_RESULTLEN
];
1853 audit_token_t token
;
1854 unsigned int upid
=0, uidversion
= 0;
1856 forself
= error
= 0;
1859 pid
= proc_selfpid();
1860 if (pid
== proc_selfpid())
1867 case CS_OPS_PIDOFFSET
:
1868 case CS_OPS_ENTITLEMENTS_BLOB
:
1870 break; /* unrestricted */
1872 if (forself
== 0 && kauth_cred_issuser(kauth_cred_get()) != TRUE
)
1877 pt
= proc_find(pid
);
1878 if (pt
== PROC_NULL
)
1882 uidversion
= pt
->p_idversion
;
1883 if (uaudittoken
!= USER_ADDR_NULL
) {
1885 error
= copyin(uaudittoken
, &token
, sizeof(audit_token_t
));
1888 /* verify the audit token pid/idversion matches with proc */
1889 if ((token
.val
[5] != upid
) || (token
.val
[7] != uidversion
)) {
1897 case CS_OPS_STATUS
: {
1901 retflags
= pt
->p_csflags
;
1902 if (cs_enforcement(pt
))
1903 retflags
|= CS_ENFORCEMENT
;
1906 if (uaddr
!= USER_ADDR_NULL
)
1907 error
= copyout(&retflags
, uaddr
, sizeof(uint32_t));
1910 case CS_OPS_MARKINVALID
:
1912 if ((pt
->p_csflags
& CS_VALID
) == CS_VALID
) { /* is currently valid */
1913 pt
->p_csflags
&= ~CS_VALID
; /* set invalid */
1914 if ((pt
->p_csflags
& CS_KILL
) == CS_KILL
) {
1915 pt
->p_csflags
|= CS_KILLED
;
1918 printf("CODE SIGNING: marked invalid by pid %d: "
1919 "p=%d[%s] honoring CS_KILL, final status 0x%x\n",
1920 proc_selfpid(), pt
->p_pid
, pt
->p_comm
, pt
->p_csflags
);
1922 psignal(pt
, SIGKILL
);
1930 case CS_OPS_MARKHARD
:
1932 pt
->p_csflags
|= CS_HARD
;
1933 if ((pt
->p_csflags
& CS_VALID
) == 0) {
1934 /* @@@ allow? reject? kill? @@@ */
1942 case CS_OPS_MARKKILL
:
1944 pt
->p_csflags
|= CS_KILL
;
1945 if ((pt
->p_csflags
& CS_VALID
) == 0) {
1947 psignal(pt
, SIGKILL
);
1952 case CS_OPS_PIDOFFSET
:
1953 toff
= pt
->p_textoff
;
1955 error
= copyout(&toff
, uaddr
, sizeof(toff
));
1960 /* pt already holds a reference on its p_textvp */
1962 toff
= pt
->p_textoff
;
1964 if (tvp
== NULLVP
|| usize
!= SHA1_RESULTLEN
) {
1969 error
= vn_getcdhash(tvp
, toff
, cdhash
);
1973 error
= copyout(cdhash
, uaddr
, sizeof (cdhash
));
1978 case CS_OPS_ENTITLEMENTS_BLOB
: {
1984 if ((pt
->p_csflags
& CS_VALID
) == 0) {
1990 error
= cs_entitlements_blob_get(pt
, &start
, &length
);
1995 error
= csops_copy_token(start
, length
, usize
, uaddr
);
1998 case CS_OPS_MARKRESTRICT
:
2000 pt
->p_csflags
|= CS_RESTRICT
;
2004 case CS_OPS_SET_STATUS
: {
2007 if (usize
< sizeof(flags
)) {
2012 error
= copyin(uaddr
, &flags
, sizeof(flags
));
2016 /* only allow setting a subset of all code sign flags */
2018 CS_HARD
| CS_EXEC_SET_HARD
|
2019 CS_KILL
| CS_EXEC_SET_KILL
|
2021 CS_ENFORCEMENT
| CS_EXEC_SET_ENFORCEMENT
;
2024 if (pt
->p_csflags
& CS_VALID
)
2025 pt
->p_csflags
|= flags
;
2037 if ((pt
->p_csflags
& CS_VALID
) == 0) {
2043 error
= cs_blob_get(pt
, &start
, &length
);
2048 error
= csops_copy_token(start
, length
, usize
, uaddr
);
2051 case CS_OPS_IDENTITY
: {
2052 const char *identity
;
2053 uint8_t fakeheader
[8];
2058 * Make identity have a blob header to make it
2059 * easier on userland to guess the identity
2062 if (usize
< sizeof(fakeheader
)) {
2066 memset(fakeheader
, 0, sizeof(fakeheader
));
2069 if ((pt
->p_csflags
& CS_VALID
) == 0) {
2075 identity
= cs_identity_get(pt
);
2077 if (identity
== NULL
) {
2082 length
= strlen(identity
) + 1; /* include NUL */
2083 idlen
= htonl(length
+ sizeof(fakeheader
));
2084 memcpy(&fakeheader
[4], &idlen
, sizeof(idlen
));
2086 error
= copyout(fakeheader
, uaddr
, sizeof(fakeheader
));
2090 if (usize
< sizeof(fakeheader
) + length
)
2092 else if (usize
> sizeof(fakeheader
))
2093 error
= copyout(identity
, uaddr
+ sizeof(fakeheader
), length
);
2098 case CS_OPS_SIGPUP_INSTALL
:
2099 error
= sigpup_install(uaddr
);
2102 case CS_OPS_SIGPUP_DROP
:
2103 error
= sigpup_drop();
2116 proc_iterate(flags
, callout
, arg
, filterfn
, filterarg
)
2118 int (*callout
)(proc_t
, void *);
2120 int (*filterfn
)(proc_t
, void *);
2125 int count
, pidcount
, alloc_count
, i
, retval
;
2128 if (count
> hard_maxproc
)
2129 count
= hard_maxproc
;
2130 alloc_count
= count
* sizeof(pid_t
);
2131 pid_list
= (pid_t
*)kalloc(alloc_count
);
2132 bzero(pid_list
, alloc_count
);
2139 if (flags
& PROC_ALLPROCLIST
) {
2140 for (p
= allproc
.lh_first
; (p
!= 0); p
= p
->p_list
.le_next
) {
2141 if (p
->p_stat
== SIDL
)
2143 if ( (filterfn
== 0 ) || (filterfn(p
, filterarg
) != 0)) {
2144 pid_list
[pidcount
] = p
->p_pid
;
2146 if (pidcount
>= count
)
2151 if ((pidcount
< count
) && (flags
& PROC_ZOMBPROCLIST
)) {
2152 for (p
= zombproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
) {
2153 if ( (filterfn
== 0 ) || (filterfn(p
, filterarg
) != 0)) {
2154 pid_list
[pidcount
] = p
->p_pid
;
2156 if (pidcount
>= count
)
2166 for (i
= 0; i
< pidcount
; i
++) {
2167 p
= proc_find(pid_list
[i
]);
2169 if ((flags
& PROC_NOWAITTRANS
) == 0)
2170 proc_transwait(p
, 0);
2171 retval
= callout(p
, arg
);
2175 case PROC_RETURNED_DONE
:
2177 if (retval
== PROC_RETURNED_DONE
) {
2182 case PROC_CLAIMED_DONE
:
2188 } else if (flags
& PROC_ZOMBPROCLIST
) {
2189 p
= proc_find_zombref(pid_list
[i
]);
2190 if (p
!= PROC_NULL
) {
2191 retval
= callout(p
, arg
);
2195 case PROC_RETURNED_DONE
:
2196 proc_drop_zombref(p
);
2197 if (retval
== PROC_RETURNED_DONE
) {
2202 case PROC_CLAIMED_DONE
:
2213 kfree(pid_list
, alloc_count
);
2220 /* This is for iteration in case of trivial non blocking callouts */
2222 proc_scanall(flags
, callout
, arg
)
2224 int (*callout
)(proc_t
, void *);
2234 if (flags
& PROC_ALLPROCLIST
) {
2235 for (p
= allproc
.lh_first
; (p
!= 0); p
= p
->p_list
.le_next
) {
2236 retval
= callout(p
, arg
);
2237 if (retval
== PROC_RETURNED_DONE
)
2241 if (flags
& PROC_ZOMBPROCLIST
) {
2242 for (p
= zombproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
) {
2243 retval
= callout(p
, arg
);
2244 if (retval
== PROC_RETURNED_DONE
)
2258 proc_rebootscan(callout
, arg
, filterfn
, filterarg
)
2259 int (*callout
)(proc_t
, void *);
2261 int (*filterfn
)(proc_t
, void *);
2265 int lockheld
= 0, retval
;
2267 proc_shutdown_exitcount
= 0;
2275 for (p
= allproc
.lh_first
; (p
!= 0); p
= p
->p_list
.le_next
) {
2276 if ( (filterfn
== 0 ) || (filterfn(p
, filterarg
) != 0)) {
2277 p
= proc_ref_locked(p
);
2283 proc_transwait(p
, 0);
2284 retval
= callout(p
, arg
);
2288 case PROC_RETURNED_DONE
:
2289 case PROC_CLAIMED_DONE
:
2293 goto ps_allprocscan
;
2295 } /* allproc walk thru */
2297 if (lockheld
== 1) {
2309 proc_childrenwalk(parent
, callout
, arg
)
2310 struct proc
* parent
;
2311 int (*callout
)(proc_t
, void *);
2314 register struct proc
*p
;
2316 int count
, pidcount
, alloc_count
, i
, retval
;
2319 if (count
> hard_maxproc
)
2320 count
= hard_maxproc
;
2321 alloc_count
= count
* sizeof(pid_t
);
2322 pid_list
= (pid_t
*)kalloc(alloc_count
);
2323 bzero(pid_list
, alloc_count
);
2330 for (p
= parent
->p_children
.lh_first
; (p
!= 0); p
= p
->p_sibling
.le_next
) {
2331 if (p
->p_stat
== SIDL
)
2333 pid_list
[pidcount
] = p
->p_pid
;
2335 if (pidcount
>= count
)
2341 for (i
= 0; i
< pidcount
; i
++) {
2342 p
= proc_find(pid_list
[i
]);
2344 proc_transwait(p
, 0);
2345 retval
= callout(p
, arg
);
2349 case PROC_RETURNED_DONE
:
2351 if (retval
== PROC_RETURNED_DONE
) {
2356 case PROC_CLAIMED_DONE
:
2366 kfree(pid_list
, alloc_count
);
2373 /* PGRP_BLOCKITERATE is not implemented yet */
2375 pgrp_iterate(pgrp
, flags
, callout
, arg
, filterfn
, filterarg
)
2378 int (*callout
)(proc_t
, void *);
2380 int (*filterfn
)(proc_t
, void *);
2385 int count
, pidcount
, i
, alloc_count
;
2388 int dropref
= flags
& PGRP_DROPREF
;
2390 int serialize
= flags
& PGRP_BLOCKITERATE
;
2397 count
= pgrp
->pg_membercnt
+ 10;
2398 if (count
> hard_maxproc
)
2399 count
= hard_maxproc
;
2400 alloc_count
= count
* sizeof(pid_t
);
2401 pid_list
= (pid_t
*)kalloc(alloc_count
);
2402 bzero(pid_list
, alloc_count
);
2405 if (serialize
!= 0) {
2406 while ((pgrp
->pg_listflags
& PGRP_FLAG_ITERABEGIN
) == PGRP_FLAG_ITERABEGIN
) {
2407 pgrp
->pg_listflags
|= PGRP_FLAG_ITERWAIT
;
2408 msleep(&pgrp
->pg_listflags
, &pgrp
->pg_mlock
, 0, "pgrp_iterate", 0);
2410 pgrp
->pg_listflags
|= PGRP_FLAG_ITERABEGIN
;
2416 for (p
= pgrp
->pg_members
.lh_first
; p
!= 0;
2417 p
= p
->p_pglist
.le_next
) {
2418 if ( (filterfn
== 0 ) || (filterfn(p
, filterarg
) != 0)) {
2419 pid_list
[pidcount
] = p
->p_pid
;
2421 if (pidcount
>= count
)
2428 if ((serialize
== 0) && (dropref
!= 0))
2432 for (i
= 0; i
< pidcount
; i
++) {
2433 /* No handling or proc0 */
2434 if (pid_list
[i
] == 0)
2436 p
= proc_find(pid_list
[i
]);
2438 if (p
->p_pgrpid
!= pgid
) {
2442 proc_transwait(p
, 0);
2443 retval
= callout(p
, arg
);
2447 case PROC_RETURNED_DONE
:
2449 if (retval
== PROC_RETURNED_DONE
) {
2454 case PROC_CLAIMED_DONE
:
2463 if (serialize
!= 0) {
2465 pgrp
->pg_listflags
&= ~PGRP_FLAG_ITERABEGIN
;
2466 if ((pgrp
->pg_listflags
& PGRP_FLAG_ITERWAIT
) == PGRP_FLAG_ITERWAIT
) {
2467 pgrp
->pg_listflags
&= ~PGRP_FLAG_ITERWAIT
;
2468 wakeup(&pgrp
->pg_listflags
);
2474 kfree(pid_list
, alloc_count
);
2479 pgrp_add(struct pgrp
* pgrp
, struct proc
* parent
, struct proc
* child
)
2482 child
->p_pgrp
= pgrp
;
2483 child
->p_pgrpid
= pgrp
->pg_id
;
2484 child
->p_listflag
|= P_LIST_INPGRP
;
2486 * When pgrp is being freed , a process can still
2487 * request addition using setpgid from bash when
2488 * login is terminated (login cycler) return ESRCH
2489 * Safe to hold lock due to refcount on pgrp
2491 if ((pgrp
->pg_listflags
& (PGRP_FLAG_TERMINATE
| PGRP_FLAG_DEAD
)) == PGRP_FLAG_TERMINATE
) {
2492 pgrp
->pg_listflags
&= ~PGRP_FLAG_TERMINATE
;
2495 if ((pgrp
->pg_listflags
& PGRP_FLAG_DEAD
) == PGRP_FLAG_DEAD
)
2496 panic("pgrp_add : pgrp is dead adding process");
2500 pgrp
->pg_membercnt
++;
2501 if ( parent
!= PROC_NULL
) {
2502 LIST_INSERT_AFTER(parent
, child
, p_pglist
);
2504 LIST_INSERT_HEAD(&pgrp
->pg_members
, child
, p_pglist
);
2509 if (((pgrp
->pg_listflags
& (PGRP_FLAG_TERMINATE
| PGRP_FLAG_DEAD
)) == PGRP_FLAG_TERMINATE
) && (pgrp
->pg_membercnt
!= 0)) {
2510 pgrp
->pg_listflags
&= ~PGRP_FLAG_TERMINATE
;
2516 pgrp_remove(struct proc
* p
)
2523 #if __PROC_INTERNAL_DEBUG
2524 if ((p
->p_listflag
& P_LIST_INPGRP
) == 0)
2525 panic("removing from pglist but no named ref\n");
2527 p
->p_pgrpid
= PGRPID_DEAD
;
2528 p
->p_listflag
&= ~P_LIST_INPGRP
;
2532 if (pg
== PGRP_NULL
)
2533 panic("pgrp_remove: pg is NULL");
2537 if (pg
->pg_membercnt
< 0)
2538 panic("pgprp: -ve membercnt pgprp:%p p:%p\n",pg
, p
);
2540 LIST_REMOVE(p
, p_pglist
);
2541 if (pg
->pg_members
.lh_first
== 0) {
2543 pgdelete_dropref(pg
);
2551 /* cannot use proc_pgrp as it maybe stalled */
2553 pgrp_replace(struct proc
* p
, struct pgrp
* newpg
)
2555 struct pgrp
* oldpg
;
2561 while ((p
->p_listflag
& P_LIST_PGRPTRANS
) == P_LIST_PGRPTRANS
) {
2562 p
->p_listflag
|= P_LIST_PGRPTRWAIT
;
2563 (void)msleep(&p
->p_pgrpid
, proc_list_mlock
, 0, "proc_pgrp", 0);
2566 p
->p_listflag
|= P_LIST_PGRPTRANS
;
2569 if (oldpg
== PGRP_NULL
)
2570 panic("pgrp_replace: oldpg NULL");
2571 oldpg
->pg_refcount
++;
2572 #if __PROC_INTERNAL_DEBUG
2573 if ((p
->p_listflag
& P_LIST_INPGRP
) == 0)
2574 panic("removing from pglist but no named ref\n");
2576 p
->p_pgrpid
= PGRPID_DEAD
;
2577 p
->p_listflag
&= ~P_LIST_INPGRP
;
2583 oldpg
->pg_membercnt
--;
2584 if (oldpg
->pg_membercnt
< 0)
2585 panic("pgprp: -ve membercnt pgprp:%p p:%p\n",oldpg
, p
);
2586 LIST_REMOVE(p
, p_pglist
);
2587 if (oldpg
->pg_members
.lh_first
== 0) {
2589 pgdelete_dropref(oldpg
);
2597 p
->p_pgrpid
= newpg
->pg_id
;
2598 p
->p_listflag
|= P_LIST_INPGRP
;
2600 * When pgrp is being freed , a process can still
2601 * request addition using setpgid from bash when
2602 * login is terminated (login cycler) return ESRCH
2603 * Safe to hold lock due to refcount on pgrp
2605 if ((newpg
->pg_listflags
& (PGRP_FLAG_TERMINATE
| PGRP_FLAG_DEAD
)) == PGRP_FLAG_TERMINATE
) {
2606 newpg
->pg_listflags
&= ~PGRP_FLAG_TERMINATE
;
2609 if ((newpg
->pg_listflags
& PGRP_FLAG_DEAD
) == PGRP_FLAG_DEAD
)
2610 panic("pgrp_add : pgrp is dead adding process");
2614 newpg
->pg_membercnt
++;
2615 LIST_INSERT_HEAD(&newpg
->pg_members
, p
, p_pglist
);
2619 if (((newpg
->pg_listflags
& (PGRP_FLAG_TERMINATE
| PGRP_FLAG_DEAD
)) == PGRP_FLAG_TERMINATE
) && (newpg
->pg_membercnt
!= 0)) {
2620 newpg
->pg_listflags
&= ~PGRP_FLAG_TERMINATE
;
2623 p
->p_listflag
&= ~P_LIST_PGRPTRANS
;
2624 if ((p
->p_listflag
& P_LIST_PGRPTRWAIT
) == P_LIST_PGRPTRWAIT
) {
2625 p
->p_listflag
&= ~P_LIST_PGRPTRWAIT
;
2626 wakeup(&p
->p_pgrpid
);
2633 pgrp_lock(struct pgrp
* pgrp
)
2635 lck_mtx_lock(&pgrp
->pg_mlock
);
2639 pgrp_unlock(struct pgrp
* pgrp
)
2641 lck_mtx_unlock(&pgrp
->pg_mlock
);
2645 session_lock(struct session
* sess
)
2647 lck_mtx_lock(&sess
->s_mlock
);
2652 session_unlock(struct session
* sess
)
2654 lck_mtx_unlock(&sess
->s_mlock
);
2666 while ((p
->p_listflag
& P_LIST_PGRPTRANS
) == P_LIST_PGRPTRANS
) {
2667 p
->p_listflag
|= P_LIST_PGRPTRWAIT
;
2668 (void)msleep(&p
->p_pgrpid
, proc_list_mlock
, 0, "proc_pgrp", 0);
2673 assert(pgrp
!= NULL
);
2675 if (pgrp
!= PGRP_NULL
) {
2676 pgrp
->pg_refcount
++;
2677 if ((pgrp
->pg_listflags
& (PGRP_FLAG_TERMINATE
| PGRP_FLAG_DEAD
)) != 0)
2678 panic("proc_pgrp: ref being povided for dead pgrp");
2687 tty_pgrp(struct tty
* tp
)
2689 struct pgrp
* pg
= PGRP_NULL
;
2694 if (pg
!= PGRP_NULL
) {
2695 if ((pg
->pg_listflags
& PGRP_FLAG_DEAD
) != 0)
2696 panic("tty_pgrp: ref being povided for dead pgrp");
2705 proc_session(proc_t p
)
2707 struct session
* sess
= SESSION_NULL
;
2710 return(SESSION_NULL
);
2714 /* wait during transitions */
2715 while ((p
->p_listflag
& P_LIST_PGRPTRANS
) == P_LIST_PGRPTRANS
) {
2716 p
->p_listflag
|= P_LIST_PGRPTRWAIT
;
2717 (void)msleep(&p
->p_pgrpid
, proc_list_mlock
, 0, "proc_pgrp", 0);
2720 if ((p
->p_pgrp
!= PGRP_NULL
) && ((sess
= p
->p_pgrp
->pg_session
) != SESSION_NULL
)) {
2721 if ((sess
->s_listflags
& (S_LIST_TERM
| S_LIST_DEAD
)) != 0)
2722 panic("proc_session:returning sesssion ref on terminating session");
2730 session_rele(struct session
*sess
)
2733 if (--sess
->s_count
== 0) {
2734 if ((sess
->s_listflags
& (S_LIST_TERM
| S_LIST_DEAD
)) != 0)
2735 panic("session_rele: terminating already terminated session");
2736 sess
->s_listflags
|= S_LIST_TERM
;
2737 LIST_REMOVE(sess
, s_hash
);
2738 sess
->s_listflags
|= S_LIST_DEAD
;
2739 if (sess
->s_count
!= 0)
2740 panic("session_rele: freeing session in use");
2742 #if CONFIG_FINE_LOCK_GROUPS
2743 lck_mtx_destroy(&sess
->s_mlock
, proc_mlock_grp
);
2745 lck_mtx_destroy(&sess
->s_mlock
, proc_lck_grp
);
2747 FREE_ZONE(sess
, sizeof(struct session
), M_SESSION
);
2753 proc_transstart(proc_t p
, int locked
)
2757 while ((p
->p_lflag
& P_LINTRANSIT
) == P_LINTRANSIT
) {
2758 if ((p
->p_lflag
& P_LTRANSCOMMIT
) == P_LTRANSCOMMIT
) {
2763 p
->p_lflag
|= P_LTRANSWAIT
;
2764 msleep(&p
->p_lflag
, &p
->p_mlock
, 0, "proc_signstart", NULL
);
2766 p
->p_lflag
|= P_LINTRANSIT
;
2767 p
->p_transholder
= current_thread();
2774 proc_transcommit(proc_t p
, int locked
)
2779 assert ((p
->p_lflag
& P_LINTRANSIT
) == P_LINTRANSIT
);
2780 assert (p
->p_transholder
== current_thread());
2781 p
->p_lflag
|= P_LTRANSCOMMIT
;
2783 if ((p
->p_lflag
& P_LTRANSWAIT
) == P_LTRANSWAIT
) {
2784 p
->p_lflag
&= ~P_LTRANSWAIT
;
2785 wakeup(&p
->p_lflag
);
2792 proc_transend(proc_t p
, int locked
)
2797 p
->p_lflag
&= ~( P_LINTRANSIT
| P_LTRANSCOMMIT
);
2798 p
->p_transholder
= NULL
;
2800 if ((p
->p_lflag
& P_LTRANSWAIT
) == P_LTRANSWAIT
) {
2801 p
->p_lflag
&= ~P_LTRANSWAIT
;
2802 wakeup(&p
->p_lflag
);
2809 proc_transwait(proc_t p
, int locked
)
2813 while ((p
->p_lflag
& P_LINTRANSIT
) == P_LINTRANSIT
) {
2814 if ((p
->p_lflag
& P_LTRANSCOMMIT
) == P_LTRANSCOMMIT
&& current_proc() == p
) {
2819 p
->p_lflag
|= P_LTRANSWAIT
;
2820 msleep(&p
->p_lflag
, &p
->p_mlock
, 0, "proc_signstart", NULL
);
2828 proc_klist_lock(void)
2830 lck_mtx_lock(proc_klist_mlock
);
2834 proc_klist_unlock(void)
2836 lck_mtx_unlock(proc_klist_mlock
);
2840 proc_knote(struct proc
* p
, long hint
)
2843 KNOTE(&p
->p_klist
, hint
);
2844 proc_klist_unlock();
2848 proc_knote_drain(struct proc
*p
)
2850 struct knote
*kn
= NULL
;
2853 * Clear the proc's klist to avoid references after the proc is reaped.
2856 while ((kn
= SLIST_FIRST(&p
->p_klist
))) {
2857 kn
->kn_ptr
.p_proc
= PROC_NULL
;
2858 KNOTE_DETACH(&p
->p_klist
, kn
);
2860 proc_klist_unlock();
2864 proc_setregister(proc_t p
)
2867 p
->p_lflag
|= P_LREGISTER
;
2872 proc_resetregister(proc_t p
)
2875 p
->p_lflag
&= ~P_LREGISTER
;
2880 proc_pgrpid(proc_t p
)
2888 return current_proc()->p_pgrpid
;
2892 /* return control and action states */
2894 proc_getpcontrol(int pid
, int * pcontrolp
)
2901 if (pcontrolp
!= NULL
)
2902 *pcontrolp
= p
->p_pcaction
;
2909 proc_dopcontrol(proc_t p
, void *num_found
)
2915 pcontrol
= PROC_CONTROL_STATE(p
);
2917 if (PROC_ACTION_STATE(p
) ==0) {
2920 PROC_SETACTION_STATE(p
);
2922 printf("low swap: throttling pid %d (%s)\n", p
->p_pid
, p
->p_comm
);
2923 (*(int *)num_found
)++;
2927 PROC_SETACTION_STATE(p
);
2929 printf("low swap: suspending pid %d (%s)\n", p
->p_pid
, p
->p_comm
);
2930 task_suspend(p
->task
);
2931 (*(int *)num_found
)++;
2935 PROC_SETACTION_STATE(p
);
2937 printf("low swap: killing pid %d (%s)\n", p
->p_pid
, p
->p_comm
);
2938 psignal(p
, SIGKILL
);
2939 (*(int *)num_found
)++;
2949 return(PROC_RETURNED
);
2954 * Resume a throttled or suspended process. This is an internal interface that's only
2955 * used by the user level code that presents the GUI when we run out of swap space and
2956 * hence is restricted to processes with superuser privileges.
2960 proc_resetpcontrol(int pid
)
2965 proc_t self
= current_proc();
2967 /* if the process has been validated to handle resource control or root is valid one */
2968 if (((self
->p_lflag
& P_LVMRSRCOWNER
) == 0) && (error
= suser(kauth_cred_get(), 0)))
2977 pcontrol
= PROC_CONTROL_STATE(p
);
2979 if(PROC_ACTION_STATE(p
) !=0) {
2982 PROC_RESETACTION_STATE(p
);
2984 printf("low swap: unthrottling pid %d (%s)\n", p
->p_pid
, p
->p_comm
);
2988 PROC_RESETACTION_STATE(p
);
2990 printf("low swap: resuming pid %d (%s)\n", p
->p_pid
, p
->p_comm
);
2991 task_resume(p
->task
);
2996 PROC_SETACTION_STATE(p
);
2998 printf("low swap: attempt to unkill pid %d (%s) ignored\n", p
->p_pid
, p
->p_comm
);
3014 * Return true if the specified process has an action state specified for it and it isn't
3015 * already in an action state and it's using more physical memory than the specified threshold.
3016 * Note: the memory_threshold argument is specified in bytes and is of type uint64_t.
3020 proc_pcontrol_filter(proc_t p
, void *memory_thresholdp
)
3023 return PROC_CONTROL_STATE(p
) && /* if there's an action state specified... */
3024 (PROC_ACTION_STATE(p
) == 0) && /* and we're not in the action state yet... */
3025 (get_task_resident_size(p
->task
) > *((uint64_t *)memory_thresholdp
)); /* and this proc is over the mem threshold, */
3026 /* then return true to take action on this proc */
3032 * Deal with the out of swap space condition. This routine gets called when
3033 * we want to swap something out but there's no more space left. Since this
3034 * creates a memory deadlock situtation, we need to take action to free up
3035 * some memory resources in order to prevent the system from hanging completely.
3036 * The action we take is based on what the system processes running at user level
3037 * have specified. Processes are marked in one of four categories: ones that
3038 * can be killed immediately, ones that should be suspended, ones that should
3039 * be throttled, and all the rest which are basically none of the above. Which
3040 * processes are marked as being in which category is a user level policy decision;
3041 * we just take action based on those decisions here.
3044 #define STARTING_PERCENTAGE 50 /* memory threshold expressed as a percentage */
3045 /* of physical memory */
3047 struct timeval last_no_space_action
= {0, 0};
3050 no_paging_space_action(void)
3053 uint64_t memory_threshold
;
3058 * Throttle how often we come through here. Once every 20 seconds should be plenty.
3063 if (now
.tv_sec
<= last_no_space_action
.tv_sec
+ 20)
3066 last_no_space_action
= now
;
3069 * Examine all processes and find those that have been marked to have some action
3070 * taken when swap space runs out. Of those processes, select one or more and
3071 * apply the specified action to them. The idea is to only take action against
3072 * a few processes rather than hitting too many at once. If the low swap condition
3073 * persists, this routine will get called again and we'll take action against more
3076 * Of the processes that have been marked, we choose which ones to take action
3077 * against according to how much physical memory they're presently using. We
3078 * start with the STARTING_THRESHOLD and any processes using more physical memory
3079 * than the percentage threshold will have action taken against it. If there
3080 * are no processes over the threshold, then the threshold is cut in half and we
3081 * look again for processes using more than this threshold. We continue in
3082 * this fashion until we find at least one process to take action against. This
3083 * iterative approach is less than ideally efficient, however we only get here
3084 * when the system is almost in a memory deadlock and is pretty much just
3085 * thrashing if it's doing anything at all. Therefore, the cpu overhead of
3086 * potentially multiple passes here probably isn't revelant.
3089 memory_threshold
= (sane_size
* STARTING_PERCENTAGE
) / 100; /* resident threshold in bytes */
3091 for (num_found
= 0; num_found
== 0; memory_threshold
= memory_threshold
/ 2) {
3092 proc_iterate(PROC_ALLPROCLIST
, proc_dopcontrol
, (void *)&num_found
, proc_pcontrol_filter
, (void *)&memory_threshold
);
3095 * If we just looked with memory_threshold == 0, then there's no need to iterate any further since
3096 * we won't find any eligible processes at this point.
3099 if (memory_threshold
== 0) {
3100 if (num_found
== 0) /* log that we couldn't do anything in this case */
3101 printf("low swap: unable to find any eligible processes to take action on\n");