]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
d9a64523 | 2 | * Copyright (c) 2000-2018 Apple Inc. All rights reserved. |
1c79356b | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
0a7de745 | 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. | |
0a7de745 | 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. | |
0a7de745 | 17 | * |
2d21ac55 A |
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. | |
0a7de745 | 25 | * |
2d21ac55 | 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
1c79356b A |
27 | */ |
28 | #include <mach/mach_types.h> | |
b0d623f7 | 29 | #include <mach/machine/vm_param.h> |
39236c6e | 30 | #include <mach/task.h> |
91447636 A |
31 | |
32 | #include <kern/kern_types.h> | |
39236c6e | 33 | #include <kern/ledger.h> |
91447636 | 34 | #include <kern/processor.h> |
1c79356b | 35 | #include <kern/thread.h> |
1c79356b A |
36 | #include <kern/task.h> |
37 | #include <kern/spl.h> | |
91447636 | 38 | #include <kern/ast.h> |
1c79356b A |
39 | #include <ipc/ipc_port.h> |
40 | #include <ipc/ipc_object.h> | |
91447636 | 41 | #include <vm/vm_map.h> |
0c530ab8 | 42 | #include <vm/vm_kern.h> |
91447636 A |
43 | #include <vm/pmap.h> |
44 | #include <vm/vm_protos.h> /* last */ | |
39236c6e | 45 | #include <sys/resource.h> |
3e170ce0 | 46 | #include <sys/signal.h> |
cb323159 | 47 | #include <sys/errno.h> |
f427ee49 | 48 | #include <sys/proc_require.h> |
1c79356b | 49 | |
5ba3f43e A |
50 | #if MONOTONIC |
51 | #include <kern/monotonic.h> | |
52 | #include <machine/monotonic.h> | |
53 | #endif /* MONOTONIC */ | |
54 | ||
55 | #include <machine/limits.h> | |
cb323159 | 56 | #include <sys/codesign.h> /* CS_CDHASH_LEN */ |
5ba3f43e | 57 | |
1c79356b | 58 | #undef thread_should_halt |
1c79356b | 59 | |
1c79356b A |
60 | /* BSD KERN COMPONENT INTERFACE */ |
61 | ||
55e303ae | 62 | extern unsigned int not_in_kdp; /* Skip acquiring locks if we're in kdp */ |
0a7de745 | 63 | |
91447636 | 64 | thread_t get_firstthread(task_t); |
1c79356b | 65 | int get_task_userstop(task_t); |
91447636 | 66 | int get_thread_userstop(thread_t); |
1c79356b | 67 | boolean_t current_thread_aborted(void); |
0a7de745 A |
68 | void task_act_iterate_wth_args(task_t, void (*)(thread_t, void *), void *); |
69 | kern_return_t get_signalact(task_t, thread_t *, int); | |
fe8ab488 A |
70 | int fill_task_rusage(task_t task, rusage_info_current *ri); |
71 | int fill_task_io_rusage(task_t task, rusage_info_current *ri); | |
72 | int fill_task_qos_rusage(task_t task, rusage_info_current *ri); | |
5ba3f43e | 73 | void fill_task_monotonic_rusage(task_t task, rusage_info_current *ri); |
cb323159 | 74 | uint64_t get_task_logical_writes(task_t task, boolean_t external); |
fe8ab488 | 75 | void fill_task_billed_usage(task_t task, rusage_info_current *ri); |
3e170ce0 A |
76 | void task_bsdtask_kill(task_t); |
77 | ||
39037602 | 78 | extern uint64_t get_dispatchqueue_serialno_offset_from_proc(void *p); |
cb323159 | 79 | extern uint64_t get_dispatchqueue_label_offset_from_proc(void *p); |
39037602 | 80 | extern uint64_t proc_uniqueid(void *p); |
5ba3f43e | 81 | extern int proc_pidversion(void *p); |
cb323159 | 82 | extern int proc_getcdhash(void *p, char *cdhash); |
39037602 | 83 | |
3e170ce0 A |
84 | #if MACH_BSD |
85 | extern void psignal(void *, int); | |
86 | #endif | |
1c79356b | 87 | |
1c79356b A |
88 | /* |
89 | * | |
90 | */ | |
0a7de745 A |
91 | void * |
92 | get_bsdtask_info(task_t t) | |
1c79356b | 93 | { |
f427ee49 | 94 | proc_require(t->bsd_info, PROC_REQUIRE_ALLOW_NULL | PROC_REQUIRE_ALLOW_KERNPROC); |
0a7de745 | 95 | return t->bsd_info; |
1c79356b A |
96 | } |
97 | ||
0a7de745 A |
98 | void |
99 | task_bsdtask_kill(task_t t) | |
3e170ce0 A |
100 | { |
101 | void * bsd_info = get_bsdtask_info(t); | |
102 | if (bsd_info != NULL) { | |
103 | psignal(bsd_info, SIGKILL); | |
104 | } | |
105 | } | |
2d21ac55 A |
106 | /* |
107 | * | |
108 | */ | |
0a7de745 A |
109 | void * |
110 | get_bsdthreadtask_info(thread_t th) | |
2d21ac55 | 111 | { |
f427ee49 A |
112 | void *bsd_info = NULL; |
113 | ||
114 | if (th->task) { | |
115 | bsd_info = get_bsdtask_info(th->task); | |
116 | } | |
117 | return bsd_info; | |
2d21ac55 A |
118 | } |
119 | ||
1c79356b A |
120 | /* |
121 | * | |
122 | */ | |
0a7de745 A |
123 | void |
124 | set_bsdtask_info(task_t t, void * v) | |
1c79356b | 125 | { |
0a7de745 | 126 | t->bsd_info = v; |
1c79356b A |
127 | } |
128 | ||
129 | /* | |
130 | * | |
131 | */ | |
0a7de745 A |
132 | void * |
133 | get_bsdthread_info(thread_t th) | |
134 | { | |
135 | return th->uthread; | |
136 | } | |
137 | ||
cb323159 A |
138 | /* |
139 | * This is used to remember any FS error from VNOP_PAGEIN code when | |
140 | * invoked under vm_fault(). The value is an errno style value. It can | |
141 | * be retrieved by exception handlers using thread_get_state(). | |
142 | */ | |
143 | void | |
144 | set_thread_pagein_error(thread_t th, int error) | |
145 | { | |
146 | assert(th == current_thread()); | |
147 | if (error == 0 || th->t_pagein_error == 0) { | |
148 | th->t_pagein_error = error; | |
149 | } | |
150 | } | |
151 | ||
0a7de745 A |
152 | #if defined(__x86_64__) |
153 | /* | |
154 | * Returns non-zero if the thread has a non-NULL task | |
155 | * and that task has an LDT. | |
156 | */ | |
157 | int | |
158 | thread_task_has_ldt(thread_t th) | |
1c79356b | 159 | { |
0a7de745 | 160 | return th->task && th->task->i386_ldt != 0; |
1c79356b | 161 | } |
0a7de745 | 162 | #endif /* __x86_64__ */ |
1c79356b | 163 | |
6d2010ae A |
164 | /* |
165 | * XXX | |
166 | */ | |
0a7de745 A |
167 | int get_thread_lock_count(thread_t th); /* forced forward */ |
168 | int | |
169 | get_thread_lock_count(thread_t th) | |
6d2010ae | 170 | { |
0a7de745 | 171 | return th->mutex_count; |
6d2010ae A |
172 | } |
173 | ||
1c79356b A |
174 | /* |
175 | * XXX: wait for BSD to fix signal code | |
176 | * Until then, we cannot block here. We know the task | |
177 | * can't go away, so we make sure it is still active after | |
178 | * retrieving the first thread for extra safety. | |
179 | */ | |
0a7de745 A |
180 | thread_t |
181 | get_firstthread(task_t task) | |
1c79356b | 182 | { |
0a7de745 | 183 | thread_t thread = (thread_t)(void *)queue_first(&task->threads); |
91447636 | 184 | |
0a7de745 | 185 | if (queue_end(&task->threads, (queue_entry_t)thread)) { |
91447636 | 186 | thread = THREAD_NULL; |
0a7de745 | 187 | } |
1c79356b | 188 | |
0a7de745 A |
189 | if (!task->active) { |
190 | return THREAD_NULL; | |
191 | } | |
91447636 | 192 | |
0a7de745 | 193 | return thread; |
1c79356b A |
194 | } |
195 | ||
91447636 A |
196 | kern_return_t |
197 | get_signalact( | |
0a7de745 A |
198 | task_t task, |
199 | thread_t *result_out, | |
200 | int setast) | |
1c79356b | 201 | { |
0a7de745 A |
202 | kern_return_t result = KERN_SUCCESS; |
203 | thread_t inc, thread = THREAD_NULL; | |
1c79356b A |
204 | |
205 | task_lock(task); | |
91447636 | 206 | |
1c79356b A |
207 | if (!task->active) { |
208 | task_unlock(task); | |
91447636 | 209 | |
0a7de745 | 210 | return KERN_FAILURE; |
1c79356b A |
211 | } |
212 | ||
39236c6e | 213 | for (inc = (thread_t)(void *)queue_first(&task->threads); |
0a7de745 | 214 | !queue_end(&task->threads, (queue_entry_t)inc);) { |
2d21ac55 A |
215 | thread_mtx_lock(inc); |
216 | if (inc->active && | |
0a7de745 | 217 | (inc->sched_flags & TH_SFLAG_ABORTED_MASK) != TH_SFLAG_ABORT) { |
2d21ac55 A |
218 | thread = inc; |
219 | break; | |
220 | } | |
221 | thread_mtx_unlock(inc); | |
222 | ||
39236c6e | 223 | inc = (thread_t)(void *)queue_next(&inc->task_threads); |
91447636 A |
224 | } |
225 | ||
0a7de745 | 226 | if (result_out) { |
91447636 | 227 | *result_out = thread; |
0a7de745 | 228 | } |
91447636 A |
229 | |
230 | if (thread) { | |
0a7de745 | 231 | if (setast) { |
91447636 | 232 | act_set_astbsd(thread); |
0a7de745 | 233 | } |
91447636 A |
234 | |
235 | thread_mtx_unlock(thread); | |
0a7de745 | 236 | } else { |
91447636 | 237 | result = KERN_FAILURE; |
0a7de745 | 238 | } |
91447636 | 239 | |
1c79356b A |
240 | task_unlock(task); |
241 | ||
0a7de745 | 242 | return result; |
1c79356b A |
243 | } |
244 | ||
0b4e3aa0 | 245 | |
91447636 A |
246 | kern_return_t |
247 | check_actforsig( | |
0a7de745 A |
248 | task_t task, |
249 | thread_t thread, | |
250 | int setast) | |
0b4e3aa0 | 251 | { |
0a7de745 A |
252 | kern_return_t result = KERN_FAILURE; |
253 | thread_t inc; | |
0b4e3aa0 A |
254 | |
255 | task_lock(task); | |
91447636 | 256 | |
0b4e3aa0 A |
257 | if (!task->active) { |
258 | task_unlock(task); | |
91447636 | 259 | |
0a7de745 | 260 | return KERN_FAILURE; |
0b4e3aa0 A |
261 | } |
262 | ||
39236c6e | 263 | for (inc = (thread_t)(void *)queue_first(&task->threads); |
0a7de745 | 264 | !queue_end(&task->threads, (queue_entry_t)inc);) { |
91447636 A |
265 | if (inc == thread) { |
266 | thread_mtx_lock(inc); | |
267 | ||
0a7de745 A |
268 | if (inc->active && |
269 | (inc->sched_flags & TH_SFLAG_ABORTED_MASK) != TH_SFLAG_ABORT) { | |
91447636 | 270 | result = KERN_SUCCESS; |
0b4e3aa0 | 271 | break; |
91447636 | 272 | } |
0b4e3aa0 | 273 | |
91447636 A |
274 | thread_mtx_unlock(inc); |
275 | break; | |
276 | } | |
277 | ||
39236c6e | 278 | inc = (thread_t)(void *)queue_next(&inc->task_threads); |
91447636 A |
279 | } |
280 | ||
281 | if (result == KERN_SUCCESS) { | |
0a7de745 | 282 | if (setast) { |
91447636 | 283 | act_set_astbsd(thread); |
0a7de745 | 284 | } |
91447636 A |
285 | |
286 | thread_mtx_unlock(thread); | |
287 | } | |
288 | ||
289 | task_unlock(task); | |
290 | ||
0a7de745 | 291 | return result; |
0b4e3aa0 A |
292 | } |
293 | ||
0a7de745 A |
294 | ledger_t |
295 | get_task_ledger(task_t t) | |
316670eb | 296 | { |
0a7de745 | 297 | return t->ledger; |
316670eb A |
298 | } |
299 | ||
1c79356b | 300 | /* |
91447636 | 301 | * This is only safe to call from a thread executing in |
3e170ce0 | 302 | * in the task's context or if the task is locked. Otherwise, |
91447636 | 303 | * the map could be switched for the task (and freed) before |
3e170ce0 | 304 | * we go to return it here. |
1c79356b | 305 | */ |
0a7de745 A |
306 | vm_map_t |
307 | get_task_map(task_t t) | |
1c79356b | 308 | { |
0a7de745 | 309 | return t->map; |
1c79356b A |
310 | } |
311 | ||
0a7de745 A |
312 | vm_map_t |
313 | get_task_map_reference(task_t t) | |
91447636 A |
314 | { |
315 | vm_map_t m; | |
316 | ||
0a7de745 | 317 | if (t == NULL) { |
91447636 | 318 | return VM_MAP_NULL; |
0a7de745 | 319 | } |
91447636 A |
320 | |
321 | task_lock(t); | |
322 | if (!t->active) { | |
323 | task_unlock(t); | |
324 | return VM_MAP_NULL; | |
325 | } | |
326 | m = t->map; | |
c3c9b80d | 327 | vm_map_reference(m); |
91447636 A |
328 | task_unlock(t); |
329 | return m; | |
330 | } | |
331 | ||
1c79356b A |
332 | /* |
333 | * | |
334 | */ | |
0a7de745 A |
335 | ipc_space_t |
336 | get_task_ipcspace(task_t t) | |
1c79356b | 337 | { |
0a7de745 | 338 | return t->itk_space; |
1c79356b A |
339 | } |
340 | ||
0a7de745 A |
341 | int |
342 | get_task_numacts(task_t t) | |
1c79356b | 343 | { |
0a7de745 | 344 | return t->thread_count; |
55e303ae A |
345 | } |
346 | ||
347 | /* does this machine need 64bit register set for signal handler */ | |
0a7de745 A |
348 | int |
349 | is_64signalregset(void) | |
55e303ae | 350 | { |
d9a64523 | 351 | if (task_has_64Bit_data(current_task())) { |
0a7de745 | 352 | return 1; |
39236c6e A |
353 | } |
354 | ||
0a7de745 | 355 | return 0; |
1c79356b A |
356 | } |
357 | ||
358 | /* | |
b0d623f7 | 359 | * Swap in a new map for the task/thread pair; the old map reference is |
d190cdc3 | 360 | * returned. Also does a pmap switch if thread provided is current thread. |
1c79356b A |
361 | */ |
362 | vm_map_t | |
d190cdc3 | 363 | swap_task_map(task_t task, thread_t thread, vm_map_t map) |
1c79356b A |
364 | { |
365 | vm_map_t old_map; | |
d190cdc3 | 366 | boolean_t doswitch = (thread == current_thread()) ? TRUE : FALSE; |
1c79356b | 367 | |
0a7de745 | 368 | if (task != thread->task) { |
55e303ae | 369 | panic("swap_task_map"); |
0a7de745 | 370 | } |
55e303ae | 371 | |
1c79356b | 372 | task_lock(task); |
6d2010ae | 373 | mp_disable_preemption(); |
39037602 | 374 | |
1c79356b | 375 | old_map = task->map; |
91447636 | 376 | thread->map = task->map = map; |
39037602 A |
377 | vm_commit_pagezero_status(map); |
378 | ||
316670eb | 379 | if (doswitch) { |
0a7de745 | 380 | PMAP_SWITCH_USER(thread, map, cpu_number()); |
316670eb | 381 | } |
6d2010ae | 382 | mp_enable_preemption(); |
1c79356b | 383 | task_unlock(task); |
0c530ab8 | 384 | |
1c79356b A |
385 | return old_map; |
386 | } | |
387 | ||
1c79356b A |
388 | /* |
389 | * | |
3e170ce0 A |
390 | * This is only safe to call from a thread executing in |
391 | * in the task's context or if the task is locked. Otherwise, | |
392 | * the map could be switched for the task (and freed) before | |
393 | * we go to return it here. | |
1c79356b | 394 | */ |
0a7de745 A |
395 | pmap_t |
396 | get_task_pmap(task_t t) | |
1c79356b | 397 | { |
0a7de745 | 398 | return t->map->pmap; |
1c79356b A |
399 | } |
400 | ||
b0d623f7 A |
401 | /* |
402 | * | |
403 | */ | |
0a7de745 A |
404 | uint64_t |
405 | get_task_resident_size(task_t task) | |
b0d623f7 A |
406 | { |
407 | vm_map_t map; | |
0a7de745 | 408 | |
b0d623f7 | 409 | map = (task == kernel_task) ? kernel_map: task->map; |
0a7de745 | 410 | return (uint64_t)pmap_resident_count(map->pmap) * PAGE_SIZE_64; |
b0d623f7 A |
411 | } |
412 | ||
0a7de745 A |
413 | uint64_t |
414 | get_task_compressed(task_t task) | |
fe8ab488 A |
415 | { |
416 | vm_map_t map; | |
0a7de745 | 417 | |
fe8ab488 | 418 | map = (task == kernel_task) ? kernel_map: task->map; |
0a7de745 | 419 | return (uint64_t)pmap_compressed(map->pmap) * PAGE_SIZE_64; |
fe8ab488 A |
420 | } |
421 | ||
0a7de745 A |
422 | uint64_t |
423 | get_task_resident_max(task_t task) | |
fe8ab488 A |
424 | { |
425 | vm_map_t map; | |
0a7de745 | 426 | |
fe8ab488 | 427 | map = (task == kernel_task) ? kernel_map: task->map; |
0a7de745 | 428 | return (uint64_t)pmap_resident_max(map->pmap) * PAGE_SIZE_64; |
fe8ab488 A |
429 | } |
430 | ||
f427ee49 A |
431 | /* |
432 | * Get the balance for a given field in the task ledger. | |
433 | * Returns 0 if the entry is invalid. | |
434 | */ | |
435 | static uint64_t | |
436 | get_task_ledger_balance(task_t task, int entry) | |
437 | { | |
438 | ledger_amount_t balance = 0; | |
439 | ||
440 | ledger_get_balance(task->ledger, entry, &balance); | |
441 | return balance; | |
442 | } | |
443 | ||
0a7de745 A |
444 | uint64_t |
445 | get_task_purgeable_size(task_t task) | |
fe8ab488 | 446 | { |
3e170ce0 | 447 | kern_return_t ret; |
f427ee49 | 448 | ledger_amount_t balance = 0; |
3e170ce0 A |
449 | uint64_t volatile_size = 0; |
450 | ||
f427ee49 | 451 | ret = ledger_get_balance(task->ledger, task_ledgers.purgeable_volatile, &balance); |
3e170ce0 A |
452 | if (ret != KERN_SUCCESS) { |
453 | return 0; | |
454 | } | |
455 | ||
f427ee49 | 456 | volatile_size += balance; |
3e170ce0 | 457 | |
f427ee49 | 458 | ret = ledger_get_balance(task->ledger, task_ledgers.purgeable_volatile_compressed, &balance); |
3e170ce0 A |
459 | if (ret != KERN_SUCCESS) { |
460 | return 0; | |
461 | } | |
fe8ab488 | 462 | |
f427ee49 | 463 | volatile_size += balance; |
3e170ce0 A |
464 | |
465 | return volatile_size; | |
fe8ab488 | 466 | } |
3e170ce0 | 467 | |
39236c6e A |
468 | /* |
469 | * | |
470 | */ | |
0a7de745 A |
471 | uint64_t |
472 | get_task_phys_footprint(task_t task) | |
5ba3f43e | 473 | { |
f427ee49 | 474 | return get_task_ledger_balance(task, task_ledgers.phys_footprint); |
39236c6e A |
475 | } |
476 | ||
d9a64523 | 477 | #if CONFIG_LEDGER_INTERVAL_MAX |
39236c6e A |
478 | /* |
479 | * | |
480 | */ | |
0a7de745 A |
481 | uint64_t |
482 | get_task_phys_footprint_interval_max(task_t task, int reset) | |
5ba3f43e | 483 | { |
39236c6e A |
484 | kern_return_t ret; |
485 | ledger_amount_t max; | |
5ba3f43e | 486 | |
d9a64523 A |
487 | ret = ledger_get_interval_max(task->ledger, task_ledgers.phys_footprint, &max, reset); |
488 | ||
0a7de745 | 489 | if (KERN_SUCCESS == ret) { |
39236c6e A |
490 | return max; |
491 | } | |
492 | ||
493 | return 0; | |
494 | } | |
d9a64523 | 495 | #endif /* CONFIG_LEDGER_INTERVAL_MAX */ |
39236c6e | 496 | |
5ba3f43e A |
497 | /* |
498 | * | |
499 | */ | |
0a7de745 A |
500 | uint64_t |
501 | get_task_phys_footprint_lifetime_max(task_t task) | |
5ba3f43e A |
502 | { |
503 | kern_return_t ret; | |
504 | ledger_amount_t max; | |
505 | ||
506 | ret = ledger_get_lifetime_max(task->ledger, task_ledgers.phys_footprint, &max); | |
507 | ||
0a7de745 | 508 | if (KERN_SUCCESS == ret) { |
5ba3f43e A |
509 | return max; |
510 | } | |
511 | ||
512 | return 0; | |
513 | } | |
514 | ||
39037602 A |
515 | /* |
516 | * | |
517 | */ | |
0a7de745 A |
518 | uint64_t |
519 | get_task_phys_footprint_limit(task_t task) | |
39037602 A |
520 | { |
521 | kern_return_t ret; | |
522 | ledger_amount_t max; | |
523 | ||
524 | ret = ledger_get_limit(task->ledger, task_ledgers.phys_footprint, &max); | |
525 | if (KERN_SUCCESS == ret) { | |
526 | return max; | |
527 | } | |
528 | ||
529 | return 0; | |
530 | } | |
531 | ||
0a7de745 A |
532 | uint64_t |
533 | get_task_internal(task_t task) | |
39037602 | 534 | { |
f427ee49 A |
535 | return get_task_ledger_balance(task, task_ledgers.internal); |
536 | } | |
39037602 | 537 | |
f427ee49 A |
538 | uint64_t |
539 | get_task_internal_compressed(task_t task) | |
540 | { | |
541 | return get_task_ledger_balance(task, task_ledgers.internal_compressed); | |
542 | } | |
39037602 | 543 | |
f427ee49 A |
544 | uint64_t |
545 | get_task_purgeable_nonvolatile(task_t task) | |
546 | { | |
547 | return get_task_ledger_balance(task, task_ledgers.purgeable_nonvolatile); | |
39037602 A |
548 | } |
549 | ||
0a7de745 | 550 | uint64_t |
f427ee49 | 551 | get_task_purgeable_nonvolatile_compressed(task_t task) |
39037602 | 552 | { |
f427ee49 A |
553 | return get_task_ledger_balance(task, task_ledgers.purgeable_nonvolatile_compressed); |
554 | } | |
39037602 | 555 | |
f427ee49 A |
556 | uint64_t |
557 | get_task_alternate_accounting(task_t task) | |
558 | { | |
559 | return get_task_ledger_balance(task, task_ledgers.alternate_accounting); | |
560 | } | |
39037602 | 561 | |
f427ee49 A |
562 | uint64_t |
563 | get_task_alternate_accounting_compressed(task_t task) | |
564 | { | |
565 | return get_task_ledger_balance(task, task_ledgers.alternate_accounting_compressed); | |
39037602 A |
566 | } |
567 | ||
0a7de745 | 568 | uint64_t |
f427ee49 | 569 | get_task_page_table(task_t task) |
39037602 | 570 | { |
f427ee49 A |
571 | return get_task_ledger_balance(task, task_ledgers.page_table); |
572 | } | |
39037602 | 573 | |
f427ee49 A |
574 | #if CONFIG_FREEZE |
575 | uint64_t | |
576 | get_task_frozen_to_swap(task_t task) | |
577 | { | |
578 | return get_task_ledger_balance(task, task_ledgers.frozen_to_swap); | |
579 | } | |
580 | #endif /* CONFIG_FREEZE */ | |
39037602 | 581 | |
f427ee49 A |
582 | uint64_t |
583 | get_task_iokit_mapped(task_t task) | |
584 | { | |
585 | return get_task_ledger_balance(task, task_ledgers.iokit_mapped); | |
39037602 A |
586 | } |
587 | ||
0a7de745 | 588 | uint64_t |
f427ee49 | 589 | get_task_network_nonvolatile(task_t task) |
39037602 | 590 | { |
f427ee49 A |
591 | return get_task_ledger_balance(task, task_ledgers.network_nonvolatile); |
592 | } | |
39037602 | 593 | |
f427ee49 A |
594 | uint64_t |
595 | get_task_network_nonvolatile_compressed(task_t task) | |
596 | { | |
597 | return get_task_ledger_balance(task, task_ledgers.network_nonvolatile_compressed); | |
598 | } | |
39037602 | 599 | |
f427ee49 A |
600 | uint64_t |
601 | get_task_wired_mem(task_t task) | |
602 | { | |
603 | return get_task_ledger_balance(task, task_ledgers.wired_mem); | |
39037602 A |
604 | } |
605 | ||
0a7de745 | 606 | uint64_t |
f427ee49 | 607 | get_task_tagged_footprint(task_t task) |
39037602 A |
608 | { |
609 | kern_return_t ret; | |
610 | ledger_amount_t credit, debit; | |
611 | ||
f427ee49 | 612 | ret = ledger_get_entries(task->ledger, task_ledgers.tagged_footprint, &credit, &debit); |
39037602 | 613 | if (KERN_SUCCESS == ret) { |
0a7de745 | 614 | return credit - debit; |
39037602 A |
615 | } |
616 | ||
617 | return 0; | |
618 | } | |
619 | ||
0a7de745 | 620 | uint64_t |
f427ee49 | 621 | get_task_tagged_footprint_compressed(task_t task) |
39037602 A |
622 | { |
623 | kern_return_t ret; | |
624 | ledger_amount_t credit, debit; | |
625 | ||
f427ee49 | 626 | ret = ledger_get_entries(task->ledger, task_ledgers.tagged_footprint_compressed, &credit, &debit); |
39037602 | 627 | if (KERN_SUCCESS == ret) { |
0a7de745 | 628 | return credit - debit; |
39037602 A |
629 | } |
630 | ||
631 | return 0; | |
632 | } | |
633 | ||
0a7de745 | 634 | uint64_t |
f427ee49 | 635 | get_task_media_footprint(task_t task) |
39037602 A |
636 | { |
637 | kern_return_t ret; | |
638 | ledger_amount_t credit, debit; | |
639 | ||
f427ee49 | 640 | ret = ledger_get_entries(task->ledger, task_ledgers.media_footprint, &credit, &debit); |
39037602 | 641 | if (KERN_SUCCESS == ret) { |
0a7de745 | 642 | return credit - debit; |
39037602 A |
643 | } |
644 | ||
645 | return 0; | |
646 | } | |
647 | ||
0a7de745 | 648 | uint64_t |
f427ee49 | 649 | get_task_media_footprint_compressed(task_t task) |
39037602 A |
650 | { |
651 | kern_return_t ret; | |
652 | ledger_amount_t credit, debit; | |
653 | ||
f427ee49 | 654 | ret = ledger_get_entries(task->ledger, task_ledgers.media_footprint_compressed, &credit, &debit); |
39037602 | 655 | if (KERN_SUCCESS == ret) { |
0a7de745 | 656 | return credit - debit; |
39037602 A |
657 | } |
658 | ||
659 | return 0; | |
660 | } | |
661 | ||
0a7de745 | 662 | uint64_t |
f427ee49 | 663 | get_task_graphics_footprint(task_t task) |
d9a64523 | 664 | { |
0a7de745 A |
665 | kern_return_t ret; |
666 | ledger_amount_t credit, debit; | |
d9a64523 | 667 | |
f427ee49 | 668 | ret = ledger_get_entries(task->ledger, task_ledgers.graphics_footprint, &credit, &debit); |
0a7de745 A |
669 | if (KERN_SUCCESS == ret) { |
670 | return credit - debit; | |
671 | } | |
d9a64523 | 672 | |
0a7de745 | 673 | return 0; |
d9a64523 A |
674 | } |
675 | ||
f427ee49 | 676 | |
0a7de745 | 677 | uint64_t |
f427ee49 | 678 | get_task_graphics_footprint_compressed(task_t task) |
d9a64523 | 679 | { |
0a7de745 A |
680 | kern_return_t ret; |
681 | ledger_amount_t credit, debit; | |
d9a64523 | 682 | |
f427ee49 | 683 | ret = ledger_get_entries(task->ledger, task_ledgers.graphics_footprint_compressed, &credit, &debit); |
0a7de745 A |
684 | if (KERN_SUCCESS == ret) { |
685 | return credit - debit; | |
686 | } | |
d9a64523 | 687 | |
0a7de745 | 688 | return 0; |
d9a64523 A |
689 | } |
690 | ||
0a7de745 | 691 | uint64_t |
f427ee49 | 692 | get_task_neural_footprint(task_t task) |
d9a64523 | 693 | { |
0a7de745 A |
694 | kern_return_t ret; |
695 | ledger_amount_t credit, debit; | |
d9a64523 | 696 | |
f427ee49 | 697 | ret = ledger_get_entries(task->ledger, task_ledgers.neural_footprint, &credit, &debit); |
0a7de745 A |
698 | if (KERN_SUCCESS == ret) { |
699 | return credit - debit; | |
700 | } | |
d9a64523 | 701 | |
0a7de745 | 702 | return 0; |
d9a64523 A |
703 | } |
704 | ||
0a7de745 | 705 | uint64_t |
f427ee49 | 706 | get_task_neural_footprint_compressed(task_t task) |
fe8ab488 A |
707 | { |
708 | kern_return_t ret; | |
709 | ledger_amount_t credit, debit; | |
0a7de745 | 710 | |
f427ee49 | 711 | ret = ledger_get_entries(task->ledger, task_ledgers.neural_footprint_compressed, &credit, &debit); |
fe8ab488 | 712 | if (KERN_SUCCESS == ret) { |
0a7de745 | 713 | return credit - debit; |
fe8ab488 A |
714 | } |
715 | ||
716 | return 0; | |
717 | } | |
718 | ||
f427ee49 A |
719 | uint64_t |
720 | get_task_cpu_time(task_t task) | |
721 | { | |
722 | return get_task_ledger_balance(task, task_ledgers.cpu_time); | |
723 | } | |
724 | ||
cb323159 A |
725 | uint32_t |
726 | get_task_loadTag(task_t task) | |
727 | { | |
728 | return os_atomic_load(&task->loadTag, relaxed); | |
729 | } | |
730 | ||
731 | uint32_t | |
732 | set_task_loadTag(task_t task, uint32_t loadTag) | |
733 | { | |
734 | return os_atomic_xchg(&task->loadTag, loadTag, relaxed); | |
735 | } | |
736 | ||
1c79356b A |
737 | /* |
738 | * | |
739 | */ | |
0a7de745 A |
740 | task_t |
741 | get_threadtask(thread_t th) | |
1c79356b | 742 | { |
0a7de745 | 743 | return th->task; |
1c79356b A |
744 | } |
745 | ||
1c79356b A |
746 | /* |
747 | * | |
748 | */ | |
91447636 | 749 | vm_map_offset_t |
1c79356b | 750 | get_map_min( |
0a7de745 | 751 | vm_map_t map) |
1c79356b | 752 | { |
0a7de745 | 753 | return vm_map_min(map); |
1c79356b A |
754 | } |
755 | ||
756 | /* | |
757 | * | |
758 | */ | |
91447636 | 759 | vm_map_offset_t |
1c79356b | 760 | get_map_max( |
0a7de745 | 761 | vm_map_t map) |
1c79356b | 762 | { |
0a7de745 | 763 | return vm_map_max(map); |
1c79356b | 764 | } |
91447636 | 765 | vm_map_size_t |
1c79356b | 766 | get_vmmap_size( |
0a7de745 | 767 | vm_map_t map) |
1c79356b | 768 | { |
f427ee49 | 769 | return vm_map_adjusted_size(map); |
1c79356b | 770 | } |
c3c9b80d A |
771 | int |
772 | get_task_page_size( | |
773 | task_t task) | |
774 | { | |
775 | return vm_map_page_size(task->map); | |
776 | } | |
1c79356b | 777 | |
39037602 A |
778 | #if CONFIG_COREDUMP |
779 | ||
780 | static int | |
1c79356b | 781 | get_vmsubmap_entries( |
0a7de745 A |
782 | vm_map_t map, |
783 | vm_object_offset_t start, | |
784 | vm_object_offset_t end) | |
1c79356b | 785 | { |
0a7de745 A |
786 | int total_entries = 0; |
787 | vm_map_entry_t entry; | |
1c79356b | 788 | |
0a7de745 A |
789 | if (not_in_kdp) { |
790 | vm_map_lock(map); | |
791 | } | |
1c79356b | 792 | entry = vm_map_first_entry(map); |
0a7de745 | 793 | while ((entry != vm_map_to_entry(map)) && (entry->vme_start < start)) { |
1c79356b A |
794 | entry = entry->vme_next; |
795 | } | |
796 | ||
0a7de745 A |
797 | while ((entry != vm_map_to_entry(map)) && (entry->vme_start < end)) { |
798 | if (entry->is_sub_map) { | |
799 | total_entries += | |
800 | get_vmsubmap_entries(VME_SUBMAP(entry), | |
801 | VME_OFFSET(entry), | |
802 | (VME_OFFSET(entry) + | |
803 | entry->vme_end - | |
804 | entry->vme_start)); | |
1c79356b A |
805 | } else { |
806 | total_entries += 1; | |
807 | } | |
808 | entry = entry->vme_next; | |
809 | } | |
0a7de745 A |
810 | if (not_in_kdp) { |
811 | vm_map_unlock(map); | |
812 | } | |
813 | return total_entries; | |
1c79356b A |
814 | } |
815 | ||
816 | int | |
817 | get_vmmap_entries( | |
0a7de745 | 818 | vm_map_t map) |
1c79356b | 819 | { |
0a7de745 A |
820 | int total_entries = 0; |
821 | vm_map_entry_t entry; | |
1c79356b | 822 | |
0a7de745 A |
823 | if (not_in_kdp) { |
824 | vm_map_lock(map); | |
825 | } | |
1c79356b A |
826 | entry = vm_map_first_entry(map); |
827 | ||
0a7de745 A |
828 | while (entry != vm_map_to_entry(map)) { |
829 | if (entry->is_sub_map) { | |
830 | total_entries += | |
831 | get_vmsubmap_entries(VME_SUBMAP(entry), | |
832 | VME_OFFSET(entry), | |
833 | (VME_OFFSET(entry) + | |
834 | entry->vme_end - | |
835 | entry->vme_start)); | |
1c79356b A |
836 | } else { |
837 | total_entries += 1; | |
838 | } | |
839 | entry = entry->vme_next; | |
840 | } | |
0a7de745 A |
841 | if (not_in_kdp) { |
842 | vm_map_unlock(map); | |
843 | } | |
844 | return total_entries; | |
1c79356b | 845 | } |
39037602 | 846 | #endif /* CONFIG_COREDUMP */ |
1c79356b A |
847 | |
848 | /* | |
849 | * | |
850 | */ | |
851 | /* | |
852 | * | |
853 | */ | |
854 | int | |
855 | get_task_userstop( | |
856 | task_t task) | |
857 | { | |
0a7de745 | 858 | return task->user_stop_count; |
1c79356b A |
859 | } |
860 | ||
861 | /* | |
862 | * | |
863 | */ | |
864 | int | |
865 | get_thread_userstop( | |
91447636 | 866 | thread_t th) |
1c79356b | 867 | { |
0a7de745 | 868 | return th->user_stop_count; |
1c79356b A |
869 | } |
870 | ||
316670eb A |
871 | /* |
872 | * | |
873 | */ | |
874 | boolean_t | |
875 | get_task_pidsuspended( | |
876 | task_t task) | |
877 | { | |
0a7de745 | 878 | return task->pidsuspended; |
316670eb A |
879 | } |
880 | ||
881 | /* | |
882 | * | |
883 | */ | |
0a7de745 | 884 | boolean_t |
316670eb A |
885 | get_task_frozen( |
886 | task_t task) | |
887 | { | |
0a7de745 | 888 | return task->frozen; |
316670eb A |
889 | } |
890 | ||
1c79356b A |
891 | /* |
892 | * | |
893 | */ | |
894 | boolean_t | |
895 | thread_should_abort( | |
55e303ae | 896 | thread_t th) |
1c79356b | 897 | { |
0a7de745 | 898 | return (th->sched_flags & TH_SFLAG_ABORTED_MASK) == TH_SFLAG_ABORT; |
1c79356b A |
899 | } |
900 | ||
901 | /* | |
9bccf70c A |
902 | * This routine is like thread_should_abort() above. It checks to |
903 | * see if the current thread is aborted. But unlike above, it also | |
904 | * checks to see if thread is safely aborted. If so, it returns | |
905 | * that fact, and clears the condition (safe aborts only should | |
906 | * have a single effect, and a poll of the abort status | |
907 | * qualifies. | |
1c79356b A |
908 | */ |
909 | boolean_t | |
0a7de745 A |
910 | current_thread_aborted( |
911 | void) | |
1c79356b A |
912 | { |
913 | thread_t th = current_thread(); | |
9bccf70c A |
914 | spl_t s; |
915 | ||
6d2010ae | 916 | if ((th->sched_flags & TH_SFLAG_ABORTED_MASK) == TH_SFLAG_ABORT && |
0a7de745 A |
917 | (th->options & TH_OPT_INTMASK) != THREAD_UNINT) { |
918 | return TRUE; | |
919 | } | |
6d2010ae | 920 | if (th->sched_flags & TH_SFLAG_ABORTSAFELY) { |
9bccf70c A |
921 | s = splsched(); |
922 | thread_lock(th); | |
0a7de745 | 923 | if (th->sched_flags & TH_SFLAG_ABORTSAFELY) { |
6d2010ae | 924 | th->sched_flags &= ~TH_SFLAG_ABORTED_MASK; |
0a7de745 | 925 | } |
9bccf70c A |
926 | thread_unlock(th); |
927 | splx(s); | |
928 | } | |
929 | return FALSE; | |
1c79356b A |
930 | } |
931 | ||
932 | /* | |
933 | * | |
934 | */ | |
935 | void | |
936 | task_act_iterate_wth_args( | |
0a7de745 A |
937 | task_t task, |
938 | void (*func_callback)(thread_t, void *), | |
939 | void *func_arg) | |
1c79356b | 940 | { |
0a7de745 | 941 | thread_t inc; |
1c79356b A |
942 | |
943 | task_lock(task); | |
91447636 | 944 | |
39236c6e | 945 | for (inc = (thread_t)(void *)queue_first(&task->threads); |
0a7de745 | 946 | !queue_end(&task->threads, (queue_entry_t)inc);) { |
91447636 | 947 | (void) (*func_callback)(inc, func_arg); |
39236c6e | 948 | inc = (thread_t)(void *)queue_next(&inc->task_threads); |
91447636 A |
949 | } |
950 | ||
1c79356b A |
951 | task_unlock(task); |
952 | } | |
953 | ||
1c79356b | 954 | |
0c530ab8 A |
955 | #include <sys/bsdtask_info.h> |
956 | ||
957 | void | |
958 | fill_taskprocinfo(task_t task, struct proc_taskinfo_internal * ptinfo) | |
959 | { | |
960 | vm_map_t map; | |
961 | task_absolutetime_info_data_t tinfo; | |
962 | thread_t thread; | |
6d2010ae A |
963 | uint32_t cswitch = 0, numrunning = 0; |
964 | uint32_t syscalls_unix = 0; | |
965 | uint32_t syscalls_mach = 0; | |
39236c6e | 966 | |
3e170ce0 A |
967 | task_lock(task); |
968 | ||
0c530ab8 A |
969 | map = (task == kernel_task)? kernel_map: task->map; |
970 | ||
f427ee49 | 971 | ptinfo->pti_virtual_size = vm_map_adjusted_size(map); |
2d21ac55 | 972 | ptinfo->pti_resident_size = |
0a7de745 A |
973 | (mach_vm_size_t)(pmap_resident_count(map->pmap)) |
974 | * PAGE_SIZE_64; | |
0c530ab8 | 975 | |
0c530ab8 | 976 | ptinfo->pti_policy = ((task != kernel_task)? |
0a7de745 | 977 | POLICY_TIMESHARE: POLICY_RR); |
0c530ab8 A |
978 | |
979 | tinfo.threads_user = tinfo.threads_system = 0; | |
980 | tinfo.total_user = task->total_user_time; | |
981 | tinfo.total_system = task->total_system_time; | |
982 | ||
983 | queue_iterate(&task->threads, thread, thread_t, task_threads) { | |
984 | uint64_t tval; | |
316670eb A |
985 | spl_t x; |
986 | ||
0a7de745 | 987 | if (thread->options & TH_OPT_IDLE_THREAD) { |
39236c6e | 988 | continue; |
0a7de745 | 989 | } |
39236c6e | 990 | |
316670eb A |
991 | x = splsched(); |
992 | thread_lock(thread); | |
0c530ab8 | 993 | |
0a7de745 | 994 | if ((thread->state & TH_RUN) == TH_RUN) { |
0c530ab8 | 995 | numrunning++; |
0a7de745 | 996 | } |
2d21ac55 | 997 | cswitch += thread->c_switch; |
0c530ab8 A |
998 | tval = timer_grab(&thread->user_timer); |
999 | tinfo.threads_user += tval; | |
1000 | tinfo.total_user += tval; | |
1001 | ||
1002 | tval = timer_grab(&thread->system_timer); | |
316670eb A |
1003 | |
1004 | if (thread->precise_user_kernel_time) { | |
1005 | tinfo.threads_system += tval; | |
1006 | tinfo.total_system += tval; | |
1007 | } else { | |
1008 | /* system_timer may represent either sys or user */ | |
1009 | tinfo.threads_user += tval; | |
1010 | tinfo.total_user += tval; | |
1011 | } | |
6d2010ae A |
1012 | |
1013 | syscalls_unix += thread->syscalls_unix; | |
1014 | syscalls_mach += thread->syscalls_mach; | |
316670eb A |
1015 | |
1016 | thread_unlock(thread); | |
1017 | splx(x); | |
0c530ab8 A |
1018 | } |
1019 | ||
1020 | ptinfo->pti_total_system = tinfo.total_system; | |
1021 | ptinfo->pti_total_user = tinfo.total_user; | |
1022 | ptinfo->pti_threads_system = tinfo.threads_system; | |
1023 | ptinfo->pti_threads_user = tinfo.threads_user; | |
0a7de745 | 1024 | |
c3c9b80d | 1025 | ptinfo->pti_faults = (int32_t) MIN(counter_load(&task->faults), INT32_MAX); |
0c530ab8 A |
1026 | ptinfo->pti_pageins = task->pageins; |
1027 | ptinfo->pti_cow_faults = task->cow_faults; | |
1028 | ptinfo->pti_messages_sent = task->messages_sent; | |
1029 | ptinfo->pti_messages_received = task->messages_received; | |
6d2010ae A |
1030 | ptinfo->pti_syscalls_mach = task->syscalls_mach + syscalls_mach; |
1031 | ptinfo->pti_syscalls_unix = task->syscalls_unix + syscalls_unix; | |
2d21ac55 | 1032 | ptinfo->pti_csw = task->c_switch + cswitch; |
0c530ab8 A |
1033 | ptinfo->pti_threadnum = task->thread_count; |
1034 | ptinfo->pti_numrunning = numrunning; | |
1035 | ptinfo->pti_priority = task->priority; | |
1036 | ||
1037 | task_unlock(task); | |
1038 | } | |
1039 | ||
0a7de745 | 1040 | int |
d9a64523 | 1041 | fill_taskthreadinfo(task_t task, uint64_t thaddr, bool thuniqueid, struct proc_threadinfo_internal * ptinfo, void * vpp, int *vidp) |
0c530ab8 A |
1042 | { |
1043 | thread_t thact; | |
0a7de745 | 1044 | int err = 0; |
2d21ac55 | 1045 | mach_msg_type_number_t count; |
0c530ab8 A |
1046 | thread_basic_info_data_t basic_info; |
1047 | kern_return_t kret; | |
316670eb | 1048 | uint64_t addr = 0; |
0c530ab8 A |
1049 | |
1050 | task_lock(task); | |
1051 | ||
39236c6e | 1052 | for (thact = (thread_t)(void *)queue_first(&task->threads); |
0a7de745 | 1053 | !queue_end(&task->threads, (queue_entry_t)thact);) { |
d9a64523 | 1054 | addr = (thuniqueid) ? thact->thread_id : thact->machine.cthread_self; |
0a7de745 | 1055 | if (addr == thaddr) { |
0c530ab8 | 1056 | count = THREAD_BASIC_INFO_COUNT; |
2d21ac55 | 1057 | if ((kret = thread_info_internal(thact, THREAD_BASIC_INFO, (thread_info_t)&basic_info, &count)) != KERN_SUCCESS) { |
0c530ab8 | 1058 | err = 1; |
0a7de745 | 1059 | goto out; |
0c530ab8 | 1060 | } |
cb323159 A |
1061 | ptinfo->pth_user_time = (((uint64_t)basic_info.user_time.seconds * NSEC_PER_SEC) + ((uint64_t)basic_info.user_time.microseconds * NSEC_PER_USEC)); |
1062 | ptinfo->pth_system_time = (((uint64_t)basic_info.system_time.seconds * NSEC_PER_SEC) + ((uint64_t)basic_info.system_time.microseconds * NSEC_PER_USEC)); | |
0c530ab8 | 1063 | |
0c530ab8 A |
1064 | ptinfo->pth_cpu_usage = basic_info.cpu_usage; |
1065 | ptinfo->pth_policy = basic_info.policy; | |
1066 | ptinfo->pth_run_state = basic_info.run_state; | |
1067 | ptinfo->pth_flags = basic_info.flags; | |
1068 | ptinfo->pth_sleep_time = basic_info.sleep_time; | |
1069 | ptinfo->pth_curpri = thact->sched_pri; | |
3e170ce0 | 1070 | ptinfo->pth_priority = thact->base_pri; |
0c530ab8 | 1071 | ptinfo->pth_maxpriority = thact->max_priority; |
0a7de745 A |
1072 | |
1073 | if ((vpp != NULL) && (thact->uthread != NULL)) { | |
2d21ac55 | 1074 | bsd_threadcdir(thact->uthread, vpp, vidp); |
0a7de745 A |
1075 | } |
1076 | bsd_getthreadname(thact->uthread, ptinfo->pth_name); | |
0c530ab8 | 1077 | err = 0; |
0a7de745 | 1078 | goto out; |
0c530ab8 | 1079 | } |
39236c6e | 1080 | thact = (thread_t)(void *)queue_next(&thact->task_threads); |
0c530ab8 A |
1081 | } |
1082 | err = 1; | |
1083 | ||
1084 | out: | |
1085 | task_unlock(task); | |
0a7de745 | 1086 | return err; |
0c530ab8 A |
1087 | } |
1088 | ||
1089 | int | |
d9a64523 | 1090 | fill_taskthreadlist(task_t task, void * buffer, int thcount, bool thuniqueid) |
0c530ab8 | 1091 | { |
0a7de745 | 1092 | int numthr = 0; |
0c530ab8 A |
1093 | thread_t thact; |
1094 | uint64_t * uptr; | |
1095 | uint64_t thaddr; | |
1096 | ||
1097 | uptr = (uint64_t *)buffer; | |
1098 | ||
1099 | task_lock(task); | |
1100 | ||
39236c6e | 1101 | for (thact = (thread_t)(void *)queue_first(&task->threads); |
0a7de745 | 1102 | !queue_end(&task->threads, (queue_entry_t)thact);) { |
d9a64523 | 1103 | thaddr = (thuniqueid) ? thact->thread_id : thact->machine.cthread_self; |
0c530ab8 A |
1104 | *uptr++ = thaddr; |
1105 | numthr++; | |
0a7de745 | 1106 | if (numthr >= thcount) { |
0c530ab8 | 1107 | goto out; |
0a7de745 | 1108 | } |
39236c6e | 1109 | thact = (thread_t)(void *)queue_next(&thact->task_threads); |
0c530ab8 A |
1110 | } |
1111 | ||
1112 | out: | |
1113 | task_unlock(task); | |
b0d623f7 | 1114 | return (int)(numthr * sizeof(uint64_t)); |
0c530ab8 A |
1115 | } |
1116 | ||
1117 | int | |
1118 | get_numthreads(task_t task) | |
1119 | { | |
0a7de745 | 1120 | return task->thread_count; |
0c530ab8 A |
1121 | } |
1122 | ||
39236c6e | 1123 | /* |
0a7de745 | 1124 | * Gather the various pieces of info about the designated task, |
39236c6e A |
1125 | * and collect it all into a single rusage_info. |
1126 | */ | |
1127 | int | |
fe8ab488 | 1128 | fill_task_rusage(task_t task, rusage_info_current *ri) |
39236c6e A |
1129 | { |
1130 | struct task_power_info powerinfo; | |
1131 | ||
cb323159 A |
1132 | uint64_t runnable_time = 0; |
1133 | ||
39236c6e A |
1134 | assert(task != TASK_NULL); |
1135 | task_lock(task); | |
1136 | ||
cb323159 | 1137 | task_power_info_locked(task, &powerinfo, NULL, NULL, &runnable_time); |
39236c6e A |
1138 | ri->ri_pkg_idle_wkups = powerinfo.task_platform_idle_wakeups; |
1139 | ri->ri_interrupt_wkups = powerinfo.task_interrupt_wakeups; | |
1140 | ri->ri_user_time = powerinfo.total_user; | |
1141 | ri->ri_system_time = powerinfo.total_system; | |
cb323159 | 1142 | ri->ri_runnable_time = runnable_time; |
39236c6e | 1143 | |
f427ee49 | 1144 | ri->ri_phys_footprint = get_task_phys_footprint(task); |
39236c6e | 1145 | ledger_get_balance(task->ledger, task_ledgers.phys_mem, |
0a7de745 | 1146 | (ledger_amount_t *)&ri->ri_resident_size); |
f427ee49 | 1147 | ri->ri_wired_size = get_task_wired_mem(task); |
39236c6e A |
1148 | |
1149 | ri->ri_pageins = task->pageins; | |
1150 | ||
1151 | task_unlock(task); | |
0a7de745 | 1152 | return 0; |
39236c6e | 1153 | } |
fe8ab488 A |
1154 | |
1155 | void | |
1156 | fill_task_billed_usage(task_t task __unused, rusage_info_current *ri) | |
1157 | { | |
5ba3f43e A |
1158 | bank_billed_balance_safe(task, &ri->ri_billed_system_time, &ri->ri_billed_energy); |
1159 | bank_serviced_balance_safe(task, &ri->ri_serviced_system_time, &ri->ri_serviced_energy); | |
fe8ab488 A |
1160 | } |
1161 | ||
1162 | int | |
1163 | fill_task_io_rusage(task_t task, rusage_info_current *ri) | |
1164 | { | |
1165 | assert(task != TASK_NULL); | |
1166 | task_lock(task); | |
1167 | ||
1168 | if (task->task_io_stats) { | |
1169 | ri->ri_diskio_bytesread = task->task_io_stats->disk_reads.size; | |
1170 | ri->ri_diskio_byteswritten = (task->task_io_stats->total_io.size - task->task_io_stats->disk_reads.size); | |
1171 | } else { | |
1172 | /* I/O Stats unavailable */ | |
1173 | ri->ri_diskio_bytesread = 0; | |
1174 | ri->ri_diskio_byteswritten = 0; | |
1175 | } | |
1176 | task_unlock(task); | |
0a7de745 | 1177 | return 0; |
fe8ab488 A |
1178 | } |
1179 | ||
1180 | int | |
1181 | fill_task_qos_rusage(task_t task, rusage_info_current *ri) | |
1182 | { | |
1183 | thread_t thread; | |
1184 | ||
1185 | assert(task != TASK_NULL); | |
1186 | task_lock(task); | |
1187 | ||
a39ff7e2 | 1188 | /* Rollup QoS time of all the threads to task */ |
fe8ab488 | 1189 | queue_iterate(&task->threads, thread, thread_t, task_threads) { |
0a7de745 | 1190 | if (thread->options & TH_OPT_IDLE_THREAD) { |
fe8ab488 | 1191 | continue; |
0a7de745 | 1192 | } |
fe8ab488 | 1193 | |
39037602 | 1194 | thread_update_qos_cpu_time(thread); |
fe8ab488 | 1195 | } |
a39ff7e2 A |
1196 | ri->ri_cpu_time_qos_default = task->cpu_time_eqos_stats.cpu_time_qos_default; |
1197 | ri->ri_cpu_time_qos_maintenance = task->cpu_time_eqos_stats.cpu_time_qos_maintenance; | |
1198 | ri->ri_cpu_time_qos_background = task->cpu_time_eqos_stats.cpu_time_qos_background; | |
1199 | ri->ri_cpu_time_qos_utility = task->cpu_time_eqos_stats.cpu_time_qos_utility; | |
1200 | ri->ri_cpu_time_qos_legacy = task->cpu_time_eqos_stats.cpu_time_qos_legacy; | |
1201 | ri->ri_cpu_time_qos_user_initiated = task->cpu_time_eqos_stats.cpu_time_qos_user_initiated; | |
1202 | ri->ri_cpu_time_qos_user_interactive = task->cpu_time_eqos_stats.cpu_time_qos_user_interactive; | |
fe8ab488 A |
1203 | |
1204 | task_unlock(task); | |
0a7de745 | 1205 | return 0; |
fe8ab488 | 1206 | } |
39037602 | 1207 | |
5ba3f43e A |
1208 | void |
1209 | fill_task_monotonic_rusage(task_t task, rusage_info_current *ri) | |
1210 | { | |
1211 | #if MONOTONIC | |
1212 | if (!mt_core_supported) { | |
1213 | return; | |
1214 | } | |
1215 | ||
1216 | assert(task != TASK_NULL); | |
1217 | ||
e8c3f781 | 1218 | uint64_t counts[MT_CORE_NFIXED] = { 0 }; |
5ba3f43e A |
1219 | mt_fixed_task_counts(task, counts); |
1220 | #ifdef MT_CORE_INSTRS | |
1221 | ri->ri_instructions = counts[MT_CORE_INSTRS]; | |
1222 | #endif /* defined(MT_CORE_INSTRS) */ | |
1223 | ri->ri_cycles = counts[MT_CORE_CYCLES]; | |
1224 | #else /* MONOTONIC */ | |
1225 | #pragma unused(task, ri) | |
1226 | #endif /* !MONOTONIC */ | |
1227 | } | |
1228 | ||
1229 | uint64_t | |
cb323159 | 1230 | get_task_logical_writes(task_t task, boolean_t external) |
5ba3f43e | 1231 | { |
0a7de745 A |
1232 | assert(task != TASK_NULL); |
1233 | struct ledger_entry_info lei; | |
5ba3f43e | 1234 | |
0a7de745 | 1235 | task_lock(task); |
cb323159 A |
1236 | |
1237 | if (external == FALSE) { | |
1238 | ledger_get_entry_info(task->ledger, task_ledgers.logical_writes, &lei); | |
1239 | } else { | |
1240 | ledger_get_entry_info(task->ledger, task_ledgers.logical_writes_to_external, &lei); | |
1241 | } | |
1242 | ||
0a7de745 | 1243 | ledger_get_entry_info(task->ledger, task_ledgers.logical_writes, &lei); |
5ba3f43e | 1244 | |
0a7de745 A |
1245 | task_unlock(task); |
1246 | return lei.lei_balance; | |
5ba3f43e A |
1247 | } |
1248 | ||
39037602 A |
1249 | uint64_t |
1250 | get_task_dispatchqueue_serialno_offset(task_t task) | |
1251 | { | |
1252 | uint64_t dq_serialno_offset = 0; | |
1253 | ||
1254 | if (task->bsd_info) { | |
1255 | dq_serialno_offset = get_dispatchqueue_serialno_offset_from_proc(task->bsd_info); | |
1256 | } | |
1257 | ||
1258 | return dq_serialno_offset; | |
1259 | } | |
1260 | ||
cb323159 A |
1261 | uint64_t |
1262 | get_task_dispatchqueue_label_offset(task_t task) | |
1263 | { | |
1264 | uint64_t dq_label_offset = 0; | |
1265 | ||
1266 | if (task->bsd_info) { | |
1267 | dq_label_offset = get_dispatchqueue_label_offset_from_proc(task->bsd_info); | |
1268 | } | |
1269 | ||
1270 | return dq_label_offset; | |
1271 | } | |
1272 | ||
39037602 A |
1273 | uint64_t |
1274 | get_task_uniqueid(task_t task) | |
1275 | { | |
1276 | if (task->bsd_info) { | |
1277 | return proc_uniqueid(task->bsd_info); | |
1278 | } else { | |
1279 | return UINT64_MAX; | |
1280 | } | |
1281 | } | |
1282 | ||
5ba3f43e A |
1283 | int |
1284 | get_task_version(task_t task) | |
1285 | { | |
1286 | if (task->bsd_info) { | |
1287 | return proc_pidversion(task->bsd_info); | |
1288 | } else { | |
1289 | return INT_MAX; | |
1290 | } | |
1291 | } | |
1292 | ||
39037602 A |
1293 | #if CONFIG_MACF |
1294 | struct label * | |
1295 | get_task_crash_label(task_t task) | |
1296 | { | |
1297 | return task->crash_label; | |
1298 | } | |
39037602 | 1299 | #endif |
cb323159 A |
1300 | |
1301 | int | |
1302 | fill_taskipctableinfo(task_t task, uint32_t *table_size, uint32_t *table_free) | |
1303 | { | |
1304 | ipc_space_t space = task->itk_space; | |
1305 | if (space == NULL) { | |
1306 | return -1; | |
1307 | } | |
1308 | ||
1309 | is_read_lock(space); | |
1310 | if (!is_active(space)) { | |
1311 | is_read_unlock(space); | |
1312 | return -1; | |
1313 | } | |
1314 | ||
1315 | *table_size = space->is_table_size; | |
1316 | *table_free = space->is_table_free; | |
1317 | ||
1318 | is_read_unlock(space); | |
1319 | ||
1320 | return 0; | |
1321 | } | |
1322 | ||
1323 | int | |
1324 | get_task_cdhash(task_t task, char cdhash[static CS_CDHASH_LEN]) | |
1325 | { | |
1326 | int result = 0; | |
1327 | ||
1328 | task_lock(task); | |
1329 | result = task->bsd_info ? proc_getcdhash(task->bsd_info, cdhash) : ESRCH; | |
1330 | task_unlock(task); | |
1331 | ||
1332 | return result; | |
1333 | } |