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/coalition.h>
103 #include <sys/coalition.h>
104 #include <kern/assert.h>
105 #include <vm/vm_protos.h>
106 #include <vm/vm_map.h> /* vm_map_switch_protect() */
107 #include <vm/vm_pageout.h>
108 #include <mach/task.h>
109 #include <mach/message.h>
110 #include <sys/priv.h>
111 #include <sys/proc_info.h>
112 #include <sys/bsdtask_info.h>
113 #include <sys/persona.h>
115 #if CONFIG_MEMORYSTATUS
116 #include <sys/kern_memorystatus.h>
120 #include <security/mac_framework.h>
123 #include <libkern/crypto/sha1.h>
126 * Structure associated with user cacheing.
129 LIST_ENTRY(uidinfo
) ui_hash
;
133 #define UIHASH(uid) (&uihashtbl[(uid) & uihash])
134 LIST_HEAD(uihashhead
, uidinfo
) *uihashtbl
;
135 u_long uihash
; /* size of hash table - 1 */
138 * Other process lists
140 struct pidhashhead
*pidhashtbl
;
142 struct pgrphashhead
*pgrphashtbl
;
144 struct sesshashhead
*sesshashtbl
;
147 struct proclist allproc
;
148 struct proclist zombproc
;
149 extern struct tty cons
;
154 #define __PROC_INTERNAL_DEBUG 1
156 /* Name to give to core files */
157 __XNU_PRIVATE_EXTERN
char corefilename
[MAXPATHLEN
+1] = {"/cores/core.%P"};
160 extern uint32_t fastbacktrace(uintptr_t* bt
, uint32_t max_frames
) __attribute__((noinline
));
163 static void orphanpg(struct pgrp
*pg
);
164 void proc_name_kdp(task_t t
, char * buf
, int size
);
165 int proc_threadname_kdp(void *uth
, char *buf
, size_t size
);
166 void proc_starttime_kdp(void *p
, uint64_t *tv_sec
, uint64_t *tv_usec
);
167 char *proc_name_address(void *p
);
169 static void pgrp_add(struct pgrp
* pgrp
, proc_t parent
, proc_t child
);
170 static void pgrp_remove(proc_t p
);
171 static void pgrp_replace(proc_t p
, struct pgrp
*pgrp
);
172 static void pgdelete_dropref(struct pgrp
*pgrp
);
173 extern void pg_rele_dropref(struct pgrp
* pgrp
);
174 static int csops_internal(pid_t pid
, int ops
, user_addr_t uaddr
, user_size_t usersize
, user_addr_t uaddittoken
);
175 static boolean_t
proc_parent_is_currentproc(proc_t p
);
177 struct fixjob_iterargs
{
179 struct session
* mysession
;
183 int fixjob_callback(proc_t
, void *);
186 * Initialize global process hashing structures.
192 LIST_INIT(&zombproc
);
193 pidhashtbl
= hashinit(maxproc
/ 4, M_PROC
, &pidhash
);
194 pgrphashtbl
= hashinit(maxproc
/ 4, M_PROC
, &pgrphash
);
195 sesshashtbl
= hashinit(maxproc
/ 4, M_PROC
, &sesshash
);
196 uihashtbl
= hashinit(maxproc
/ 16, M_PROC
, &uihash
);
198 personas_bootstrap();
203 * Change the count associated with number of processes
204 * a given user is using. This routine protects the uihash
208 chgproccnt(uid_t uid
, int diff
)
211 struct uidinfo
*newuip
= NULL
;
212 struct uihashhead
*uipp
;
218 for (uip
= uipp
->lh_first
; uip
!= 0; uip
= uip
->ui_hash
.le_next
)
219 if (uip
->ui_uid
== uid
)
222 uip
->ui_proccnt
+= diff
;
223 if (uip
->ui_proccnt
> 0) {
224 retval
= uip
->ui_proccnt
;
228 if (uip
->ui_proccnt
< 0)
229 panic("chgproccnt: procs < 0");
230 LIST_REMOVE(uip
, ui_hash
);
233 FREE_ZONE(uip
, sizeof(*uip
), M_PROC
);
242 panic("chgproccnt: lost user");
244 if (newuip
!= NULL
) {
247 LIST_INSERT_HEAD(uipp
, uip
, ui_hash
);
249 uip
->ui_proccnt
= diff
;
255 MALLOC_ZONE(newuip
, struct uidinfo
*, sizeof(*uip
), M_PROC
, M_WAITOK
);
257 panic("chgproccnt: M_PROC zone depleted");
261 FREE_ZONE(newuip
, sizeof(*uip
), M_PROC
);
266 * Is p an inferior of the current process?
274 for (; p
!= current_proc(); p
= p
->p_pptr
)
284 * Is p an inferior of t ?
287 isinferior(proc_t p
, proc_t t
)
293 /* if p==t they are not inferior */
298 for (; p
!= t
; p
= p
->p_pptr
) {
301 /* Detect here if we're in a cycle */
302 if ((p
->p_pid
== 0) || (p
->p_pptr
== start
) || (nchecked
>= nprocs
))
312 proc_isinferior(int pid1
, int pid2
)
314 proc_t p
= PROC_NULL
;
315 proc_t t
= PROC_NULL
;
318 if (((p
= proc_find(pid1
)) != (proc_t
)0 ) && ((t
= proc_find(pid2
)) != (proc_t
)0))
319 retval
= isinferior(p
, t
);
332 return(proc_findinternal(pid
, 0));
336 proc_findinternal(int pid
, int locked
)
338 proc_t p
= PROC_NULL
;
344 p
= pfind_locked(pid
);
345 if ((p
== PROC_NULL
) || (p
!= proc_ref_locked(p
)))
356 proc_findthread(thread_t thread
)
358 proc_t p
= PROC_NULL
;
362 uth
= get_bsdthread_info(thread
);
363 if (uth
&& (uth
->uu_flag
& UT_VFORK
))
366 p
= (proc_t
)(get_bsdthreadtask_info(thread
));
367 p
= proc_ref_locked(p
);
374 uthread_reset_proc_refcount(void *uthread
) {
377 if (proc_ref_tracking_disabled
) {
381 uth
= (uthread_t
) uthread
;
383 uth
->uu_proc_refcount
= 0;
388 uthread_get_proc_refcount(void *uthread
) {
391 if (proc_ref_tracking_disabled
) {
395 uth
= (uthread_t
) uthread
;
397 return uth
->uu_proc_refcount
;
401 record_procref(proc_t p
, int count
) {
404 if (proc_ref_tracking_disabled
) {
408 uth
= current_uthread();
409 uth
->uu_proc_refcount
+= count
;
412 if (uth
->uu_pindex
< NUM_PROC_REFS_TO_TRACK
) {
413 fastbacktrace((uintptr_t *) &uth
->uu_proc_pcs
[uth
->uu_pindex
], PROC_REF_STACK_DEPTH
);
415 uth
->uu_proc_ps
[uth
->uu_pindex
] = p
;
440 if (p
!= proc_ref_locked(p
))
448 proc_ref_locked(proc_t p
)
452 /* if process still in creation return failure */
453 if ((p
== PROC_NULL
) || ((p
->p_listflag
& P_LIST_INCREATE
) != 0))
455 /* do not return process marked for termination */
456 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)) {
459 record_procref(p
, 1);
469 proc_rele_locked(proc_t p
)
472 if (p
->p_refcount
> 0) {
475 record_procref(p
, -1);
477 if ((p
->p_refcount
== 0) && ((p
->p_listflag
& P_LIST_DRAINWAIT
) == P_LIST_DRAINWAIT
)) {
478 p
->p_listflag
&= ~P_LIST_DRAINWAIT
;
479 wakeup(&p
->p_refcount
);
482 panic("proc_rele_locked -ve ref\n");
487 proc_find_zombref(int pid
)
494 p
= pfind_locked(pid
);
496 /* should we bail? */
497 if ((p
== PROC_NULL
) /* not found */
498 || ((p
->p_listflag
& P_LIST_INCREATE
) != 0) /* not created yet */
499 || ((p
->p_listflag
& P_LIST_EXITED
) == 0)) { /* not started exit */
505 /* If someone else is controlling the (unreaped) zombie - wait */
506 if ((p
->p_listflag
& P_LIST_WAITING
) != 0) {
507 (void)msleep(&p
->p_stat
, proc_list_mlock
, PWAIT
, "waitcoll", 0);
510 p
->p_listflag
|= P_LIST_WAITING
;
518 proc_drop_zombref(proc_t p
)
521 if ((p
->p_listflag
& P_LIST_WAITING
) == P_LIST_WAITING
) {
522 p
->p_listflag
&= ~P_LIST_WAITING
;
530 proc_refdrain(proc_t p
)
535 p
->p_listflag
|= P_LIST_DRAIN
;
536 while (p
->p_refcount
) {
537 p
->p_listflag
|= P_LIST_DRAINWAIT
;
538 msleep(&p
->p_refcount
, proc_list_mlock
, 0, "proc_refdrain", 0) ;
540 p
->p_listflag
&= ~P_LIST_DRAIN
;
541 p
->p_listflag
|= P_LIST_DEAD
;
549 proc_parentholdref(proc_t p
)
551 proc_t parent
= PROC_NULL
;
559 if ((pp
== PROC_NULL
) || (pp
->p_stat
== SZOMB
) || ((pp
->p_listflag
& (P_LIST_CHILDDRSTART
| P_LIST_CHILDDRAINED
)) == (P_LIST_CHILDDRSTART
| P_LIST_CHILDDRAINED
))) {
564 if ((pp
->p_listflag
& (P_LIST_CHILDDRSTART
| P_LIST_CHILDDRAINED
)) == P_LIST_CHILDDRSTART
) {
565 pp
->p_listflag
|= P_LIST_CHILDDRWAIT
;
566 msleep(&pp
->p_childrencnt
, proc_list_mlock
, 0, "proc_parent", 0);
575 if ((pp
->p_listflag
& (P_LIST_CHILDDRSTART
| P_LIST_CHILDDRAINED
)) == 0) {
586 proc_parentdropref(proc_t p
, int listlocked
)
591 if (p
->p_parentref
> 0) {
593 if ((p
->p_parentref
== 0) && ((p
->p_listflag
& P_LIST_PARENTREFWAIT
) == P_LIST_PARENTREFWAIT
)) {
594 p
->p_listflag
&= ~P_LIST_PARENTREFWAIT
;
595 wakeup(&p
->p_parentref
);
598 panic("proc_parentdropref -ve ref\n");
606 proc_childdrainstart(proc_t p
)
608 #if __PROC_INTERNAL_DEBUG
609 if ((p
->p_listflag
& P_LIST_CHILDDRSTART
) == P_LIST_CHILDDRSTART
)
610 panic("proc_childdrainstart: childdrain already started\n");
612 p
->p_listflag
|= P_LIST_CHILDDRSTART
;
613 /* wait for all that hold parentrefs to drop */
614 while (p
->p_parentref
> 0) {
615 p
->p_listflag
|= P_LIST_PARENTREFWAIT
;
616 msleep(&p
->p_parentref
, proc_list_mlock
, 0, "proc_childdrainstart", 0) ;
622 proc_childdrainend(proc_t p
)
624 #if __PROC_INTERNAL_DEBUG
625 if (p
->p_childrencnt
> 0)
626 panic("exiting: children stil hanging around\n");
628 p
->p_listflag
|= P_LIST_CHILDDRAINED
;
629 if ((p
->p_listflag
& (P_LIST_CHILDLKWAIT
|P_LIST_CHILDDRWAIT
)) != 0) {
630 p
->p_listflag
&= ~(P_LIST_CHILDLKWAIT
|P_LIST_CHILDDRWAIT
);
631 wakeup(&p
->p_childrencnt
);
636 proc_checkdeadrefs(__unused proc_t p
)
638 #if __PROC_INTERNAL_DEBUG
639 if ((p
->p_listflag
& P_LIST_INHASH
) != 0)
640 panic("proc being freed and still in hash %p: %u\n", p
, p
->p_listflag
);
641 if (p
->p_childrencnt
!= 0)
642 panic("proc being freed and pending children cnt %p:%d\n", p
, p
->p_childrencnt
);
643 if (p
->p_refcount
!= 0)
644 panic("proc being freed and pending refcount %p:%d\n", p
, p
->p_refcount
);
645 if (p
->p_parentref
!= 0)
646 panic("proc being freed and pending parentrefs %p:%d\n", p
, p
->p_parentref
);
669 return (current_proc()->p_pid
);
675 return (current_proc()->p_ppid
);
679 proc_selfcsflags(void)
681 return (current_proc()->p_csflags
);
686 dtrace_current_proc_vforking(void)
688 thread_t th
= current_thread();
689 struct uthread
*ut
= get_bsdthread_info(th
);
692 ((ut
->uu_flag
& (UT_VFORK
|UT_VFORKING
)) == (UT_VFORK
|UT_VFORKING
))) {
694 * Handle the narrow window where we're in the vfork syscall,
695 * but we're not quite ready to claim (in particular, to DTrace)
696 * that we're running as the child.
698 return (get_bsdtask_info(get_threadtask(th
)));
700 return (current_proc());
704 dtrace_proc_selfpid(void)
706 return (dtrace_current_proc_vforking()->p_pid
);
710 dtrace_proc_selfppid(void)
712 return (dtrace_current_proc_vforking()->p_ppid
);
716 dtrace_proc_selfruid(void)
718 return (dtrace_current_proc_vforking()->p_ruid
);
720 #endif /* CONFIG_DTRACE */
723 proc_parent(proc_t p
)
731 parent
= proc_ref_locked(pp
);
732 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)){
733 pp
->p_listflag
|= P_LIST_CHILDLKWAIT
;
734 msleep(&pp
->p_childrencnt
, proc_list_mlock
, 0, "proc_parent", 0);
742 proc_parent_is_currentproc(proc_t p
)
744 boolean_t ret
= FALSE
;
747 if (p
->p_pptr
== current_proc())
755 proc_name(int pid
, char * buf
, int size
)
759 if ((p
= proc_find(pid
)) != PROC_NULL
) {
760 strlcpy(buf
, &p
->p_comm
[0], size
);
766 proc_name_kdp(task_t t
, char * buf
, int size
)
768 proc_t p
= get_bsdtask_info(t
);
772 if ((size_t)size
> sizeof(p
->p_comm
))
773 strlcpy(buf
, &p
->p_name
[0], MIN((int)sizeof(p
->p_name
), size
));
775 strlcpy(buf
, &p
->p_comm
[0], MIN((int)sizeof(p
->p_comm
), size
));
780 proc_threadname_kdp(void *uth
, char *buf
, size_t size
)
782 if (size
< MAXTHREADNAMESIZE
) {
783 /* this is really just a protective measure for the future in
784 * case the thread name size in stackshot gets out of sync with
785 * the BSD max thread name size. Note that bsd_getthreadname
786 * doesn't take input buffer size into account. */
791 bsd_getthreadname(uth
, buf
);
796 /* note that this function is generally going to be called from stackshot,
797 * and the arguments will be coming from a struct which is declared packed
798 * thus the input arguments will in general be unaligned. We have to handle
801 proc_starttime_kdp(void *p
, uint64_t *tv_sec
, uint64_t *tv_usec
)
803 proc_t pp
= (proc_t
)p
;
806 } __attribute__((packed
));
808 if (pp
!= PROC_NULL
) {
810 ((struct uint64p
*)tv_sec
)->val
= pp
->p_start
.tv_sec
;
812 ((struct uint64p
*)tv_usec
)->val
= pp
->p_start
.tv_usec
;
817 proc_name_address(void *p
)
819 return &((proc_t
)p
)->p_comm
[0];
823 proc_selfname(char * buf
, int size
)
827 if ((p
= current_proc())!= (proc_t
)0) {
828 strlcpy(buf
, &p
->p_comm
[0], size
);
833 proc_signal(int pid
, int signum
)
837 if ((p
= proc_find(pid
)) != PROC_NULL
) {
844 proc_issignal(int pid
, sigset_t mask
)
849 if ((p
= proc_find(pid
)) != PROC_NULL
) {
850 error
= proc_pendingsignals(p
, mask
);
858 proc_noremotehang(proc_t p
)
863 retval
= p
->p_flag
& P_NOREMOTEHANG
;
864 return(retval
? 1: 0);
869 proc_exiting(proc_t p
)
874 retval
= p
->p_lflag
& P_LEXIT
;
875 return(retval
? 1: 0);
879 proc_forcequota(proc_t p
)
884 retval
= p
->p_flag
& P_FORCEQUOTA
;
885 return(retval
? 1: 0);
892 kauth_cred_t my_cred
;
895 my_cred
= kauth_cred_proc_ref(p
);
896 error
= suser(my_cred
, &p
->p_acflag
);
897 kauth_cred_unref(&my_cred
);
902 proc_task(proc_t proc
)
904 return (task_t
)proc
->task
;
908 * Obtain the first thread in a process
910 * XXX This is a bad thing to do; it exists predominantly to support the
911 * XXX use of proc_t's in places that should really be using
912 * XXX thread_t's instead. This maintains historical behaviour, but really
913 * XXX needs an audit of the context (proxy vs. not) to clean up.
916 proc_thread(proc_t proc
)
918 uthread_t uth
= TAILQ_FIRST(&proc
->p_uthlist
);
921 return(uth
->uu_context
.vc_thread
);
935 thread_t th
= current_thread();
937 return((struct uthread
*)get_bsdthread_info(th
));
942 proc_is64bit(proc_t p
)
944 return(IS_64BIT_PROCESS(p
));
948 proc_pidversion(proc_t p
)
950 return(p
->p_idversion
);
954 proc_persona_id(proc_t p
)
956 return (uint32_t)persona_id_from_proc(p
);
960 proc_getuid(proc_t p
)
966 proc_getgid(proc_t p
)
972 proc_uniqueid(proc_t p
)
974 return(p
->p_uniqueid
);
978 proc_puniqueid(proc_t p
)
980 return(p
->p_puniqueid
);
984 proc_coalitionids(__unused proc_t p
, __unused
uint64_t ids
[COALITION_NUM_TYPES
])
986 #if CONFIG_COALITIONS
987 task_coalition_ids(p
->task
, ids
);
989 memset(ids
, 0, sizeof(uint64_t [COALITION_NUM_TYPES
]));
995 proc_was_throttled(proc_t p
)
997 return (p
->was_throttled
);
1001 proc_did_throttle(proc_t p
)
1003 return (p
->did_throttle
);
1007 proc_getcdhash(proc_t p
, unsigned char *cdhash
)
1009 return vn_getcdhash(p
->p_textvp
, p
->p_textoff
, cdhash
);
1013 proc_getexecutableuuid(proc_t p
, unsigned char *uuidbuf
, unsigned long size
)
1015 if (size
>= sizeof(p
->p_uuid
)) {
1016 memcpy(uuidbuf
, p
->p_uuid
, sizeof(p
->p_uuid
));
1020 /* Return vnode for executable with an iocount. Must be released with vnode_put() */
1022 proc_getexecutablevnode(proc_t p
)
1024 vnode_t tvp
= p
->p_textvp
;
1026 if ( tvp
!= NULLVP
) {
1027 if (vnode_getwithref(tvp
) == 0) {
1037 bsd_set_dependency_capable(task_t task
)
1039 proc_t p
= get_bsdtask_info(task
);
1042 OSBitOrAtomic(P_DEPENDENCY_CAPABLE
, &p
->p_flag
);
1048 IS_64BIT_PROCESS(proc_t p
)
1050 if (p
&& (p
->p_flag
& P_LP64
))
1057 * Locate a process by number
1060 pfind_locked(pid_t pid
)
1070 for (p
= PIDHASH(pid
)->lh_first
; p
!= 0; p
= p
->p_hash
.le_next
) {
1071 if (p
->p_pid
== pid
) {
1073 for (q
= p
->p_hash
.le_next
; q
!= 0; q
= q
->p_hash
.le_next
) {
1074 if ((p
!=q
) && (q
->p_pid
== pid
))
1075 panic("two procs with same pid %p:%p:%d:%d\n", p
, q
, p
->p_pid
, q
->p_pid
);
1085 * Locate a zombie by PID
1087 __private_extern__ proc_t
1095 for (p
= zombproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
)
1096 if (p
->p_pid
== pid
)
1105 * Locate a process group by number
1114 pgrp
= pgfind_internal(pgid
);
1115 if ((pgrp
== NULL
) || ((pgrp
->pg_listflags
& PGRP_FLAG_TERMINATE
) != 0))
1118 pgrp
->pg_refcount
++;
1126 pgfind_internal(pid_t pgid
)
1130 for (pgrp
= PGRPHASH(pgid
)->lh_first
; pgrp
!= 0; pgrp
= pgrp
->pg_hash
.le_next
)
1131 if (pgrp
->pg_id
== pgid
)
1137 pg_rele(struct pgrp
* pgrp
)
1139 if(pgrp
== PGRP_NULL
)
1141 pg_rele_dropref(pgrp
);
1145 pg_rele_dropref(struct pgrp
* pgrp
)
1148 if ((pgrp
->pg_refcount
== 1) && ((pgrp
->pg_listflags
& PGRP_FLAG_TERMINATE
) == PGRP_FLAG_TERMINATE
)) {
1150 pgdelete_dropref(pgrp
);
1154 pgrp
->pg_refcount
--;
1159 session_find_internal(pid_t sessid
)
1161 struct session
*sess
;
1163 for (sess
= SESSHASH(sessid
)->lh_first
; sess
!= 0; sess
= sess
->s_hash
.le_next
)
1164 if (sess
->s_sid
== sessid
)
1171 * Make a new process ready to become a useful member of society by making it
1172 * visible in all the right places and initialize its own lists to empty.
1174 * Parameters: parent The parent of the process to insert
1175 * child The child process to insert
1179 * Notes: Insert a child process into the parents process group, assign
1180 * the child the parent process pointer and PPID of the parent,
1181 * place it on the parents p_children list as a sibling,
1182 * initialize its own child list, place it in the allproc list,
1183 * insert it in the proper hash bucket, and initialize its
1187 pinsertchild(proc_t parent
, proc_t child
)
1191 LIST_INIT(&child
->p_children
);
1192 TAILQ_INIT(&child
->p_evlist
);
1193 child
->p_pptr
= parent
;
1194 child
->p_ppid
= parent
->p_pid
;
1195 child
->p_puniqueid
= parent
->p_uniqueid
;
1197 pg
= proc_pgrp(parent
);
1198 pgrp_add(pg
, parent
, child
);
1203 #if CONFIG_MEMORYSTATUS
1204 memorystatus_add(child
, TRUE
);
1207 parent
->p_childrencnt
++;
1208 LIST_INSERT_HEAD(&parent
->p_children
, child
, p_sibling
);
1210 LIST_INSERT_HEAD(&allproc
, child
, p_list
);
1211 /* mark the completion of proc creation */
1212 child
->p_listflag
&= ~P_LIST_INCREATE
;
1218 * Move p to a new or existing process group (and session)
1220 * Returns: 0 Success
1221 * ESRCH No such process
1224 enterpgrp(proc_t p
, pid_t pgid
, int mksess
)
1227 struct pgrp
*mypgrp
;
1228 struct session
* procsp
;
1230 pgrp
= pgfind(pgid
);
1231 mypgrp
= proc_pgrp(p
);
1232 procsp
= proc_session(p
);
1235 if (pgrp
!= NULL
&& mksess
) /* firewalls */
1236 panic("enterpgrp: setsid into non-empty pgrp");
1237 if (SESS_LEADER(p
, procsp
))
1238 panic("enterpgrp: session leader attempted setpgrp");
1240 if (pgrp
== PGRP_NULL
) {
1241 pid_t savepid
= p
->p_pid
;
1242 proc_t np
= PROC_NULL
;
1247 if (p
->p_pid
!= pgid
)
1248 panic("enterpgrp: new pgrp and pid != pgid");
1250 MALLOC_ZONE(pgrp
, struct pgrp
*, sizeof(struct pgrp
), M_PGRP
,
1253 panic("enterpgrp: M_PGRP zone depleted");
1254 if ((np
= proc_find(savepid
)) == NULL
|| np
!= p
) {
1255 if (np
!= PROC_NULL
)
1257 if (mypgrp
!= PGRP_NULL
)
1259 if (procsp
!= SESSION_NULL
)
1260 session_rele(procsp
);
1261 FREE_ZONE(pgrp
, sizeof(struct pgrp
), M_PGRP
);
1266 struct session
*sess
;
1271 MALLOC_ZONE(sess
, struct session
*,
1272 sizeof(struct session
), M_SESSION
, M_WAITOK
);
1274 panic("enterpgrp: M_SESSION zone depleted");
1276 sess
->s_sid
= p
->p_pid
;
1278 sess
->s_ttyvp
= NULL
;
1279 sess
->s_ttyp
= TTY_NULL
;
1281 sess
->s_listflags
= 0;
1282 sess
->s_ttypgrpid
= NO_PID
;
1283 #if CONFIG_FINE_LOCK_GROUPS
1284 lck_mtx_init(&sess
->s_mlock
, proc_mlock_grp
, proc_lck_attr
);
1286 lck_mtx_init(&sess
->s_mlock
, proc_lck_grp
, proc_lck_attr
);
1288 bcopy(procsp
->s_login
, sess
->s_login
,
1289 sizeof(sess
->s_login
));
1290 OSBitAndAtomic(~((uint32_t)P_CONTROLT
), &p
->p_flag
);
1292 LIST_INSERT_HEAD(SESSHASH(sess
->s_sid
), sess
, s_hash
);
1294 pgrp
->pg_session
= sess
;
1296 if (p
!= current_proc())
1297 panic("enterpgrp: mksession and p != curproc");
1301 pgrp
->pg_session
= procsp
;
1303 if ((pgrp
->pg_session
->s_listflags
& (S_LIST_TERM
| S_LIST_DEAD
)) != 0)
1304 panic("enterpgrp: providing ref to terminating session ");
1305 pgrp
->pg_session
->s_count
++;
1309 #if CONFIG_FINE_LOCK_GROUPS
1310 lck_mtx_init(&pgrp
->pg_mlock
, proc_mlock_grp
, proc_lck_attr
);
1312 lck_mtx_init(&pgrp
->pg_mlock
, proc_lck_grp
, proc_lck_attr
);
1314 LIST_INIT(&pgrp
->pg_members
);
1315 pgrp
->pg_membercnt
= 0;
1318 pgrp
->pg_refcount
= 1;
1319 pgrp
->pg_listflags
= 0;
1320 LIST_INSERT_HEAD(PGRPHASH(pgid
), pgrp
, pg_hash
);
1322 } else if (pgrp
== mypgrp
) {
1326 if (procsp
!= SESSION_NULL
)
1327 session_rele(procsp
);
1331 if (procsp
!= SESSION_NULL
)
1332 session_rele(procsp
);
1334 * Adjust eligibility of affected pgrps to participate in job control.
1335 * Increment eligibility counts before decrementing, otherwise we
1336 * could reach 0 spuriously during the first call.
1338 fixjobc(p
, pgrp
, 1);
1339 fixjobc(p
, mypgrp
, 0);
1341 if(mypgrp
!= PGRP_NULL
)
1343 pgrp_replace(p
, pgrp
);
1350 * remove process from process group
1361 * delete a process group
1364 pgdelete_dropref(struct pgrp
*pgrp
)
1368 struct session
*sessp
;
1372 if (pgrp
->pg_membercnt
!= 0) {
1378 pgrp
->pg_refcount
--;
1379 if ((emptypgrp
== 0) || (pgrp
->pg_membercnt
!= 0)) {
1384 pgrp
->pg_listflags
|= PGRP_FLAG_TERMINATE
;
1386 if (pgrp
->pg_refcount
> 0) {
1391 pgrp
->pg_listflags
|= PGRP_FLAG_DEAD
;
1392 LIST_REMOVE(pgrp
, pg_hash
);
1396 ttyp
= SESSION_TP(pgrp
->pg_session
);
1397 if (ttyp
!= TTY_NULL
) {
1398 if (ttyp
->t_pgrp
== pgrp
) {
1400 /* Re-check after acquiring the lock */
1401 if (ttyp
->t_pgrp
== pgrp
) {
1402 ttyp
->t_pgrp
= NULL
;
1403 pgrp
->pg_session
->s_ttypgrpid
= NO_PID
;
1411 sessp
= pgrp
->pg_session
;
1412 if ((sessp
->s_listflags
& (S_LIST_TERM
| S_LIST_DEAD
)) != 0)
1413 panic("pg_deleteref: manipulating refs of already terminating session");
1414 if (--sessp
->s_count
== 0) {
1415 if ((sessp
->s_listflags
& (S_LIST_TERM
| S_LIST_DEAD
)) != 0)
1416 panic("pg_deleteref: terminating already terminated session");
1417 sessp
->s_listflags
|= S_LIST_TERM
;
1418 ttyp
= SESSION_TP(sessp
);
1419 LIST_REMOVE(sessp
, s_hash
);
1421 if (ttyp
!= TTY_NULL
) {
1423 if (ttyp
->t_session
== sessp
)
1424 ttyp
->t_session
= NULL
;
1428 sessp
->s_listflags
|= S_LIST_DEAD
;
1429 if (sessp
->s_count
!= 0)
1430 panic("pg_deleteref: freeing session in use");
1432 #if CONFIG_FINE_LOCK_GROUPS
1433 lck_mtx_destroy(&sessp
->s_mlock
, proc_mlock_grp
);
1435 lck_mtx_destroy(&sessp
->s_mlock
, proc_lck_grp
);
1437 FREE_ZONE(sessp
, sizeof(struct session
), M_SESSION
);
1440 #if CONFIG_FINE_LOCK_GROUPS
1441 lck_mtx_destroy(&pgrp
->pg_mlock
, proc_mlock_grp
);
1443 lck_mtx_destroy(&pgrp
->pg_mlock
, proc_lck_grp
);
1445 FREE_ZONE(pgrp
, sizeof(*pgrp
), M_PGRP
);
1450 * Adjust pgrp jobc counters when specified process changes process group.
1451 * We count the number of processes in each process group that "qualify"
1452 * the group for terminal job control (those with a parent in a different
1453 * process group of the same session). If that count reaches zero, the
1454 * process group becomes orphaned. Check both the specified process'
1455 * process group and that of its children.
1456 * entering == 0 => p is leaving specified group.
1457 * entering == 1 => p is entering specified group.
1460 fixjob_callback(proc_t p
, void * arg
)
1462 struct fixjob_iterargs
*fp
;
1463 struct pgrp
* pg
, *hispg
;
1464 struct session
* mysession
, *hissess
;
1467 fp
= (struct fixjob_iterargs
*)arg
;
1469 mysession
= fp
->mysession
;
1470 entering
= fp
->entering
;
1472 hispg
= proc_pgrp(p
);
1473 hissess
= proc_session(p
);
1475 if ((hispg
!= pg
) &&
1476 (hissess
== mysession
)) {
1481 } else if (--hispg
->pg_jobc
== 0) {
1487 if (hissess
!= SESSION_NULL
)
1488 session_rele(hissess
);
1489 if (hispg
!= PGRP_NULL
)
1492 return(PROC_RETURNED
);
1496 fixjobc(proc_t p
, struct pgrp
*pgrp
, int entering
)
1498 struct pgrp
*hispgrp
= PGRP_NULL
;
1499 struct session
*hissess
= SESSION_NULL
;
1500 struct session
*mysession
= pgrp
->pg_session
;
1502 struct fixjob_iterargs fjarg
;
1503 boolean_t proc_parent_self
;
1506 * Check if p's parent is current proc, if yes then no need to take
1507 * a ref; calling proc_parent with current proc as parent may
1508 * deadlock if current proc is exiting.
1510 proc_parent_self
= proc_parent_is_currentproc(p
);
1511 if (proc_parent_self
)
1512 parent
= current_proc();
1514 parent
= proc_parent(p
);
1516 if (parent
!= PROC_NULL
) {
1517 hispgrp
= proc_pgrp(parent
);
1518 hissess
= proc_session(parent
);
1519 if (!proc_parent_self
)
1525 * Check p's parent to see whether p qualifies its own process
1526 * group; if so, adjust count for p's process group.
1528 if ((hispgrp
!= pgrp
) &&
1529 (hissess
== mysession
)) {
1534 }else if (--pgrp
->pg_jobc
== 0) {
1541 if (hissess
!= SESSION_NULL
)
1542 session_rele(hissess
);
1543 if (hispgrp
!= PGRP_NULL
)
1547 * Check this process' children to see whether they qualify
1548 * their process groups; if so, adjust counts for children's
1552 fjarg
.mysession
= mysession
;
1553 fjarg
.entering
= entering
;
1554 proc_childrenwalk(p
, fixjob_callback
, &fjarg
);
1558 * A process group has become orphaned;
1559 * if there are any stopped processes in the group,
1560 * hang-up all process in that group.
1563 orphanpg(struct pgrp
* pgrp
)
1567 int count
, pidcount
, i
, alloc_count
;
1569 if (pgrp
== PGRP_NULL
)
1573 for (p
= pgrp
->pg_members
.lh_first
; p
!= 0; p
= p
->p_pglist
.le_next
) {
1574 if (p
->p_stat
== SSTOP
) {
1575 for (p
= pgrp
->pg_members
.lh_first
; p
!= 0;
1576 p
= p
->p_pglist
.le_next
)
1578 break; /* ??? stops after finding one.. */
1584 if (count
> hard_maxproc
)
1585 count
= hard_maxproc
;
1586 alloc_count
= count
* sizeof(pid_t
);
1587 pid_list
= (pid_t
*)kalloc(alloc_count
);
1588 bzero(pid_list
, alloc_count
);
1592 for (p
= pgrp
->pg_members
.lh_first
; p
!= 0;
1593 p
= p
->p_pglist
.le_next
) {
1594 if (p
->p_stat
== SSTOP
) {
1595 for (p
= pgrp
->pg_members
.lh_first
; p
!= 0;
1596 p
= p
->p_pglist
.le_next
) {
1597 pid_list
[pidcount
] = p
->p_pid
;
1599 if (pidcount
>= count
)
1602 break; /* ??? stops after finding one.. */
1611 for (i
= 0; i
< pidcount
; i
++) {
1612 /* No handling or proc0 */
1613 if (pid_list
[i
] == 0)
1615 p
= proc_find(pid_list
[i
]);
1617 proc_transwait(p
, 0);
1620 psignal(p
, SIGCONT
);
1625 kfree(pid_list
, alloc_count
);
1630 proc_is_classic(proc_t p __unused
)
1635 /* XXX Why does this function exist? Need to kill it off... */
1637 current_proc_EXTERNAL(void)
1639 return (current_proc());
1643 proc_is_forcing_hfs_case_sensitivity(proc_t p
)
1645 return (p
->p_vfs_iopolicy
& P_VFS_IOPOLICY_FORCE_HFS_CASE_SENSITIVITY
) ? 1 : 0;
1649 * proc_core_name(name, uid, pid)
1650 * Expand the name described in corefilename, using name, uid, and pid.
1651 * corefilename is a printf-like string, with three format specifiers:
1652 * %N name of process ("name")
1653 * %P process id (pid)
1655 * For example, "%N.core" is the default; they can be disabled completely
1656 * by using "/dev/null", or all core files can be stored in "/cores/%U/%N-%P".
1657 * This is controlled by the sysctl variable kern.corefile (see above).
1659 __private_extern__
int
1660 proc_core_name(const char *name
, uid_t uid
, pid_t pid
, char *cf_name
,
1663 const char *format
, *appendstr
;
1664 char id_buf
[11]; /* Buffer for pid/uid -- max 4B */
1667 if (cf_name
== NULL
)
1670 format
= corefilename
;
1671 for (i
= 0, n
= 0; n
< cf_name_len
&& format
[i
]; i
++) {
1672 switch (format
[i
]) {
1673 case '%': /* Format character */
1675 switch (format
[i
]) {
1679 case 'N': /* process name */
1682 case 'P': /* process id */
1683 snprintf(id_buf
, sizeof(id_buf
), "%u", pid
);
1686 case 'U': /* user id */
1687 snprintf(id_buf
, sizeof(id_buf
), "%u", uid
);
1693 "Unknown format character %c in `%s'\n",
1696 l
= strlen(appendstr
);
1697 if ((n
+ l
) >= cf_name_len
)
1699 bcopy(appendstr
, cf_name
+ n
, l
);
1703 cf_name
[n
++] = format
[i
];
1706 if (format
[i
] != '\0')
1710 log(LOG_ERR
, "pid %ld (%s), uid (%u): corename is too long\n",
1711 (long)pid
, name
, (uint32_t)uid
);
1715 /* Code Signing related routines */
1718 csops(__unused proc_t p
, struct csops_args
*uap
, __unused
int32_t *retval
)
1720 return(csops_internal(uap
->pid
, uap
->ops
, uap
->useraddr
,
1721 uap
->usersize
, USER_ADDR_NULL
));
1725 csops_audittoken(__unused proc_t p
, struct csops_audittoken_args
*uap
, __unused
int32_t *retval
)
1727 if (uap
->uaudittoken
== USER_ADDR_NULL
)
1729 return(csops_internal(uap
->pid
, uap
->ops
, uap
->useraddr
,
1730 uap
->usersize
, uap
->uaudittoken
));
1734 csops_copy_token(void *start
, size_t length
, user_size_t usize
, user_addr_t uaddr
)
1736 char fakeheader
[8] = { 0 };
1739 if (usize
< sizeof(fakeheader
))
1742 /* if no blob, fill in zero header */
1743 if (NULL
== start
) {
1745 length
= sizeof(fakeheader
);
1746 } else if (usize
< length
) {
1747 /* ... if input too short, copy out length of entitlement */
1748 uint32_t length32
= htonl((uint32_t)length
);
1749 memcpy(&fakeheader
[4], &length32
, sizeof(length32
));
1751 error
= copyout(fakeheader
, uaddr
, sizeof(fakeheader
));
1753 return ERANGE
; /* input buffer to short, ERANGE signals that */
1756 return copyout(start
, uaddr
, length
);
1760 csops_internal(pid_t pid
, int ops
, user_addr_t uaddr
, user_size_t usersize
, user_addr_t uaudittoken
)
1762 size_t usize
= (size_t)CAST_DOWN(size_t, usersize
);
1768 unsigned char cdhash
[SHA1_RESULTLEN
];
1769 audit_token_t token
;
1770 unsigned int upid
=0, uidversion
= 0;
1772 forself
= error
= 0;
1775 pid
= proc_selfpid();
1776 if (pid
== proc_selfpid())
1783 case CS_OPS_PIDOFFSET
:
1784 case CS_OPS_ENTITLEMENTS_BLOB
:
1785 case CS_OPS_IDENTITY
:
1787 break; /* not restricted to root */
1789 if (forself
== 0 && kauth_cred_issuser(kauth_cred_get()) != TRUE
)
1794 pt
= proc_find(pid
);
1795 if (pt
== PROC_NULL
)
1799 uidversion
= pt
->p_idversion
;
1800 if (uaudittoken
!= USER_ADDR_NULL
) {
1802 error
= copyin(uaudittoken
, &token
, sizeof(audit_token_t
));
1805 /* verify the audit token pid/idversion matches with proc */
1806 if ((token
.val
[5] != upid
) || (token
.val
[7] != uidversion
)) {
1814 case CS_OPS_MARKINVALID
:
1815 case CS_OPS_MARKHARD
:
1816 case CS_OPS_MARKKILL
:
1817 case CS_OPS_MARKRESTRICT
:
1818 case CS_OPS_SET_STATUS
:
1819 if ((error
= mac_proc_check_set_cs_info(current_proc(), pt
, ops
)))
1823 if ((error
= mac_proc_check_get_cs_info(current_proc(), pt
, ops
)))
1830 case CS_OPS_STATUS
: {
1834 retflags
= pt
->p_csflags
;
1835 if (cs_enforcement(pt
))
1836 retflags
|= CS_ENFORCEMENT
;
1837 if (csproc_get_platform_binary(pt
))
1838 retflags
|= CS_PLATFORM_BINARY
;
1841 if (uaddr
!= USER_ADDR_NULL
)
1842 error
= copyout(&retflags
, uaddr
, sizeof(uint32_t));
1845 case CS_OPS_MARKINVALID
:
1847 if ((pt
->p_csflags
& CS_VALID
) == CS_VALID
) { /* is currently valid */
1848 pt
->p_csflags
&= ~CS_VALID
; /* set invalid */
1849 if ((pt
->p_csflags
& CS_KILL
) == CS_KILL
) {
1850 pt
->p_csflags
|= CS_KILLED
;
1853 printf("CODE SIGNING: marked invalid by pid %d: "
1854 "p=%d[%s] honoring CS_KILL, final status 0x%x\n",
1855 proc_selfpid(), pt
->p_pid
, pt
->p_comm
, pt
->p_csflags
);
1857 psignal(pt
, SIGKILL
);
1865 case CS_OPS_MARKHARD
:
1867 pt
->p_csflags
|= CS_HARD
;
1868 if ((pt
->p_csflags
& CS_VALID
) == 0) {
1869 /* @@@ allow? reject? kill? @@@ */
1877 case CS_OPS_MARKKILL
:
1879 pt
->p_csflags
|= CS_KILL
;
1880 if ((pt
->p_csflags
& CS_VALID
) == 0) {
1882 psignal(pt
, SIGKILL
);
1887 case CS_OPS_PIDOFFSET
:
1888 toff
= pt
->p_textoff
;
1890 error
= copyout(&toff
, uaddr
, sizeof(toff
));
1895 /* pt already holds a reference on its p_textvp */
1897 toff
= pt
->p_textoff
;
1899 if (tvp
== NULLVP
|| usize
!= SHA1_RESULTLEN
) {
1904 error
= vn_getcdhash(tvp
, toff
, cdhash
);
1908 error
= copyout(cdhash
, uaddr
, sizeof (cdhash
));
1913 case CS_OPS_ENTITLEMENTS_BLOB
: {
1919 if ((pt
->p_csflags
& (CS_VALID
| CS_DEBUGGED
)) == 0) {
1925 error
= cs_entitlements_blob_get(pt
, &start
, &length
);
1930 error
= csops_copy_token(start
, length
, usize
, uaddr
);
1933 case CS_OPS_MARKRESTRICT
:
1935 pt
->p_csflags
|= CS_RESTRICT
;
1939 case CS_OPS_SET_STATUS
: {
1942 if (usize
< sizeof(flags
)) {
1947 error
= copyin(uaddr
, &flags
, sizeof(flags
));
1951 /* only allow setting a subset of all code sign flags */
1953 CS_HARD
| CS_EXEC_SET_HARD
|
1954 CS_KILL
| CS_EXEC_SET_KILL
|
1957 CS_ENFORCEMENT
| CS_EXEC_SET_ENFORCEMENT
|
1958 CS_ENTITLEMENTS_VALIDATED
;
1961 if (pt
->p_csflags
& CS_VALID
)
1962 pt
->p_csflags
|= flags
;
1974 if ((pt
->p_csflags
& (CS_VALID
| CS_DEBUGGED
)) == 0) {
1980 error
= cs_blob_get(pt
, &start
, &length
);
1985 error
= csops_copy_token(start
, length
, usize
, uaddr
);
1988 case CS_OPS_IDENTITY
: {
1989 const char *identity
;
1990 uint8_t fakeheader
[8];
1995 * Make identity have a blob header to make it
1996 * easier on userland to guess the identity
1999 if (usize
< sizeof(fakeheader
)) {
2003 memset(fakeheader
, 0, sizeof(fakeheader
));
2006 if ((pt
->p_csflags
& (CS_VALID
| CS_DEBUGGED
)) == 0) {
2012 identity
= cs_identity_get(pt
);
2014 if (identity
== NULL
) {
2019 length
= strlen(identity
) + 1; /* include NUL */
2020 idlen
= htonl(length
+ sizeof(fakeheader
));
2021 memcpy(&fakeheader
[4], &idlen
, sizeof(idlen
));
2023 error
= copyout(fakeheader
, uaddr
, sizeof(fakeheader
));
2027 if (usize
< sizeof(fakeheader
) + length
)
2029 else if (usize
> sizeof(fakeheader
))
2030 error
= copyout(identity
, uaddr
+ sizeof(fakeheader
), length
);
2045 proc_iterate(flags
, callout
, arg
, filterfn
, filterarg
)
2047 int (*callout
)(proc_t
, void *);
2049 int (*filterfn
)(proc_t
, void *);
2054 int count
, pidcount
, alloc_count
, i
, retval
;
2057 if (count
> hard_maxproc
)
2058 count
= hard_maxproc
;
2059 alloc_count
= count
* sizeof(pid_t
);
2060 pid_list
= (pid_t
*)kalloc(alloc_count
);
2061 bzero(pid_list
, alloc_count
);
2068 if (flags
& PROC_ALLPROCLIST
) {
2069 for (p
= allproc
.lh_first
; (p
!= 0); p
= p
->p_list
.le_next
) {
2070 if (p
->p_stat
== SIDL
)
2072 if ( (filterfn
== 0 ) || (filterfn(p
, filterarg
) != 0)) {
2073 pid_list
[pidcount
] = p
->p_pid
;
2075 if (pidcount
>= count
)
2080 if ((pidcount
< count
) && (flags
& PROC_ZOMBPROCLIST
)) {
2081 for (p
= zombproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
) {
2082 if ( (filterfn
== 0 ) || (filterfn(p
, filterarg
) != 0)) {
2083 pid_list
[pidcount
] = p
->p_pid
;
2085 if (pidcount
>= count
)
2095 for (i
= 0; i
< pidcount
; i
++) {
2096 p
= proc_find(pid_list
[i
]);
2098 if ((flags
& PROC_NOWAITTRANS
) == 0)
2099 proc_transwait(p
, 0);
2100 retval
= callout(p
, arg
);
2106 case PROC_RETURNED_DONE
:
2109 case PROC_CLAIMED_DONE
:
2115 } else if (flags
& PROC_ZOMBPROCLIST
) {
2116 p
= proc_find_zombref(pid_list
[i
]);
2117 if (p
!= PROC_NULL
) {
2118 retval
= callout(p
, arg
);
2122 proc_drop_zombref(p
);
2124 case PROC_RETURNED_DONE
:
2125 proc_drop_zombref(p
);
2127 case PROC_CLAIMED_DONE
:
2138 kfree(pid_list
, alloc_count
);
2145 /* This is for iteration in case of trivial non blocking callouts */
2147 proc_scanall(flags
, callout
, arg
)
2149 int (*callout
)(proc_t
, void *);
2159 if (flags
& PROC_ALLPROCLIST
) {
2160 for (p
= allproc
.lh_first
; (p
!= 0); p
= p
->p_list
.le_next
) {
2161 retval
= callout(p
, arg
);
2162 if (retval
== PROC_RETURNED_DONE
)
2166 if (flags
& PROC_ZOMBPROCLIST
) {
2167 for (p
= zombproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
) {
2168 retval
= callout(p
, arg
);
2169 if (retval
== PROC_RETURNED_DONE
)
2183 proc_rebootscan(callout
, arg
, filterfn
, filterarg
)
2184 int (*callout
)(proc_t
, void *);
2186 int (*filterfn
)(proc_t
, void *);
2190 int lockheld
= 0, retval
;
2192 proc_shutdown_exitcount
= 0;
2200 for (p
= allproc
.lh_first
; (p
!= 0); p
= p
->p_list
.le_next
) {
2201 if ( (filterfn
== 0 ) || (filterfn(p
, filterarg
) != 0)) {
2202 p
= proc_ref_locked(p
);
2208 proc_transwait(p
, 0);
2209 retval
= callout(p
, arg
);
2213 case PROC_RETURNED_DONE
:
2214 case PROC_CLAIMED_DONE
:
2218 goto ps_allprocscan
;
2220 } /* allproc walk thru */
2222 if (lockheld
== 1) {
2234 proc_childrenwalk(parent
, callout
, arg
)
2235 struct proc
* parent
;
2236 int (*callout
)(proc_t
, void *);
2239 register struct proc
*p
;
2241 int count
, pidcount
, alloc_count
, i
, retval
;
2244 if (count
> hard_maxproc
)
2245 count
= hard_maxproc
;
2246 alloc_count
= count
* sizeof(pid_t
);
2247 pid_list
= (pid_t
*)kalloc(alloc_count
);
2248 bzero(pid_list
, alloc_count
);
2255 for (p
= parent
->p_children
.lh_first
; (p
!= 0); p
= p
->p_sibling
.le_next
) {
2256 if (p
->p_stat
== SIDL
)
2258 pid_list
[pidcount
] = p
->p_pid
;
2260 if (pidcount
>= count
)
2266 for (i
= 0; i
< pidcount
; i
++) {
2267 p
= proc_find(pid_list
[i
]);
2269 proc_transwait(p
, 0);
2270 retval
= callout(p
, arg
);
2274 case PROC_RETURNED_DONE
:
2276 if (retval
== PROC_RETURNED_DONE
) {
2281 case PROC_CLAIMED_DONE
:
2291 kfree(pid_list
, alloc_count
);
2298 /* PGRP_BLOCKITERATE is not implemented yet */
2300 pgrp_iterate(pgrp
, flags
, callout
, arg
, filterfn
, filterarg
)
2303 int (*callout
)(proc_t
, void *);
2305 int (*filterfn
)(proc_t
, void *);
2310 int count
, pidcount
, i
, alloc_count
;
2313 int dropref
= flags
& PGRP_DROPREF
;
2315 int serialize
= flags
& PGRP_BLOCKITERATE
;
2322 count
= pgrp
->pg_membercnt
+ 10;
2323 if (count
> hard_maxproc
)
2324 count
= hard_maxproc
;
2325 alloc_count
= count
* sizeof(pid_t
);
2326 pid_list
= (pid_t
*)kalloc(alloc_count
);
2327 bzero(pid_list
, alloc_count
);
2330 if (serialize
!= 0) {
2331 while ((pgrp
->pg_listflags
& PGRP_FLAG_ITERABEGIN
) == PGRP_FLAG_ITERABEGIN
) {
2332 pgrp
->pg_listflags
|= PGRP_FLAG_ITERWAIT
;
2333 msleep(&pgrp
->pg_listflags
, &pgrp
->pg_mlock
, 0, "pgrp_iterate", 0);
2335 pgrp
->pg_listflags
|= PGRP_FLAG_ITERABEGIN
;
2341 for (p
= pgrp
->pg_members
.lh_first
; p
!= 0;
2342 p
= p
->p_pglist
.le_next
) {
2343 if ( (filterfn
== 0 ) || (filterfn(p
, filterarg
) != 0)) {
2344 pid_list
[pidcount
] = p
->p_pid
;
2346 if (pidcount
>= count
)
2353 if ((serialize
== 0) && (dropref
!= 0))
2357 for (i
= 0; i
< pidcount
; i
++) {
2358 /* No handling or proc0 */
2359 if (pid_list
[i
] == 0)
2361 p
= proc_find(pid_list
[i
]);
2363 if (p
->p_pgrpid
!= pgid
) {
2367 proc_transwait(p
, 0);
2368 retval
= callout(p
, arg
);
2372 case PROC_RETURNED_DONE
:
2374 if (retval
== PROC_RETURNED_DONE
) {
2379 case PROC_CLAIMED_DONE
:
2388 if (serialize
!= 0) {
2390 pgrp
->pg_listflags
&= ~PGRP_FLAG_ITERABEGIN
;
2391 if ((pgrp
->pg_listflags
& PGRP_FLAG_ITERWAIT
) == PGRP_FLAG_ITERWAIT
) {
2392 pgrp
->pg_listflags
&= ~PGRP_FLAG_ITERWAIT
;
2393 wakeup(&pgrp
->pg_listflags
);
2399 kfree(pid_list
, alloc_count
);
2404 pgrp_add(struct pgrp
* pgrp
, struct proc
* parent
, struct proc
* child
)
2407 child
->p_pgrp
= pgrp
;
2408 child
->p_pgrpid
= pgrp
->pg_id
;
2409 child
->p_listflag
|= P_LIST_INPGRP
;
2411 * When pgrp is being freed , a process can still
2412 * request addition using setpgid from bash when
2413 * login is terminated (login cycler) return ESRCH
2414 * Safe to hold lock due to refcount on pgrp
2416 if ((pgrp
->pg_listflags
& (PGRP_FLAG_TERMINATE
| PGRP_FLAG_DEAD
)) == PGRP_FLAG_TERMINATE
) {
2417 pgrp
->pg_listflags
&= ~PGRP_FLAG_TERMINATE
;
2420 if ((pgrp
->pg_listflags
& PGRP_FLAG_DEAD
) == PGRP_FLAG_DEAD
)
2421 panic("pgrp_add : pgrp is dead adding process");
2425 pgrp
->pg_membercnt
++;
2426 if ( parent
!= PROC_NULL
) {
2427 LIST_INSERT_AFTER(parent
, child
, p_pglist
);
2429 LIST_INSERT_HEAD(&pgrp
->pg_members
, child
, p_pglist
);
2434 if (((pgrp
->pg_listflags
& (PGRP_FLAG_TERMINATE
| PGRP_FLAG_DEAD
)) == PGRP_FLAG_TERMINATE
) && (pgrp
->pg_membercnt
!= 0)) {
2435 pgrp
->pg_listflags
&= ~PGRP_FLAG_TERMINATE
;
2441 pgrp_remove(struct proc
* p
)
2448 #if __PROC_INTERNAL_DEBUG
2449 if ((p
->p_listflag
& P_LIST_INPGRP
) == 0)
2450 panic("removing from pglist but no named ref\n");
2452 p
->p_pgrpid
= PGRPID_DEAD
;
2453 p
->p_listflag
&= ~P_LIST_INPGRP
;
2457 if (pg
== PGRP_NULL
)
2458 panic("pgrp_remove: pg is NULL");
2462 if (pg
->pg_membercnt
< 0)
2463 panic("pgprp: -ve membercnt pgprp:%p p:%p\n",pg
, p
);
2465 LIST_REMOVE(p
, p_pglist
);
2466 if (pg
->pg_members
.lh_first
== 0) {
2468 pgdelete_dropref(pg
);
2476 /* cannot use proc_pgrp as it maybe stalled */
2478 pgrp_replace(struct proc
* p
, struct pgrp
* newpg
)
2480 struct pgrp
* oldpg
;
2486 while ((p
->p_listflag
& P_LIST_PGRPTRANS
) == P_LIST_PGRPTRANS
) {
2487 p
->p_listflag
|= P_LIST_PGRPTRWAIT
;
2488 (void)msleep(&p
->p_pgrpid
, proc_list_mlock
, 0, "proc_pgrp", 0);
2491 p
->p_listflag
|= P_LIST_PGRPTRANS
;
2494 if (oldpg
== PGRP_NULL
)
2495 panic("pgrp_replace: oldpg NULL");
2496 oldpg
->pg_refcount
++;
2497 #if __PROC_INTERNAL_DEBUG
2498 if ((p
->p_listflag
& P_LIST_INPGRP
) == 0)
2499 panic("removing from pglist but no named ref\n");
2501 p
->p_pgrpid
= PGRPID_DEAD
;
2502 p
->p_listflag
&= ~P_LIST_INPGRP
;
2508 oldpg
->pg_membercnt
--;
2509 if (oldpg
->pg_membercnt
< 0)
2510 panic("pgprp: -ve membercnt pgprp:%p p:%p\n",oldpg
, p
);
2511 LIST_REMOVE(p
, p_pglist
);
2512 if (oldpg
->pg_members
.lh_first
== 0) {
2514 pgdelete_dropref(oldpg
);
2522 p
->p_pgrpid
= newpg
->pg_id
;
2523 p
->p_listflag
|= P_LIST_INPGRP
;
2525 * When pgrp is being freed , a process can still
2526 * request addition using setpgid from bash when
2527 * login is terminated (login cycler) return ESRCH
2528 * Safe to hold lock due to refcount on pgrp
2530 if ((newpg
->pg_listflags
& (PGRP_FLAG_TERMINATE
| PGRP_FLAG_DEAD
)) == PGRP_FLAG_TERMINATE
) {
2531 newpg
->pg_listflags
&= ~PGRP_FLAG_TERMINATE
;
2534 if ((newpg
->pg_listflags
& PGRP_FLAG_DEAD
) == PGRP_FLAG_DEAD
)
2535 panic("pgrp_add : pgrp is dead adding process");
2539 newpg
->pg_membercnt
++;
2540 LIST_INSERT_HEAD(&newpg
->pg_members
, p
, p_pglist
);
2544 if (((newpg
->pg_listflags
& (PGRP_FLAG_TERMINATE
| PGRP_FLAG_DEAD
)) == PGRP_FLAG_TERMINATE
) && (newpg
->pg_membercnt
!= 0)) {
2545 newpg
->pg_listflags
&= ~PGRP_FLAG_TERMINATE
;
2548 p
->p_listflag
&= ~P_LIST_PGRPTRANS
;
2549 if ((p
->p_listflag
& P_LIST_PGRPTRWAIT
) == P_LIST_PGRPTRWAIT
) {
2550 p
->p_listflag
&= ~P_LIST_PGRPTRWAIT
;
2551 wakeup(&p
->p_pgrpid
);
2558 pgrp_lock(struct pgrp
* pgrp
)
2560 lck_mtx_lock(&pgrp
->pg_mlock
);
2564 pgrp_unlock(struct pgrp
* pgrp
)
2566 lck_mtx_unlock(&pgrp
->pg_mlock
);
2570 session_lock(struct session
* sess
)
2572 lck_mtx_lock(&sess
->s_mlock
);
2577 session_unlock(struct session
* sess
)
2579 lck_mtx_unlock(&sess
->s_mlock
);
2591 while ((p
->p_listflag
& P_LIST_PGRPTRANS
) == P_LIST_PGRPTRANS
) {
2592 p
->p_listflag
|= P_LIST_PGRPTRWAIT
;
2593 (void)msleep(&p
->p_pgrpid
, proc_list_mlock
, 0, "proc_pgrp", 0);
2598 assert(pgrp
!= NULL
);
2600 if (pgrp
!= PGRP_NULL
) {
2601 pgrp
->pg_refcount
++;
2602 if ((pgrp
->pg_listflags
& (PGRP_FLAG_TERMINATE
| PGRP_FLAG_DEAD
)) != 0)
2603 panic("proc_pgrp: ref being povided for dead pgrp");
2612 tty_pgrp(struct tty
* tp
)
2614 struct pgrp
* pg
= PGRP_NULL
;
2619 if (pg
!= PGRP_NULL
) {
2620 if ((pg
->pg_listflags
& PGRP_FLAG_DEAD
) != 0)
2621 panic("tty_pgrp: ref being povided for dead pgrp");
2630 proc_session(proc_t p
)
2632 struct session
* sess
= SESSION_NULL
;
2635 return(SESSION_NULL
);
2639 /* wait during transitions */
2640 while ((p
->p_listflag
& P_LIST_PGRPTRANS
) == P_LIST_PGRPTRANS
) {
2641 p
->p_listflag
|= P_LIST_PGRPTRWAIT
;
2642 (void)msleep(&p
->p_pgrpid
, proc_list_mlock
, 0, "proc_pgrp", 0);
2645 if ((p
->p_pgrp
!= PGRP_NULL
) && ((sess
= p
->p_pgrp
->pg_session
) != SESSION_NULL
)) {
2646 if ((sess
->s_listflags
& (S_LIST_TERM
| S_LIST_DEAD
)) != 0)
2647 panic("proc_session:returning sesssion ref on terminating session");
2655 session_rele(struct session
*sess
)
2658 if (--sess
->s_count
== 0) {
2659 if ((sess
->s_listflags
& (S_LIST_TERM
| S_LIST_DEAD
)) != 0)
2660 panic("session_rele: terminating already terminated session");
2661 sess
->s_listflags
|= S_LIST_TERM
;
2662 LIST_REMOVE(sess
, s_hash
);
2663 sess
->s_listflags
|= S_LIST_DEAD
;
2664 if (sess
->s_count
!= 0)
2665 panic("session_rele: freeing session in use");
2667 #if CONFIG_FINE_LOCK_GROUPS
2668 lck_mtx_destroy(&sess
->s_mlock
, proc_mlock_grp
);
2670 lck_mtx_destroy(&sess
->s_mlock
, proc_lck_grp
);
2672 FREE_ZONE(sess
, sizeof(struct session
), M_SESSION
);
2678 proc_transstart(proc_t p
, int locked
, int non_blocking
)
2682 while ((p
->p_lflag
& P_LINTRANSIT
) == P_LINTRANSIT
) {
2683 if (((p
->p_lflag
& P_LTRANSCOMMIT
) == P_LTRANSCOMMIT
) || non_blocking
) {
2688 p
->p_lflag
|= P_LTRANSWAIT
;
2689 msleep(&p
->p_lflag
, &p
->p_mlock
, 0, "proc_signstart", NULL
);
2691 p
->p_lflag
|= P_LINTRANSIT
;
2692 p
->p_transholder
= current_thread();
2699 proc_transcommit(proc_t p
, int locked
)
2704 assert ((p
->p_lflag
& P_LINTRANSIT
) == P_LINTRANSIT
);
2705 assert (p
->p_transholder
== current_thread());
2706 p
->p_lflag
|= P_LTRANSCOMMIT
;
2708 if ((p
->p_lflag
& P_LTRANSWAIT
) == P_LTRANSWAIT
) {
2709 p
->p_lflag
&= ~P_LTRANSWAIT
;
2710 wakeup(&p
->p_lflag
);
2717 proc_transend(proc_t p
, int locked
)
2722 p
->p_lflag
&= ~( P_LINTRANSIT
| P_LTRANSCOMMIT
);
2723 p
->p_transholder
= NULL
;
2725 if ((p
->p_lflag
& P_LTRANSWAIT
) == P_LTRANSWAIT
) {
2726 p
->p_lflag
&= ~P_LTRANSWAIT
;
2727 wakeup(&p
->p_lflag
);
2734 proc_transwait(proc_t p
, int locked
)
2738 while ((p
->p_lflag
& P_LINTRANSIT
) == P_LINTRANSIT
) {
2739 if ((p
->p_lflag
& P_LTRANSCOMMIT
) == P_LTRANSCOMMIT
&& current_proc() == p
) {
2744 p
->p_lflag
|= P_LTRANSWAIT
;
2745 msleep(&p
->p_lflag
, &p
->p_mlock
, 0, "proc_signstart", NULL
);
2753 proc_klist_lock(void)
2755 lck_mtx_lock(proc_klist_mlock
);
2759 proc_klist_unlock(void)
2761 lck_mtx_unlock(proc_klist_mlock
);
2765 proc_knote(struct proc
* p
, long hint
)
2768 KNOTE(&p
->p_klist
, hint
);
2769 proc_klist_unlock();
2773 proc_knote_drain(struct proc
*p
)
2775 struct knote
*kn
= NULL
;
2778 * Clear the proc's klist to avoid references after the proc is reaped.
2781 while ((kn
= SLIST_FIRST(&p
->p_klist
))) {
2782 kn
->kn_ptr
.p_proc
= PROC_NULL
;
2783 KNOTE_DETACH(&p
->p_klist
, kn
);
2785 proc_klist_unlock();
2789 proc_setregister(proc_t p
)
2792 p
->p_lflag
|= P_LREGISTER
;
2797 proc_resetregister(proc_t p
)
2800 p
->p_lflag
&= ~P_LREGISTER
;
2805 proc_pgrpid(proc_t p
)
2813 return current_proc()->p_pgrpid
;
2817 /* return control and action states */
2819 proc_getpcontrol(int pid
, int * pcontrolp
)
2826 if (pcontrolp
!= NULL
)
2827 *pcontrolp
= p
->p_pcaction
;
2834 proc_dopcontrol(proc_t p
)
2840 pcontrol
= PROC_CONTROL_STATE(p
);
2842 if (PROC_ACTION_STATE(p
) == 0) {
2845 PROC_SETACTION_STATE(p
);
2847 printf("low swap: throttling pid %d (%s)\n", p
->p_pid
, p
->p_comm
);
2851 PROC_SETACTION_STATE(p
);
2853 printf("low swap: suspending pid %d (%s)\n", p
->p_pid
, p
->p_comm
);
2854 task_suspend(p
->task
);
2858 PROC_SETACTION_STATE(p
);
2860 printf("low swap: killing pid %d (%s)\n", p
->p_pid
, p
->p_comm
);
2861 psignal(p
, SIGKILL
);
2871 return(PROC_RETURNED
);
2876 * Resume a throttled or suspended process. This is an internal interface that's only
2877 * used by the user level code that presents the GUI when we run out of swap space and
2878 * hence is restricted to processes with superuser privileges.
2882 proc_resetpcontrol(int pid
)
2887 proc_t self
= current_proc();
2889 /* if the process has been validated to handle resource control or root is valid one */
2890 if (((self
->p_lflag
& P_LVMRSRCOWNER
) == 0) && (error
= suser(kauth_cred_get(), 0)))
2899 pcontrol
= PROC_CONTROL_STATE(p
);
2901 if(PROC_ACTION_STATE(p
) !=0) {
2904 PROC_RESETACTION_STATE(p
);
2906 printf("low swap: unthrottling pid %d (%s)\n", p
->p_pid
, p
->p_comm
);
2910 PROC_RESETACTION_STATE(p
);
2912 printf("low swap: resuming pid %d (%s)\n", p
->p_pid
, p
->p_comm
);
2913 task_resume(p
->task
);
2918 PROC_SETACTION_STATE(p
);
2920 printf("low swap: attempt to unkill pid %d (%s) ignored\n", p
->p_pid
, p
->p_comm
);
2936 struct no_paging_space
2938 uint64_t pcs_max_size
;
2939 uint64_t pcs_uniqueid
;
2942 uint64_t pcs_total_size
;
2944 uint64_t npcs_max_size
;
2945 uint64_t npcs_uniqueid
;
2947 int npcs_proc_count
;
2948 uint64_t npcs_total_size
;
2950 int apcs_proc_count
;
2951 uint64_t apcs_total_size
;
2956 proc_pcontrol_filter(proc_t p
, void *arg
)
2958 struct no_paging_space
*nps
;
2959 uint64_t compressed
;
2961 nps
= (struct no_paging_space
*)arg
;
2963 compressed
= get_task_compressed(p
->task
);
2965 if (PROC_CONTROL_STATE(p
)) {
2966 if (PROC_ACTION_STATE(p
) == 0) {
2967 if (compressed
> nps
->pcs_max_size
) {
2968 nps
->pcs_pid
= p
->p_pid
;
2969 nps
->pcs_uniqueid
= p
->p_uniqueid
;
2970 nps
->pcs_max_size
= compressed
;
2972 nps
->pcs_total_size
+= compressed
;
2973 nps
->pcs_proc_count
++;
2975 nps
->apcs_total_size
+= compressed
;
2976 nps
->apcs_proc_count
++;
2979 if (compressed
> nps
->npcs_max_size
) {
2980 nps
->npcs_pid
= p
->p_pid
;
2981 nps
->npcs_uniqueid
= p
->p_uniqueid
;
2982 nps
->npcs_max_size
= compressed
;
2984 nps
->npcs_total_size
+= compressed
;
2985 nps
->npcs_proc_count
++;
2993 proc_pcontrol_null(__unused proc_t p
, __unused
void *arg
)
2995 return(PROC_RETURNED
);
3000 * Deal with the low on compressor pool space condition... this function
3001 * gets called when we are approaching the limits of the compressor pool or
3002 * we are unable to create a new swap file.
3003 * Since this eventually creates a memory deadlock situtation, we need to take action to free up
3004 * memory resources (both compressed and uncompressed) in order to prevent the system from hanging completely.
3005 * There are 2 categories of processes to deal with. Those that have an action
3006 * associated with them by the task itself and those that do not. Actionable
3007 * tasks can have one of three categories specified: ones that
3008 * can be killed immediately, ones that should be suspended, and ones that should
3009 * be throttled. Processes that do not have an action associated with them are normally
3010 * ignored unless they are utilizing such a large percentage of the compressor pool (currently 50%)
3011 * that only by killing them can we hope to put the system back into a usable state.
3014 #define NO_PAGING_SPACE_DEBUG 0
3016 extern uint64_t vm_compressor_pages_compressed(void);
3018 struct timeval last_no_space_action
= {0, 0};
3021 no_paging_space_action()
3024 struct no_paging_space nps
;
3028 * Throttle how often we come through here. Once every 5 seconds should be plenty.
3032 if (now
.tv_sec
<= last_no_space_action
.tv_sec
+ 5)
3036 * Examine all processes and find the biggest (biggest is based on the number of pages this
3037 * task has in the compressor pool) that has been marked to have some action
3038 * taken when swap space runs out... we also find the biggest that hasn't been marked for
3041 * If the biggest non-actionable task is over the "dangerously big" threashold (currently 50% of
3042 * the total number of pages held by the compressor, we go ahead and kill it since no other task
3043 * can have any real effect on the situation. Otherwise, we go after the actionable process.
3045 bzero(&nps
, sizeof(nps
));
3047 proc_iterate(PROC_ALLPROCLIST
, proc_pcontrol_null
, (void *)NULL
, proc_pcontrol_filter
, (void *)&nps
);
3049 #if NO_PAGING_SPACE_DEBUG
3050 printf("low swap: npcs_proc_count = %d, npcs_total_size = %qd, npcs_max_size = %qd\n",
3051 nps
.npcs_proc_count
, nps
.npcs_total_size
, nps
.npcs_max_size
);
3052 printf("low swap: pcs_proc_count = %d, pcs_total_size = %qd, pcs_max_size = %qd\n",
3053 nps
.pcs_proc_count
, nps
.pcs_total_size
, nps
.pcs_max_size
);
3054 printf("low swap: apcs_proc_count = %d, apcs_total_size = %qd\n",
3055 nps
.apcs_proc_count
, nps
.apcs_total_size
);
3057 if (nps
.npcs_max_size
> (vm_compressor_pages_compressed() * 50) / 100) {
3059 * for now we'll knock out any task that has more then 50% of the pages
3060 * held by the compressor
3062 if ((p
= proc_find(nps
.npcs_pid
)) != PROC_NULL
) {
3064 if (nps
.npcs_uniqueid
== p
->p_uniqueid
) {
3066 * verify this is still the same process
3067 * in case the proc exited and the pid got reused while
3068 * we were finishing the proc_iterate and getting to this point
3070 last_no_space_action
= now
;
3072 printf("low swap: killing pid %d (%s)\n", p
->p_pid
, p
->p_comm
);
3073 psignal(p
, SIGKILL
);
3084 if (nps
.pcs_max_size
> 0) {
3085 if ((p
= proc_find(nps
.pcs_pid
)) != PROC_NULL
) {
3087 if (nps
.pcs_uniqueid
== p
->p_uniqueid
) {
3089 * verify this is still the same process
3090 * in case the proc exited and the pid got reused while
3091 * we were finishing the proc_iterate and getting to this point
3093 last_no_space_action
= now
;
3105 last_no_space_action
= now
;
3107 printf("low swap: unable to find any eligible processes to take action on\n");
3113 proc_trace_log(__unused proc_t p
, struct proc_trace_log_args
*uap
, __unused
int *retval
)
3116 proc_t target_proc
= PROC_NULL
;
3117 pid_t target_pid
= uap
->pid
;
3118 uint64_t target_uniqueid
= uap
->uniqueid
;
3119 task_t target_task
= NULL
;
3121 if (priv_check_cred(kauth_cred_get(), PRIV_PROC_TRACE_INSPECT
, 0)) {
3125 target_proc
= proc_find(target_pid
);
3126 if (target_proc
!= PROC_NULL
) {
3127 if (target_uniqueid
!= proc_uniqueid(target_proc
)) {
3132 target_task
= proc_task(target_proc
);
3133 if (task_send_trace_memory(target_task
, target_pid
, target_uniqueid
)) {
3141 if (target_proc
!= PROC_NULL
)
3142 proc_rele(target_proc
);
3146 #if VM_SCAN_FOR_SHADOW_CHAIN
3147 extern int vm_map_shadow_max(vm_map_t map
);
3148 int proc_shadow_max(void);
3149 int proc_shadow_max(void)
3158 for (p
= allproc
.lh_first
; (p
!= 0); p
= p
->p_list
.le_next
) {
3159 if (p
->p_stat
== SIDL
)
3165 map
= get_task_map(task
);
3169 retval
= vm_map_shadow_max(map
);
3177 #endif /* VM_SCAN_FOR_SHADOW_CHAIN */
3179 void proc_set_responsible_pid(proc_t target_proc
, pid_t responsible_pid
);
3180 void proc_set_responsible_pid(proc_t target_proc
, pid_t responsible_pid
)
3182 if (target_proc
!= NULL
) {
3183 target_proc
->p_responsible_pid
= responsible_pid
;
3189 proc_chrooted(proc_t p
)
3195 retval
= (p
->p_fd
->fd_rdir
!= NULL
) ? 1 : 0;