]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/task.c
xnu-3248.30.4.tar.gz
[apple/xnu.git] / osfmk / kern / task.c
CommitLineData
1c79356b 1/*
3e170ce0 2 * Copyright (c) 2000-2010, 2015 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
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.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * @OSF_FREE_COPYRIGHT@
30 */
31/*
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University
34 * All Rights Reserved.
35 *
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
41 *
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56/*
57 * File: kern/task.c
58 * Author: Avadis Tevanian, Jr., Michael Wayne Young, David Golub,
59 * David Black
60 *
61 * Task management primitives implementation.
62 */
63/*
64 * Copyright (c) 1993 The University of Utah and
65 * the Computer Systems Laboratory (CSL). All rights reserved.
66 *
67 * Permission to use, copy, modify and distribute this software and its
68 * documentation is hereby granted, provided that both the copyright
69 * notice and this permission notice appear in all copies of the
70 * software, derivative works or modified versions, and any portions
71 * thereof, and that both notices appear in supporting documentation.
72 *
73 * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
74 * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
75 * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
76 *
77 * CSL requests users of this software to return to csl-dist@cs.utah.edu any
78 * improvements that they make and grant CSL redistribution rights.
79 *
80 */
2d21ac55
A
81/*
82 * NOTICE: This file was modified by McAfee Research in 2004 to introduce
83 * support for mandatory and extensible security protections. This notice
84 * is included in support of clause 2.2 (b) of the Apple Public License,
85 * Version 2.0.
86 * Copyright (c) 2005 SPARTA, Inc.
87 */
1c79356b 88
91447636 89#include <mach/mach_types.h>
1c79356b 90#include <mach/boolean.h>
91447636 91#include <mach/host_priv.h>
1c79356b
A
92#include <mach/machine/vm_types.h>
93#include <mach/vm_param.h>
3e170ce0 94#include <mach/mach_vm.h>
1c79356b
A
95#include <mach/semaphore.h>
96#include <mach/task_info.h>
97#include <mach/task_special_ports.h>
91447636 98
fe8ab488 99#include <ipc/ipc_importance.h>
91447636 100#include <ipc/ipc_types.h>
1c79356b
A
101#include <ipc/ipc_space.h>
102#include <ipc/ipc_entry.h>
39236c6e 103#include <ipc/ipc_hash.h>
91447636
A
104
105#include <kern/kern_types.h>
1c79356b
A
106#include <kern/mach_param.h>
107#include <kern/misc_protos.h>
108#include <kern/task.h>
109#include <kern/thread.h>
fe8ab488 110#include <kern/coalition.h>
1c79356b
A
111#include <kern/zalloc.h>
112#include <kern/kalloc.h>
3e170ce0 113#include <kern/kern_cdata.h>
1c79356b
A
114#include <kern/processor.h>
115#include <kern/sched_prim.h> /* for thread_wakeup */
1c79356b 116#include <kern/ipc_tt.h>
1c79356b 117#include <kern/host.h>
91447636
A
118#include <kern/clock.h>
119#include <kern/timer.h>
1c79356b
A
120#include <kern/assert.h>
121#include <kern/sync_lock.h>
2d21ac55 122#include <kern/affinity.h>
39236c6e 123#include <kern/exc_resource.h>
3e170ce0
A
124#include <kern/machine.h>
125#include <corpses/task_corpse.h>
39236c6e
A
126#if CONFIG_TELEMETRY
127#include <kern/telemetry.h>
128#endif
91447636
A
129
130#include <vm/pmap.h>
131#include <vm/vm_map.h>
132#include <vm/vm_kern.h> /* for kernel_map, ipc_kernel_map */
133#include <vm/vm_pageout.h>
2d21ac55 134#include <vm/vm_protos.h>
39236c6e 135#include <vm/vm_purgeable_internal.h>
91447636 136
39236c6e 137#include <sys/resource.h>
3e170ce0
A
138#include <sys/signalvar.h> /* for coredump */
139
1c79356b
A
140/*
141 * Exported interfaces
142 */
143
144#include <mach/task_server.h>
145#include <mach/mach_host_server.h>
146#include <mach/host_security_server.h>
91447636
A
147#include <mach/mach_port_server.h>
148
2d21ac55
A
149#include <vm/vm_shared_region.h>
150
39236c6e
A
151#include <libkern/OSDebug.h>
152#include <libkern/OSAtomic.h>
153
fe8ab488
A
154#if CONFIG_ATM
155#include <atm/atm_internal.h>
156#endif
157
158#include <kern/sfi.h>
159
160#if KPERF
161extern int kpc_force_all_ctrs(task_t, int);
162#endif
163
a1c7dba1
A
164uint32_t qos_override_mode;
165
b0d623f7
A
166task_t kernel_task;
167zone_t task_zone;
168lck_attr_t task_lck_attr;
169lck_grp_t task_lck_grp;
170lck_grp_attr_t task_lck_grp_attr;
171
15129b1c
A
172/* Flag set by core audio when audio is playing. Used to stifle EXC_RESOURCE generation when active. */
173int audio_active = 0;
174
6d2010ae
A
175zinfo_usage_store_t tasks_tkm_private;
176zinfo_usage_store_t tasks_tkm_shared;
177
4b17d6b6 178/* A container to accumulate statistics for expired tasks */
39236c6e
A
179expired_task_statistics_t dead_task_statistics;
180lck_spin_t dead_task_statistics_lock;
4b17d6b6 181
fe8ab488
A
182ledger_template_t task_ledger_template = NULL;
183
184struct _task_ledger_indices task_ledgers __attribute__((used)) =
3e170ce0 185 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
fe8ab488
A
186 { 0 /* initialized at runtime */},
187#ifdef CONFIG_BANK
188 -1, -1,
189#endif
190 };
191
4bd07ac2
A
192/* System sleep state */
193boolean_t tasks_suspend_state;
194
195
316670eb 196void init_task_ledgers(void);
39236c6e
A
197void task_footprint_exceeded(int warning, __unused const void *param0, __unused const void *param1);
198void task_wakeups_rate_exceeded(int warning, __unused const void *param0, __unused const void *param1);
199void __attribute__((noinline)) THIS_PROCESS_IS_CAUSING_TOO_MANY_WAKEUPS__SENDING_EXC_RESOURCE(void);
3e170ce0 200void __attribute__((noinline)) PROC_CROSSED_HIGH_WATERMARK__SEND_EXC_RESOURCE_AND_SUSPEND(int max_footprint_mb);
39236c6e
A
201
202kern_return_t task_suspend_internal(task_t);
203kern_return_t task_resume_internal(task_t);
3e170ce0
A
204static kern_return_t task_start_halt_locked(task_t task, boolean_t should_mark_corpse);
205
39236c6e
A
206
207void proc_init_cpumon_params(void);
3e170ce0 208extern kern_return_t exception_deliver(thread_t, exception_type_t, mach_exception_data_t, mach_msg_type_number_t, struct exception_action *, lck_mtx_t *);
39236c6e
A
209
210// Warn tasks when they hit 80% of their memory limit.
211#define PHYS_FOOTPRINT_WARNING_LEVEL 80
212
213#define TASK_WAKEUPS_MONITOR_DEFAULT_LIMIT 150 /* wakeups per second */
214#define TASK_WAKEUPS_MONITOR_DEFAULT_INTERVAL 300 /* in seconds. */
215
216/*
217 * Level (in terms of percentage of the limit) at which the wakeups monitor triggers telemetry.
218 *
219 * (ie when the task's wakeups rate exceeds 70% of the limit, start taking user
220 * stacktraces, aka micro-stackshots)
221 */
222#define TASK_WAKEUPS_MONITOR_DEFAULT_USTACKSHOTS_TRIGGER 70
223
224int task_wakeups_monitor_interval; /* In seconds. Time period over which wakeups rate is observed */
225int task_wakeups_monitor_rate; /* In hz. Maximum allowable wakeups per task before EXC_RESOURCE is sent */
226
227int task_wakeups_monitor_ustackshots_trigger_pct; /* Percentage. Level at which we start gathering telemetry. */
316670eb 228
39236c6e 229int disable_exc_resource; /* Global override to supress EXC_RESOURCE for resource monitor violations. */
316670eb 230
3e170ce0
A
231ledger_amount_t max_task_footprint = 0; /* Per-task limit on physical memory consumption in bytes */
232int max_task_footprint_mb = 0; /* Per-task limit on physical memory consumption in megabytes */
233
fe8ab488
A
234#if MACH_ASSERT
235int pmap_ledgers_panic = 1;
236#endif /* MACH_ASSERT */
237
b0d623f7 238int task_max = CONFIG_TASK_MAX; /* Max number of tasks */
1c79356b 239
39236c6e
A
240int hwm_user_cores = 0; /* high watermark violations generate user core files */
241
242#ifdef MACH_BSD
243extern void proc_getexecutableuuid(void *, unsigned char *, unsigned long);
244extern int proc_pid(struct proc *p);
245extern int proc_selfpid(void);
246extern char *proc_name_address(struct proc *p);
3e170ce0 247extern uint64_t get_dispatchqueue_offset_from_proc(void *);
39236c6e 248#if CONFIG_JETSAM
3e170ce0 249extern void proc_memstat_terminated(struct proc* p, boolean_t set);
39236c6e
A
250extern void memorystatus_on_ledger_footprint_exceeded(int warning, const int max_footprint_mb);
251#endif
252#endif
fe8ab488
A
253#if MACH_ASSERT
254extern int pmap_ledgers_panic;
255#endif /* MACH_ASSERT */
6d2010ae 256
1c79356b
A
257/* Forwards */
258
259void task_hold_locked(
260 task_t task);
261void task_wait_locked(
316670eb
A
262 task_t task,
263 boolean_t until_not_runnable);
1c79356b
A
264void task_release_locked(
265 task_t task);
1c79356b
A
266void task_free(
267 task_t task );
268void task_synchronizer_destroy_all(
269 task_t task);
1c79356b 270
b0d623f7
A
271int check_for_tasksuspend(
272 task_t task);
273
55e303ae
A
274void
275task_backing_store_privileged(
276 task_t task)
277{
278 task_lock(task);
279 task->priv_flags |= VM_BACKING_STORE_PRIV;
280 task_unlock(task);
281 return;
282}
283
91447636
A
284
285void
286task_set_64bit(
287 task_t task,
288 boolean_t is64bit)
289{
fe8ab488 290#if defined(__i386__) || defined(__x86_64__) || defined(__arm64__)
2d21ac55 291 thread_t thread;
fe8ab488 292#endif /* defined(__i386__) || defined(__x86_64__) || defined(__arm64__) */
39236c6e
A
293
294 task_lock(task);
0c530ab8
A
295
296 if (is64bit) {
2d21ac55 297 if (task_has_64BitAddr(task))
39236c6e 298 goto out;
91447636 299 task_set_64BitAddr(task);
91447636 300 } else {
2d21ac55 301 if ( !task_has_64BitAddr(task))
39236c6e 302 goto out;
91447636 303 task_clear_64BitAddr(task);
91447636 304 }
0c530ab8
A
305 /* FIXME: On x86, the thread save state flavor can diverge from the
306 * task's 64-bit feature flag due to the 32-bit/64-bit register save
307 * state dichotomy. Since we can be pre-empted in this interval,
308 * certain routines may observe the thread as being in an inconsistent
309 * state with respect to its task's 64-bitness.
310 */
39236c6e 311
fe8ab488 312#if defined(__i386__) || defined(__x86_64__) || defined(__arm64__)
0c530ab8 313 queue_iterate(&task->threads, thread, thread_t, task_threads) {
b0d623f7 314 thread_mtx_lock(thread);
2d21ac55 315 machine_thread_switch_addrmode(thread);
b0d623f7 316 thread_mtx_unlock(thread);
0c530ab8 317 }
fe8ab488 318#endif /* defined(__i386__) || defined(__x86_64__) || defined(__arm64__) */
39236c6e
A
319
320out:
b0d623f7 321 task_unlock(task);
91447636
A
322}
323
b0d623f7
A
324
325void
326task_set_dyld_info(task_t task, mach_vm_address_t addr, mach_vm_size_t size)
327{
328 task_lock(task);
329 task->all_image_info_addr = addr;
330 task->all_image_info_size = size;
331 task_unlock(task);
332}
333
fe8ab488
A
334void
335task_atm_reset(__unused task_t task) {
336
337#if CONFIG_ATM
338 if (task->atm_context != NULL) {
339 atm_task_descriptor_destroy(task->atm_context);
340 task->atm_context = NULL;
341 }
342#endif
343
344}
345
39236c6e
A
346#if TASK_REFERENCE_LEAK_DEBUG
347#include <kern/btlog.h>
348
349decl_simple_lock_data(static,task_ref_lock);
350static btlog_t *task_ref_btlog;
351#define TASK_REF_OP_INCR 0x1
352#define TASK_REF_OP_DECR 0x2
353
354#define TASK_REF_BTDEPTH 7
355
356static void
357task_ref_lock_lock(void *context)
358{
359 simple_lock((simple_lock_t)context);
360}
361static void
362task_ref_lock_unlock(void *context)
363{
364 simple_unlock((simple_lock_t)context);
365}
366
367void
368task_reference_internal(task_t task)
369{
370 void * bt[TASK_REF_BTDEPTH];
371 int numsaved = 0;
372
373 numsaved = OSBacktrace(bt, TASK_REF_BTDEPTH);
374
375 (void)hw_atomic_add(&(task)->ref_count, 1);
376 btlog_add_entry(task_ref_btlog, task, TASK_REF_OP_INCR,
377 bt, numsaved);
378}
379
380uint32_t
381task_deallocate_internal(task_t task)
382{
383 void * bt[TASK_REF_BTDEPTH];
384 int numsaved = 0;
385
386 numsaved = OSBacktrace(bt, TASK_REF_BTDEPTH);
387
388 btlog_add_entry(task_ref_btlog, task, TASK_REF_OP_DECR,
389 bt, numsaved);
390 return hw_atomic_sub(&(task)->ref_count, 1);
391}
392
393#endif /* TASK_REFERENCE_LEAK_DEBUG */
394
1c79356b
A
395void
396task_init(void)
397{
b0d623f7
A
398
399 lck_grp_attr_setdefault(&task_lck_grp_attr);
400 lck_grp_init(&task_lck_grp, "task", &task_lck_grp_attr);
401 lck_attr_setdefault(&task_lck_attr);
402 lck_mtx_init(&tasks_threads_lock, &task_lck_grp, &task_lck_attr);
403
1c79356b
A
404 task_zone = zinit(
405 sizeof(struct task),
b0d623f7 406 task_max * sizeof(struct task),
1c79356b
A
407 TASK_CHUNK * sizeof(struct task),
408 "tasks");
6d2010ae 409
0b4c1975 410 zone_change(task_zone, Z_NOENCRYPT, TRUE);
1c79356b 411
39236c6e 412 /*
fe8ab488
A
413 * Configure per-task memory limit.
414 * The boot-arg is interpreted as Megabytes,
415 * and takes precedence over the device tree.
416 * Setting the boot-arg to 0 disables task limits.
39236c6e 417 */
3e170ce0
A
418 if (!PE_parse_boot_argn("max_task_pmem", &max_task_footprint_mb,
419 sizeof (max_task_footprint_mb))) {
39236c6e
A
420 /*
421 * No limit was found in boot-args, so go look in the device tree.
422 */
3e170ce0
A
423 if (!PE_get_default("kern.max_task_pmem", &max_task_footprint_mb,
424 sizeof(max_task_footprint_mb))) {
fe8ab488
A
425 /*
426 * No limit was found in device tree.
427 */
3e170ce0 428 max_task_footprint_mb = 0;
39236c6e
A
429 }
430 }
431
3e170ce0 432 if (max_task_footprint_mb != 0) {
39236c6e 433#if CONFIG_JETSAM
3e170ce0 434 if (max_task_footprint_mb < 50) {
39236c6e 435 printf("Warning: max_task_pmem %d below minimum.\n",
3e170ce0
A
436 max_task_footprint_mb);
437 max_task_footprint_mb = 50;
39236c6e
A
438 }
439 printf("Limiting task physical memory footprint to %d MB\n",
3e170ce0
A
440 max_task_footprint_mb);
441
442 max_task_footprint = (ledger_amount_t)max_task_footprint_mb * 1024 * 1024; // Convert MB to bytes
39236c6e
A
443#else
444 printf("Warning: max_task_footprint specified, but jetsam not configured; ignoring.\n");
445#endif
446 }
447
fe8ab488
A
448#if MACH_ASSERT
449 PE_parse_boot_argn("pmap_ledgers_panic", &pmap_ledgers_panic,
450 sizeof (pmap_ledgers_panic));
451#endif /* MACH_ASSERT */
452
39236c6e
A
453 if (!PE_parse_boot_argn("hwm_user_cores", &hwm_user_cores,
454 sizeof (hwm_user_cores))) {
455 hwm_user_cores = 0;
456 }
457
a1c7dba1
A
458 if (PE_parse_boot_argn("qos_override_mode", &qos_override_mode, sizeof(qos_override_mode))) {
459 printf("QOS override mode: 0x%08x\n", qos_override_mode);
460 } else {
461 qos_override_mode = QOS_OVERRIDE_MODE_FINE_GRAINED_OVERRIDE_BUT_SINGLE_MUTEX_OVERRIDE;
462 }
463
39236c6e
A
464 proc_init_cpumon_params();
465
466 if (!PE_parse_boot_argn("task_wakeups_monitor_rate", &task_wakeups_monitor_rate, sizeof (task_wakeups_monitor_rate))) {
467 task_wakeups_monitor_rate = TASK_WAKEUPS_MONITOR_DEFAULT_LIMIT;
468 }
469
470 if (!PE_parse_boot_argn("task_wakeups_monitor_interval", &task_wakeups_monitor_interval, sizeof (task_wakeups_monitor_interval))) {
471 task_wakeups_monitor_interval = TASK_WAKEUPS_MONITOR_DEFAULT_INTERVAL;
472 }
473
474 if (!PE_parse_boot_argn("task_wakeups_monitor_ustackshots_trigger_pct", &task_wakeups_monitor_ustackshots_trigger_pct,
475 sizeof (task_wakeups_monitor_ustackshots_trigger_pct))) {
476 task_wakeups_monitor_ustackshots_trigger_pct = TASK_WAKEUPS_MONITOR_DEFAULT_USTACKSHOTS_TRIGGER;
477 }
478
479 if (!PE_parse_boot_argn("disable_exc_resource", &disable_exc_resource,
480 sizeof (disable_exc_resource))) {
481 disable_exc_resource = 0;
482 }
483
fe8ab488
A
484/*
485 * If we have coalitions, coalition_init() will call init_task_ledgers() as it
486 * sets up the ledgers for the default coalition. If we don't have coalitions,
487 * then we have to call it now.
488 */
489#if CONFIG_COALITIONS
490 assert(task_ledger_template);
491#else /* CONFIG_COALITIONS */
316670eb 492 init_task_ledgers();
fe8ab488 493#endif /* CONFIG_COALITIONS */
316670eb 494
39236c6e
A
495#if TASK_REFERENCE_LEAK_DEBUG
496 simple_lock_init(&task_ref_lock, 0);
497 task_ref_btlog = btlog_create(100000,
498 TASK_REF_BTDEPTH,
499 task_ref_lock_lock,
500 task_ref_lock_unlock,
501 &task_ref_lock);
502 assert(task_ref_btlog);
503#endif
504
1c79356b
A
505 /*
506 * Create the kernel task as the first task.
1c79356b 507 */
b0d623f7 508#ifdef __LP64__
3e170ce0 509 if (task_create_internal(TASK_NULL, NULL, FALSE, TRUE, &kernel_task) != KERN_SUCCESS)
b0d623f7 510#else
3e170ce0 511 if (task_create_internal(TASK_NULL, NULL, FALSE, FALSE, &kernel_task) != KERN_SUCCESS)
b0d623f7 512#endif
1c79356b 513 panic("task_init\n");
55e303ae 514
1c79356b
A
515 vm_map_deallocate(kernel_task->map);
516 kernel_task->map = kernel_map;
4b17d6b6 517 lck_spin_init(&dead_task_statistics_lock, &task_lck_grp, &task_lck_attr);
fe8ab488 518
1c79356b
A
519}
520
1c79356b
A
521/*
522 * Create a task running in the kernel address space. It may
523 * have its own map of size mem_size and may have ipc privileges.
524 */
525kern_return_t
526kernel_task_create(
91447636
A
527 __unused task_t parent_task,
528 __unused vm_offset_t map_base,
529 __unused vm_size_t map_size,
530 __unused task_t *child_task)
1c79356b 531{
55e303ae 532 return (KERN_INVALID_ARGUMENT);
1c79356b
A
533}
534
535kern_return_t
536task_create(
2d21ac55 537 task_t parent_task,
91447636 538 __unused ledger_port_array_t ledger_ports,
2d21ac55
A
539 __unused mach_msg_type_number_t num_ledger_ports,
540 __unused boolean_t inherit_memory,
541 __unused task_t *child_task) /* OUT */
1c79356b
A
542{
543 if (parent_task == TASK_NULL)
544 return(KERN_INVALID_ARGUMENT);
545
2d21ac55
A
546 /*
547 * No longer supported: too many calls assume that a task has a valid
548 * process attached.
549 */
550 return(KERN_FAILURE);
1c79356b
A
551}
552
553kern_return_t
554host_security_create_task_token(
91447636 555 host_security_t host_security,
2d21ac55
A
556 task_t parent_task,
557 __unused security_token_t sec_token,
558 __unused audit_token_t audit_token,
559 __unused host_priv_t host_priv,
91447636
A
560 __unused ledger_port_array_t ledger_ports,
561 __unused mach_msg_type_number_t num_ledger_ports,
2d21ac55
A
562 __unused boolean_t inherit_memory,
563 __unused task_t *child_task) /* OUT */
1c79356b 564{
1c79356b
A
565 if (parent_task == TASK_NULL)
566 return(KERN_INVALID_ARGUMENT);
567
568 if (host_security == HOST_NULL)
569 return(KERN_INVALID_SECURITY);
570
2d21ac55
A
571 /*
572 * No longer supported.
573 */
574 return(KERN_FAILURE);
1c79356b
A
575}
576
39236c6e
A
577/*
578 * Task ledgers
579 * ------------
580 *
581 * phys_footprint
582 * Physical footprint: This is the sum of:
3e170ce0
A
583 * + (internal - alternate_accounting)
584 * + (internal_compressed - alternate_accounting_compressed)
fe8ab488 585 * + iokit_mapped
3e170ce0
A
586 * + purgeable_nonvolatile
587 * + purgeable_nonvolatile_compressed
39236c6e 588 *
fe8ab488
A
589 * internal
590 * The task's anonymous memory, which on iOS is always resident.
591 *
592 * internal_compressed
593 * Amount of this task's internal memory which is held by the compressor.
39236c6e
A
594 * Such memory is no longer actually resident for the task [i.e., resident in its pmap],
595 * and could be either decompressed back into memory, or paged out to storage, depending
596 * on our implementation.
fe8ab488
A
597 *
598 * iokit_mapped
599 * IOKit mappings: The total size of all IOKit mappings in this task, regardless of
600 clean/dirty or internal/external state].
601 *
602 * alternate_accounting
603 * The number of internal dirty pages which are part of IOKit mappings. By definition, these pages
604 * are counted in both internal *and* iokit_mapped, so we must subtract them from the total to avoid
605 * double counting.
39236c6e 606 */
316670eb
A
607void
608init_task_ledgers(void)
609{
610 ledger_template_t t;
611
612 assert(task_ledger_template == NULL);
613 assert(kernel_task == TASK_NULL);
614
615 if ((t = ledger_template_create("Per-task ledger")) == NULL)
616 panic("couldn't create task ledger template");
617
618 task_ledgers.cpu_time = ledger_entry_add(t, "cpu_time", "sched", "ns");
619 task_ledgers.tkm_private = ledger_entry_add(t, "tkm_private",
620 "physmem", "bytes");
621 task_ledgers.tkm_shared = ledger_entry_add(t, "tkm_shared", "physmem",
622 "bytes");
623 task_ledgers.phys_mem = ledger_entry_add(t, "phys_mem", "physmem",
624 "bytes");
625 task_ledgers.wired_mem = ledger_entry_add(t, "wired_mem", "physmem",
626 "bytes");
fe8ab488
A
627 task_ledgers.internal = ledger_entry_add(t, "internal", "physmem",
628 "bytes");
629 task_ledgers.iokit_mapped = ledger_entry_add(t, "iokit_mapped", "mappings",
630 "bytes");
631 task_ledgers.alternate_accounting = ledger_entry_add(t, "alternate_accounting", "physmem",
39236c6e 632 "bytes");
3e170ce0
A
633 task_ledgers.alternate_accounting_compressed = ledger_entry_add(t, "alternate_accounting_compressed", "physmem",
634 "bytes");
39236c6e
A
635 task_ledgers.phys_footprint = ledger_entry_add(t, "phys_footprint", "physmem",
636 "bytes");
fe8ab488 637 task_ledgers.internal_compressed = ledger_entry_add(t, "internal_compressed", "physmem",
39236c6e 638 "bytes");
fe8ab488
A
639 task_ledgers.purgeable_volatile = ledger_entry_add(t, "purgeable_volatile", "physmem", "bytes");
640 task_ledgers.purgeable_nonvolatile = ledger_entry_add(t, "purgeable_nonvolatile", "physmem", "bytes");
641 task_ledgers.purgeable_volatile_compressed = ledger_entry_add(t, "purgeable_volatile_compress", "physmem", "bytes");
642 task_ledgers.purgeable_nonvolatile_compressed = ledger_entry_add(t, "purgeable_nonvolatile_compress", "physmem", "bytes");
4b17d6b6 643 task_ledgers.platform_idle_wakeups = ledger_entry_add(t, "platform_idle_wakeups", "power",
39236c6e 644 "count");
4b17d6b6 645 task_ledgers.interrupt_wakeups = ledger_entry_add(t, "interrupt_wakeups", "power",
39236c6e 646 "count");
fe8ab488 647
3e170ce0 648#if CONFIG_SCHED_SFI
fe8ab488
A
649 sfi_class_id_t class_id, ledger_alias;
650 for (class_id = SFI_CLASS_UNSPECIFIED; class_id < MAX_SFI_CLASS_ID; class_id++) {
651 task_ledgers.sfi_wait_times[class_id] = -1;
652 }
653
654 /* don't account for UNSPECIFIED */
655 for (class_id = SFI_CLASS_UNSPECIFIED + 1; class_id < MAX_SFI_CLASS_ID; class_id++) {
656 ledger_alias = sfi_get_ledger_alias_for_class(class_id);
657 if (ledger_alias != SFI_CLASS_UNSPECIFIED) {
658 /* Check to see if alias has been registered yet */
659 if (task_ledgers.sfi_wait_times[ledger_alias] != -1) {
660 task_ledgers.sfi_wait_times[class_id] = task_ledgers.sfi_wait_times[ledger_alias];
661 } else {
662 /* Otherwise, initialize it first */
663 task_ledgers.sfi_wait_times[class_id] = task_ledgers.sfi_wait_times[ledger_alias] = sfi_ledger_entry_add(t, ledger_alias);
664 }
665 } else {
666 task_ledgers.sfi_wait_times[class_id] = sfi_ledger_entry_add(t, class_id);
667 }
668
669 if (task_ledgers.sfi_wait_times[class_id] < 0) {
670 panic("couldn't create entries for task ledger template for SFI class 0x%x", class_id);
671 }
672 }
316670eb 673
3e170ce0
A
674 assert(task_ledgers.sfi_wait_times[MAX_SFI_CLASS_ID -1] != -1);
675#endif /* CONFIG_SCHED_SFI */
676
fe8ab488
A
677#ifdef CONFIG_BANK
678 task_ledgers.cpu_time_billed_to_me = ledger_entry_add(t, "cpu_time_billed_to_me", "sched", "ns");
679 task_ledgers.cpu_time_billed_to_others = ledger_entry_add(t, "cpu_time_billed_to_others", "sched", "ns");
680#endif
fe8ab488
A
681 if ((task_ledgers.cpu_time < 0) ||
682 (task_ledgers.tkm_private < 0) ||
683 (task_ledgers.tkm_shared < 0) ||
684 (task_ledgers.phys_mem < 0) ||
685 (task_ledgers.wired_mem < 0) ||
686 (task_ledgers.internal < 0) ||
687 (task_ledgers.iokit_mapped < 0) ||
688 (task_ledgers.alternate_accounting < 0) ||
3e170ce0 689 (task_ledgers.alternate_accounting_compressed < 0) ||
fe8ab488
A
690 (task_ledgers.phys_footprint < 0) ||
691 (task_ledgers.internal_compressed < 0) ||
692 (task_ledgers.purgeable_volatile < 0) ||
693 (task_ledgers.purgeable_nonvolatile < 0) ||
694 (task_ledgers.purgeable_volatile_compressed < 0) ||
695 (task_ledgers.purgeable_nonvolatile_compressed < 0) ||
696 (task_ledgers.platform_idle_wakeups < 0) ||
697 (task_ledgers.interrupt_wakeups < 0)
698#ifdef CONFIG_BANK
699 || (task_ledgers.cpu_time_billed_to_me < 0) || (task_ledgers.cpu_time_billed_to_others < 0)
700#endif
701 ) {
316670eb
A
702 panic("couldn't create entries for task ledger template");
703 }
704
39236c6e 705 ledger_track_maximum(t, task_ledgers.phys_footprint, 60);
fe8ab488
A
706#if MACH_ASSERT
707 if (pmap_ledgers_panic) {
708 ledger_panic_on_negative(t, task_ledgers.phys_footprint);
709 ledger_panic_on_negative(t, task_ledgers.internal);
710 ledger_panic_on_negative(t, task_ledgers.internal_compressed);
711 ledger_panic_on_negative(t, task_ledgers.iokit_mapped);
712 ledger_panic_on_negative(t, task_ledgers.alternate_accounting);
3e170ce0 713 ledger_panic_on_negative(t, task_ledgers.alternate_accounting_compressed);
fe8ab488
A
714 ledger_panic_on_negative(t, task_ledgers.purgeable_volatile);
715 ledger_panic_on_negative(t, task_ledgers.purgeable_nonvolatile);
716 ledger_panic_on_negative(t, task_ledgers.purgeable_volatile_compressed);
717 ledger_panic_on_negative(t, task_ledgers.purgeable_nonvolatile_compressed);
718 }
719#endif /* MACH_ASSERT */
39236c6e
A
720
721#if CONFIG_JETSAM
722 ledger_set_callback(t, task_ledgers.phys_footprint, task_footprint_exceeded, NULL, NULL);
723#endif
724
725 ledger_set_callback(t, task_ledgers.interrupt_wakeups,
726 task_wakeups_rate_exceeded, NULL, NULL);
727
316670eb
A
728 task_ledger_template = t;
729}
730
1c79356b 731kern_return_t
55e303ae 732task_create_internal(
1c79356b 733 task_t parent_task,
3e170ce0 734 coalition_t *parent_coalitions __unused,
1c79356b 735 boolean_t inherit_memory,
0c530ab8 736 boolean_t is_64bit,
1c79356b
A
737 task_t *child_task) /* OUT */
738{
2d21ac55
A
739 task_t new_task;
740 vm_shared_region_t shared_region;
316670eb 741 ledger_t ledger = NULL;
1c79356b
A
742
743 new_task = (task_t) zalloc(task_zone);
744
745 if (new_task == TASK_NULL)
746 return(KERN_RESOURCE_SHORTAGE);
747
748 /* one ref for just being alive; one for our caller */
749 new_task->ref_count = 2;
750
316670eb
A
751 /* allocate with active entries */
752 assert(task_ledger_template != NULL);
753 if ((ledger = ledger_instantiate(task_ledger_template,
754 LEDGER_CREATE_ACTIVE_ENTRIES)) == NULL) {
755 zfree(task_zone, new_task);
756 return(KERN_RESOURCE_SHORTAGE);
757 }
39236c6e 758
316670eb
A
759 new_task->ledger = ledger;
760
fe8ab488
A
761#if defined(CONFIG_SCHED_MULTIQ)
762 new_task->sched_group = sched_group_create();
763#endif
764
b0d623f7 765 /* if inherit_memory is true, parent_task MUST not be NULL */
1c79356b 766 if (inherit_memory)
316670eb 767 new_task->map = vm_map_fork(ledger, parent_task->map);
1c79356b 768 else
316670eb
A
769 new_task->map = vm_map_create(pmap_create(ledger, 0, is_64bit),
770 (vm_map_offset_t)(VM_MIN_ADDRESS),
771 (vm_map_offset_t)(VM_MAX_ADDRESS), TRUE);
1c79356b 772
2d21ac55
A
773 /* Inherit memlock limit from parent */
774 if (parent_task)
b0d623f7 775 vm_map_set_user_wire_limit(new_task->map, (vm_size_t)parent_task->map->user_wire_limit);
2d21ac55 776
b0d623f7 777 lck_mtx_init(&new_task->lock, &task_lck_grp, &task_lck_attr);
55e303ae 778 queue_init(&new_task->threads);
1c79356b 779 new_task->suspend_count = 0;
55e303ae 780 new_task->thread_count = 0;
55e303ae 781 new_task->active_thread_count = 0;
1c79356b 782 new_task->user_stop_count = 0;
39236c6e 783 new_task->legacy_stop_count = 0;
1c79356b 784 new_task->active = TRUE;
b0d623f7 785 new_task->halting = FALSE;
2d21ac55 786 new_task->user_data = NULL;
1c79356b
A
787 new_task->faults = 0;
788 new_task->cow_faults = 0;
789 new_task->pageins = 0;
790 new_task->messages_sent = 0;
791 new_task->messages_received = 0;
792 new_task->syscalls_mach = 0;
55e303ae 793 new_task->priv_flags = 0;
1c79356b 794 new_task->syscalls_unix=0;
2d21ac55 795 new_task->c_switch = new_task->p_switch = new_task->ps_switch = 0;
39236c6e
A
796 new_task->t_flags = 0;
797 new_task->importance = 0;
1c79356b 798
fe8ab488
A
799#if CONFIG_ATM
800 new_task->atm_context = NULL;
801#endif
802#if CONFIG_BANK
803 new_task->bank_context = NULL;
804#endif
805
6d2010ae
A
806 zinfo_task_init(new_task);
807
1c79356b 808#ifdef MACH_BSD
2d21ac55 809 new_task->bsd_info = NULL;
3e170ce0 810 new_task->corpse_info = NULL;
1c79356b
A
811#endif /* MACH_BSD */
812
39236c6e
A
813#if CONFIG_JETSAM
814 if (max_task_footprint != 0) {
815 ledger_set_limit(ledger, task_ledgers.phys_footprint, max_task_footprint, PHYS_FOOTPRINT_WARNING_LEVEL);
816 }
817#endif
818
819 if (task_wakeups_monitor_rate != 0) {
820 uint32_t flags = WAKEMON_ENABLE | WAKEMON_SET_DEFAULTS;
821 int32_t rate; // Ignored because of WAKEMON_SET_DEFAULTS
822 task_wakeups_monitor_ctl(new_task, &flags, &rate);
823 }
824
b0d623f7 825#if defined(__i386__) || defined(__x86_64__)
0c530ab8
A
826 new_task->i386_ldt = 0;
827#endif
828
39236c6e 829 new_task->task_debug = NULL;
55e303ae 830
1c79356b 831 queue_init(&new_task->semaphore_list);
1c79356b 832 new_task->semaphores_owned = 0;
1c79356b 833
1c79356b
A
834 ipc_task_init(new_task, parent_task);
835
91447636
A
836 new_task->total_user_time = 0;
837 new_task->total_system_time = 0;
1c79356b 838
2d21ac55 839 new_task->vtimers = 0;
1c79356b 840
2d21ac55
A
841 new_task->shared_region = NULL;
842
843 new_task->affinity_space = NULL;
1c79356b 844
316670eb
A
845 new_task->pidsuspended = FALSE;
846 new_task->frozen = FALSE;
39236c6e 847 new_task->changing_freeze_state = FALSE;
316670eb
A
848 new_task->rusage_cpu_flags = 0;
849 new_task->rusage_cpu_percentage = 0;
850 new_task->rusage_cpu_interval = 0;
851 new_task->rusage_cpu_deadline = 0;
852 new_task->rusage_cpu_callt = NULL;
39236c6e
A
853#if MACH_ASSERT
854 new_task->suspends_outstanding = 0;
855#endif
856
fe8ab488
A
857#if HYPERVISOR
858 new_task->hv_task_target = NULL;
859#endif /* HYPERVISOR */
860
316670eb 861
39236c6e
A
862 new_task->low_mem_notified_warn = 0;
863 new_task->low_mem_notified_critical = 0;
3e170ce0 864 new_task->low_mem_privileged_listener = 0;
39236c6e
A
865 new_task->purged_memory_warn = 0;
866 new_task->purged_memory_critical = 0;
867 new_task->mem_notify_reserved = 0;
868#if IMPORTANCE_INHERITANCE
fe8ab488 869 new_task->task_imp_base = NULL;
39236c6e
A
870#endif /* IMPORTANCE_INHERITANCE */
871
872#if defined(__x86_64__)
db609669 873 new_task->uexc_range_start = new_task->uexc_range_size = new_task->uexc_handler = 0;
39236c6e
A
874#endif
875
876 new_task->requested_policy = default_task_requested_policy;
877 new_task->effective_policy = default_task_effective_policy;
878 new_task->pended_policy = default_task_pended_policy;
db609669 879
2d21ac55 880 if (parent_task != TASK_NULL) {
1c79356b 881 new_task->sec_token = parent_task->sec_token;
55e303ae 882 new_task->audit_token = parent_task->audit_token;
1c79356b 883
2d21ac55
A
884 /* inherit the parent's shared region */
885 shared_region = vm_shared_region_get(parent_task);
886 vm_shared_region_set(new_task, shared_region);
1c79356b 887
91447636
A
888 if(task_has_64BitAddr(parent_task))
889 task_set_64BitAddr(new_task);
b0d623f7
A
890 new_task->all_image_info_addr = parent_task->all_image_info_addr;
891 new_task->all_image_info_size = parent_task->all_image_info_size;
0c530ab8 892
b0d623f7 893#if defined(__i386__) || defined(__x86_64__)
0c530ab8
A
894 if (inherit_memory && parent_task->i386_ldt)
895 new_task->i386_ldt = user_ldt_copy(parent_task->i386_ldt);
896#endif
2d21ac55
A
897 if (inherit_memory && parent_task->affinity_space)
898 task_affinity_create(parent_task, new_task);
b0d623f7
A
899
900 new_task->pset_hint = parent_task->pset_hint = task_choose_pset(parent_task);
39236c6e
A
901
902#if IMPORTANCE_INHERITANCE
fe8ab488
A
903 ipc_importance_task_t new_task_imp = IIT_NULL;
904
905 if (task_is_marked_importance_donor(parent_task)) {
906 new_task_imp = ipc_importance_for_task(new_task, FALSE);
907 assert(IIT_NULL != new_task_imp);
908 ipc_importance_task_mark_donor(new_task_imp, TRUE);
909 }
39236c6e 910 /* Embedded doesn't want this to inherit */
fe8ab488
A
911 if (task_is_marked_importance_receiver(parent_task)) {
912 if (IIT_NULL == new_task_imp)
913 new_task_imp = ipc_importance_for_task(new_task, FALSE);
914 assert(IIT_NULL != new_task_imp);
915 ipc_importance_task_mark_receiver(new_task_imp, TRUE);
916 }
917 if (task_is_marked_importance_denap_receiver(parent_task)) {
918 if (IIT_NULL == new_task_imp)
919 new_task_imp = ipc_importance_for_task(new_task, FALSE);
920 assert(IIT_NULL != new_task_imp);
921 ipc_importance_task_mark_denap_receiver(new_task_imp, TRUE);
922 }
923
924 if (IIT_NULL != new_task_imp) {
925 assert(new_task->task_imp_base == new_task_imp);
926 ipc_importance_task_release(new_task_imp);
927 }
39236c6e
A
928#endif /* IMPORTANCE_INHERITANCE */
929
fe8ab488
A
930 new_task->priority = BASEPRI_DEFAULT;
931 new_task->max_priority = MAXPRI_USER;
932
39236c6e
A
933 new_task->requested_policy.t_apptype = parent_task->requested_policy.t_apptype;
934
935 new_task->requested_policy.int_darwinbg = parent_task->requested_policy.int_darwinbg;
936 new_task->requested_policy.ext_darwinbg = parent_task->requested_policy.ext_darwinbg;
937 new_task->requested_policy.int_iotier = parent_task->requested_policy.int_iotier;
938 new_task->requested_policy.ext_iotier = parent_task->requested_policy.ext_iotier;
939 new_task->requested_policy.int_iopassive = parent_task->requested_policy.int_iopassive;
940 new_task->requested_policy.ext_iopassive = parent_task->requested_policy.ext_iopassive;
941 new_task->requested_policy.bg_iotier = parent_task->requested_policy.bg_iotier;
942 new_task->requested_policy.terminated = parent_task->requested_policy.terminated;
fe8ab488 943 new_task->requested_policy.t_qos_clamp = parent_task->requested_policy.t_qos_clamp;
39236c6e
A
944
945 task_policy_create(new_task, parent_task->requested_policy.t_boosted);
946 } else {
1c79356b 947 new_task->sec_token = KERNEL_SECURITY_TOKEN;
55e303ae 948 new_task->audit_token = KERNEL_AUDIT_TOKEN;
b0d623f7
A
949#ifdef __LP64__
950 if(is_64bit)
951 task_set_64BitAddr(new_task);
952#endif
6d2010ae
A
953 new_task->all_image_info_addr = (mach_vm_address_t)0;
954 new_task->all_image_info_size = (mach_vm_size_t)0;
b0d623f7
A
955
956 new_task->pset_hint = PROCESSOR_SET_NULL;
fe8ab488
A
957
958 if (kernel_task == TASK_NULL) {
959 new_task->priority = BASEPRI_KERNEL;
960 new_task->max_priority = MAXPRI_KERNEL;
961 } else {
962 new_task->priority = BASEPRI_DEFAULT;
963 new_task->max_priority = MAXPRI_USER;
964 }
1c79356b
A
965 }
966
3e170ce0
A
967 bzero(new_task->coalition, sizeof(new_task->coalition));
968 for (int i = 0; i < COALITION_NUM_TYPES; i++)
969 queue_chain_init(new_task->task_coalition[i]);
fe8ab488
A
970
971 /* Allocate I/O Statistics */
972 new_task->task_io_stats = (io_stat_info_t)kalloc(sizeof(struct io_stat_info));
973 assert(new_task->task_io_stats != NULL);
974 bzero(new_task->task_io_stats, sizeof(struct io_stat_info));
4bd07ac2
A
975 new_task->task_immediate_writes = 0;
976 new_task->task_deferred_writes = 0;
977 new_task->task_invalidated_writes = 0;
978 new_task->task_metadata_writes = 0;
fe8ab488
A
979
980 bzero(&(new_task->cpu_time_qos_stats), sizeof(struct _cpu_time_qos_stats));
981
6d2010ae 982 bzero(&new_task->extmod_statistics, sizeof(new_task->extmod_statistics));
4b17d6b6 983 new_task->task_timer_wakeups_bin_1 = new_task->task_timer_wakeups_bin_2 = 0;
fe8ab488 984 new_task->task_gpu_ns = 0;
3e170ce0
A
985
986#if CONFIG_COALITIONS
987
988 /* TODO: there is no graceful failure path here... */
989 if (parent_coalitions && parent_coalitions[COALITION_TYPE_RESOURCE]) {
990 coalitions_adopt_task(parent_coalitions, new_task);
991 } else if (parent_task && parent_task->coalition[COALITION_TYPE_RESOURCE]) {
992 /*
993 * all tasks at least have a resource coalition, so
994 * if the parent has one then inherit all coalitions
995 * the parent is a part of
996 */
997 coalitions_adopt_task(parent_task->coalition, new_task);
998 } else {
999 /* TODO: assert that new_task will be PID 1 (launchd) */
1000 coalitions_adopt_init_task(new_task);
1001 }
1002
1003 if (new_task->coalition[COALITION_TYPE_RESOURCE] == COALITION_NULL) {
1004 panic("created task is not a member of a resource coalition");
1005 }
1006#endif /* CONFIG_COALITIONS */
1007
1008 new_task->dispatchqueue_offset = 0;
1009 if (parent_task != NULL) {
1010 new_task->dispatchqueue_offset = parent_task->dispatchqueue_offset;
1011 }
1c79356b 1012
55e303ae
A
1013 if (vm_backing_store_low && parent_task != NULL)
1014 new_task->priv_flags |= (parent_task->priv_flags&VM_BACKING_STORE_PRIV);
1c79356b 1015
39236c6e 1016 new_task->task_volatile_objects = 0;
fe8ab488
A
1017 new_task->task_nonvolatile_objects = 0;
1018 new_task->task_purgeable_disowning = FALSE;
1019 new_task->task_purgeable_disowned = FALSE;
39236c6e 1020
1c79356b
A
1021 ipc_task_enable(new_task);
1022
3e170ce0
A
1023 lck_mtx_lock(&tasks_threads_lock);
1024 queue_enter(&tasks, new_task, task_t, tasks);
1025 tasks_count++;
4bd07ac2
A
1026 if (tasks_suspend_state) {
1027 task_suspend_internal(new_task);
1028 }
3e170ce0
A
1029 lck_mtx_unlock(&tasks_threads_lock);
1030
1c79356b
A
1031 *child_task = new_task;
1032 return(KERN_SUCCESS);
1033}
1034
fe8ab488
A
1035int task_dropped_imp_count = 0;
1036
1c79356b 1037/*
91447636 1038 * task_deallocate:
1c79356b 1039 *
91447636 1040 * Drop a reference on a task.
1c79356b
A
1041 */
1042void
9bccf70c 1043task_deallocate(
1c79356b
A
1044 task_t task)
1045{
4b17d6b6 1046 ledger_amount_t credit, debit, interrupt_wakeups, platform_idle_wakeups;
fe8ab488 1047 uint32_t refs;
316670eb 1048
9bccf70c
A
1049 if (task == TASK_NULL)
1050 return;
1051
fe8ab488
A
1052 refs = task_deallocate_internal(task);
1053
1054#if IMPORTANCE_INHERITANCE
1055 if (refs > 1)
9bccf70c 1056 return;
fe8ab488
A
1057
1058 if (refs == 1) {
1059 /*
1060 * If last ref potentially comes from the task's importance,
1061 * disconnect it. But more task refs may be added before
1062 * that completes, so wait for the reference to go to zero
1063 * naturually (it may happen on a recursive task_deallocate()
1064 * from the ipc_importance_disconnect_task() call).
1065 */
1066 if (IIT_NULL != task->task_imp_base)
1067 ipc_importance_disconnect_task(task);
1068 return;
1069 }
1070#else
1071 if (refs > 0)
1072 return;
1073#endif /* IMPORTANCE_INHERITANCE */
1c79356b 1074
6d2010ae
A
1075 lck_mtx_lock(&tasks_threads_lock);
1076 queue_remove(&terminated_tasks, task, task_t, tasks);
39236c6e 1077 terminated_tasks_count--;
6d2010ae
A
1078 lck_mtx_unlock(&tasks_threads_lock);
1079
fe8ab488
A
1080 /*
1081 * remove the reference on atm descriptor
1082 */
1083 task_atm_reset(task);
1084
1085#if CONFIG_BANK
1086 /*
1087 * remove the reference on bank context
1088 */
1089 if (task->bank_context != NULL) {
1090 bank_task_destroy(task->bank_context);
1091 task->bank_context = NULL;
1092 }
1093#endif
1094
1095 if (task->task_io_stats)
1096 kfree(task->task_io_stats, sizeof(struct io_stat_info));
1097
316670eb
A
1098 /*
1099 * Give the machine dependent code a chance
1100 * to perform cleanup before ripping apart
1101 * the task.
1102 */
1103 machine_task_terminate(task);
1104
9bccf70c
A
1105 ipc_task_terminate(task);
1106
2d21ac55
A
1107 if (task->affinity_space)
1108 task_affinity_deallocate(task);
1109
fe8ab488
A
1110#if MACH_ASSERT
1111 if (task->ledger != NULL &&
1112 task->map != NULL &&
1113 task->map->pmap != NULL &&
1114 task->map->pmap->ledger != NULL) {
1115 assert(task->ledger == task->map->pmap->ledger);
1116 }
1117#endif /* MACH_ASSERT */
1118
1119 vm_purgeable_disown(task);
1120 assert(task->task_purgeable_disowned);
1121 if (task->task_volatile_objects != 0 ||
1122 task->task_nonvolatile_objects != 0) {
1123 panic("task_deallocate(%p): "
1124 "volatile_objects=%d nonvolatile_objects=%d\n",
1125 task,
1126 task->task_volatile_objects,
1127 task->task_nonvolatile_objects);
1128 }
1129
1c79356b
A
1130 vm_map_deallocate(task->map);
1131 is_release(task->itk_space);
1c79356b 1132
4b17d6b6
A
1133 ledger_get_entries(task->ledger, task_ledgers.interrupt_wakeups,
1134 &interrupt_wakeups, &debit);
1135 ledger_get_entries(task->ledger, task_ledgers.platform_idle_wakeups,
1136 &platform_idle_wakeups, &debit);
1137
fe8ab488
A
1138#if defined(CONFIG_SCHED_MULTIQ)
1139 sched_group_destroy(task->sched_group);
1140#endif
1141
4b17d6b6
A
1142 /* Accumulate statistics for dead tasks */
1143 lck_spin_lock(&dead_task_statistics_lock);
1144 dead_task_statistics.total_user_time += task->total_user_time;
1145 dead_task_statistics.total_system_time += task->total_system_time;
1146
1147 dead_task_statistics.task_interrupt_wakeups += interrupt_wakeups;
1148 dead_task_statistics.task_platform_idle_wakeups += platform_idle_wakeups;
1149
1150 dead_task_statistics.task_timer_wakeups_bin_1 += task->task_timer_wakeups_bin_1;
1151 dead_task_statistics.task_timer_wakeups_bin_2 += task->task_timer_wakeups_bin_2;
1152
1153 lck_spin_unlock(&dead_task_statistics_lock);
b0d623f7
A
1154 lck_mtx_destroy(&task->lock, &task_lck_grp);
1155
316670eb
A
1156 if (!ledger_get_entries(task->ledger, task_ledgers.tkm_private, &credit,
1157 &debit)) {
1158 OSAddAtomic64(credit, (int64_t *)&tasks_tkm_private.alloc);
1159 OSAddAtomic64(debit, (int64_t *)&tasks_tkm_private.free);
1160 }
1161 if (!ledger_get_entries(task->ledger, task_ledgers.tkm_shared, &credit,
1162 &debit)) {
1163 OSAddAtomic64(credit, (int64_t *)&tasks_tkm_shared.alloc);
1164 OSAddAtomic64(debit, (int64_t *)&tasks_tkm_shared.free);
1165 }
1166 ledger_dereference(task->ledger);
6d2010ae 1167 zinfo_task_free(task);
39236c6e
A
1168
1169#if TASK_REFERENCE_LEAK_DEBUG
1170 btlog_remove_entries_for_element(task_ref_btlog, task);
1171#endif
1172
fe8ab488 1173#if CONFIG_COALITIONS
3e170ce0
A
1174 if (!task->coalition[COALITION_TYPE_RESOURCE])
1175 panic("deallocating task was not a member of a resource coalition");
1176 task_release_coalitions(task);
fe8ab488
A
1177#endif /* CONFIG_COALITIONS */
1178
3e170ce0
A
1179 bzero(task->coalition, sizeof(task->coalition));
1180
1181#if MACH_BSD
1182 /* clean up collected information since last reference to task is gone */
1183 if (task->corpse_info) {
1184 task_crashinfo_destroy(task->corpse_info);
1185 task->corpse_info = NULL;
1186 }
1187#endif
39236c6e 1188
91447636 1189 zfree(task_zone, task);
1c79356b
A
1190}
1191
0c530ab8
A
1192/*
1193 * task_name_deallocate:
1194 *
1195 * Drop a reference on a task name.
1196 */
1197void
1198task_name_deallocate(
1199 task_name_t task_name)
1200{
1201 return(task_deallocate((task_t)task_name));
1202}
1203
39236c6e
A
1204/*
1205 * task_suspension_token_deallocate:
1206 *
1207 * Drop a reference on a task suspension token.
1208 */
1209void
1210task_suspension_token_deallocate(
1211 task_suspension_token_t token)
1212{
1213 return(task_deallocate((task_t)token));
1214}
0c530ab8 1215
3e170ce0
A
1216
1217/*
1218 * task_collect_crash_info:
1219 *
1220 * collect crash info from bsd and mach based data
1221 */
1222kern_return_t
1223task_collect_crash_info(task_t task)
1224{
1225 kern_return_t kr = KERN_SUCCESS;
1226
1227 kcdata_descriptor_t crash_data = NULL;
1228 kcdata_descriptor_t crash_data_release = NULL;
1229 mach_msg_type_number_t size = CORPSEINFO_ALLOCATION_SIZE;
1230 mach_vm_offset_t crash_data_user_ptr = 0;
1231
1232 if (!corpses_enabled()) {
1233 return KERN_NOT_SUPPORTED;
1234 }
1235
1236 task_lock(task);
1237 assert(task->bsd_info != NULL);
1238 if (task->corpse_info == NULL && task->bsd_info != NULL) {
1239 task_unlock(task);
1240 /* map crash data memory in task's vm map */
1241 kr = mach_vm_allocate(task->map, &crash_data_user_ptr, size, (VM_MAKE_TAG(VM_MEMORY_CORPSEINFO) | VM_FLAGS_ANYWHERE));
1242
1243 if (kr != KERN_SUCCESS)
1244 goto out_no_lock;
1245
1246 crash_data = task_crashinfo_alloc_init((mach_vm_address_t)crash_data_user_ptr, size);
1247 if (crash_data) {
1248 task_lock(task);
1249 crash_data_release = task->corpse_info;
1250 task->corpse_info = crash_data;
1251 task_unlock(task);
1252 kr = KERN_SUCCESS;
1253 } else {
1254 /* if failed to create corpse info, free the mapping */
1255 if (KERN_SUCCESS != mach_vm_deallocate(task->map, crash_data_user_ptr, size)) {
1256 printf("mach_vm_deallocate failed to clear corpse_data for pid %d.\n", task_pid(task));
1257 }
1258 kr = KERN_FAILURE;
1259 }
1260
1261 if (crash_data_release != NULL) {
1262 task_crashinfo_destroy(crash_data_release);
1263 }
1264 } else {
1265 task_unlock(task);
1266 }
1267
1268out_no_lock:
1269 return kr;
1270}
1271
1272/*
1273 * task_deliver_crash_notification:
1274 *
1275 * Makes outcall to registered host port for a corpse.
1276 */
1277kern_return_t
1278task_deliver_crash_notification(task_t task)
1279{
1280 kcdata_descriptor_t crash_info = task->corpse_info;
1281 thread_t th_iter = NULL;
1282 kern_return_t kr = KERN_SUCCESS;
1283 wait_interrupt_t wsave;
1284 mach_exception_data_type_t code[EXCEPTION_CODE_MAX];
1285
1286 if (crash_info == NULL)
1287 return KERN_FAILURE;
1288
1289 code[0] = crash_info->kcd_addr_begin;
1290 code[1] = crash_info->kcd_length;
1291
1292 task_lock(task);
1293 queue_iterate(&task->threads, th_iter, thread_t, task_threads)
1294 {
1295 ipc_thread_reset(th_iter);
1296 }
1297 task_unlock(task);
1298
1299 wsave = thread_interrupt_level(THREAD_UNINT);
1300 kr = exception_triage(EXC_CORPSE_NOTIFY, code, EXCEPTION_CODE_MAX);
1301 if (kr != KERN_SUCCESS) {
1302 printf("Failed to send exception EXC_CORPSE_NOTIFY. error code: %d for pid %d\n", kr, task_pid(task));
1303 }
1304
1305 /*
1306 * crash reporting is done. Now release threads
1307 * for reaping by thread_terminate_daemon
1308 */
1309 task_lock(task);
1310 assert(task->active_thread_count == 0);
1311 queue_iterate(&task->threads, th_iter, thread_t, task_threads)
1312 {
1313 thread_mtx_lock(th_iter);
1314 assert(th_iter->inspection == TRUE);
1315 th_iter->inspection = FALSE;
1316 /* now that the corpse has been autopsied, dispose of the thread name */
1317 uthread_cleanup_name(th_iter->uthread);
1318 thread_mtx_unlock(th_iter);
1319 }
1320
1321 thread_terminate_crashed_threads();
1322 /* remove the pending corpse report flag */
1323 task_clear_corpse_pending_report(task);
1324
1325 task_unlock(task);
1326
1327 (void)thread_interrupt_level(wsave);
1328 task_terminate_internal(task);
1329
1330 return kr;
1331}
1332
1c79356b
A
1333/*
1334 * task_terminate:
1335 *
1336 * Terminate the specified task. See comments on thread_terminate
1337 * (kern/thread.c) about problems with terminating the "current task."
1338 */
1339
1340kern_return_t
1341task_terminate(
1342 task_t task)
1343{
1344 if (task == TASK_NULL)
91447636
A
1345 return (KERN_INVALID_ARGUMENT);
1346
1c79356b 1347 if (task->bsd_info)
91447636
A
1348 return (KERN_FAILURE);
1349
1c79356b
A
1350 return (task_terminate_internal(task));
1351}
1352
fe8ab488
A
1353#if MACH_ASSERT
1354extern int proc_pid(struct proc *);
1355extern void proc_name_kdp(task_t t, char *buf, int size);
1356#endif /* MACH_ASSERT */
1357
1358#define VM_MAP_PARTIAL_REAP 0x54 /* 0x150 */
1359static void
1360__unused task_partial_reap(task_t task, __unused int pid)
1361{
1362 unsigned int reclaimed_resident = 0;
1363 unsigned int reclaimed_compressed = 0;
1364 uint64_t task_page_count;
1365
1366 task_page_count = (get_task_phys_footprint(task) / PAGE_SIZE_64);
1367
1368 KERNEL_DEBUG_CONSTANT((MACHDBG_CODE(DBG_MACH_VM, VM_MAP_PARTIAL_REAP) | DBG_FUNC_START),
1369 pid, task_page_count, 0, 0, 0);
1370
1371 vm_map_partial_reap(task->map, &reclaimed_resident, &reclaimed_compressed);
1372
1373 KERNEL_DEBUG_CONSTANT((MACHDBG_CODE(DBG_MACH_VM, VM_MAP_PARTIAL_REAP) | DBG_FUNC_END),
1374 pid, reclaimed_resident, reclaimed_compressed, 0, 0);
1375}
1376
3e170ce0
A
1377kern_return_t
1378task_mark_corpse(task_t task)
1379{
1380 kern_return_t kr = KERN_SUCCESS;
1381 thread_t self_thread;
1382 (void) self_thread;
1383 wait_interrupt_t wsave;
1384
1385 assert(task != kernel_task);
1386 assert(task == current_task());
1387 assert(!task_is_a_corpse(task));
1388
1389 kr = task_collect_crash_info(task);
1390 if (kr != KERN_SUCCESS) {
1391 return kr;
1392 }
1393
1394 self_thread = current_thread();
1395
1396 wsave = thread_interrupt_level(THREAD_UNINT);
1397 task_lock(task);
1398
1399 task_set_corpse_pending_report(task);
1400 task_set_corpse(task);
1401
1402 kr = task_start_halt_locked(task, TRUE);
1403 assert(kr == KERN_SUCCESS);
1404 ipc_task_reset(task);
1405 ipc_task_enable(task);
1406
1407 task_unlock(task);
1408 /* terminate the ipc space */
1409 ipc_space_terminate(task->itk_space);
1410
1411 task_start_halt(task);
1412 thread_terminate_internal(self_thread);
1413 (void) thread_interrupt_level(wsave);
1414 assert(task->halting == TRUE);
1415 return kr;
1416}
1417
1c79356b
A
1418kern_return_t
1419task_terminate_internal(
91447636 1420 task_t task)
1c79356b 1421{
91447636
A
1422 thread_t thread, self;
1423 task_t self_task;
1424 boolean_t interrupt_save;
fe8ab488 1425 int pid = 0;
1c79356b
A
1426
1427 assert(task != kernel_task);
1428
91447636
A
1429 self = current_thread();
1430 self_task = self->task;
1c79356b
A
1431
1432 /*
1433 * Get the task locked and make sure that we are not racing
1434 * with someone else trying to terminate us.
1435 */
91447636 1436 if (task == self_task)
1c79356b 1437 task_lock(task);
91447636
A
1438 else
1439 if (task < self_task) {
1c79356b 1440 task_lock(task);
91447636
A
1441 task_lock(self_task);
1442 }
1443 else {
1444 task_lock(self_task);
1c79356b
A
1445 task_lock(task);
1446 }
1447
6d2010ae 1448 if (!task->active) {
1c79356b 1449 /*
6d2010ae 1450 * Task is already being terminated.
1c79356b
A
1451 * Just return an error. If we are dying, this will
1452 * just get us to our AST special handler and that
1453 * will get us to finalize the termination of ourselves.
1454 */
1455 task_unlock(task);
91447636
A
1456 if (self_task != task)
1457 task_unlock(self_task);
1458
1459 return (KERN_FAILURE);
1c79356b 1460 }
91447636 1461
3e170ce0
A
1462 if (task_corpse_pending_report(task)) {
1463 /*
1464 * Task is marked for reporting as corpse.
1465 * Just return an error. This will
1466 * just get us to our AST special handler and that
1467 * will get us to finish the path to death
1468 */
1469 task_unlock(task);
1470 if (self_task != task)
1471 task_unlock(self_task);
1472
1473 return (KERN_FAILURE);
1474 }
1475
91447636
A
1476 if (self_task != task)
1477 task_unlock(self_task);
1c79356b 1478
e7c99d92
A
1479 /*
1480 * Make sure the current thread does not get aborted out of
1481 * the waits inside these operations.
1482 */
9bccf70c 1483 interrupt_save = thread_interrupt_level(THREAD_UNINT);
e7c99d92 1484
1c79356b
A
1485 /*
1486 * Indicate that we want all the threads to stop executing
1487 * at user space by holding the task (we would have held
1488 * each thread independently in thread_terminate_internal -
1489 * but this way we may be more likely to already find it
1490 * held there). Mark the task inactive, and prevent
1491 * further task operations via the task port.
1492 */
1493 task_hold_locked(task);
1494 task->active = FALSE;
1495 ipc_task_disable(task);
1496
39236c6e
A
1497#if CONFIG_TELEMETRY
1498 /*
1499 * Notify telemetry that this task is going away.
1500 */
1501 telemetry_task_ctl_locked(task, TF_TELEMETRY, 0);
1502#endif
1503
1c79356b 1504 /*
91447636
A
1505 * Terminate each thread in the task.
1506 */
1507 queue_iterate(&task->threads, thread, thread_t, task_threads) {
1508 thread_terminate_internal(thread);
1c79356b 1509 }
e7c99d92 1510
fe8ab488
A
1511#ifdef MACH_BSD
1512 if (task->bsd_info != NULL) {
1513 pid = proc_pid(task->bsd_info);
1514 }
1515#endif /* MACH_BSD */
1516
316670eb
A
1517 task_unlock(task);
1518
a1c7dba1 1519 proc_set_task_policy(task, THREAD_NULL, TASK_POLICY_ATTRIBUTE,
3e170ce0 1520 TASK_POLICY_TERMINATED, TASK_POLICY_ENABLE);
a1c7dba1 1521
fe8ab488
A
1522 /* Early object reap phase */
1523
1524// PR-17045188: Revisit implementation
1525// task_partial_reap(task, pid);
1526
1c79356b
A
1527
1528 /*
1529 * Destroy all synchronizers owned by the task.
1530 */
1531 task_synchronizer_destroy_all(task);
1532
1c79356b
A
1533 /*
1534 * Destroy the IPC space, leaving just a reference for it.
1535 */
316670eb 1536 ipc_space_terminate(task->itk_space);
1c79356b 1537
fe8ab488
A
1538#if 00
1539 /* if some ledgers go negative on tear-down again... */
1540 ledger_disable_panic_on_negative(task->map->pmap->ledger,
1541 task_ledgers.phys_footprint);
1542 ledger_disable_panic_on_negative(task->map->pmap->ledger,
1543 task_ledgers.internal);
1544 ledger_disable_panic_on_negative(task->map->pmap->ledger,
1545 task_ledgers.internal_compressed);
1546 ledger_disable_panic_on_negative(task->map->pmap->ledger,
1547 task_ledgers.iokit_mapped);
1548 ledger_disable_panic_on_negative(task->map->pmap->ledger,
1549 task_ledgers.alternate_accounting);
3e170ce0
A
1550 ledger_disable_panic_on_negative(task->map->pmap->ledger,
1551 task_ledgers.alternate_accounting_compressed);
fe8ab488 1552#endif
91447636 1553
1c79356b
A
1554 /*
1555 * If the current thread is a member of the task
1556 * being terminated, then the last reference to
1557 * the task will not be dropped until the thread
1558 * is finally reaped. To avoid incurring the
1559 * expense of removing the address space regions
1560 * at reap time, we do it explictly here.
1561 */
3e170ce0
A
1562
1563 vm_map_lock(task->map);
1564 vm_map_disable_hole_optimization(task->map);
1565 vm_map_unlock(task->map);
1566
2d21ac55
A
1567 vm_map_remove(task->map,
1568 task->map->min_offset,
1569 task->map->max_offset,
3e170ce0
A
1570 /* no unnesting on final cleanup: */
1571 VM_MAP_REMOVE_NO_UNNESTING);
1c79356b 1572
2d21ac55
A
1573 /* release our shared region */
1574 vm_shared_region_set(task, NULL);
9bccf70c 1575
3e170ce0 1576
fe8ab488
A
1577#if MACH_ASSERT
1578 /*
1579 * Identify the pmap's process, in case the pmap ledgers drift
1580 * and we have to report it.
1581 */
1582 char procname[17];
1583 if (task->bsd_info) {
1584 pid = proc_pid(task->bsd_info);
1585 proc_name_kdp(task, procname, sizeof (procname));
1586 } else {
1587 pid = 0;
1588 strlcpy(procname, "<unknown>", sizeof (procname));
1589 }
1590 pmap_set_process(task->map->pmap, pid, procname);
1591#endif /* MACH_ASSERT */
1592
b0d623f7 1593 lck_mtx_lock(&tasks_threads_lock);
2d21ac55 1594 queue_remove(&tasks, task, task_t, tasks);
6d2010ae 1595 queue_enter(&terminated_tasks, task, task_t, tasks);
2d21ac55 1596 tasks_count--;
39236c6e 1597 terminated_tasks_count++;
b0d623f7 1598 lck_mtx_unlock(&tasks_threads_lock);
9bccf70c 1599
1c79356b 1600 /*
e7c99d92
A
1601 * We no longer need to guard against being aborted, so restore
1602 * the previous interruptible state.
1603 */
9bccf70c 1604 thread_interrupt_level(interrupt_save);
e7c99d92 1605
fe8ab488
A
1606#if KPERF
1607 /* force the task to release all ctrs */
1608 if (task->t_chud & TASK_KPC_FORCED_ALL_CTRS)
1609 kpc_force_all_ctrs(task, 0);
1610#endif
1611
1612#if CONFIG_COALITIONS
1613 /*
3e170ce0 1614 * Leave our coalitions. (drop activation but not reference)
fe8ab488 1615 */
3e170ce0 1616 coalitions_remove_task(task);
fe8ab488
A
1617#endif
1618
e7c99d92
A
1619 /*
1620 * Get rid of the task active reference on itself.
1c79356b 1621 */
1c79356b
A
1622 task_deallocate(task);
1623
91447636 1624 return (KERN_SUCCESS);
1c79356b
A
1625}
1626
4bd07ac2
A
1627void
1628tasks_system_suspend(boolean_t suspend)
1629{
1630 task_t task;
1631
1632 lck_mtx_lock(&tasks_threads_lock);
1633 assert(tasks_suspend_state != suspend);
1634 tasks_suspend_state = suspend;
1635 queue_iterate(&tasks, task, task_t, tasks) {
1636 if (task == kernel_task) {
1637 continue;
1638 }
1639 suspend ? task_suspend_internal(task) : task_resume_internal(task);
1640 }
1641 lck_mtx_unlock(&tasks_threads_lock);
1642}
1643
1c79356b 1644/*
b0d623f7 1645 * task_start_halt:
91447636
A
1646 *
1647 * Shut the current task down (except for the current thread) in
1648 * preparation for dramatic changes to the task (probably exec).
b0d623f7
A
1649 * We hold the task and mark all other threads in the task for
1650 * termination.
1c79356b
A
1651 */
1652kern_return_t
3e170ce0
A
1653task_start_halt(task_t task)
1654{
1655 kern_return_t kr = KERN_SUCCESS;
1656 task_lock(task);
1657 kr = task_start_halt_locked(task, FALSE);
1658 task_unlock(task);
1659 return kr;
1660}
1661
1662static kern_return_t
1663task_start_halt_locked(task_t task, boolean_t should_mark_corpse)
1c79356b 1664{
3e170ce0
A
1665 thread_t thread, self;
1666 uint64_t dispatchqueue_offset;
1c79356b
A
1667
1668 assert(task != kernel_task);
1669
91447636 1670 self = current_thread();
1c79356b 1671
91447636
A
1672 if (task != self->task)
1673 return (KERN_INVALID_ARGUMENT);
1c79356b 1674
b0d623f7 1675 if (task->halting || !task->active || !self->active) {
1c79356b 1676 /*
3e170ce0
A
1677 * Task or current thread is already being terminated.
1678 * Hurry up and return out of the current kernel context
1679 * so that we run our AST special handler to terminate
1680 * ourselves.
1c79356b 1681 */
91447636 1682 return (KERN_FAILURE);
1c79356b
A
1683 }
1684
b0d623f7
A
1685 task->halting = TRUE;
1686
3e170ce0
A
1687 /*
1688 * Mark all the threads to keep them from starting any more
1689 * user-level execution. The thread_terminate_internal code
1690 * would do this on a thread by thread basis anyway, but this
1691 * gives us a better chance of not having to wait there.
1692 */
1693 task_hold_locked(task);
1694 dispatchqueue_offset = get_dispatchqueue_offset_from_proc(task->bsd_info);
1c79356b 1695
3e170ce0
A
1696 /*
1697 * Terminate all the other threads in the task.
1698 */
1699 queue_iterate(&task->threads, thread, thread_t, task_threads)
1700 {
1701 if (should_mark_corpse) {
1702 thread_mtx_lock(thread);
1703 thread->inspection = TRUE;
1704 thread_mtx_unlock(thread);
1c79356b 1705 }
3e170ce0
A
1706 if (thread != self)
1707 thread_terminate_internal(thread);
1c79356b 1708 }
3e170ce0
A
1709 task->dispatchqueue_offset = dispatchqueue_offset;
1710
1711 task_release_locked(task);
1712
b0d623f7
A
1713 return KERN_SUCCESS;
1714}
1715
1716
1717/*
1718 * task_complete_halt:
1719 *
1720 * Complete task halt by waiting for threads to terminate, then clean
1721 * up task resources (VM, port namespace, etc...) and then let the
1722 * current thread go in the (practically empty) task context.
1723 */
1724void
1725task_complete_halt(task_t task)
1726{
1727 task_lock(task);
1728 assert(task->halting);
1729 assert(task == current_task());
e7c99d92 1730
b0d623f7
A
1731 /*
1732 * Wait for the other threads to get shut down.
1733 * When the last other thread is reaped, we'll be
316670eb 1734 * woken up.
b0d623f7
A
1735 */
1736 if (task->thread_count > 1) {
1737 assert_wait((event_t)&task->halting, THREAD_UNINT);
1738 task_unlock(task);
1739 thread_block(THREAD_CONTINUE_NULL);
1740 } else {
1741 task_unlock(task);
1742 }
1c79356b 1743
316670eb
A
1744 /*
1745 * Give the machine dependent code a chance
1746 * to perform cleanup of task-level resources
1747 * associated with the current thread before
1748 * ripping apart the task.
1749 */
1750 machine_task_terminate(task);
1751
1c79356b
A
1752 /*
1753 * Destroy all synchronizers owned by the task.
1754 */
1755 task_synchronizer_destroy_all(task);
1756
1757 /*
9bccf70c
A
1758 * Destroy the contents of the IPC space, leaving just
1759 * a reference for it.
e7c99d92 1760 */
55e303ae 1761 ipc_space_clean(task->itk_space);
1c79356b
A
1762
1763 /*
1764 * Clean out the address space, as we are going to be
1765 * getting a new one.
1766 */
91447636 1767 vm_map_remove(task->map, task->map->min_offset,
3e170ce0
A
1768 task->map->max_offset,
1769 /* no unnesting on final cleanup: */
1770 VM_MAP_REMOVE_NO_UNNESTING);
1c79356b 1771
b0d623f7 1772 task->halting = FALSE;
1c79356b
A
1773}
1774
1775/*
1776 * task_hold_locked:
1777 *
1778 * Suspend execution of the specified task.
1779 * This is a recursive-style suspension of the task, a count of
1780 * suspends is maintained.
1781 *
1782 * CONDITIONS: the task is locked and active.
1783 */
1784void
1785task_hold_locked(
91447636 1786 register task_t task)
1c79356b 1787{
91447636 1788 register thread_t thread;
1c79356b
A
1789
1790 assert(task->active);
1791
9bccf70c
A
1792 if (task->suspend_count++ > 0)
1793 return;
1c79356b
A
1794
1795 /*
91447636 1796 * Iterate through all the threads and hold them.
1c79356b 1797 */
91447636
A
1798 queue_iterate(&task->threads, thread, thread_t, task_threads) {
1799 thread_mtx_lock(thread);
1800 thread_hold(thread);
1801 thread_mtx_unlock(thread);
1c79356b
A
1802 }
1803}
1804
1805/*
1806 * task_hold:
1807 *
1808 * Same as the internal routine above, except that is must lock
1809 * and verify that the task is active. This differs from task_suspend
1810 * in that it places a kernel hold on the task rather than just a
1811 * user-level hold. This keeps users from over resuming and setting
1812 * it running out from under the kernel.
1813 *
1814 * CONDITIONS: the caller holds a reference on the task
1815 */
1816kern_return_t
91447636
A
1817task_hold(
1818 register task_t task)
1c79356b 1819{
1c79356b
A
1820 if (task == TASK_NULL)
1821 return (KERN_INVALID_ARGUMENT);
91447636 1822
1c79356b 1823 task_lock(task);
91447636 1824
1c79356b
A
1825 if (!task->active) {
1826 task_unlock(task);
91447636 1827
1c79356b
A
1828 return (KERN_FAILURE);
1829 }
1c79356b 1830
91447636
A
1831 task_hold_locked(task);
1832 task_unlock(task);
1833
1834 return (KERN_SUCCESS);
1c79356b
A
1835}
1836
316670eb
A
1837kern_return_t
1838task_wait(
1839 task_t task,
1840 boolean_t until_not_runnable)
1841{
1842 if (task == TASK_NULL)
1843 return (KERN_INVALID_ARGUMENT);
1844
1845 task_lock(task);
1846
1847 if (!task->active) {
1848 task_unlock(task);
1849
1850 return (KERN_FAILURE);
1851 }
1852
1853 task_wait_locked(task, until_not_runnable);
1854 task_unlock(task);
1855
1856 return (KERN_SUCCESS);
1857}
1858
1c79356b 1859/*
91447636
A
1860 * task_wait_locked:
1861 *
1c79356b
A
1862 * Wait for all threads in task to stop.
1863 *
1864 * Conditions:
1865 * Called with task locked, active, and held.
1866 */
1867void
1868task_wait_locked(
316670eb
A
1869 register task_t task,
1870 boolean_t until_not_runnable)
1c79356b 1871{
91447636 1872 register thread_t thread, self;
1c79356b
A
1873
1874 assert(task->active);
1875 assert(task->suspend_count > 0);
1876
91447636
A
1877 self = current_thread();
1878
1c79356b 1879 /*
91447636 1880 * Iterate through all the threads and wait for them to
1c79356b
A
1881 * stop. Do not wait for the current thread if it is within
1882 * the task.
1883 */
91447636
A
1884 queue_iterate(&task->threads, thread, thread_t, task_threads) {
1885 if (thread != self)
316670eb 1886 thread_wait(thread, until_not_runnable);
1c79356b
A
1887 }
1888}
1889
1890/*
1891 * task_release_locked:
1892 *
1893 * Release a kernel hold on a task.
1894 *
1895 * CONDITIONS: the task is locked and active
1896 */
1897void
1898task_release_locked(
91447636 1899 register task_t task)
1c79356b 1900{
91447636 1901 register thread_t thread;
1c79356b
A
1902
1903 assert(task->active);
9bccf70c 1904 assert(task->suspend_count > 0);
1c79356b 1905
9bccf70c
A
1906 if (--task->suspend_count > 0)
1907 return;
1c79356b 1908
91447636
A
1909 queue_iterate(&task->threads, thread, thread_t, task_threads) {
1910 thread_mtx_lock(thread);
1911 thread_release(thread);
1912 thread_mtx_unlock(thread);
1c79356b
A
1913 }
1914}
1915
1916/*
1917 * task_release:
1918 *
1919 * Same as the internal routine above, except that it must lock
1920 * and verify that the task is active.
1921 *
1922 * CONDITIONS: The caller holds a reference to the task
1923 */
1924kern_return_t
91447636
A
1925task_release(
1926 task_t task)
1c79356b 1927{
1c79356b
A
1928 if (task == TASK_NULL)
1929 return (KERN_INVALID_ARGUMENT);
91447636 1930
1c79356b 1931 task_lock(task);
91447636 1932
1c79356b
A
1933 if (!task->active) {
1934 task_unlock(task);
91447636 1935
1c79356b
A
1936 return (KERN_FAILURE);
1937 }
1c79356b 1938
91447636
A
1939 task_release_locked(task);
1940 task_unlock(task);
1941
1942 return (KERN_SUCCESS);
1c79356b
A
1943}
1944
1945kern_return_t
1946task_threads(
91447636
A
1947 task_t task,
1948 thread_act_array_t *threads_out,
1c79356b
A
1949 mach_msg_type_number_t *count)
1950{
91447636 1951 mach_msg_type_number_t actual;
2d21ac55 1952 thread_t *thread_list;
91447636
A
1953 thread_t thread;
1954 vm_size_t size, size_needed;
1955 void *addr;
1956 unsigned int i, j;
1c79356b
A
1957
1958 if (task == TASK_NULL)
91447636 1959 return (KERN_INVALID_ARGUMENT);
1c79356b 1960
2d21ac55 1961 size = 0; addr = NULL;
1c79356b
A
1962
1963 for (;;) {
1964 task_lock(task);
1965 if (!task->active) {
1966 task_unlock(task);
91447636 1967
1c79356b
A
1968 if (size != 0)
1969 kfree(addr, size);
91447636
A
1970
1971 return (KERN_FAILURE);
1c79356b
A
1972 }
1973
55e303ae 1974 actual = task->thread_count;
1c79356b
A
1975
1976 /* do we have the memory we need? */
91447636 1977 size_needed = actual * sizeof (mach_port_t);
1c79356b
A
1978 if (size_needed <= size)
1979 break;
1980
1981 /* unlock the task and allocate more memory */
1982 task_unlock(task);
1983
1984 if (size != 0)
1985 kfree(addr, size);
1986
1987 assert(size_needed > 0);
1988 size = size_needed;
1989
1990 addr = kalloc(size);
1991 if (addr == 0)
91447636 1992 return (KERN_RESOURCE_SHORTAGE);
1c79356b
A
1993 }
1994
1995 /* OK, have memory and the task is locked & active */
2d21ac55 1996 thread_list = (thread_t *)addr;
91447636
A
1997
1998 i = j = 0;
1999
2000 for (thread = (thread_t)queue_first(&task->threads); i < actual;
2001 ++i, thread = (thread_t)queue_next(&thread->task_threads)) {
2002 thread_reference_internal(thread);
2d21ac55 2003 thread_list[j++] = thread;
1c79356b 2004 }
91447636
A
2005
2006 assert(queue_end(&task->threads, (queue_entry_t)thread));
1c79356b
A
2007
2008 actual = j;
91447636 2009 size_needed = actual * sizeof (mach_port_t);
1c79356b 2010
91447636 2011 /* can unlock task now that we've got the thread refs */
1c79356b
A
2012 task_unlock(task);
2013
2014 if (actual == 0) {
91447636 2015 /* no threads, so return null pointer and deallocate memory */
1c79356b 2016
2d21ac55 2017 *threads_out = NULL;
1c79356b
A
2018 *count = 0;
2019
2020 if (size != 0)
2021 kfree(addr, size);
91447636
A
2022 }
2023 else {
1c79356b
A
2024 /* if we allocated too much, must copy */
2025
2026 if (size_needed < size) {
91447636 2027 void *newaddr;
1c79356b
A
2028
2029 newaddr = kalloc(size_needed);
2030 if (newaddr == 0) {
91447636 2031 for (i = 0; i < actual; ++i)
2d21ac55 2032 thread_deallocate(thread_list[i]);
1c79356b 2033 kfree(addr, size);
91447636 2034 return (KERN_RESOURCE_SHORTAGE);
1c79356b
A
2035 }
2036
91447636 2037 bcopy(addr, newaddr, size_needed);
1c79356b 2038 kfree(addr, size);
2d21ac55 2039 thread_list = (thread_t *)newaddr;
1c79356b
A
2040 }
2041
2d21ac55 2042 *threads_out = thread_list;
1c79356b
A
2043 *count = actual;
2044
2045 /* do the conversion that Mig should handle */
2046
91447636 2047 for (i = 0; i < actual; ++i)
2d21ac55 2048 ((ipc_port_t *) thread_list)[i] = convert_thread_to_port(thread_list[i]);
1c79356b
A
2049 }
2050
91447636 2051 return (KERN_SUCCESS);
1c79356b
A
2052}
2053
39236c6e
A
2054#define TASK_HOLD_NORMAL 0
2055#define TASK_HOLD_PIDSUSPEND 1
2056#define TASK_HOLD_LEGACY 2
2057#define TASK_HOLD_LEGACY_ALL 3
2058
316670eb
A
2059static kern_return_t
2060place_task_hold (
39236c6e
A
2061 register task_t task,
2062 int mode)
316670eb 2063{
1c79356b 2064 if (!task->active) {
1c79356b
A
2065 return (KERN_FAILURE);
2066 }
91447636 2067
39236c6e
A
2068 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
2069 MACHDBG_CODE(DBG_MACH_IPC,MACH_TASK_SUSPEND) | DBG_FUNC_NONE,
3e170ce0 2070 task_pid(task), ((thread_t)queue_first(&task->threads))->thread_id,
39236c6e
A
2071 task->user_stop_count, task->user_stop_count + 1, 0);
2072
2073#if MACH_ASSERT
2074 current_task()->suspends_outstanding++;
2075#endif
2076
2077 if (mode == TASK_HOLD_LEGACY)
2078 task->legacy_stop_count++;
2079
91447636 2080 if (task->user_stop_count++ > 0) {
1c79356b
A
2081 /*
2082 * If the stop count was positive, the task is
2083 * already stopped and we can exit.
2084 */
1c79356b
A
2085 return (KERN_SUCCESS);
2086 }
2087
2088 /*
2089 * Put a kernel-level hold on the threads in the task (all
2090 * user-level task suspensions added together represent a
2091 * single kernel-level hold). We then wait for the threads
2092 * to stop executing user code.
2093 */
2094 task_hold_locked(task);
39236c6e 2095 task_wait_locked(task, FALSE);
316670eb
A
2096
2097 return (KERN_SUCCESS);
2098}
2099
2100static kern_return_t
2101release_task_hold (
2102 register task_t task,
39236c6e 2103 int mode)
316670eb
A
2104{
2105 register boolean_t release = FALSE;
2106
2107 if (!task->active) {
2108 return (KERN_FAILURE);
2109 }
2110
39236c6e 2111 if (mode == TASK_HOLD_PIDSUSPEND) {
316670eb 2112 if (task->pidsuspended == FALSE) {
39236c6e 2113 return (KERN_FAILURE);
316670eb
A
2114 }
2115 task->pidsuspended = FALSE;
2116 }
2117
39236c6e
A
2118 if (task->user_stop_count > (task->pidsuspended ? 1 : 0)) {
2119
2120 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
2121 MACHDBG_CODE(DBG_MACH_IPC,MACH_TASK_RESUME) | DBG_FUNC_NONE,
3e170ce0 2122 task_pid(task), ((thread_t)queue_first(&task->threads))->thread_id,
39236c6e
A
2123 task->user_stop_count, mode, task->legacy_stop_count);
2124
2125#if MACH_ASSERT
2126 /*
2127 * This is obviously not robust; if we suspend one task and then resume a different one,
2128 * we'll fly under the radar. This is only meant to catch the common case of a crashed
2129 * or buggy suspender.
2130 */
2131 current_task()->suspends_outstanding--;
2132#endif
2133
2134 if (mode == TASK_HOLD_LEGACY_ALL) {
2135 if (task->legacy_stop_count >= task->user_stop_count) {
2136 task->user_stop_count = 0;
2137 release = TRUE;
2138 } else {
2139 task->user_stop_count -= task->legacy_stop_count;
2140 }
2141 task->legacy_stop_count = 0;
2142 } else {
2143 if (mode == TASK_HOLD_LEGACY && task->legacy_stop_count > 0)
2144 task->legacy_stop_count--;
2145 if (--task->user_stop_count == 0)
2146 release = TRUE;
316670eb
A
2147 }
2148 }
2149 else {
2150 return (KERN_FAILURE);
2151 }
2152
2153 /*
2154 * Release the task if necessary.
2155 */
2156 if (release)
2157 task_release_locked(task);
2158
2159 return (KERN_SUCCESS);
2160}
2161
39236c6e 2162
316670eb
A
2163/*
2164 * task_suspend:
2165 *
39236c6e
A
2166 * Implement an (old-fashioned) user-level suspension on a task.
2167 *
2168 * Because the user isn't expecting to have to manage a suspension
2169 * token, we'll track it for him in the kernel in the form of a naked
2170 * send right to the task's resume port. All such send rights
2171 * account for a single suspension against the task (unlike task_suspend2()
2172 * where each caller gets a unique suspension count represented by a
2173 * unique send-once right).
316670eb
A
2174 *
2175 * Conditions:
2176 * The caller holds a reference to the task
2177 */
2178kern_return_t
2179task_suspend(
2180 register task_t task)
2181{
39236c6e
A
2182 kern_return_t kr;
2183 mach_port_t port, send, old_notify;
2184 mach_port_name_t name;
2185
316670eb
A
2186 if (task == TASK_NULL || task == kernel_task)
2187 return (KERN_INVALID_ARGUMENT);
2188
2189 task_lock(task);
2190
39236c6e
A
2191 /*
2192 * Claim a send right on the task resume port, and request a no-senders
2193 * notification on that port (if none outstanding).
2194 */
2195 if (task->itk_resume == IP_NULL) {
2196 task->itk_resume = ipc_port_alloc_kernel();
2197 if (!IP_VALID(task->itk_resume))
2198 panic("failed to create resume port");
2199 ipc_kobject_set(task->itk_resume, (ipc_kobject_t)task, IKOT_TASK_RESUME);
2200 }
2201
2202 port = task->itk_resume;
2203 ip_lock(port);
2204 assert(ip_active(port));
2205
2206 send = ipc_port_make_send_locked(port);
2207 assert(IP_VALID(send));
2208
2209 if (port->ip_nsrequest == IP_NULL) {
2210 ipc_port_nsrequest(port, port->ip_mscount, ipc_port_make_sonce_locked(port), &old_notify);
2211 assert(old_notify == IP_NULL);
2212 /* port unlocked */
2213 } else {
2214 ip_unlock(port);
2215 }
2216
2217 /*
2218 * place a legacy hold on the task.
2219 */
2220 kr = place_task_hold(task, TASK_HOLD_LEGACY);
2221 if (kr != KERN_SUCCESS) {
2222 task_unlock(task);
2223 ipc_port_release_send(send);
2224 return kr;
2225 }
91447636 2226
1c79356b 2227 task_unlock(task);
91447636 2228
39236c6e
A
2229 /*
2230 * Copyout the send right into the calling task's IPC space. It won't know it is there,
2231 * but we'll look it up when calling a traditional resume. Any IPC operations that
2232 * deallocate the send right will auto-release the suspension.
2233 */
2234 if ((kr = ipc_kmsg_copyout_object(current_task()->itk_space, (ipc_object_t)send,
2235 MACH_MSG_TYPE_MOVE_SEND, &name)) != KERN_SUCCESS) {
3e170ce0
A
2236 printf("warning: %s(%d) failed to copyout suspension token for pid %d with error: %d\n",
2237 proc_name_address(current_task()->bsd_info), proc_pid(current_task()->bsd_info),
2238 task_pid(task), kr);
39236c6e
A
2239 return (kr);
2240 }
2241
316670eb 2242 return (kr);
1c79356b
A
2243}
2244
2245/*
91447636 2246 * task_resume:
39236c6e 2247 * Release a user hold on a task.
1c79356b
A
2248 *
2249 * Conditions:
2250 * The caller holds a reference to the task
2251 */
2252kern_return_t
91447636
A
2253task_resume(
2254 register task_t task)
1c79356b 2255{
316670eb 2256 kern_return_t kr;
39236c6e
A
2257 mach_port_name_t resume_port_name;
2258 ipc_entry_t resume_port_entry;
2259 ipc_space_t space = current_task()->itk_space;
2260
2261 if (task == TASK_NULL || task == kernel_task )
2262 return (KERN_INVALID_ARGUMENT);
2263
2264 /* release a legacy task hold */
2265 task_lock(task);
2266 kr = release_task_hold(task, TASK_HOLD_LEGACY);
2267 task_unlock(task);
2268
2269 is_write_lock(space);
2270 if (is_active(space) && IP_VALID(task->itk_resume) &&
2271 ipc_hash_lookup(space, (ipc_object_t)task->itk_resume, &resume_port_name, &resume_port_entry) == TRUE) {
2272 /*
2273 * We found a suspension token in the caller's IPC space. Release a send right to indicate that
2274 * we are holding one less legacy hold on the task from this caller. If the release failed,
2275 * go ahead and drop all the rights, as someone either already released our holds or the task
2276 * is gone.
2277 */
2278 if (kr == KERN_SUCCESS)
2279 ipc_right_dealloc(space, resume_port_name, resume_port_entry);
2280 else
2281 ipc_right_destroy(space, resume_port_name, resume_port_entry, FALSE, 0);
2282 /* space unlocked */
2283 } else {
2284 is_write_unlock(space);
2285 if (kr == KERN_SUCCESS)
3e170ce0 2286 printf("warning: %s(%d) performed out-of-band resume on pid %d\n",
39236c6e 2287 proc_name_address(current_task()->bsd_info), proc_pid(current_task()->bsd_info),
3e170ce0 2288 task_pid(task));
39236c6e
A
2289 }
2290
2291 return kr;
2292}
1c79356b 2293
39236c6e
A
2294/*
2295 * Suspend the target task.
2296 * Making/holding a token/reference/port is the callers responsibility.
2297 */
2298kern_return_t
2299task_suspend_internal(task_t task)
2300{
2301 kern_return_t kr;
2302
91447636
A
2303 if (task == TASK_NULL || task == kernel_task)
2304 return (KERN_INVALID_ARGUMENT);
1c79356b 2305
1c79356b 2306 task_lock(task);
39236c6e
A
2307 kr = place_task_hold(task, TASK_HOLD_NORMAL);
2308 task_unlock(task);
2309 return (kr);
2310}
2311
2312/*
2313 * Suspend the target task, and return a suspension token. The token
2314 * represents a reference on the suspended task.
2315 */
2316kern_return_t
2317task_suspend2(
2318 register task_t task,
2319 task_suspension_token_t *suspend_token)
2320{
2321 kern_return_t kr;
2322
2323 kr = task_suspend_internal(task);
2324 if (kr != KERN_SUCCESS) {
2325 *suspend_token = TASK_NULL;
2326 return (kr);
2327 }
2328
2329 /*
2330 * Take a reference on the target task and return that to the caller
2331 * as a "suspension token," which can be converted into an SO right to
2332 * the now-suspended task's resume port.
2333 */
2334 task_reference_internal(task);
2335 *suspend_token = task;
2336
2337 return (KERN_SUCCESS);
2338}
2339
2340/*
2341 * Resume the task
2342 * (reference/token/port management is caller's responsibility).
2343 */
2344kern_return_t
2345task_resume_internal(
2346 register task_suspension_token_t task)
2347{
2348 kern_return_t kr;
91447636 2349
39236c6e
A
2350 if (task == TASK_NULL || task == kernel_task)
2351 return (KERN_INVALID_ARGUMENT);
91447636 2352
39236c6e
A
2353 task_lock(task);
2354 kr = release_task_hold(task, TASK_HOLD_NORMAL);
316670eb 2355 task_unlock(task);
39236c6e
A
2356 return (kr);
2357}
2358
2359/*
2360 * Resume the task using a suspension token. Consumes the token's ref.
2361 */
2362kern_return_t
2363task_resume2(
2364 register task_suspension_token_t task)
2365{
2366 kern_return_t kr;
2367
2368 kr = task_resume_internal(task);
2369 task_suspension_token_deallocate(task);
91447636 2370
316670eb
A
2371 return (kr);
2372}
2373
39236c6e
A
2374boolean_t
2375task_suspension_notify(mach_msg_header_t *request_header)
2376{
2377 ipc_port_t port = (ipc_port_t) request_header->msgh_remote_port;
2378 task_t task = convert_port_to_task_suspension_token(port);
2379 mach_msg_type_number_t not_count;
2380
2381 if (task == TASK_NULL || task == kernel_task)
2382 return TRUE; /* nothing to do */
2383
2384 switch (request_header->msgh_id) {
2385
2386 case MACH_NOTIFY_SEND_ONCE:
2387 /* release the hold held by this specific send-once right */
2388 task_lock(task);
2389 release_task_hold(task, TASK_HOLD_NORMAL);
2390 task_unlock(task);
2391 break;
2392
2393 case MACH_NOTIFY_NO_SENDERS:
2394 not_count = ((mach_no_senders_notification_t *)request_header)->not_count;
2395
2396 task_lock(task);
2397 ip_lock(port);
2398 if (port->ip_mscount == not_count) {
2399
2400 /* release all the [remaining] outstanding legacy holds */
2401 assert(port->ip_nsrequest == IP_NULL);
2402 ip_unlock(port);
2403 release_task_hold(task, TASK_HOLD_LEGACY_ALL);
2404 task_unlock(task);
2405
2406 } else if (port->ip_nsrequest == IP_NULL) {
2407 ipc_port_t old_notify;
2408
2409 task_unlock(task);
2410 /* new send rights, re-arm notification at current make-send count */
2411 ipc_port_nsrequest(port, port->ip_mscount, ipc_port_make_sonce_locked(port), &old_notify);
2412 assert(old_notify == IP_NULL);
2413 /* port unlocked */
2414 } else {
2415 ip_unlock(port);
2416 task_unlock(task);
2417 }
2418 break;
2419
2420 default:
2421 break;
2422 }
2423
2424 task_suspension_token_deallocate(task); /* drop token reference */
2425 return TRUE;
2426}
2427
316670eb
A
2428kern_return_t
2429task_pidsuspend_locked(task_t task)
2430{
2431 kern_return_t kr;
2432
2433 if (task->pidsuspended) {
2434 kr = KERN_FAILURE;
2435 goto out;
1c79356b 2436 }
91447636 2437
316670eb
A
2438 task->pidsuspended = TRUE;
2439
39236c6e 2440 kr = place_task_hold(task, TASK_HOLD_PIDSUSPEND);
316670eb
A
2441 if (kr != KERN_SUCCESS) {
2442 task->pidsuspended = FALSE;
1c79356b 2443 }
316670eb
A
2444out:
2445 return(kr);
2446}
1c79356b 2447
316670eb
A
2448
2449/*
2450 * task_pidsuspend:
2451 *
2452 * Suspends a task by placing a hold on its threads.
2453 *
2454 * Conditions:
2455 * The caller holds a reference to the task
2456 */
2457kern_return_t
2458task_pidsuspend(
2459 register task_t task)
2460{
2461 kern_return_t kr;
2462
2463 if (task == TASK_NULL || task == kernel_task)
2464 return (KERN_INVALID_ARGUMENT);
2465
2466 task_lock(task);
2467
2468 kr = task_pidsuspend_locked(task);
1c79356b
A
2469
2470 task_unlock(task);
91447636 2471
316670eb
A
2472 return (kr);
2473}
2474
2475/* If enabled, we bring all the frozen pages back in prior to resumption; otherwise, they're faulted back in on demand */
2476#define THAW_ON_RESUME 1
2477
2478/*
2479 * task_pidresume:
2480 * Resumes a previously suspended task.
2481 *
2482 * Conditions:
2483 * The caller holds a reference to the task
2484 */
2485kern_return_t
2486task_pidresume(
2487 register task_t task)
2488{
2489 kern_return_t kr;
316670eb
A
2490
2491 if (task == TASK_NULL || task == kernel_task)
2492 return (KERN_INVALID_ARGUMENT);
2493
2494 task_lock(task);
2495
2496#if (CONFIG_FREEZE && THAW_ON_RESUME)
316670eb 2497
39236c6e 2498 while (task->changing_freeze_state) {
316670eb 2499
39236c6e
A
2500 assert_wait((event_t)&task->changing_freeze_state, THREAD_UNINT);
2501 task_unlock(task);
2502 thread_block(THREAD_CONTINUE_NULL);
316670eb 2503
39236c6e 2504 task_lock(task);
316670eb 2505 }
39236c6e
A
2506 task->changing_freeze_state = TRUE;
2507#endif
2508
2509 kr = release_task_hold(task, TASK_HOLD_PIDSUSPEND);
2510
2511 task_unlock(task);
2512
2513#if (CONFIG_FREEZE && THAW_ON_RESUME)
2514 if ((kr == KERN_SUCCESS) && (task->frozen == TRUE)) {
2515
2516 if (COMPRESSED_PAGER_IS_ACTIVE || DEFAULT_FREEZER_COMPRESSED_PAGER_IS_ACTIVE) {
2517
2518 kr = KERN_SUCCESS;
2519 } else {
2520
2521 kr = vm_map_thaw(task->map);
2522 }
2523 }
2524 task_lock(task);
2525
2526 if (kr == KERN_SUCCESS)
2527 task->frozen = FALSE;
2528 task->changing_freeze_state = FALSE;
2529 thread_wakeup(&task->changing_freeze_state);
2530
2531 task_unlock(task);
316670eb
A
2532#endif
2533
2534 return (kr);
1c79356b
A
2535}
2536
6d2010ae
A
2537#if CONFIG_FREEZE
2538
2539/*
2540 * task_freeze:
2541 *
316670eb 2542 * Freeze a task.
6d2010ae
A
2543 *
2544 * Conditions:
2545 * The caller holds a reference to the task
2546 */
3e170ce0
A
2547extern void vm_wake_compactor_swapper();
2548extern queue_head_t c_swapout_list_head;
2549
6d2010ae
A
2550kern_return_t
2551task_freeze(
2552 register task_t task,
2553 uint32_t *purgeable_count,
2554 uint32_t *wired_count,
2555 uint32_t *clean_count,
2556 uint32_t *dirty_count,
316670eb 2557 uint32_t dirty_budget,
6d2010ae
A
2558 boolean_t *shared,
2559 boolean_t walk_only)
2560{
316670eb
A
2561 kern_return_t kr;
2562
6d2010ae
A
2563 if (task == TASK_NULL || task == kernel_task)
2564 return (KERN_INVALID_ARGUMENT);
2565
316670eb
A
2566 task_lock(task);
2567
39236c6e
A
2568 while (task->changing_freeze_state) {
2569
2570 assert_wait((event_t)&task->changing_freeze_state, THREAD_UNINT);
2571 task_unlock(task);
2572 thread_block(THREAD_CONTINUE_NULL);
2573
2574 task_lock(task);
2575 }
316670eb 2576 if (task->frozen) {
39236c6e
A
2577 task_unlock(task);
2578 return (KERN_FAILURE);
316670eb 2579 }
39236c6e 2580 task->changing_freeze_state = TRUE;
316670eb
A
2581
2582 task_unlock(task);
2583
6d2010ae 2584 if (walk_only) {
316670eb 2585 kr = vm_map_freeze_walk(task->map, purgeable_count, wired_count, clean_count, dirty_count, dirty_budget, shared);
6d2010ae 2586 } else {
316670eb 2587 kr = vm_map_freeze(task->map, purgeable_count, wired_count, clean_count, dirty_count, dirty_budget, shared);
6d2010ae
A
2588 }
2589
39236c6e
A
2590 task_lock(task);
2591
2592 if (walk_only == FALSE && kr == KERN_SUCCESS)
2593 task->frozen = TRUE;
2594 task->changing_freeze_state = FALSE;
2595 thread_wakeup(&task->changing_freeze_state);
2596
2597 task_unlock(task);
2598
3e170ce0
A
2599 if (COMPRESSED_PAGER_IS_ACTIVE || DEFAULT_FREEZER_COMPRESSED_PAGER_IS_ACTIVE) {
2600 vm_wake_compactor_swapper();
2601 /*
2602 * We do an explicit wakeup of the swapout thread here
2603 * because the compact_and_swap routines don't have
2604 * knowledge about these kind of "per-task packed c_segs"
2605 * and so will not be evaluating whether we need to do
2606 * a wakeup there.
2607 */
2608 thread_wakeup((event_t)&c_swapout_list_head);
2609 }
2610
316670eb 2611 return (kr);
6d2010ae
A
2612}
2613
2614/*
2615 * task_thaw:
2616 *
2617 * Thaw a currently frozen task.
2618 *
2619 * Conditions:
2620 * The caller holds a reference to the task
2621 */
2622kern_return_t
2623task_thaw(
2624 register task_t task)
2625{
316670eb
A
2626 kern_return_t kr;
2627
6d2010ae
A
2628 if (task == TASK_NULL || task == kernel_task)
2629 return (KERN_INVALID_ARGUMENT);
2630
316670eb
A
2631 task_lock(task);
2632
39236c6e
A
2633 while (task->changing_freeze_state) {
2634
2635 assert_wait((event_t)&task->changing_freeze_state, THREAD_UNINT);
2636 task_unlock(task);
2637 thread_block(THREAD_CONTINUE_NULL);
2638
2639 task_lock(task);
2640 }
316670eb 2641 if (!task->frozen) {
39236c6e
A
2642 task_unlock(task);
2643 return (KERN_FAILURE);
316670eb 2644 }
39236c6e
A
2645 task->changing_freeze_state = TRUE;
2646
2647 if (DEFAULT_PAGER_IS_ACTIVE || DEFAULT_FREEZER_IS_ACTIVE) {
2648 task_unlock(task);
2649
2650 kr = vm_map_thaw(task->map);
316670eb 2651
39236c6e
A
2652 task_lock(task);
2653
2654 if (kr == KERN_SUCCESS)
2655 task->frozen = FALSE;
2656 } else {
2657 task->frozen = FALSE;
2658 kr = KERN_SUCCESS;
2659 }
6d2010ae 2660
39236c6e
A
2661 task->changing_freeze_state = FALSE;
2662 thread_wakeup(&task->changing_freeze_state);
2663
316670eb
A
2664 task_unlock(task);
2665
39236c6e 2666 if (COMPRESSED_PAGER_IS_ACTIVE || DEFAULT_FREEZER_COMPRESSED_PAGER_IS_ACTIVE) {
3e170ce0 2667 vm_wake_compactor_swapper();
39236c6e 2668 }
316670eb
A
2669
2670 return (kr);
6d2010ae
A
2671}
2672
2673#endif /* CONFIG_FREEZE */
2674
1c79356b
A
2675kern_return_t
2676host_security_set_task_token(
2677 host_security_t host_security,
2678 task_t task,
2679 security_token_t sec_token,
55e303ae 2680 audit_token_t audit_token,
1c79356b
A
2681 host_priv_t host_priv)
2682{
55e303ae 2683 ipc_port_t host_port;
1c79356b
A
2684 kern_return_t kr;
2685
2686 if (task == TASK_NULL)
2687 return(KERN_INVALID_ARGUMENT);
2688
2689 if (host_security == HOST_NULL)
2690 return(KERN_INVALID_SECURITY);
2691
2692 task_lock(task);
2693 task->sec_token = sec_token;
55e303ae 2694 task->audit_token = audit_token;
39236c6e
A
2695
2696 task_unlock(task);
1c79356b
A
2697
2698 if (host_priv != HOST_PRIV_NULL) {
55e303ae 2699 kr = host_get_host_priv_port(host_priv, &host_port);
1c79356b 2700 } else {
55e303ae 2701 kr = host_get_host_port(host_priv_self(), &host_port);
1c79356b 2702 }
55e303ae
A
2703 assert(kr == KERN_SUCCESS);
2704 kr = task_set_special_port(task, TASK_HOST_PORT, host_port);
1c79356b
A
2705 return(kr);
2706}
2707
fe8ab488
A
2708kern_return_t
2709task_send_trace_memory(
2710 task_t target_task,
2711 __unused uint32_t pid,
2712 __unused uint64_t uniqueid)
2713{
2714 kern_return_t kr = KERN_INVALID_ARGUMENT;
2715 if (target_task == TASK_NULL)
2716 return (KERN_INVALID_ARGUMENT);
2717
2718#if CONFIG_ATM
2719 kr = atm_send_proc_inspect_notification(target_task,
2720 pid,
2721 uniqueid);
2722
2723#endif
2724 return (kr);
2725}
1c79356b
A
2726/*
2727 * This routine was added, pretty much exclusively, for registering the
2728 * RPC glue vector for in-kernel short circuited tasks. Rather than
2729 * removing it completely, I have only disabled that feature (which was
2730 * the only feature at the time). It just appears that we are going to
2731 * want to add some user data to tasks in the future (i.e. bsd info,
2732 * task names, etc...), so I left it in the formal task interface.
2733 */
2734kern_return_t
2735task_set_info(
2736 task_t task,
2737 task_flavor_t flavor,
91447636
A
2738 __unused task_info_t task_info_in, /* pointer to IN array */
2739 __unused mach_msg_type_number_t task_info_count)
1c79356b 2740{
1c79356b
A
2741 if (task == TASK_NULL)
2742 return(KERN_INVALID_ARGUMENT);
2743
2744 switch (flavor) {
fe8ab488
A
2745
2746#if CONFIG_ATM
2747 case TASK_TRACE_MEMORY_INFO:
2748 {
2749 if (task_info_count != TASK_TRACE_MEMORY_INFO_COUNT)
2750 return (KERN_INVALID_ARGUMENT);
2751
2752 assert(task_info_in != NULL);
2753 task_trace_memory_info_t mem_info;
2754 mem_info = (task_trace_memory_info_t) task_info_in;
2755 kern_return_t kr = atm_register_trace_memory(task,
2756 mem_info->user_memory_address,
3e170ce0 2757 mem_info->buffer_size);
fe8ab488
A
2758 return kr;
2759 break;
2760 }
2761
2762#endif
1c79356b
A
2763 default:
2764 return (KERN_INVALID_ARGUMENT);
2765 }
2766 return (KERN_SUCCESS);
2767}
2768
3e170ce0 2769int radar_20146450 = 1;
1c79356b
A
2770kern_return_t
2771task_info(
39236c6e
A
2772 task_t task,
2773 task_flavor_t flavor,
2774 task_info_t task_info_out,
1c79356b
A
2775 mach_msg_type_number_t *task_info_count)
2776{
b0d623f7
A
2777 kern_return_t error = KERN_SUCCESS;
2778
1c79356b 2779 if (task == TASK_NULL)
91447636 2780 return (KERN_INVALID_ARGUMENT);
1c79356b 2781
b0d623f7
A
2782 task_lock(task);
2783
2784 if ((task != current_task()) && (!task->active)) {
2785 task_unlock(task);
2786 return (KERN_INVALID_ARGUMENT);
2787 }
2788
1c79356b
A
2789 switch (flavor) {
2790
91447636 2791 case TASK_BASIC_INFO_32:
2d21ac55 2792 case TASK_BASIC2_INFO_32:
91447636
A
2793 {
2794 task_basic_info_32_t basic_info;
b0d623f7
A
2795 vm_map_t map;
2796 clock_sec_t secs;
2797 clock_usec_t usecs;
1c79356b 2798
b0d623f7
A
2799 if (*task_info_count < TASK_BASIC_INFO_32_COUNT) {
2800 error = KERN_INVALID_ARGUMENT;
2801 break;
2802 }
1c79356b 2803
91447636 2804 basic_info = (task_basic_info_32_t)task_info_out;
1c79356b 2805
91447636 2806 map = (task == kernel_task)? kernel_map: task->map;
b0d623f7 2807 basic_info->virtual_size = (typeof(basic_info->virtual_size))map->size;
2d21ac55
A
2808 if (flavor == TASK_BASIC2_INFO_32) {
2809 /*
2810 * The "BASIC2" flavor gets the maximum resident
2811 * size instead of the current resident size...
2812 */
2813 basic_info->resident_size = pmap_resident_max(map->pmap);
2814 } else {
2815 basic_info->resident_size = pmap_resident_count(map->pmap);
2816 }
2817 basic_info->resident_size *= PAGE_SIZE;
1c79356b 2818
0b4e3aa0
A
2819 basic_info->policy = ((task != kernel_task)?
2820 POLICY_TIMESHARE: POLICY_RR);
1c79356b 2821 basic_info->suspend_count = task->user_stop_count;
91447636 2822
b0d623f7
A
2823 absolutetime_to_microtime(task->total_user_time, &secs, &usecs);
2824 basic_info->user_time.seconds =
2825 (typeof(basic_info->user_time.seconds))secs;
2826 basic_info->user_time.microseconds = usecs;
2827
2828 absolutetime_to_microtime(task->total_system_time, &secs, &usecs);
2829 basic_info->system_time.seconds =
2830 (typeof(basic_info->system_time.seconds))secs;
2831 basic_info->system_time.microseconds = usecs;
1c79356b 2832
91447636 2833 *task_info_count = TASK_BASIC_INFO_32_COUNT;
1c79356b 2834 break;
91447636 2835 }
1c79356b 2836
91447636
A
2837 case TASK_BASIC_INFO_64:
2838 {
2839 task_basic_info_64_t basic_info;
b0d623f7
A
2840 vm_map_t map;
2841 clock_sec_t secs;
2842 clock_usec_t usecs;
1c79356b 2843
b0d623f7
A
2844 if (*task_info_count < TASK_BASIC_INFO_64_COUNT) {
2845 error = KERN_INVALID_ARGUMENT;
2846 break;
2847 }
91447636
A
2848
2849 basic_info = (task_basic_info_64_t)task_info_out;
2850
2851 map = (task == kernel_task)? kernel_map: task->map;
2852 basic_info->virtual_size = map->size;
2d21ac55
A
2853 basic_info->resident_size =
2854 (mach_vm_size_t)(pmap_resident_count(map->pmap))
2855 * PAGE_SIZE_64;
91447636 2856
91447636
A
2857 basic_info->policy = ((task != kernel_task)?
2858 POLICY_TIMESHARE: POLICY_RR);
2859 basic_info->suspend_count = task->user_stop_count;
2860
b0d623f7
A
2861 absolutetime_to_microtime(task->total_user_time, &secs, &usecs);
2862 basic_info->user_time.seconds =
2863 (typeof(basic_info->user_time.seconds))secs;
2864 basic_info->user_time.microseconds = usecs;
2865
2866 absolutetime_to_microtime(task->total_system_time, &secs, &usecs);
2867 basic_info->system_time.seconds =
2868 (typeof(basic_info->system_time.seconds))secs;
2869 basic_info->system_time.microseconds = usecs;
91447636
A
2870
2871 *task_info_count = TASK_BASIC_INFO_64_COUNT;
2872 break;
2873 }
2874
316670eb
A
2875 case MACH_TASK_BASIC_INFO:
2876 {
2877 mach_task_basic_info_t basic_info;
2878 vm_map_t map;
2879 clock_sec_t secs;
2880 clock_usec_t usecs;
2881
2882 if (*task_info_count < MACH_TASK_BASIC_INFO_COUNT) {
2883 error = KERN_INVALID_ARGUMENT;
2884 break;
2885 }
2886
2887 basic_info = (mach_task_basic_info_t)task_info_out;
2888
2889 map = (task == kernel_task) ? kernel_map : task->map;
2890
2891 basic_info->virtual_size = map->size;
2892
2893 basic_info->resident_size =
2894 (mach_vm_size_t)(pmap_resident_count(map->pmap));
2895 basic_info->resident_size *= PAGE_SIZE_64;
2896
2897 basic_info->resident_size_max =
2898 (mach_vm_size_t)(pmap_resident_max(map->pmap));
2899 basic_info->resident_size_max *= PAGE_SIZE_64;
2900
2901 basic_info->policy = ((task != kernel_task) ?
2902 POLICY_TIMESHARE : POLICY_RR);
2903
2904 basic_info->suspend_count = task->user_stop_count;
2905
2906 absolutetime_to_microtime(task->total_user_time, &secs, &usecs);
2907 basic_info->user_time.seconds =
2908 (typeof(basic_info->user_time.seconds))secs;
2909 basic_info->user_time.microseconds = usecs;
2910
2911 absolutetime_to_microtime(task->total_system_time, &secs, &usecs);
2912 basic_info->system_time.seconds =
2913 (typeof(basic_info->system_time.seconds))secs;
2914 basic_info->system_time.microseconds = usecs;
2915
2916 *task_info_count = MACH_TASK_BASIC_INFO_COUNT;
2917 break;
2918 }
2919
91447636
A
2920 case TASK_THREAD_TIMES_INFO:
2921 {
2922 register task_thread_times_info_t times_info;
2923 register thread_t thread;
2924
b0d623f7
A
2925 if (*task_info_count < TASK_THREAD_TIMES_INFO_COUNT) {
2926 error = KERN_INVALID_ARGUMENT;
2927 break;
2928 }
1c79356b
A
2929
2930 times_info = (task_thread_times_info_t) task_info_out;
2931 times_info->user_time.seconds = 0;
2932 times_info->user_time.microseconds = 0;
2933 times_info->system_time.seconds = 0;
2934 times_info->system_time.microseconds = 0;
2935
1c79356b 2936
91447636 2937 queue_iterate(&task->threads, thread, thread_t, task_threads) {
39236c6e 2938 time_value_t user_time, system_time;
1c79356b 2939
39236c6e
A
2940 if (thread->options & TH_OPT_IDLE_THREAD)
2941 continue;
1c79356b 2942
39236c6e 2943 thread_read_times(thread, &user_time, &system_time);
91447636 2944
39236c6e
A
2945 time_value_add(&times_info->user_time, &user_time);
2946 time_value_add(&times_info->system_time, &system_time);
2947 }
1c79356b
A
2948
2949 *task_info_count = TASK_THREAD_TIMES_INFO_COUNT;
2950 break;
91447636
A
2951 }
2952
2953 case TASK_ABSOLUTETIME_INFO:
2954 {
2955 task_absolutetime_info_t info;
2956 register thread_t thread;
2957
b0d623f7
A
2958 if (*task_info_count < TASK_ABSOLUTETIME_INFO_COUNT) {
2959 error = KERN_INVALID_ARGUMENT;
2960 break;
2961 }
91447636
A
2962
2963 info = (task_absolutetime_info_t)task_info_out;
2964 info->threads_user = info->threads_system = 0;
2965
91447636
A
2966
2967 info->total_user = task->total_user_time;
2968 info->total_system = task->total_system_time;
2969
2970 queue_iterate(&task->threads, thread, thread_t, task_threads) {
2971 uint64_t tval;
316670eb
A
2972 spl_t x;
2973
39236c6e
A
2974 if (thread->options & TH_OPT_IDLE_THREAD)
2975 continue;
2976
316670eb
A
2977 x = splsched();
2978 thread_lock(thread);
91447636
A
2979
2980 tval = timer_grab(&thread->user_timer);
2981 info->threads_user += tval;
2982 info->total_user += tval;
2983
2984 tval = timer_grab(&thread->system_timer);
316670eb
A
2985 if (thread->precise_user_kernel_time) {
2986 info->threads_system += tval;
2987 info->total_system += tval;
2988 } else {
2989 /* system_timer may represent either sys or user */
2990 info->threads_user += tval;
2991 info->total_user += tval;
2992 }
2993
2994 thread_unlock(thread);
2995 splx(x);
91447636
A
2996 }
2997
91447636
A
2998
2999 *task_info_count = TASK_ABSOLUTETIME_INFO_COUNT;
3000 break;
3001 }
1c79356b 3002
b0d623f7
A
3003 case TASK_DYLD_INFO:
3004 {
3005 task_dyld_info_t info;
3006
6d2010ae
A
3007 /*
3008 * We added the format field to TASK_DYLD_INFO output. For
3009 * temporary backward compatibility, accept the fact that
3010 * clients may ask for the old version - distinquished by the
3011 * size of the expected result structure.
3012 */
3013#define TASK_LEGACY_DYLD_INFO_COUNT \
3014 offsetof(struct task_dyld_info, all_image_info_format)/sizeof(natural_t)
3015
3016 if (*task_info_count < TASK_LEGACY_DYLD_INFO_COUNT) {
b0d623f7
A
3017 error = KERN_INVALID_ARGUMENT;
3018 break;
3019 }
6d2010ae 3020
b0d623f7
A
3021 info = (task_dyld_info_t)task_info_out;
3022 info->all_image_info_addr = task->all_image_info_addr;
3023 info->all_image_info_size = task->all_image_info_size;
6d2010ae
A
3024
3025 /* only set format on output for those expecting it */
3026 if (*task_info_count >= TASK_DYLD_INFO_COUNT) {
3027 info->all_image_info_format = task_has_64BitAddr(task) ?
3028 TASK_DYLD_ALL_IMAGE_INFO_64 :
3029 TASK_DYLD_ALL_IMAGE_INFO_32 ;
3030 *task_info_count = TASK_DYLD_INFO_COUNT;
3031 } else {
3032 *task_info_count = TASK_LEGACY_DYLD_INFO_COUNT;
3033 }
b0d623f7
A
3034 break;
3035 }
3036
6d2010ae
A
3037 case TASK_EXTMOD_INFO:
3038 {
3039 task_extmod_info_t info;
3040 void *p;
3041
3042 if (*task_info_count < TASK_EXTMOD_INFO_COUNT) {
3043 error = KERN_INVALID_ARGUMENT;
3044 break;
3045 }
3046
3047 info = (task_extmod_info_t)task_info_out;
3048
3049 p = get_bsdtask_info(task);
3050 if (p) {
3051 proc_getexecutableuuid(p, info->task_uuid, sizeof(info->task_uuid));
3052 } else {
3053 bzero(info->task_uuid, sizeof(info->task_uuid));
3054 }
3055 info->extmod_statistics = task->extmod_statistics;
3056 *task_info_count = TASK_EXTMOD_INFO_COUNT;
3057
3058 break;
3059 }
3060
3061 case TASK_KERNELMEMORY_INFO:
3062 {
3063 task_kernelmemory_info_t tkm_info;
316670eb 3064 ledger_amount_t credit, debit;
6d2010ae
A
3065
3066 if (*task_info_count < TASK_KERNELMEMORY_INFO_COUNT) {
3067 error = KERN_INVALID_ARGUMENT;
3068 break;
3069 }
3070
3071 tkm_info = (task_kernelmemory_info_t) task_info_out;
316670eb
A
3072 tkm_info->total_palloc = 0;
3073 tkm_info->total_pfree = 0;
3074 tkm_info->total_salloc = 0;
3075 tkm_info->total_sfree = 0;
6d2010ae
A
3076
3077 if (task == kernel_task) {
3078 /*
3079 * All shared allocs/frees from other tasks count against
3080 * the kernel private memory usage. If we are looking up
3081 * info for the kernel task, gather from everywhere.
3082 */
3083 task_unlock(task);
3084
3085 /* start by accounting for all the terminated tasks against the kernel */
3086 tkm_info->total_palloc = tasks_tkm_private.alloc + tasks_tkm_shared.alloc;
3087 tkm_info->total_pfree = tasks_tkm_private.free + tasks_tkm_shared.free;
6d2010ae
A
3088
3089 /* count all other task/thread shared alloc/free against the kernel */
3090 lck_mtx_lock(&tasks_threads_lock);
316670eb
A
3091
3092 /* XXX this really shouldn't be using the function parameter 'task' as a local var! */
6d2010ae
A
3093 queue_iterate(&tasks, task, task_t, tasks) {
3094 if (task == kernel_task) {
316670eb
A
3095 if (ledger_get_entries(task->ledger,
3096 task_ledgers.tkm_private, &credit,
3097 &debit) == KERN_SUCCESS) {
3098 tkm_info->total_palloc += credit;
3099 tkm_info->total_pfree += debit;
3100 }
6d2010ae 3101 }
316670eb
A
3102 if (!ledger_get_entries(task->ledger,
3103 task_ledgers.tkm_shared, &credit, &debit)) {
3104 tkm_info->total_palloc += credit;
3105 tkm_info->total_pfree += debit;
6d2010ae 3106 }
6d2010ae
A
3107 }
3108 lck_mtx_unlock(&tasks_threads_lock);
3109 } else {
316670eb
A
3110 if (!ledger_get_entries(task->ledger,
3111 task_ledgers.tkm_private, &credit, &debit)) {
3112 tkm_info->total_palloc = credit;
3113 tkm_info->total_pfree = debit;
3114 }
3115 if (!ledger_get_entries(task->ledger,
3116 task_ledgers.tkm_shared, &credit, &debit)) {
3117 tkm_info->total_salloc = credit;
3118 tkm_info->total_sfree = debit;
6d2010ae
A
3119 }
3120 task_unlock(task);
3121 }
3122
3123 *task_info_count = TASK_KERNELMEMORY_INFO_COUNT;
3124 return KERN_SUCCESS;
3125 }
3126
91447636
A
3127 /* OBSOLETE */
3128 case TASK_SCHED_FIFO_INFO:
3129 {
1c79356b 3130
b0d623f7
A
3131 if (*task_info_count < POLICY_FIFO_BASE_COUNT) {
3132 error = KERN_INVALID_ARGUMENT;
3133 break;
3134 }
1c79356b 3135
b0d623f7 3136 error = KERN_INVALID_POLICY;
6d2010ae 3137 break;
91447636 3138 }
1c79356b 3139
91447636
A
3140 /* OBSOLETE */
3141 case TASK_SCHED_RR_INFO:
3142 {
1c79356b 3143 register policy_rr_base_t rr_base;
6d2010ae
A
3144 uint32_t quantum_time;
3145 uint64_t quantum_ns;
1c79356b 3146
b0d623f7
A
3147 if (*task_info_count < POLICY_RR_BASE_COUNT) {
3148 error = KERN_INVALID_ARGUMENT;
3149 break;
3150 }
1c79356b
A
3151
3152 rr_base = (policy_rr_base_t) task_info_out;
3153
0b4e3aa0 3154 if (task != kernel_task) {
b0d623f7
A
3155 error = KERN_INVALID_POLICY;
3156 break;
1c79356b
A
3157 }
3158
3159 rr_base->base_priority = task->priority;
1c79356b 3160
6d2010ae
A
3161 quantum_time = SCHED(initial_quantum_size)(THREAD_NULL);
3162 absolutetime_to_nanoseconds(quantum_time, &quantum_ns);
3163
3164 rr_base->quantum = (uint32_t)(quantum_ns / 1000 / 1000);
1c79356b
A
3165
3166 *task_info_count = POLICY_RR_BASE_COUNT;
3167 break;
91447636 3168 }
1c79356b 3169
91447636
A
3170 /* OBSOLETE */
3171 case TASK_SCHED_TIMESHARE_INFO:
3172 {
1c79356b
A
3173 register policy_timeshare_base_t ts_base;
3174
b0d623f7
A
3175 if (*task_info_count < POLICY_TIMESHARE_BASE_COUNT) {
3176 error = KERN_INVALID_ARGUMENT;
3177 break;
3178 }
1c79356b
A
3179
3180 ts_base = (policy_timeshare_base_t) task_info_out;
3181
0b4e3aa0 3182 if (task == kernel_task) {
b0d623f7
A
3183 error = KERN_INVALID_POLICY;
3184 break;
1c79356b
A
3185 }
3186
3187 ts_base->base_priority = task->priority;
1c79356b
A
3188
3189 *task_info_count = POLICY_TIMESHARE_BASE_COUNT;
3190 break;
91447636 3191 }
1c79356b 3192
91447636
A
3193 case TASK_SECURITY_TOKEN:
3194 {
3195 register security_token_t *sec_token_p;
1c79356b 3196
b0d623f7
A
3197 if (*task_info_count < TASK_SECURITY_TOKEN_COUNT) {
3198 error = KERN_INVALID_ARGUMENT;
3199 break;
3200 }
1c79356b
A
3201
3202 sec_token_p = (security_token_t *) task_info_out;
3203
1c79356b 3204 *sec_token_p = task->sec_token;
1c79356b
A
3205
3206 *task_info_count = TASK_SECURITY_TOKEN_COUNT;
91447636
A
3207 break;
3208 }
1c79356b 3209
91447636
A
3210 case TASK_AUDIT_TOKEN:
3211 {
3212 register audit_token_t *audit_token_p;
55e303ae 3213
b0d623f7
A
3214 if (*task_info_count < TASK_AUDIT_TOKEN_COUNT) {
3215 error = KERN_INVALID_ARGUMENT;
3216 break;
3217 }
55e303ae
A
3218
3219 audit_token_p = (audit_token_t *) task_info_out;
3220
55e303ae 3221 *audit_token_p = task->audit_token;
55e303ae
A
3222
3223 *task_info_count = TASK_AUDIT_TOKEN_COUNT;
91447636
A
3224 break;
3225 }
55e303ae 3226
91447636 3227 case TASK_SCHED_INFO:
b0d623f7 3228 error = KERN_INVALID_ARGUMENT;
6d2010ae 3229 break;
1c79356b 3230
91447636
A
3231 case TASK_EVENTS_INFO:
3232 {
1c79356b 3233 register task_events_info_t events_info;
2d21ac55 3234 register thread_t thread;
1c79356b 3235
b0d623f7
A
3236 if (*task_info_count < TASK_EVENTS_INFO_COUNT) {
3237 error = KERN_INVALID_ARGUMENT;
3238 break;
3239 }
1c79356b
A
3240
3241 events_info = (task_events_info_t) task_info_out;
3242
2d21ac55 3243
1c79356b
A
3244 events_info->faults = task->faults;
3245 events_info->pageins = task->pageins;
3246 events_info->cow_faults = task->cow_faults;
3247 events_info->messages_sent = task->messages_sent;
3248 events_info->messages_received = task->messages_received;
3249 events_info->syscalls_mach = task->syscalls_mach;
3250 events_info->syscalls_unix = task->syscalls_unix;
2d21ac55
A
3251
3252 events_info->csw = task->c_switch;
3253
3254 queue_iterate(&task->threads, thread, thread_t, task_threads) {
6d2010ae
A
3255 events_info->csw += thread->c_switch;
3256 events_info->syscalls_mach += thread->syscalls_mach;
3257 events_info->syscalls_unix += thread->syscalls_unix;
2d21ac55
A
3258 }
3259
1c79356b
A
3260
3261 *task_info_count = TASK_EVENTS_INFO_COUNT;
3262 break;
91447636 3263 }
2d21ac55
A
3264 case TASK_AFFINITY_TAG_INFO:
3265 {
b0d623f7
A
3266 if (*task_info_count < TASK_AFFINITY_TAG_INFO_COUNT) {
3267 error = KERN_INVALID_ARGUMENT;
3268 break;
3269 }
2d21ac55 3270
b0d623f7 3271 error = task_affinity_info(task, task_info_out, task_info_count);
6d2010ae 3272 break;
2d21ac55 3273 }
4b17d6b6
A
3274 case TASK_POWER_INFO:
3275 {
4b17d6b6
A
3276 if (*task_info_count < TASK_POWER_INFO_COUNT) {
3277 error = KERN_INVALID_ARGUMENT;
3278 break;
3279 }
3280
fe8ab488
A
3281 task_power_info_locked(task, (task_power_info_t)task_info_out, NULL);
3282 break;
3283 }
3284
3285 case TASK_POWER_INFO_V2:
3286 {
3287 if (*task_info_count < TASK_POWER_INFO_V2_COUNT) {
3288 error = KERN_INVALID_ARGUMENT;
3289 break;
3290 }
3291 task_power_info_v2_t tpiv2 = (task_power_info_v2_t) task_info_out;
3292 task_power_info_locked(task, &tpiv2->cpu_energy, &tpiv2->gpu_energy);
39236c6e
A
3293 break;
3294 }
4b17d6b6 3295
39236c6e
A
3296 case TASK_VM_INFO:
3297 case TASK_VM_INFO_PURGEABLE:
3298 {
3299 task_vm_info_t vm_info;
3300 vm_map_t map;
4b17d6b6 3301
3e170ce0 3302 if (*task_info_count < TASK_VM_INFO_REV0_COUNT) {
39236c6e
A
3303 error = KERN_INVALID_ARGUMENT;
3304 break;
3305 }
4b17d6b6 3306
39236c6e 3307 vm_info = (task_vm_info_t)task_info_out;
4b17d6b6 3308
39236c6e
A
3309 if (task == kernel_task) {
3310 map = kernel_map;
3311 /* no lock */
3312 } else {
3313 map = task->map;
3314 vm_map_lock_read(map);
3315 }
4b17d6b6 3316
39236c6e
A
3317 vm_info->virtual_size = (typeof(vm_info->virtual_size))map->size;
3318 vm_info->region_count = map->hdr.nentries;
3319 vm_info->page_size = vm_map_page_size(map);
3320
3321 vm_info->resident_size = pmap_resident_count(map->pmap);
3322 vm_info->resident_size *= PAGE_SIZE;
3323 vm_info->resident_size_peak = pmap_resident_max(map->pmap);
3324 vm_info->resident_size_peak *= PAGE_SIZE;
3325
3326#define _VM_INFO(_name) \
3327 vm_info->_name = ((mach_vm_size_t) map->pmap->stats._name) * PAGE_SIZE
3328
3329 _VM_INFO(device);
3330 _VM_INFO(device_peak);
3331 _VM_INFO(external);
3332 _VM_INFO(external_peak);
3333 _VM_INFO(internal);
3334 _VM_INFO(internal_peak);
3335 _VM_INFO(reusable);
3336 _VM_INFO(reusable_peak);
3337 _VM_INFO(compressed);
3338 _VM_INFO(compressed_peak);
3339 _VM_INFO(compressed_lifetime);
3340
3341 vm_info->purgeable_volatile_pmap = 0;
3342 vm_info->purgeable_volatile_resident = 0;
3343 vm_info->purgeable_volatile_virtual = 0;
3344 if (task == kernel_task) {
3345 /*
3346 * We do not maintain the detailed stats for the
3347 * kernel_pmap, so just count everything as
3348 * "internal"...
3349 */
3350 vm_info->internal = vm_info->resident_size;
3351 /*
3352 * ... but since the memory held by the VM compressor
3353 * in the kernel address space ought to be attributed
3354 * to user-space tasks, we subtract it from "internal"
3355 * to give memory reporting tools a more accurate idea
3356 * of what the kernel itself is actually using, instead
3357 * of making it look like the kernel is leaking memory
3358 * when the system is under memory pressure.
3359 */
3360 vm_info->internal -= (VM_PAGE_COMPRESSOR_COUNT *
3361 PAGE_SIZE);
3362 } else {
3363 mach_vm_size_t volatile_virtual_size;
3364 mach_vm_size_t volatile_resident_size;
3e170ce0 3365 mach_vm_size_t volatile_compressed_size;
39236c6e 3366 mach_vm_size_t volatile_pmap_size;
3e170ce0 3367 mach_vm_size_t volatile_compressed_pmap_size;
39236c6e
A
3368 kern_return_t kr;
3369
3370 if (flavor == TASK_VM_INFO_PURGEABLE) {
3371 kr = vm_map_query_volatile(
3372 map,
3373 &volatile_virtual_size,
3374 &volatile_resident_size,
3e170ce0
A
3375 &volatile_compressed_size,
3376 &volatile_pmap_size,
3377 &volatile_compressed_pmap_size);
39236c6e
A
3378 if (kr == KERN_SUCCESS) {
3379 vm_info->purgeable_volatile_pmap =
3380 volatile_pmap_size;
3e170ce0
A
3381 if (radar_20146450) {
3382 vm_info->compressed -=
3383 volatile_compressed_pmap_size;
3384 }
39236c6e
A
3385 vm_info->purgeable_volatile_resident =
3386 volatile_resident_size;
3387 vm_info->purgeable_volatile_virtual =
3388 volatile_virtual_size;
3389 }
4b17d6b6 3390 }
39236c6e 3391 vm_map_unlock_read(map);
4b17d6b6 3392 }
39236c6e 3393
3e170ce0
A
3394 if (*task_info_count >= TASK_VM_INFO_COUNT) {
3395 vm_info->phys_footprint = 0;
3396 *task_info_count = TASK_VM_INFO_COUNT;
3397 } else {
3398 *task_info_count = TASK_VM_INFO_REV0_COUNT;
3399 }
3400
4b17d6b6
A
3401 break;
3402 }
3403
fe8ab488
A
3404 case TASK_WAIT_STATE_INFO:
3405 {
3406 /*
3407 * Deprecated flavor. Currently allowing some results until all users
3408 * stop calling it. The results may not be accurate.
3409 */
3410 task_wait_state_info_t wait_state_info;
3411 uint64_t total_sfi_ledger_val = 0;
3412
3413 if (*task_info_count < TASK_WAIT_STATE_INFO_COUNT) {
3414 error = KERN_INVALID_ARGUMENT;
3415 break;
3416 }
3417
3418 wait_state_info = (task_wait_state_info_t) task_info_out;
3419
3420 wait_state_info->total_wait_state_time = 0;
3421 bzero(wait_state_info->_reserved, sizeof(wait_state_info->_reserved));
3422
3e170ce0 3423#if CONFIG_SCHED_SFI
fe8ab488
A
3424 int i, prev_lentry = -1;
3425 int64_t val_credit, val_debit;
3426
3427 for (i = 0; i < MAX_SFI_CLASS_ID; i++){
3428 val_credit =0;
3429 /*
3430 * checking with prev_lentry != entry ensures adjacent classes
3431 * which share the same ledger do not add wait times twice.
3432 * Note: Use ledger() call to get data for each individual sfi class.
3433 */
3434 if (prev_lentry != task_ledgers.sfi_wait_times[i] &&
3435 KERN_SUCCESS == ledger_get_entries(task->ledger,
3436 task_ledgers.sfi_wait_times[i], &val_credit, &val_debit)) {
3437 total_sfi_ledger_val += val_credit;
3438 }
3439 prev_lentry = task_ledgers.sfi_wait_times[i];
3440 }
3441
3e170ce0 3442#endif /* CONFIG_SCHED_SFI */
fe8ab488
A
3443 wait_state_info->total_wait_sfi_state_time = total_sfi_ledger_val;
3444 *task_info_count = TASK_WAIT_STATE_INFO_COUNT;
3445
3446 break;
3447 }
3e170ce0
A
3448 case TASK_VM_INFO_PURGEABLE_ACCOUNT:
3449 {
3450#if DEVELOPMENT || DEBUG
3451 pvm_account_info_t acnt_info;
3452
3453 if (*task_info_count < PVM_ACCOUNT_INFO_COUNT) {
3454 error = KERN_INVALID_ARGUMENT;
3455 break;
3456 }
fe8ab488 3457
3e170ce0
A
3458 if (task_info_out == NULL) {
3459 error = KERN_INVALID_ARGUMENT;
3460 break;
3461 }
3462
3463 acnt_info = (pvm_account_info_t) task_info_out;
3464
3465 error = vm_purgeable_account(task, acnt_info);
3466
3467 *task_info_count = PVM_ACCOUNT_INFO_COUNT;
3468
3469 break;
3470#else /* DEVELOPMENT || DEBUG */
3471 error = KERN_NOT_SUPPORTED;
3472 break;
3473#endif /* DEVELOPMENT || DEBUG */
3474 }
3475 case TASK_FLAGS_INFO:
3476 {
3477 task_flags_info_t flags_info;
3478
3479 if (*task_info_count < TASK_FLAGS_INFO_COUNT) {
3480 error = KERN_INVALID_ARGUMENT;
3481 break;
3482 }
3483
3484 flags_info = (task_flags_info_t)task_info_out;
3485
3486 /* only publish the 64-bit flag of the task */
3487 flags_info->flags = task->t_flags & TF_64B_ADDR;
3488
3489 *task_info_count = TASK_FLAGS_INFO_COUNT;
3490 break;
3491 }
3492
3493 case TASK_DEBUG_INFO_INTERNAL:
3494 {
3495#if DEVELOPMENT || DEBUG
3496 task_debug_info_internal_t dbg_info;
3497 if (*task_info_count < TASK_DEBUG_INFO_INTERNAL_COUNT) {
3498 error = KERN_NOT_SUPPORTED;
3499 break;
3500 }
3501
3502 if (task_info_out == NULL) {
3503 error = KERN_INVALID_ARGUMENT;
3504 break;
3505 }
3506 dbg_info = (task_debug_info_internal_t) task_info_out;
3507 dbg_info->ipc_space_size = 0;
3508 if (task->itk_space){
3509 dbg_info->ipc_space_size = task->itk_space->is_table_size;
3510 }
3511
3512 error = KERN_SUCCESS;
3513 *task_info_count = TASK_DEBUG_INFO_INTERNAL_COUNT;
3514 break;
3515#else /* DEVELOPMENT || DEBUG */
3516 error = KERN_NOT_SUPPORTED;
3517 break;
3518#endif /* DEVELOPMENT || DEBUG */
3519 }
91447636 3520 default:
b0d623f7 3521 error = KERN_INVALID_ARGUMENT;
1c79356b
A
3522 }
3523
b0d623f7
A
3524 task_unlock(task);
3525 return (error);
1c79356b
A
3526}
3527
39236c6e
A
3528/*
3529 * task_power_info
3530 *
3531 * Returns power stats for the task.
3532 * Note: Called with task locked.
3533 */
3534void
3535task_power_info_locked(
3536 task_t task,
fe8ab488
A
3537 task_power_info_t info,
3538 gpu_energy_data_t ginfo)
39236c6e
A
3539{
3540 thread_t thread;
3541 ledger_amount_t tmp;
3542
3543 task_lock_assert_owned(task);
3544
3545 ledger_get_entries(task->ledger, task_ledgers.interrupt_wakeups,
3546 (ledger_amount_t *)&info->task_interrupt_wakeups, &tmp);
3547 ledger_get_entries(task->ledger, task_ledgers.platform_idle_wakeups,
3548 (ledger_amount_t *)&info->task_platform_idle_wakeups, &tmp);
3549
3550 info->task_timer_wakeups_bin_1 = task->task_timer_wakeups_bin_1;
3551 info->task_timer_wakeups_bin_2 = task->task_timer_wakeups_bin_2;
3552
3553 info->total_user = task->total_user_time;
3554 info->total_system = task->total_system_time;
3555
fe8ab488
A
3556 if (ginfo) {
3557 ginfo->task_gpu_utilisation = task->task_gpu_ns;
3558 }
3559
39236c6e
A
3560 queue_iterate(&task->threads, thread, thread_t, task_threads) {
3561 uint64_t tval;
3562 spl_t x;
3563
3564 if (thread->options & TH_OPT_IDLE_THREAD)
3565 continue;
3566
3567 x = splsched();
3568 thread_lock(thread);
3569
3570 info->task_timer_wakeups_bin_1 += thread->thread_timer_wakeups_bin_1;
3571 info->task_timer_wakeups_bin_2 += thread->thread_timer_wakeups_bin_2;
3572
3573 tval = timer_grab(&thread->user_timer);
3574 info->total_user += tval;
3575
3576 tval = timer_grab(&thread->system_timer);
3577 if (thread->precise_user_kernel_time) {
3578 info->total_system += tval;
3579 } else {
3580 /* system_timer may represent either sys or user */
3581 info->total_user += tval;
3582 }
3583
fe8ab488
A
3584 if (ginfo) {
3585 ginfo->task_gpu_utilisation += ml_gpu_stat(thread);
3586 }
3587 thread_unlock(thread);
3588 splx(x);
3589 }
3590}
3591
3592/*
3593 * task_gpu_utilisation
3594 *
3595 * Returns the total gpu time used by the all the threads of the task
3596 * (both dead and alive)
3597 */
3598uint64_t
3599task_gpu_utilisation(
3600 task_t task)
3601{
3602 uint64_t gpu_time = 0;
3603 thread_t thread;
3604
3605 task_lock(task);
3606 gpu_time += task->task_gpu_ns;
3607
3608 queue_iterate(&task->threads, thread, thread_t, task_threads) {
3609 spl_t x;
3610 x = splsched();
3611 thread_lock(thread);
3612 gpu_time += ml_gpu_stat(thread);
39236c6e
A
3613 thread_unlock(thread);
3614 splx(x);
3615 }
fe8ab488
A
3616
3617 task_unlock(task);
3618 return gpu_time;
39236c6e
A
3619}
3620
3621kern_return_t
3622task_purgable_info(
3623 task_t task,
3624 task_purgable_info_t *stats)
3625{
3626 if (task == TASK_NULL || stats == NULL)
3627 return KERN_INVALID_ARGUMENT;
3628 /* Take task reference */
3629 task_reference(task);
3630 vm_purgeable_stats((vm_purgeable_info_t)stats, task);
3631 /* Drop task reference */
3632 task_deallocate(task);
3633 return KERN_SUCCESS;
3634}
3635
2d21ac55
A
3636void
3637task_vtimer_set(
3638 task_t task,
3639 integer_t which)
3640{
3641 thread_t thread;
316670eb 3642 spl_t x;
2d21ac55
A
3643
3644 /* assert(task == current_task()); */ /* bogus assert 4803227 4807483 */
3645
3646 task_lock(task);
3647
3648 task->vtimers |= which;
3649
3650 switch (which) {
3651
3652 case TASK_VTIMER_USER:
3653 queue_iterate(&task->threads, thread, thread_t, task_threads) {
316670eb
A
3654 x = splsched();
3655 thread_lock(thread);
3656 if (thread->precise_user_kernel_time)
3657 thread->vtimer_user_save = timer_grab(&thread->user_timer);
3658 else
3659 thread->vtimer_user_save = timer_grab(&thread->system_timer);
3660 thread_unlock(thread);
3661 splx(x);
2d21ac55
A
3662 }
3663 break;
3664
3665 case TASK_VTIMER_PROF:
3666 queue_iterate(&task->threads, thread, thread_t, task_threads) {
316670eb
A
3667 x = splsched();
3668 thread_lock(thread);
2d21ac55
A
3669 thread->vtimer_prof_save = timer_grab(&thread->user_timer);
3670 thread->vtimer_prof_save += timer_grab(&thread->system_timer);
316670eb
A
3671 thread_unlock(thread);
3672 splx(x);
2d21ac55
A
3673 }
3674 break;
3675
3676 case TASK_VTIMER_RLIM:
3677 queue_iterate(&task->threads, thread, thread_t, task_threads) {
316670eb
A
3678 x = splsched();
3679 thread_lock(thread);
2d21ac55
A
3680 thread->vtimer_rlim_save = timer_grab(&thread->user_timer);
3681 thread->vtimer_rlim_save += timer_grab(&thread->system_timer);
316670eb
A
3682 thread_unlock(thread);
3683 splx(x);
2d21ac55
A
3684 }
3685 break;
3686 }
3687
3688 task_unlock(task);
3689}
3690
3691void
3692task_vtimer_clear(
3693 task_t task,
3694 integer_t which)
3695{
3696 assert(task == current_task());
3697
3698 task_lock(task);
3699
3700 task->vtimers &= ~which;
3701
3702 task_unlock(task);
3703}
3704
3705void
3706task_vtimer_update(
3707__unused
3708 task_t task,
3709 integer_t which,
3710 uint32_t *microsecs)
3711{
3712 thread_t thread = current_thread();
b0d623f7
A
3713 uint32_t tdelt;
3714 clock_sec_t secs;
2d21ac55
A
3715 uint64_t tsum;
3716
3717 assert(task == current_task());
3718
3719 assert(task->vtimers & which);
3720
b0d623f7 3721 secs = tdelt = 0;
2d21ac55
A
3722
3723 switch (which) {
3724
3725 case TASK_VTIMER_USER:
316670eb
A
3726 if (thread->precise_user_kernel_time) {
3727 tdelt = (uint32_t)timer_delta(&thread->user_timer,
3728 &thread->vtimer_user_save);
3729 } else {
3730 tdelt = (uint32_t)timer_delta(&thread->system_timer,
2d21ac55 3731 &thread->vtimer_user_save);
316670eb 3732 }
b0d623f7 3733 absolutetime_to_microtime(tdelt, &secs, microsecs);
2d21ac55
A
3734 break;
3735
3736 case TASK_VTIMER_PROF:
3737 tsum = timer_grab(&thread->user_timer);
3738 tsum += timer_grab(&thread->system_timer);
b0d623f7
A
3739 tdelt = (uint32_t)(tsum - thread->vtimer_prof_save);
3740 absolutetime_to_microtime(tdelt, &secs, microsecs);
3741 /* if the time delta is smaller than a usec, ignore */
3742 if (*microsecs != 0)
3743 thread->vtimer_prof_save = tsum;
2d21ac55
A
3744 break;
3745
3746 case TASK_VTIMER_RLIM:
3747 tsum = timer_grab(&thread->user_timer);
3748 tsum += timer_grab(&thread->system_timer);
b0d623f7 3749 tdelt = (uint32_t)(tsum - thread->vtimer_rlim_save);
2d21ac55 3750 thread->vtimer_rlim_save = tsum;
b0d623f7 3751 absolutetime_to_microtime(tdelt, &secs, microsecs);
2d21ac55
A
3752 break;
3753 }
3754
2d21ac55
A
3755}
3756
1c79356b
A
3757/*
3758 * task_assign:
3759 *
3760 * Change the assigned processor set for the task
3761 */
3762kern_return_t
3763task_assign(
91447636
A
3764 __unused task_t task,
3765 __unused processor_set_t new_pset,
3766 __unused boolean_t assign_threads)
1c79356b 3767{
1c79356b
A
3768 return(KERN_FAILURE);
3769}
3770
3771/*
3772 * task_assign_default:
3773 *
3774 * Version of task_assign to assign to default processor set.
3775 */
3776kern_return_t
3777task_assign_default(
3778 task_t task,
3779 boolean_t assign_threads)
3780{
2d21ac55 3781 return (task_assign(task, &pset0, assign_threads));
1c79356b
A
3782}
3783
3784/*
3785 * task_get_assignment
3786 *
3787 * Return name of processor set that task is assigned to.
3788 */
3789kern_return_t
3790task_get_assignment(
3791 task_t task,
3792 processor_set_t *pset)
3793{
3794 if (!task->active)
3795 return(KERN_FAILURE);
3796
2d21ac55
A
3797 *pset = &pset0;
3798
3799 return (KERN_SUCCESS);
1c79356b
A
3800}
3801
3e170ce0
A
3802uint64_t
3803get_task_dispatchqueue_offset(
3804 task_t task)
3805{
3806 return task->dispatchqueue_offset;
3807}
1c79356b
A
3808
3809/*
3810 * task_policy
3811 *
3812 * Set scheduling policy and parameters, both base and limit, for
3813 * the given task. Policy must be a policy which is enabled for the
3814 * processor set. Change contained threads if requested.
3815 */
3816kern_return_t
3817task_policy(
91447636
A
3818 __unused task_t task,
3819 __unused policy_t policy_id,
3820 __unused policy_base_t base,
3821 __unused mach_msg_type_number_t count,
3822 __unused boolean_t set_limit,
3823 __unused boolean_t change)
1c79356b
A
3824{
3825 return(KERN_FAILURE);
3826}
3827
3828/*
3829 * task_set_policy
3830 *
3831 * Set scheduling policy and parameters, both base and limit, for
3832 * the given task. Policy can be any policy implemented by the
3833 * processor set, whether enabled or not. Change contained threads
3834 * if requested.
3835 */
3836kern_return_t
3837task_set_policy(
91447636
A
3838 __unused task_t task,
3839 __unused processor_set_t pset,
3840 __unused policy_t policy_id,
3841 __unused policy_base_t base,
3842 __unused mach_msg_type_number_t base_count,
3843 __unused policy_limit_t limit,
3844 __unused mach_msg_type_number_t limit_count,
3845 __unused boolean_t change)
1c79356b
A
3846{
3847 return(KERN_FAILURE);
3848}
3849
91447636
A
3850kern_return_t
3851task_set_ras_pc(
3852 __unused task_t task,
3853 __unused vm_offset_t pc,
3854 __unused vm_offset_t endpc)
3855{
1c79356b 3856 return KERN_FAILURE;
1c79356b
A
3857}
3858
3859void
3860task_synchronizer_destroy_all(task_t task)
3861{
1c79356b
A
3862 /*
3863 * Destroy owned semaphores
3864 */
4bd07ac2 3865 semaphore_destroy_all(task);
1c79356b
A
3866}
3867
b0d623f7
A
3868/*
3869 * Install default (machine-dependent) initial thread state
3870 * on the task. Subsequent thread creation will have this initial
3871 * state set on the thread by machine_thread_inherit_taskwide().
3872 * Flavors and structures are exactly the same as those to thread_set_state()
3873 */
3874kern_return_t
3875task_set_state(
3876 task_t task,
3877 int flavor,
3878 thread_state_t state,
3879 mach_msg_type_number_t state_count)
3880{
3881 kern_return_t ret;
3882
3883 if (task == TASK_NULL) {
3884 return (KERN_INVALID_ARGUMENT);
3885 }
3886
3887 task_lock(task);
3888
3889 if (!task->active) {
3890 task_unlock(task);
3891 return (KERN_FAILURE);
3892 }
3893
3894 ret = machine_task_set_state(task, flavor, state, state_count);
3895
3896 task_unlock(task);
3897 return ret;
3898}
3899
3900/*
3901 * Examine the default (machine-dependent) initial thread state
3902 * on the task, as set by task_set_state(). Flavors and structures
3903 * are exactly the same as those passed to thread_get_state().
3904 */
3905kern_return_t
3906task_get_state(
3907 task_t task,
3908 int flavor,
3909 thread_state_t state,
3910 mach_msg_type_number_t *state_count)
3911{
3912 kern_return_t ret;
3913
3914 if (task == TASK_NULL) {
3915 return (KERN_INVALID_ARGUMENT);
3916 }
3917
3918 task_lock(task);
3919
3920 if (!task->active) {
3921 task_unlock(task);
3922 return (KERN_FAILURE);
3923 }
3924
3925 ret = machine_task_get_state(task, flavor, state, state_count);
3926
3927 task_unlock(task);
3928 return ret;
3929}
3930
39236c6e
A
3931#if CONFIG_JETSAM
3932#define HWM_USERCORE_MINSPACE 250 // free space (in MB) required *after* core file creation
3933
3934void __attribute__((noinline))
3e170ce0 3935PROC_CROSSED_HIGH_WATERMARK__SEND_EXC_RESOURCE_AND_SUSPEND(int max_footprint_mb)
39236c6e
A
3936{
3937 task_t task = current_task();
3938 int pid = 0;
3e170ce0 3939 const char *procname = "unknown";
39236c6e
A
3940 mach_exception_data_type_t code[EXCEPTION_CODE_MAX];
3941
3942#ifdef MACH_BSD
3943 pid = proc_selfpid();
fe8ab488
A
3944
3945 if (pid == 1) {
3946 /*
3947 * Cannot have ReportCrash analyzing
3948 * a suspended initproc.
3949 */
3950 return;
3951 }
3952
39236c6e
A
3953 if (task->bsd_info != NULL)
3954 procname = proc_name_address(current_task()->bsd_info);
3955#endif
3956
3957 if (hwm_user_cores) {
3958 int error;
3959 uint64_t starttime, end;
3960 clock_sec_t secs = 0;
3961 uint32_t microsecs = 0;
3962
3963 starttime = mach_absolute_time();
3964 /*
3965 * Trigger a coredump of this process. Don't proceed unless we know we won't
3966 * be filling up the disk; and ignore the core size resource limit for this
3967 * core file.
3968 */
3e170ce0 3969 if ((error = coredump(current_task()->bsd_info, HWM_USERCORE_MINSPACE, COREDUMP_IGNORE_ULIMIT)) != 0) {
39236c6e
A
3970 printf("couldn't take coredump of %s[%d]: %d\n", procname, pid, error);
3971 }
3972 /*
3973 * coredump() leaves the task suspended.
3974 */
3975 task_resume_internal(current_task());
3976
3977 end = mach_absolute_time();
3978 absolutetime_to_microtime(end - starttime, &secs, &microsecs);
3979 printf("coredump of %s[%d] taken in %d secs %d microsecs\n",
3980 proc_name_address(current_task()->bsd_info), pid, (int)secs, microsecs);
3981 }
3982
3983 if (disable_exc_resource) {
3984 printf("process %s[%d] crossed memory high watermark (%d MB); EXC_RESOURCE "
3985 "supressed by a boot-arg.\n", procname, pid, max_footprint_mb);
3986 return;
3987 }
3988
3e170ce0
A
3989 /*
3990 * A task that has triggered an EXC_RESOURCE, should not be
3991 * jetsammed when the device is under memory pressure. Here
3992 * we set the P_MEMSTAT_TERMINATED flag so that the process
3993 * will be skipped if the memorystatus_thread wakes up.
3994 */
3995 proc_memstat_terminated(current_task()->bsd_info, TRUE);
3996
39236c6e
A
3997 printf("process %s[%d] crossed memory high watermark (%d MB); sending "
3998 "EXC_RESOURCE.\n", procname, pid, max_footprint_mb);
3999
4000 code[0] = code[1] = 0;
4001 EXC_RESOURCE_ENCODE_TYPE(code[0], RESOURCE_TYPE_MEMORY);
4002 EXC_RESOURCE_ENCODE_FLAVOR(code[0], FLAVOR_HIGH_WATERMARK);
4003 EXC_RESOURCE_HWM_ENCODE_LIMIT(code[0], max_footprint_mb);
3e170ce0 4004
fe8ab488
A
4005 /*
4006 * Use the _internal_ variant so that no user-space
4007 * process can resume our task from under us.
4008 */
4009 task_suspend_internal(task);
39236c6e 4010 exception_triage(EXC_RESOURCE, code, EXCEPTION_CODE_MAX);
fe8ab488 4011 task_resume_internal(task);
3e170ce0
A
4012
4013 /*
4014 * After the EXC_RESOURCE has been handled, we must clear the
4015 * P_MEMSTAT_TERMINATED flag so that the process can again be
4016 * considered for jetsam if the memorystatus_thread wakes up.
4017 */
4018 proc_memstat_terminated(current_task()->bsd_info, FALSE); /* clear the flag */
39236c6e
A
4019}
4020
4021/*
4022 * Callback invoked when a task exceeds its physical footprint limit.
4023 */
4024void
4025task_footprint_exceeded(int warning, __unused const void *param0, __unused const void *param1)
4026{
fe8ab488
A
4027 ledger_amount_t max_footprint, max_footprint_mb;
4028 ledger_amount_t footprint_after_purge;
4029 task_t task;
39236c6e
A
4030
4031 if (warning == LEDGER_WARNING_DIPPED_BELOW) {
4032 /*
4033 * Task memory limits only provide a warning on the way up.
4034 */
4035 return;
4036 }
4037
fe8ab488
A
4038 task = current_task();
4039
4040 ledger_get_limit(task->ledger, task_ledgers.phys_footprint, &max_footprint);
4041 max_footprint_mb = max_footprint >> 20;
4042
4043 /*
4044 * Try and purge all "volatile" memory in that task first.
4045 */
4046 (void) task_purge_volatile_memory(task);
4047 /* are we still over the limit ? */
4048 ledger_get_balance(task->ledger,
4049 task_ledgers.phys_footprint,
4050 &footprint_after_purge);
4051 if ((!warning &&
4052 footprint_after_purge <= max_footprint) ||
4053 (warning &&
4054 footprint_after_purge <= ((max_footprint *
4055 PHYS_FOOTPRINT_WARNING_LEVEL) / 100))) {
4056 /* all better now */
4057 ledger_reset_callback_state(task->ledger,
4058 task_ledgers.phys_footprint);
4059 return;
4060 }
4061 /* still over the limit after purging... */
39236c6e
A
4062
4063 /*
4064 * If this an actual violation (not a warning),
4065 * generate a non-fatal high watermark EXC_RESOURCE.
4066 */
fe8ab488 4067 if ((warning == 0) && (task->rusage_cpu_flags & TASK_RUSECPU_FLAGS_PHYS_FOOTPRINT_EXCEPTION)) {
3e170ce0 4068 PROC_CROSSED_HIGH_WATERMARK__SEND_EXC_RESOURCE_AND_SUSPEND((int)max_footprint_mb);
39236c6e
A
4069 }
4070
4071 memorystatus_on_ledger_footprint_exceeded((warning == LEDGER_WARNING_ROSE_ABOVE) ? TRUE : FALSE,
4072 (int)max_footprint_mb);
4073}
4074
4075extern int proc_check_footprint_priv(void);
4076
4077kern_return_t
4078task_set_phys_footprint_limit(
4079 task_t task,
4080 int new_limit_mb,
4081 int *old_limit_mb)
4082{
4083 kern_return_t error;
4084
4085 if ((error = proc_check_footprint_priv())) {
4086 return (KERN_NO_ACCESS);
4087 }
4088
4089 return task_set_phys_footprint_limit_internal(task, new_limit_mb, old_limit_mb, FALSE);
4090}
4091
3e170ce0
A
4092kern_return_t
4093task_convert_phys_footprint_limit(
4094 int limit_mb,
4095 int *converted_limit_mb)
4096{
4097 if (limit_mb == -1) {
4098 /*
4099 * No limit
4100 */
4101 if (max_task_footprint != 0) {
4102 *converted_limit_mb = (int)(max_task_footprint / 1024 / 1024); /* bytes to MB */
4103 } else {
4104 *converted_limit_mb = (int)(LEDGER_LIMIT_INFINITY >> 20);
4105 }
4106 } else {
4107 /* nothing to convert */
4108 *converted_limit_mb = limit_mb;
4109 }
4110 return (KERN_SUCCESS);
4111}
4112
4113
39236c6e
A
4114kern_return_t
4115task_set_phys_footprint_limit_internal(
4116 task_t task,
4117 int new_limit_mb,
4118 int *old_limit_mb,
4119 boolean_t trigger_exception)
4120{
4121 ledger_amount_t old;
4122
4123 ledger_get_limit(task->ledger, task_ledgers.phys_footprint, &old);
4124
4125 if (old_limit_mb) {
3e170ce0
A
4126 /*
4127 * Check that limit >> 20 will not give an "unexpected" 32-bit
4128 * result. There are, however, implicit assumptions that -1 mb limit
4129 * equates to LEDGER_LIMIT_INFINITY.
4130 */
4131 assert(((old & 0xFFF0000000000000LL) == 0) || (old == LEDGER_LIMIT_INFINITY));
4132 *old_limit_mb = (int)(old >> 20);
39236c6e
A
4133 }
4134
4135 if (new_limit_mb == -1) {
4136 /*
4137 * Caller wishes to remove the limit.
4138 */
4139 ledger_set_limit(task->ledger, task_ledgers.phys_footprint,
4140 max_task_footprint ? max_task_footprint : LEDGER_LIMIT_INFINITY,
4141 max_task_footprint ? PHYS_FOOTPRINT_WARNING_LEVEL : 0);
4142 return (KERN_SUCCESS);
4143 }
4144
4145#ifdef CONFIG_NOMONITORS
4146 return (KERN_SUCCESS);
4147#endif /* CONFIG_NOMONITORS */
4148
4149 task_lock(task);
4150
4151 if (trigger_exception) {
4152 task->rusage_cpu_flags |= TASK_RUSECPU_FLAGS_PHYS_FOOTPRINT_EXCEPTION;
4153 } else {
4154 task->rusage_cpu_flags &= ~TASK_RUSECPU_FLAGS_PHYS_FOOTPRINT_EXCEPTION;
4155 }
4156
4157 ledger_set_limit(task->ledger, task_ledgers.phys_footprint,
4158 (ledger_amount_t)new_limit_mb << 20, PHYS_FOOTPRINT_WARNING_LEVEL);
4159
3e170ce0
A
4160 if (task == current_task()) {
4161 ledger_check_new_balance(task->ledger, task_ledgers.phys_footprint);
4162 }
4163
39236c6e
A
4164 task_unlock(task);
4165
4166 return (KERN_SUCCESS);
4167}
4168
4169kern_return_t
4170task_get_phys_footprint_limit(
4171 task_t task,
4172 int *limit_mb)
4173{
4174 ledger_amount_t limit;
4175
4176 ledger_get_limit(task->ledger, task_ledgers.phys_footprint, &limit);
3e170ce0
A
4177 /*
4178 * Check that limit >> 20 will not give an "unexpected" signed, 32-bit
4179 * result. There are, however, implicit assumptions that -1 mb limit
4180 * equates to LEDGER_LIMIT_INFINITY.
4181 */
4182 assert(((limit & 0xFFF0000000000000LL) == 0) || (limit == LEDGER_LIMIT_INFINITY));
4183 *limit_mb = (int)(limit >> 20);
39236c6e
A
4184
4185 return (KERN_SUCCESS);
4186}
4187#else /* CONFIG_JETSAM */
4188kern_return_t
4189task_set_phys_footprint_limit(
4190 __unused task_t task,
4191 __unused int new_limit_mb,
4192 __unused int *old_limit_mb)
4193{
4194 return (KERN_FAILURE);
4195}
4196
4197kern_return_t
4198task_get_phys_footprint_limit(
4199 __unused task_t task,
4200 __unused int *limit_mb)
4201{
4202 return (KERN_FAILURE);
4203}
4204#endif /* CONFIG_JETSAM */
b0d623f7 4205
1c79356b
A
4206/*
4207 * We need to export some functions to other components that
4208 * are currently implemented in macros within the osfmk
4209 * component. Just export them as functions of the same name.
4210 */
4211boolean_t is_kerneltask(task_t t)
4212{
4213 if (t == kernel_task)
55e303ae
A
4214 return (TRUE);
4215
4216 return (FALSE);
1c79356b
A
4217}
4218
b0d623f7
A
4219int
4220check_for_tasksuspend(task_t task)
4221{
4222
4223 if (task == TASK_NULL)
4224 return (0);
4225
4226 return (task->suspend_count > 0);
4227}
4228
1c79356b 4229#undef current_task
91447636
A
4230task_t current_task(void);
4231task_t current_task(void)
1c79356b
A
4232{
4233 return (current_task_fast());
4234}
91447636
A
4235
4236#undef task_reference
4237void task_reference(task_t task);
4238void
4239task_reference(
4240 task_t task)
4241{
4242 if (task != TASK_NULL)
4243 task_reference_internal(task);
4244}
2d21ac55 4245
3e170ce0
A
4246/* defined in bsd/kern/kern_prot.c */
4247extern int get_audit_token_pid(audit_token_t *audit_token);
4248
4249int task_pid(task_t task)
4250{
4251 if (task)
4252 return get_audit_token_pid(&task->audit_token);
4253 return -1;
4254}
4255
4256
6d2010ae
A
4257/*
4258 * This routine is called always with task lock held.
4259 * And it returns a thread handle without reference as the caller
4260 * operates on it under the task lock held.
4261 */
4262thread_t
4263task_findtid(task_t task, uint64_t tid)
4264{
4265 thread_t thread= THREAD_NULL;
4266
4267 queue_iterate(&task->threads, thread, thread_t, task_threads) {
4268 if (thread->thread_id == tid)
316670eb 4269 return(thread);
6d2010ae 4270 }
316670eb 4271 return(THREAD_NULL);
6d2010ae
A
4272}
4273
39236c6e
A
4274/*
4275 * Control the CPU usage monitor for a task.
4276 */
4277kern_return_t
4278task_cpu_usage_monitor_ctl(task_t task, uint32_t *flags)
4279{
4280 int error = KERN_SUCCESS;
4281
4282 if (*flags & CPUMON_MAKE_FATAL) {
4283 task->rusage_cpu_flags |= TASK_RUSECPU_FLAGS_FATAL_CPUMON;
4284 } else {
4285 error = KERN_INVALID_ARGUMENT;
4286 }
4287
4288 return error;
4289}
4290
4291/*
4292 * Control the wakeups monitor for a task.
4293 */
4294kern_return_t
4295task_wakeups_monitor_ctl(task_t task, uint32_t *flags, int32_t *rate_hz)
4296{
4297 ledger_t ledger = task->ledger;
4298
4299 task_lock(task);
4300 if (*flags & WAKEMON_GET_PARAMS) {
4301 ledger_amount_t limit;
4302 uint64_t period;
4303
4304 ledger_get_limit(ledger, task_ledgers.interrupt_wakeups, &limit);
4305 ledger_get_period(ledger, task_ledgers.interrupt_wakeups, &period);
4306
4307 if (limit != LEDGER_LIMIT_INFINITY) {
4308 /*
4309 * An active limit means the wakeups monitor is enabled.
4310 */
4311 *rate_hz = (int32_t)(limit / (int64_t)(period / NSEC_PER_SEC));
4312 *flags = WAKEMON_ENABLE;
4313 if (task->rusage_cpu_flags & TASK_RUSECPU_FLAGS_FATAL_WAKEUPSMON) {
4314 *flags |= WAKEMON_MAKE_FATAL;
4315 }
4316 } else {
4317 *flags = WAKEMON_DISABLE;
4318 *rate_hz = -1;
4319 }
4320
4321 /*
4322 * If WAKEMON_GET_PARAMS is present in flags, all other flags are ignored.
4323 */
4324 task_unlock(task);
4325 return KERN_SUCCESS;
4326 }
4327
4328 if (*flags & WAKEMON_ENABLE) {
4329 if (*flags & WAKEMON_SET_DEFAULTS) {
4330 *rate_hz = task_wakeups_monitor_rate;
4331 }
4332
4333#ifndef CONFIG_NOMONITORS
4334 if (*flags & WAKEMON_MAKE_FATAL) {
4335 task->rusage_cpu_flags |= TASK_RUSECPU_FLAGS_FATAL_WAKEUPSMON;
4336 }
4337#endif /* CONFIG_NOMONITORS */
4338
4339 if (*rate_hz < 0) {
4340 task_unlock(task);
4341 return KERN_INVALID_ARGUMENT;
4342 }
4343
4344#ifndef CONFIG_NOMONITORS
4345 ledger_set_limit(ledger, task_ledgers.interrupt_wakeups, *rate_hz * task_wakeups_monitor_interval,
4346 task_wakeups_monitor_ustackshots_trigger_pct);
4347 ledger_set_period(ledger, task_ledgers.interrupt_wakeups, task_wakeups_monitor_interval * NSEC_PER_SEC);
4348 ledger_enable_callback(ledger, task_ledgers.interrupt_wakeups);
4349#endif /* CONFIG_NOMONITORS */
4350 } else if (*flags & WAKEMON_DISABLE) {
4351 /*
4352 * Caller wishes to disable wakeups monitor on the task.
4353 *
4354 * Disable telemetry if it was triggered by the wakeups monitor, and
4355 * remove the limit & callback on the wakeups ledger entry.
4356 */
4357#if CONFIG_TELEMETRY
4358 telemetry_task_ctl_locked(current_task(), TF_WAKEMON_WARNING, 0);
4359#endif
4360 ledger_disable_refill(ledger, task_ledgers.interrupt_wakeups);
4361 ledger_disable_callback(ledger, task_ledgers.interrupt_wakeups);
4362 }
4363
4364 task_unlock(task);
4365 return KERN_SUCCESS;
4366}
4367
4368void
4369task_wakeups_rate_exceeded(int warning, __unused const void *param0, __unused const void *param1)
4370{
4371 if (warning == LEDGER_WARNING_ROSE_ABOVE) {
4372#if CONFIG_TELEMETRY
4373 /*
4374 * This task is in danger of violating the wakeups monitor. Enable telemetry on this task
4375 * so there are micro-stackshots available if and when EXC_RESOURCE is triggered.
4376 */
4377 telemetry_task_ctl(current_task(), TF_WAKEMON_WARNING, 1);
4378#endif
4379 return;
4380 }
4381
4382#if CONFIG_TELEMETRY
4383 /*
4384 * If the balance has dipped below the warning level (LEDGER_WARNING_DIPPED_BELOW) or
4385 * exceeded the limit, turn telemetry off for the task.
4386 */
4387 telemetry_task_ctl(current_task(), TF_WAKEMON_WARNING, 0);
4388#endif
4389
4390 if (warning == 0) {
4391 THIS_PROCESS_IS_CAUSING_TOO_MANY_WAKEUPS__SENDING_EXC_RESOURCE();
4392 }
4393}
4394
4395void __attribute__((noinline))
4396THIS_PROCESS_IS_CAUSING_TOO_MANY_WAKEUPS__SENDING_EXC_RESOURCE(void)
4397{
4398 task_t task = current_task();
4399 int pid = 0;
3e170ce0 4400 const char *procname = "unknown";
39236c6e
A
4401 uint64_t observed_wakeups_rate;
4402 uint64_t permitted_wakeups_rate;
4403 uint64_t observation_interval;
4404 mach_exception_data_type_t code[EXCEPTION_CODE_MAX];
4405 struct ledger_entry_info lei;
4406
4407#ifdef MACH_BSD
4408 pid = proc_selfpid();
4409 if (task->bsd_info != NULL)
4410 procname = proc_name_address(current_task()->bsd_info);
4411#endif
4412
4413 ledger_get_entry_info(task->ledger, task_ledgers.interrupt_wakeups, &lei);
4414
4415 /*
4416 * Disable the exception notification so we don't overwhelm
4417 * the listener with an endless stream of redundant exceptions.
4418 */
4419 uint32_t flags = WAKEMON_DISABLE;
4420 task_wakeups_monitor_ctl(task, &flags, NULL);
4421
4422 observed_wakeups_rate = (lei.lei_balance * (int64_t)NSEC_PER_SEC) / lei.lei_last_refill;
4423 permitted_wakeups_rate = lei.lei_limit / task_wakeups_monitor_interval;
4424 observation_interval = lei.lei_refill_period / NSEC_PER_SEC;
4425
4426 if (disable_exc_resource) {
4427 printf("process %s[%d] caught causing excessive wakeups. EXC_RESOURCE "
4428 "supressed by a boot-arg\n", procname, pid);
4429 return;
4430 }
15129b1c
A
4431 if (audio_active) {
4432 printf("process %s[%d] caught causing excessive wakeups. EXC_RESOURCE "
4433 "supressed due to audio playback\n", procname, pid);
4434 return;
4435 }
39236c6e
A
4436 printf("process %s[%d] caught causing excessive wakeups. Observed wakeups rate "
4437 "(per sec): %lld; Maximum permitted wakeups rate (per sec): %lld; Observation "
4438 "period: %lld seconds; Task lifetime number of wakeups: %lld\n",
4439 procname, pid, observed_wakeups_rate, permitted_wakeups_rate,
4440 observation_interval, lei.lei_credit);
4441
4442 code[0] = code[1] = 0;
4443 EXC_RESOURCE_ENCODE_TYPE(code[0], RESOURCE_TYPE_WAKEUPS);
4444 EXC_RESOURCE_ENCODE_FLAVOR(code[0], FLAVOR_WAKEUPS_MONITOR);
4445 EXC_RESOURCE_CPUMONITOR_ENCODE_WAKEUPS_PERMITTED(code[0], task_wakeups_monitor_rate);
4446 EXC_RESOURCE_CPUMONITOR_ENCODE_OBSERVATION_INTERVAL(code[0], observation_interval);
4447 EXC_RESOURCE_CPUMONITOR_ENCODE_WAKEUPS_OBSERVED(code[1], lei.lei_balance * (int64_t)NSEC_PER_SEC / lei.lei_last_refill);
4448 exception_triage(EXC_RESOURCE, code, EXCEPTION_CODE_MAX);
4449
4450 if (task->rusage_cpu_flags & TASK_RUSECPU_FLAGS_FATAL_WAKEUPSMON) {
4451 task_terminate_internal(task);
4452 }
4453}
fe8ab488
A
4454
4455kern_return_t
4456task_purge_volatile_memory(
4457 task_t task)
4458{
4459 vm_map_t map;
4460 int num_object_purged;
4461
4462 if (task == TASK_NULL)
4463 return KERN_INVALID_TASK;
4464
4465 task_lock(task);
4466
4467 if (!task->active) {
4468 task_unlock(task);
4469 return KERN_INVALID_TASK;
4470 }
4471 map = task->map;
4472 if (map == VM_MAP_NULL) {
4473 task_unlock(task);
4474 return KERN_INVALID_TASK;
4475 }
4476 vm_map_reference(task->map);
4477
4478 task_unlock(task);
4479
4480 num_object_purged = vm_map_purge(map);
4481 vm_map_deallocate(map);
4482
4483 return KERN_SUCCESS;
4484}
4485
4486/* Placeholders for the task set/get voucher interfaces */
4487kern_return_t
4488task_get_mach_voucher(
4489 task_t task,
4490 mach_voucher_selector_t __unused which,
4491 ipc_voucher_t *voucher)
4492{
4493 if (TASK_NULL == task)
4494 return KERN_INVALID_TASK;
4495
4496 *voucher = NULL;
4497 return KERN_SUCCESS;
4498}
4499
4500kern_return_t
4501task_set_mach_voucher(
4502 task_t task,
4503 ipc_voucher_t __unused voucher)
4504{
4505 if (TASK_NULL == task)
4506 return KERN_INVALID_TASK;
4507
4508 return KERN_SUCCESS;
4509}
4510
4511kern_return_t
4512task_swap_mach_voucher(
4513 task_t task,
4514 ipc_voucher_t new_voucher,
4515 ipc_voucher_t *in_out_old_voucher)
4516{
4517 if (TASK_NULL == task)
4518 return KERN_INVALID_TASK;
4519
4520 *in_out_old_voucher = new_voucher;
4521 return KERN_SUCCESS;
4522}
4523
4524void task_set_gpu_denied(task_t task, boolean_t denied)
4525{
4526 task_lock(task);
4527
4528 if (denied) {
4529 task->t_flags |= TF_GPU_DENIED;
4530 } else {
4531 task->t_flags &= ~TF_GPU_DENIED;
4532 }
4533
4534 task_unlock(task);
4535}
4536
4537boolean_t task_is_gpu_denied(task_t task)
4538{
4539 /* We don't need the lock to read this flag */
4540 return (task->t_flags & TF_GPU_DENIED) ? TRUE : FALSE;
4541}
4bd07ac2
A
4542
4543void task_update_logical_writes(task_t task, uint32_t io_size, int flags)
4544{
4545 KERNEL_DEBUG_CONSTANT((MACHDBG_CODE(DBG_MACH_VM, VM_DATA_WRITE)) | DBG_FUNC_NONE, task_pid(task), io_size, flags, 0, 0);
4546 switch(flags) {
4547 case TASK_WRITE_IMMEDIATE:
4548 OSAddAtomic64(io_size, (SInt64 *)&(task->task_immediate_writes));
4549 break;
4550 case TASK_WRITE_DEFERRED:
4551 OSAddAtomic64(io_size, (SInt64 *)&(task->task_deferred_writes));
4552 break;
4553 case TASK_WRITE_INVALIDATED:
4554 OSAddAtomic64(io_size, (SInt64 *)&(task->task_invalidated_writes));
4555 break;
4556 case TASK_WRITE_METADATA:
4557 OSAddAtomic64(io_size, (SInt64 *)&(task->task_metadata_writes));
4558 break;
4559 }
4560 return;
4561}