]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/task_policy.c
2cbb2daa2d0500c0bf9301e2ba11695f5b0a6303
[apple/xnu.git] / osfmk / kern / task_policy.c
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <mach/mach_types.h>
30 #include <mach/task_server.h>
31
32 #include <kern/sched.h>
33 #include <kern/task.h>
34 #include <mach/thread_policy.h>
35 #include <sys/errno.h>
36 #include <sys/resource.h>
37 #include <machine/limits.h>
38 #include <kern/ledger.h>
39 #include <kern/thread_call.h>
40 #if CONFIG_EMBEDDED
41 #include <kern/kalloc.h>
42 #include <sys/errno.h>
43 #endif /* CONFIG_EMBEDDED */
44 #include <sys/kdebug.h>
45
46 #if CONFIG_MEMORYSTATUS
47 extern void memorystatus_on_suspend(int pid);
48 extern void memorystatus_on_resume(int pid);
49 #endif
50
51 static int proc_apply_bgtaskpolicy_internal(task_t, int, int);
52 static int proc_restore_bgtaskpolicy_internal(task_t, int, int, int);
53 static int task_get_cpuusage(task_t task, uint32_t * percentagep, uint64_t * intervalp, uint64_t * deadlinep);
54 int task_set_cpuusage(task_t task, uint64_t percentage, uint64_t interval, uint64_t deadline, int scope);
55 static int task_clear_cpuusage_locked(task_t task);
56 static int task_apply_resource_actions(task_t task, int type);
57 static void task_priority(task_t task, integer_t priority, integer_t max_priority);
58 static kern_return_t task_role_default_handler(task_t task, task_role_t role);
59 void task_action_cpuusage(thread_call_param_t param0, thread_call_param_t param1);
60 static int proc_apply_bgthreadpolicy_locked(thread_t thread, int selfset);
61 static void restore_bgthreadpolicy_locked(thread_t thread, int selfset, int importance);
62 static int proc_get_task_selfdiskacc_internal(task_t task, thread_t thread);
63 extern void unthrottle_thread(void * uthread);
64
65 #if CONFIG_EMBEDDED
66 static void set_thread_appbg(thread_t thread, int setbg,int importance);
67 static void apply_bgthreadpolicy_external(thread_t thread);
68 static void add_taskwatch_locked(task_t task, task_watch_t * twp);
69 static void remove_taskwatch_locked(task_t task, task_watch_t * twp);
70 static void task_watch_lock(void);
71 static void task_watch_unlock(void);
72 static void apply_appstate_watchers(task_t task, int setbg);
73 void proc_apply_task_networkbg_internal(void *, thread_t);
74 void proc_restore_task_networkbg_internal(void *, thread_t);
75 int proc_pid(void * proc);
76
77 typedef struct thread_watchlist {
78 thread_t thread; /* thread being worked on for taskwatch action */
79 int importance; /* importance to be restored if thread is being made active */
80 } thread_watchlist_t;
81
82 #endif /* CONFIG_EMBEDDED */
83
84
85 process_policy_t default_task_proc_policy = {0,
86 0,
87 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
88 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
89 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
90 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
91 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
92 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
93 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
94 0,
95 TASK_POLICY_HWACCESS_CPU_ATTRIBUTE_FULLACCESS,
96 TASK_POLICY_HWACCESS_NET_ATTRIBUTE_FULLACCESS,
97 TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_FULLACCESS,
98 TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_NORMAL,
99 TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL
100 };
101
102 process_policy_t default_task_null_policy = {0,
103 0,
104 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
105 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
106 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
107 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
108 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
109 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
110 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
111 0,
112 TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NONE,
113 TASK_POLICY_HWACCESS_NET_ATTRIBUTE_NONE,
114 TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NONE,
115 TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_NORMAL,
116 TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE
117 };
118
119
120
121 /*
122 * This routine should always be called with the task lock held.
123 * This routine handles Default operations for TASK_FOREGROUND_APPLICATION
124 * and TASK_BACKGROUND_APPLICATION of task with no special app type.
125 */
126 static kern_return_t
127 task_role_default_handler(task_t task, task_role_t role)
128 {
129 kern_return_t result = KERN_SUCCESS;
130
131 switch (task->role) {
132 case TASK_FOREGROUND_APPLICATION:
133 case TASK_BACKGROUND_APPLICATION:
134 case TASK_UNSPECIFIED:
135 /* if there are no process wide backgrounding ... */
136 if ((task->ext_appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) &&
137 (task->appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE)) {
138 task_priority(task,
139 ((role == TASK_FOREGROUND_APPLICATION)?
140 BASEPRI_FOREGROUND: BASEPRI_BACKGROUND),
141 task->max_priority);
142 }
143 task->role = role;
144 break;
145
146 case TASK_CONTROL_APPLICATION:
147 case TASK_RENICED:
148 /* else fail silently */
149 break;
150
151 default:
152 result = KERN_INVALID_ARGUMENT;
153 break;
154 }
155 return(result);
156 }
157
158
159 kern_return_t
160 task_policy_set(
161 task_t task,
162 task_policy_flavor_t flavor,
163 task_policy_t policy_info,
164 mach_msg_type_number_t count)
165 {
166 kern_return_t result = KERN_SUCCESS;
167 void * bsdinfo = NULL;
168 int setbg = 0;
169
170 if (task == TASK_NULL || task == kernel_task)
171 return (KERN_INVALID_ARGUMENT);
172
173 switch (flavor) {
174
175 case TASK_CATEGORY_POLICY:
176 {
177 task_category_policy_t info = (task_category_policy_t)policy_info;
178
179 if (count < TASK_CATEGORY_POLICY_COUNT)
180 return (KERN_INVALID_ARGUMENT);
181
182 #if CONFIG_EMBEDDED
183 if ((current_task() == task) && (info != NULL) &&
184 (info->role != TASK_THROTTLE_APPLICATION))
185 return (KERN_INVALID_ARGUMENT);
186 #endif
187
188 task_lock(task);
189 switch(info->role) {
190 case TASK_FOREGROUND_APPLICATION : {
191 if (task->ext_appliedstate.apptype == PROC_POLICY_OSX_APPTYPE_NONE) {
192 result = task_role_default_handler(task, info->role);
193 } else {
194 switch (task->ext_appliedstate.apptype) {
195 #if !CONFIG_EMBEDDED
196 case PROC_POLICY_OSX_APPTYPE_TAL:
197 /* Move the app to foreground with no DarwinBG */
198 proc_restore_bgtaskpolicy_internal(task, 1, 1, BASEPRI_FOREGROUND);
199 bsdinfo = task->bsd_info;
200 setbg = 0;
201 break;
202
203 case PROC_POLICY_OSX_APPTYPE_DBCLIENT:
204 /* reset the apptype so enforcement on background/foregound */
205 task->ext_appliedstate.apptype = PROC_POLICY_OSX_APPTYPE_NONE;
206 /* Internal application and make it foreground pri */
207 proc_restore_bgtaskpolicy_internal(task, 1, 0, BASEPRI_FOREGROUND);
208 bsdinfo = task->bsd_info;
209 setbg = 0;
210 break;
211 #endif /* !CONFIG_EMBEDDED */
212
213 default:
214 /* the app types cannot be in CONTROL, GRAPHICS STATE, so it will de default state here */
215 task_priority(task, BASEPRI_FOREGROUND, task->max_priority);
216 break;
217
218 } /* switch (task->ext_appliedstate.apptype) */
219 task->role = TASK_FOREGROUND_APPLICATION;
220 }
221 }
222 break;
223
224 case TASK_BACKGROUND_APPLICATION : {
225 if (task->ext_appliedstate.apptype == PROC_POLICY_OSX_APPTYPE_NONE) {
226 result = task_role_default_handler(task, info->role);
227 } else { /* apptype != PROC_POLICY_OSX_APPTYPE_NONE */
228 switch (task->ext_appliedstate.apptype) {
229 #if !CONFIG_EMBEDDED
230 case PROC_POLICY_OSX_APPTYPE_TAL:
231 /* TAL apps will get Darwin backgrounded if not already set */
232 if (task->ext_appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) {
233 proc_apply_bgtaskpolicy_internal(task, 1, 1);
234 bsdinfo = task->bsd_info;
235 setbg = 1;
236 }
237 break;
238 #endif /* !CONFIG_EMBEDDED */
239 default:
240 task_priority(task, BASEPRI_BACKGROUND, task->max_priority);
241 break;
242 } /* switch (task->ext_appliedstate.apptype) */
243 task->role = TASK_BACKGROUND_APPLICATION;
244 }
245 }
246 break;
247
248 case TASK_CONTROL_APPLICATION:
249 if (task != current_task()||
250 task->sec_token.val[0] != 0)
251 result = KERN_INVALID_ARGUMENT;
252 else {
253 task_priority(task, BASEPRI_CONTROL, task->max_priority);
254 task->role = info->role;
255 }
256 break;
257
258 case TASK_GRAPHICS_SERVER:
259 if (task != current_task() ||
260 task->sec_token.val[0] != 0)
261 result = KERN_INVALID_ARGUMENT;
262 else {
263 task_priority(task, MAXPRI_RESERVED - 3, MAXPRI_RESERVED);
264 task->role = info->role;
265 }
266 break;
267 case TASK_DEFAULT_APPLICATION:
268 task_priority(task, BASEPRI_DEFAULT, MAXPRI_USER);
269 task->role = info->role;
270 break;
271
272 default :
273 result = KERN_INVALID_ARGUMENT;
274 break;
275 } /* switch (info->role) */
276
277 task_unlock(task);
278
279 /* if backgrounding action ... */
280 if (bsdinfo != NULL)
281 proc_set_task_networkbg(bsdinfo, setbg);
282
283 break;
284 }
285
286 default:
287 result = KERN_INVALID_ARGUMENT;
288 break;
289 }
290
291 return (result);
292 }
293
294 static void
295 task_priority(
296 task_t task,
297 integer_t priority,
298 integer_t max_priority)
299 {
300 thread_t thread;
301
302 task->max_priority = max_priority;
303
304 if (priority > task->max_priority)
305 priority = task->max_priority;
306 else
307 if (priority < MINPRI)
308 priority = MINPRI;
309
310 task->priority = priority;
311
312 queue_iterate(&task->threads, thread, thread_t, task_threads) {
313 thread_mtx_lock(thread);
314
315 if (thread->active)
316 thread_task_priority(thread, priority, max_priority);
317
318 thread_mtx_unlock(thread);
319 }
320 }
321
322 kern_return_t
323 task_importance(
324 task_t task,
325 integer_t importance)
326 {
327 if (task == TASK_NULL || task == kernel_task)
328 return (KERN_INVALID_ARGUMENT);
329
330 task_lock(task);
331
332 if (!task->active) {
333 task_unlock(task);
334
335 return (KERN_TERMINATED);
336 }
337
338 if (task->role >= TASK_CONTROL_APPLICATION) {
339 task_unlock(task);
340
341 return (KERN_INVALID_ARGUMENT);
342 }
343
344 task_priority(task, importance + BASEPRI_DEFAULT, task->max_priority);
345 task->role = TASK_RENICED;
346
347 task_unlock(task);
348
349 return (KERN_SUCCESS);
350 }
351
352 kern_return_t
353 task_policy_get(
354 task_t task,
355 task_policy_flavor_t flavor,
356 task_policy_t policy_info,
357 mach_msg_type_number_t *count,
358 boolean_t *get_default)
359 {
360 if (task == TASK_NULL || task == kernel_task)
361 return (KERN_INVALID_ARGUMENT);
362
363 switch (flavor) {
364
365 case TASK_CATEGORY_POLICY:
366 {
367 task_category_policy_t info = (task_category_policy_t)policy_info;
368
369 if (*count < TASK_CATEGORY_POLICY_COUNT)
370 return (KERN_INVALID_ARGUMENT);
371
372 if (*get_default)
373 info->role = TASK_UNSPECIFIED;
374 else {
375 task_lock(task);
376 info->role = task->role;
377 task_unlock(task);
378 }
379 break;
380 }
381
382 default:
383 return (KERN_INVALID_ARGUMENT);
384 }
385
386 return (KERN_SUCCESS);
387 }
388
389 /* task Darwin BG enforcement/settings related routines */
390 int
391 proc_get_task_bg_policy(task_t task)
392 {
393
394 int selfset = 0;
395 int val = 0;
396
397 if (current_task() == task)
398 selfset = 1;
399
400 if (selfset == 0) {
401 val = task->ext_policystate.hw_bg;
402 } else {
403 val = task->policystate.hw_bg;
404 }
405
406 return(val);
407 }
408
409
410 int
411 proc_get_thread_bg_policy(task_t task, uint64_t tid)
412 {
413 int selfset = 0;
414 thread_t self = current_thread();
415 thread_t thread = THREAD_NULL;
416 int val = 0;
417
418 if (tid == self->thread_id)
419 selfset = 1;
420
421 if (selfset == 0) {
422 task_lock(task);
423 thread = task_findtid(task, tid);
424 if (thread != NULL)
425 val = thread->ext_policystate.hw_bg;
426 task_unlock(task);
427 } else {
428 val = self->policystate.hw_bg;
429 }
430
431 return(val);
432 }
433
434 int
435 proc_get_self_isbackground(void)
436 {
437 task_t task = current_task();;
438 thread_t thread = current_thread();
439
440 if ((task->ext_appliedstate.hw_bg != TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) ||
441 (task->appliedstate.hw_bg != TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) ||
442 (thread->ext_appliedstate.hw_bg != TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) ||
443 (thread->appliedstate.hw_bg != TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE))
444 return(1);
445 else
446 return(0);
447
448 }
449
450 int proc_get_selfthread_isbackground(void)
451 {
452 thread_t thread = current_thread();
453
454 if ((thread->ext_appliedstate.hw_bg != TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) ||
455 (thread->appliedstate.hw_bg != TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE))
456 return(1);
457 else
458 return(0);
459 }
460
461
462 int
463 proc_set_bgtaskpolicy(task_t task, int intval)
464 {
465
466 int selfset = 0;
467
468 if (current_task() == task)
469 selfset = 1;
470
471 task_lock(task);
472
473 if (selfset == 0) {
474 /* allready set? */
475 if (task->ext_policystate.hw_bg != intval)
476 task->ext_policystate.hw_bg = intval;
477 } else {
478 if (task->policystate.hw_bg != intval)
479 task->policystate.hw_bg = intval;
480 }
481
482 task_unlock(task);
483 return(0);
484 }
485
486 /* set and apply as well , handles reset of NONUI due to setprio() task app state implmn side effect */
487 int
488 proc_set_and_apply_bgtaskpolicy(task_t task, int prio)
489 {
490 int error = 0;
491
492 if (prio == PRIO_DARWIN_BG) {
493 error = proc_set_bgtaskpolicy(task, TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL);
494 if (error == 0) {
495 error = proc_apply_bgtaskpolicy(task);
496 #if CONFIG_EMBEDDED
497 /* XXX: till SB uses newer SPIs */
498 apply_appstate_watchers(task, 1);
499 #endif /* CONFIG_EMBEDDED */
500 }
501 } else {
502 error = proc_restore_bgtaskpolicy(task);
503 if (error == 0) {
504 /* since prior impl of non UI was overloaded with bg state, need to reset */
505 error = proc_apply_task_gpuacc(task, TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_DEFAULT);
506 #if CONFIG_EMBEDDED
507 /* XXX: till SB uses newer SPIs */
508 apply_appstate_watchers(task, 0);
509 #endif /* CONFIG_EMBEDDED */
510 }
511
512 }
513
514 return(error);
515 }
516
517
518 int
519 proc_set_bgthreadpolicy(task_t task, uint64_t tid, int prio)
520 {
521 int selfset = 0;
522 thread_t self = current_thread();
523 thread_t thread = THREAD_NULL;
524 int reset;
525
526 if (prio == 0)
527 reset = 1;
528 if (tid == self->thread_id)
529 selfset = 1;
530
531 task_lock(task);
532 if (selfset == 0) {
533 thread = task_findtid(task, tid);
534 if (thread != NULL)
535 thread->ext_policystate.hw_bg = prio;
536 } else {
537 self->policystate.hw_bg = prio;
538 }
539
540 task_unlock(task);
541
542 return(0);
543 }
544
545 int
546 proc_set_and_apply_bgthreadpolicy(task_t task, uint64_t tid, int prio)
547 {
548 int error = 0;
549
550 if (prio == PRIO_DARWIN_BG) {
551 error = proc_set_bgthreadpolicy(task, tid, TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL);
552 if (error == 0)
553 error = proc_apply_bgthreadpolicy(task, tid);
554 } else {
555 error = proc_restore_bgthreadpolicy(task, tid);
556 }
557
558 return(error);
559 }
560
561 int
562 proc_add_bgtaskpolicy(task_t task, int val)
563 {
564 int selfset = 0;
565
566 if (current_task() == task)
567 selfset = 1;
568
569 task_lock(task);
570
571 if (selfset == 0) {
572 task->policystate.hw_bg |= val;
573 } else {
574 task->ext_policystate.hw_bg |= val;
575 }
576
577 task_unlock(task);
578 return(0);
579 }
580
581 int
582 proc_add_bgthreadpolicy(task_t task, uint64_t tid, int val)
583 {
584 int selfset = 0;
585 thread_t self = current_thread();
586 thread_t thread = THREAD_NULL;
587 int reset;
588
589 if (val == 0)
590 reset = 1;
591 if (tid == self->thread_id)
592 selfset = 1;
593
594 task_lock(task);
595 if (selfset == 0) {
596 thread = task_findtid(task, tid);
597 if (thread != NULL)
598 thread->ext_policystate.hw_bg |= val;
599 } else {
600 self->policystate.hw_bg |= val;
601 }
602
603 task_unlock(task);
604
605 return(val);
606 }
607
608 int
609 proc_remove_bgtaskpolicy(task_t task, int intval)
610 {
611 int selfset = 0;
612
613 if (current_task() == task)
614 selfset = 1;
615
616 task_lock(task);
617
618 if (selfset == 0) {
619 task->policystate.hw_bg &= ~intval;
620 } else {
621 task->ext_policystate.hw_bg &= ~intval;
622 }
623
624 task_unlock(task);
625 return(0);
626 }
627
628 int
629 proc_remove_bgthreadpolicy(task_t task, uint64_t tid, int val)
630 {
631 int selfset = 0;
632 thread_t self = current_thread();
633 thread_t thread = THREAD_NULL;
634 int reset;
635
636 if (val == 0)
637 reset = 1;
638 if (tid == self->thread_id)
639 selfset = 1;
640
641 task_lock(task);
642 if (selfset == 0) {
643 thread = task_findtid(task, tid);
644 if (thread != NULL)
645 thread->ext_policystate.hw_bg &= ~val;
646 } else {
647 self->policystate.hw_bg &= ~val;
648 }
649
650 task_unlock(task);
651
652 return(val);
653 }
654
655 int
656 proc_apply_bgtask_selfpolicy(void)
657 {
658 return(proc_apply_bgtaskpolicy(current_task()));
659 }
660
661 int
662 proc_apply_bgtaskpolicy(task_t task)
663 {
664 int external = 1;
665
666 if (task == current_task())
667 external = 0;
668 return(proc_apply_bgtaskpolicy_internal(task, 0, external));
669 }
670
671 int
672 proc_apply_bgtaskpolicy_external(task_t task)
673 {
674 return(proc_apply_bgtaskpolicy_internal(task, 0, 1));
675 }
676
677 static int
678 proc_apply_bgtaskpolicy_internal(task_t task, int locked, int external)
679 {
680
681 if (locked == 0)
682 task_lock(task);
683
684 /* if the process is exiting, no action to be done */
685 if (task->proc_terminate != 0)
686 goto out;
687
688 if (external != 0) {
689 /* allready set? */
690 if (task->ext_appliedstate.hw_bg != task->ext_policystate.hw_bg) {
691 task->ext_appliedstate.hw_bg = task->ext_policystate.hw_bg;
692 task_priority(task, MAXPRI_THROTTLE, MAXPRI_THROTTLE);
693 /* background state applied */
694 }
695 } else {
696 if (task->appliedstate.hw_bg != task->policystate.hw_bg) {
697 task->appliedstate.hw_bg = task->policystate.hw_bg;
698 task_priority(task, MAXPRI_THROTTLE, MAXPRI_THROTTLE);
699 }
700 }
701 out:
702 if (locked == 0)
703 task_unlock(task);
704 return(0);
705 }
706
707 /* apply the self backgrounding even if the thread is not current thread */
708 int
709 proc_apply_workq_bgthreadpolicy(thread_t thread)
710 {
711 int error;
712 task_t wqtask = TASK_NULL;
713
714 if (thread != THREAD_NULL) {
715 wqtask = thread->task;
716 task_lock(wqtask);
717 /* apply the background as selfset internal one */
718 error = proc_apply_bgthreadpolicy_locked(thread, 1);
719 task_unlock(wqtask);
720 } else
721 error = ESRCH;
722
723 return(error);
724 }
725
726 int
727 proc_apply_bgthreadpolicy(task_t task, uint64_t tid)
728 {
729 int selfset = 0, error = 0;
730 thread_t self = current_thread();
731 thread_t thread = THREAD_NULL;
732 task_t localtask = TASK_NULL;
733
734 if (tid == self->thread_id) {
735 selfset = 1;
736 localtask = current_task();
737 } else
738 localtask = task;
739
740 task_lock(localtask);
741 if (selfset != 0) {
742 thread = self;
743 } else {
744 thread = task_findtid(localtask, tid);
745 }
746
747 error = proc_apply_bgthreadpolicy_locked(thread, selfset);
748
749 task_unlock(localtask);
750
751 return(error);
752 }
753
754 static int
755 proc_apply_bgthreadpolicy_locked(thread_t thread, int selfset)
756 {
757 int set = 0;
758 thread_precedence_policy_data_t policy;
759
760
761 if (thread != NULL) {
762 /* if the process is exiting, no action to be done */
763 if (thread->task->proc_terminate != 0)
764 goto out;
765
766 if (selfset != 0) {
767 /* internal application */
768 if (thread->appliedstate.hw_bg != thread->policystate.hw_bg) {
769 thread->appliedstate.hw_bg = thread->policystate.hw_bg;
770 if (thread->ext_appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE)
771 set = 1;
772
773 }
774 } else {
775 /* external application */
776 if (thread->ext_appliedstate.hw_bg != thread->ext_policystate.hw_bg) {
777 thread->ext_appliedstate.hw_bg = thread->ext_policystate.hw_bg;
778 if (thread->appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE)
779 set = 1;
780 }
781 }
782
783 if (set != 0) {
784 #if CONFIG_EMBEDDED
785 if (thread->task->ext_appliedstate.apptype == PROC_POLICY_IOS_APPLE_DAEMON) {
786 thread->saved_importance = thread->importance;
787 }
788 #endif /* CONFIG_EMBEDDED */
789 /* set thread priority (we did not save previous value) */
790 policy.importance = INT_MIN;
791
792 thread_policy_set_internal(thread, THREAD_PRECEDENCE_POLICY,
793 (thread_policy_t)&policy,
794 THREAD_PRECEDENCE_POLICY_COUNT );
795
796 }
797 } else
798 return(ESRCH);
799
800 out:
801 return(0);
802 }
803
804 #if CONFIG_EMBEDDED
805 /* set external application of background */
806 static void
807 apply_bgthreadpolicy_external(thread_t thread)
808 {
809 int set = 0;
810 thread_precedence_policy_data_t policy;
811
812 /* if the process is exiting, no action to be done */
813 if (thread->task->proc_terminate != 0)
814 return;
815
816 thread->ext_policystate.hw_bg = TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL;
817
818 if (thread->ext_appliedstate.hw_bg != thread->ext_policystate.hw_bg) {
819 thread->ext_appliedstate.hw_bg = thread->ext_policystate.hw_bg;
820 if (thread->appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE)
821 set = 1;
822 }
823
824 if (set != 0) {
825 /* set thread priority (we did not save previous value) */
826 policy.importance = INT_MIN;
827
828 thread_policy_set_internal(thread, THREAD_PRECEDENCE_POLICY,
829 (thread_policy_t)&policy,
830 THREAD_PRECEDENCE_POLICY_COUNT );
831 }
832
833 }
834 #endif /* CONFIG_EMBEDDED */
835
836 int
837 proc_apply_bgthread_selfpolicy(void)
838 {
839 return(proc_apply_bgthreadpolicy(current_task(), current_thread()->thread_id));
840 }
841
842
843 int
844 proc_restore_bgtaskpolicy(task_t task)
845 {
846 int external = 1;
847
848 if (current_task() == task)
849 external = 0;
850 return(proc_restore_bgtaskpolicy_internal(task, 0, external, BASEPRI_DEFAULT));
851 }
852
853 static int
854 proc_restore_bgtaskpolicy_internal(task_t task, int locked, int external, int pri)
855 {
856 if (locked == 0)
857 task_lock(task);
858
859 /* if the process is exiting, no action to be done */
860 if (task->proc_terminate != 0)
861 goto out;
862
863 if (external != 0) {
864 task->ext_appliedstate.hw_bg = TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE;
865 /* self BG in flight? */
866 if (task->appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) {
867 task_priority(task, pri, MAXPRI_USER);
868 #if CONFIG_EMBEDDED
869 task->role = TASK_DEFAULT_APPLICATION;
870 #endif /* CONFIG_EMBEDDED */
871 }
872 } else {
873 task->appliedstate.hw_bg = TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE;
874 /* external BG in flight? */
875 if (task->ext_appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) {
876 task_priority(task, pri, MAXPRI_USER);
877 #if CONFIG_EMBEDDED
878 task->role = TASK_DEFAULT_APPLICATION;
879 #endif /* CONFIG_EMBEDDED */
880 }
881 }
882 out:
883 if (locked == 0)
884 task_unlock(task);
885
886 return(0);
887 }
888
889 /* restore the self backgrounding even if the thread is not current thread */
890 int
891 proc_restore_workq_bgthreadpolicy(thread_t thread)
892 {
893 int error = 0;
894 task_t wqtask = TASK_NULL;
895 int importance = 0;
896
897 if (thread != THREAD_NULL) {
898 wqtask = thread->task;
899 task_lock(wqtask);
900 /* remove the background and restore default importance as self(internal) removal */
901 #if CONFIG_EMBEDDED
902 if (thread->task->ext_appliedstate.apptype == PROC_POLICY_IOS_APPLE_DAEMON) {
903 /* restore prev set importnace */
904 importance = thread->saved_importance;
905 thread->saved_importance = 0;
906 }
907 #endif /* CONFIG_EMBEDDED */
908 restore_bgthreadpolicy_locked(thread, 1, importance);
909 task_unlock(wqtask);
910 } else
911 error = ESRCH;
912
913 return(error);
914 }
915
916 int
917 proc_restore_bgthread_selfpolicy(void)
918 {
919 return(proc_restore_bgthreadpolicy(current_task(), thread_tid(current_thread())));
920 }
921
922 int
923 proc_restore_bgthreadpolicy(task_t task, uint64_t tid)
924 {
925
926 int selfset = 0;
927 thread_t self = current_thread();
928 thread_t thread = THREAD_NULL;
929 int importance = 0;
930
931 if (tid == self->thread_id)
932 selfset = 1;
933
934 task_lock(task);
935 if (selfset == 0) {
936 thread = task_findtid(task, tid);
937 } else {
938 thread = self;
939 }
940
941 if (thread != NULL) {
942 #if CONFIG_EMBEDDED
943 if (thread->task->ext_appliedstate.apptype == PROC_POLICY_IOS_APPLE_DAEMON) {
944 /* restore prev set importnace */
945 importance = thread->saved_importance;
946 thread->saved_importance = 0;
947 }
948 #endif /* CONFIG_EMBEDDED */
949 restore_bgthreadpolicy_locked(thread, selfset, importance);
950 }
951 task_unlock(task);
952
953 if (thread != NULL)
954 return(0);
955 else
956 return(1);
957 }
958
959 static void
960 restore_bgthreadpolicy_locked(thread_t thread, int selfset, int importance)
961 {
962 thread_precedence_policy_data_t policy;
963 int reset = 0;
964
965 if (thread != NULL) {
966 /* if the process is exiting, no action to be done */
967 if (thread->task->proc_terminate != 0)
968 return;
969
970 if (selfset != 0) {
971 thread->appliedstate.hw_bg = TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE;
972 /* external BG in flight? */
973 if (thread->ext_appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE)
974 reset = 1;
975
976 } else {
977 thread->ext_appliedstate.hw_bg = TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE;
978 /* self BG in flight? */
979 if (thread->appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE)
980 reset = 1;
981 }
982
983 if (reset != 0) {
984 /* reset thread priority (we did not save previous value) */
985 policy.importance = importance;
986 thread_policy_set_internal(thread, THREAD_PRECEDENCE_POLICY,
987 (thread_policy_t)&policy,
988 THREAD_PRECEDENCE_POLICY_COUNT );
989 }
990 }
991 }
992
993 void
994 #if CONFIG_EMBEDDED
995 proc_set_task_apptype(task_t task, int type, thread_t thread)
996 #else
997 proc_set_task_apptype(task_t task, int type, __unused thread_t thread)
998 #endif
999 {
1000 #if CONFIG_EMBEDDED
1001 thread_t th = THREAD_NULL;
1002 #endif /* CONFIG_EMBEDDED */
1003
1004 switch (type) {
1005 #if CONFIG_EMBEDDED
1006 case PROC_POLICY_IOS_RESV1_APPTYPE:
1007 task->ext_policystate.apptype = type;
1008 task->policystate.apptype = type;
1009 proc_apply_bgtaskpolicy_external(task);
1010 /* indicate that BG is set and next foreground needs to reset */
1011 task->ext_appliedstate.apptype = type;
1012 break;
1013
1014 case PROC_POLICY_IOS_APPLE_DAEMON:
1015 task->ext_policystate.apptype = type;
1016 task->policystate.apptype = type;
1017 task->ext_appliedstate.apptype = type;
1018 /* posix spawn will already have thread created, so backround it */
1019 if (thread == NULL)
1020 th = current_thread();
1021 else
1022 th = thread;
1023 if (th->appliedstate.hw_bg != TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL) {
1024 /* apply self backgrounding if not already set */
1025 task_lock(th->task);
1026 proc_apply_bgthreadpolicy_locked(th, 1);
1027 task_unlock(th->task);
1028 }
1029 break;
1030
1031 case PROC_POLICY_IOS_APPTYPE:
1032 task->ext_policystate.apptype = type;
1033 task->policystate.apptype = type;
1034 break;
1035 case PROC_POLICY_IOS_NONUITYPE:
1036 task->ext_policystate.apptype = type;
1037 task->policystate.apptype = type;
1038 /* set to deny access to gpu */
1039 task->ext_appliedstate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS;
1040 task->ext_policystate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS;
1041 break;
1042 #else /* CONFIG_EMBEDDED */
1043 case PROC_POLICY_OSX_APPTYPE_TAL:
1044 task->ext_policystate.apptype = type;
1045 task->policystate.apptype = type;
1046 proc_apply_bgtaskpolicy_external(task);
1047 /* indicate that BG is set and next foreground needs to reset */
1048 task->ext_appliedstate.apptype = type;
1049 break;
1050
1051 case PROC_POLICY_OSX_APPTYPE_DBCLIENT:
1052 task->ext_policystate.apptype = type;
1053 task->policystate.apptype = type;
1054 proc_apply_bgtaskpolicy_internal(task, 0, 0);
1055 break;
1056
1057 #endif /* CONFIG_EMBEDDED */
1058
1059 default:
1060 break;
1061 }
1062 }
1063
1064 /* update the darwin backdground action state in the flags field for libproc */
1065 #define PROC_FLAG_DARWINBG 0x8000 /* process in darwin background */
1066 #define PROC_FLAG_EXT_DARWINBG 0x10000 /* process in darwin background - external enforcement */
1067 #define PROC_FLAG_IOS_APPLEDAEMON 0x20000 /* process is apple ios daemon */
1068
1069 int
1070 proc_get_darwinbgstate(task_t task, uint32_t * flagsp)
1071 {
1072 if (task->ext_appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL){
1073 *flagsp |= PROC_FLAG_EXT_DARWINBG;
1074 }
1075 if (task->appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL){
1076 *flagsp |= PROC_FLAG_DARWINBG;
1077 }
1078 #if CONFIG_EMBEDDED
1079 if (task->ext_appliedstate.apptype == PROC_POLICY_IOS_APPLE_DAEMON) {
1080 *flagsp |= PROC_FLAG_IOS_APPLEDAEMON;
1081 }
1082 #endif /* CONFIG_EMBEDDED */
1083
1084 return(0);
1085 }
1086
1087 /*
1088 * HW disk access realted routines, they need to return
1089 * IOPOL_XXX equivalents for spec_xxx/throttle updates.
1090 */
1091
1092 int
1093 proc_get_task_disacc(task_t task)
1094 {
1095 #if CONFIG_EMBEDDED
1096 if ((task->ext_appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0)
1097 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE);
1098 #else /* CONFIG_EMBEDDED */
1099 if ((task->ext_appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0) {
1100 /* if it is a TAL or DBClient and not self throttled, return Utility */
1101 if ((task->ext_appliedstate.apptype == PROC_POLICY_OSX_APPTYPE_TAL) || (task->ext_appliedstate.apptype == PROC_POLICY_OSX_APPTYPE_DBCLIENT)) {
1102 /* any setting for DBG, we need to honor that */
1103 if ((task->ext_appliedstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE) &&
1104 ((task->appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE)!= 0) &&
1105 (task->appliedstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE)) {
1106 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_UTILITY);
1107 } else
1108 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE);
1109 } else
1110 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE);
1111 }
1112 #endif /* CONFIG_EMBEDDED */
1113 if (task->ext_appliedstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS)
1114 return(task->ext_appliedstate.hw_disk);
1115 if ((task->appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0)
1116 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE);
1117 if (task->appliedstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS)
1118 return(task->appliedstate.hw_disk);
1119 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS);
1120 }
1121
1122 int
1123 proc_get_task_selfdiskacc_internal(task_t task, thread_t thread)
1124 {
1125 /* if the task is marked for proc_terminate, no throttling for it */
1126 if (task->proc_terminate != 0)
1127 goto out;
1128 /*
1129 * As per defined iopolicysys behavior, thread trumps task.
1130 * Do we need to follow that for external enforcements of BG or hw access?
1131 * Status quo for now..
1132 */
1133
1134 if((thread->ext_appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0)
1135 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE);
1136 if (thread->ext_appliedstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS)
1137 return(thread->ext_appliedstate.hw_disk);
1138 if((thread->appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0)
1139 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE);
1140 if (thread->appliedstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS)
1141 return(thread->appliedstate.hw_disk);
1142
1143 #if CONFIG_EMBEDDED
1144 if ((task->ext_appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0)
1145 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE);
1146 #else /* CONFIG_EMBEDDED */
1147 if ((task->ext_appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0) {
1148 /* if it is a TAL or DBClient and not self throttled, return Utility */
1149 if ((task->ext_appliedstate.apptype == PROC_POLICY_OSX_APPTYPE_TAL) || (task->ext_appliedstate.apptype == PROC_POLICY_OSX_APPTYPE_DBCLIENT)) {
1150 /* any setting for DBG, we need to honor that */
1151 if ((task->ext_appliedstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE) &&
1152 ((task->appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE)!= 0) &&
1153 (task->appliedstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE)) {
1154 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_UTILITY);
1155 } else
1156 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE);
1157 } else
1158 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE);
1159 }
1160 #endif /* CONFIG_EMBEDDED */
1161 if (task->ext_appliedstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS)
1162 return(task->ext_appliedstate.hw_disk);
1163 if ((task->appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0)
1164 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE);
1165 if (task->appliedstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS)
1166 return(task->appliedstate.hw_disk);
1167 out:
1168 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS);
1169 }
1170
1171
1172 int
1173 proc_get_task_selfdiskacc(void)
1174 {
1175 return(proc_get_task_selfdiskacc_internal(current_task(), current_thread()));
1176 }
1177
1178
1179 int
1180 proc_get_diskacc(thread_t thread)
1181 {
1182 return(proc_get_task_selfdiskacc_internal(thread->task, thread));
1183 }
1184
1185
1186 int
1187 proc_get_thread_selfdiskacc(void)
1188 {
1189 thread_t thread = current_thread();
1190
1191 if((thread->ext_appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0)
1192 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE);
1193 if (thread->ext_appliedstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS)
1194 return(thread->ext_appliedstate.hw_disk);
1195 if((thread->appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0)
1196 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE);
1197 if (thread->appliedstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS)
1198 return(thread->appliedstate.hw_disk);
1199 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS);
1200 }
1201
1202 int
1203 proc_apply_task_diskacc(task_t task, int policy)
1204 {
1205 task_t self = current_task();
1206
1207 task_lock(task);
1208 if (task == self) {
1209 task->appliedstate.hw_disk = policy;
1210 task->policystate.hw_disk = policy;
1211 } else {
1212 task->ext_appliedstate.hw_disk = policy;
1213 task->ext_policystate.hw_disk = policy;
1214 }
1215 task_unlock(task);
1216 return(0);
1217 }
1218
1219 int
1220 proc_apply_thread_diskacc(task_t task, uint64_t tid, int policy)
1221 {
1222 thread_t thread;
1223
1224 if (tid == TID_NULL) {
1225 thread = current_thread();
1226 proc_apply_thread_selfdiskacc(policy);
1227 } else {
1228 task_lock(task);
1229 thread = task_findtid(task, tid);
1230 if (thread != NULL) {
1231 thread->ext_appliedstate.hw_disk = policy;
1232 thread->ext_policystate.hw_disk = policy;
1233 }
1234 task_unlock(task);
1235 }
1236 if (thread != NULL)
1237 return(0);
1238 else
1239 return(0);
1240 }
1241
1242 void
1243 proc_task_remove_throttle(task_t task)
1244 {
1245 thread_t thread;
1246 int importance = 0;
1247
1248 task_lock(task);
1249
1250
1251 /* remove processwide internal DBG applicationn */
1252 proc_restore_bgtaskpolicy_internal(task, 1, 0, BASEPRI_DEFAULT);
1253 /* remove processwide external DBG applicationn */
1254 proc_restore_bgtaskpolicy_internal(task, 1, 1, BASEPRI_DEFAULT);
1255
1256 for (thread = (thread_t)queue_first(&task->threads);
1257 !queue_end(&task->threads, (queue_entry_t)thread); ) {
1258 #if CONFIG_EMBEDDED
1259 if (thread->task->ext_appliedstate.apptype == PROC_POLICY_IOS_APPLE_DAEMON) {
1260 /* restore prev set importnace */
1261 importance = thread->saved_importance;
1262 thread->saved_importance = 0;
1263 }
1264 #endif /* CONFIG_EMBEDDED */
1265 /* remove thread level internal DBG application */
1266 restore_bgthreadpolicy_locked(thread, 1, importance);
1267 /* remove thread level external DBG application */
1268 restore_bgthreadpolicy_locked(thread, 0, importance);
1269 /* reset thread io policy */
1270 thread->ext_appliedstate.hw_disk = TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS;
1271 thread->appliedstate.hw_disk = TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS;
1272 unthrottle_thread(thread->uthread);
1273 thread = (thread_t)queue_next(&thread->task_threads);
1274 }
1275
1276 /* reset task iopolicy */
1277 task->ext_appliedstate.hw_disk = TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS;
1278 task->appliedstate.hw_disk = TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS;
1279 task->proc_terminate = 1;
1280
1281 task_unlock(task);
1282 }
1283
1284
1285
1286 int
1287 proc_apply_thread_selfdiskacc(int policy)
1288 {
1289 task_t task = current_task();
1290 thread_t thread = current_thread();
1291
1292 task_lock(task);
1293 thread->appliedstate.hw_disk = policy;
1294 thread->policystate.hw_disk = policy;
1295 task_unlock(task);
1296 return(0);
1297 }
1298
1299 int
1300 proc_denyinherit_policy(__unused task_t task)
1301 {
1302 return(0);
1303 }
1304
1305 int
1306 proc_denyselfset_policy(__unused task_t task)
1307 {
1308 return(0);
1309 }
1310
1311 /* HW GPU access related routines */
1312 int
1313 proc_get_task_selfgpuacc_deny(void)
1314 {
1315 task_t task = current_task();
1316 #ifdef NOTYET
1317 thread_t thread = current_thread();
1318 #endif /* NOTYET */
1319
1320 if (((task->ext_appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_NOGPU) != 0) || (task->ext_appliedstate.hw_gpu == TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS))
1321 return(TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS);
1322 if (((task->appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_NOGPU) != 0) || (task->appliedstate.hw_gpu == TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS))
1323 return(TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS);
1324 #ifdef NOTYET
1325 /*
1326 * Since background dispatch items run in a thread can also be
1327 * denied access, we need to make sure there are no unintended
1328 * consequences of background dispatch usage. So till this is
1329 * hashed out, disable thread level checking.
1330 */
1331 if (((thread->ext_appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_NOGPU) != 0) || (thread->ext_appliedstate.hw_gpu == TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS))
1332 return(TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS);
1333 if (((thread->appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_NOGPU) != 0) || (thread->appliedstate.hw_gpu == TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS))
1334 return(TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS);
1335
1336 #endif /* NOTYET */
1337 return(TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_FULLACCESS);
1338 }
1339
1340 int
1341 proc_apply_task_gpuacc(task_t task, int policy)
1342 {
1343
1344 task_t self = current_task();
1345
1346 task_lock(task);
1347 if (task == self) {
1348 task->appliedstate.hw_gpu = policy;
1349 task->policystate.hw_gpu = policy;
1350 } else {
1351 task->ext_appliedstate.hw_gpu = policy;
1352 task->ext_policystate.hw_gpu = policy;
1353 }
1354 task_unlock(task);
1355
1356 return(0);
1357 }
1358
1359 /* Resource usage , CPU realted routines */
1360 int
1361 proc_get_task_ruse_cpu(task_t task, uint32_t * policyp, uint32_t * percentagep, uint64_t * intervalp, uint64_t * deadlinep)
1362 {
1363
1364 int error = 0;
1365
1366 task_lock(task);
1367 if (task != current_task()) {
1368 *policyp = task->ext_policystate.ru_cpu;
1369 } else {
1370 *policyp = task->policystate.ru_cpu;
1371 }
1372
1373 error = task_get_cpuusage(task, percentagep, intervalp, deadlinep);
1374
1375 return(error);
1376 }
1377
1378 /*
1379 * Currently supported configurations for CPU limits.
1380 *
1381 * Deadline-based CPU limit Percentage-based CPU limit
1382 * PROC_POLICY_RSRCACT_THROTTLE ENOTSUP Task-wide scope only
1383 * PROC_POLICY_RSRCACT_SUSPEND Task-wide scope only ENOTSUP
1384 * PROC_POLICY_RSRCACT_TERMINATE Task-wide scope only ENOTSUP
1385 * PROC_POLICY_RSRCACT_NOTIFY_KQ Task-wide scope only ENOTSUP
1386 * PROC_POLICY_RSRCACT_NOTIFY_EXC ENOTSUP Per-thread scope only
1387 *
1388 * A deadline-based CPU limit is actually a simple wallclock timer - the requested action is performed
1389 * after the specified amount of wallclock time has elapsed.
1390 *
1391 * A percentage-based CPU limit performs the requested action after the specified amount of actual CPU time
1392 * has been consumed -- regardless of how much wallclock time has elapsed -- by either the task as an
1393 * aggregate entity (so-called "Task-wide" or "Proc-wide" scope, whereby the CPU time consumed by all threads
1394 * in the task are added together), or by any one thread in the task (so-called "per-thread" scope).
1395 *
1396 * We support either deadline != 0 OR percentage != 0, but not both. The original intention in having them
1397 * share an API was to use actual CPU time as the basis of the deadline-based limit (as in: perform an action
1398 * after I have used some amount of CPU time; this is different than the recurring percentage/interval model)
1399 * but the potential consumer of the API at the time was insisting on wallclock time instead.
1400 *
1401 * Currently, requesting notification via an exception is the only way to get per-thread scope for a
1402 * CPU limit. All other types of notifications force task-wide scope for the limit.
1403 */
1404 int
1405 proc_set_task_ruse_cpu(task_t task, uint32_t policy, uint32_t percentage, uint64_t interval, uint64_t deadline)
1406 {
1407 int error = 0;
1408 int scope;
1409
1410 /*
1411 * Enforce the matrix of supported configurations for policy, percentage, and deadline.
1412 */
1413 switch (policy) {
1414 // If no policy is explicitly given, the default is to throttle.
1415 case TASK_POLICY_RESOURCE_ATTRIBUTE_NONE:
1416 case TASK_POLICY_RESOURCE_ATTRIBUTE_THROTTLE:
1417 if (deadline != 0)
1418 return (ENOTSUP);
1419 scope = TASK_RUSECPU_FLAGS_PROC_LIMIT;
1420 break;
1421 case TASK_POLICY_RESOURCE_ATTRIBUTE_SUSPEND:
1422 case TASK_POLICY_RESOURCE_ATTRIBUTE_TERMINATE:
1423 case TASK_POLICY_RESOURCE_ATTRIBUTE_NOTIFY_KQ:
1424 if (percentage != 0)
1425 return (ENOTSUP);
1426 scope = TASK_RUSECPU_FLAGS_DEADLINE;
1427 break;
1428 case TASK_POLICY_RESOURCE_ATTRIBUTE_NOTIFY_EXC:
1429 if (deadline != 0)
1430 return (ENOTSUP);
1431 scope = TASK_RUSECPU_FLAGS_PERTHR_LIMIT;
1432 break;
1433 default:
1434 return (EINVAL);
1435 }
1436
1437 task_lock(task);
1438 if (task != current_task()) {
1439 task->ext_policystate.ru_cpu = policy;
1440 } else {
1441 task->policystate.ru_cpu = policy;
1442 }
1443 error = task_set_cpuusage(task, percentage, interval, deadline, scope);
1444 task_unlock(task);
1445 return(error);
1446 }
1447
1448 int
1449 proc_clear_task_ruse_cpu(task_t task)
1450 {
1451 int error = 0;
1452 int action;
1453 void * bsdinfo = NULL;
1454
1455 task_lock(task);
1456 if (task != current_task()) {
1457 task->ext_policystate.ru_cpu = TASK_POLICY_RESOURCE_ATTRIBUTE_DEFAULT;
1458 } else {
1459 task->policystate.ru_cpu = TASK_POLICY_RESOURCE_ATTRIBUTE_DEFAULT;
1460 }
1461
1462 error = task_clear_cpuusage_locked(task);
1463 if (error != 0)
1464 goto out;
1465
1466 action = task->ext_appliedstate.ru_cpu;
1467 if (task->ext_appliedstate.ru_cpu != TASK_POLICY_RESOURCE_ATTRIBUTE_NONE) {
1468 /* reset action */
1469 task->ext_appliedstate.ru_cpu = TASK_POLICY_RESOURCE_ATTRIBUTE_NONE;
1470 }
1471 if (action != TASK_POLICY_RESOURCE_ATTRIBUTE_NONE) {
1472 bsdinfo = task->bsd_info;
1473 task_unlock(task);
1474 proc_restore_resource_actions(bsdinfo, TASK_POLICY_CPU_RESOURCE_USAGE, action);
1475 goto out1;
1476 }
1477
1478 out:
1479 task_unlock(task);
1480 out1:
1481 return(error);
1482
1483 }
1484
1485 /* used to apply resource limit related actions */
1486 static int
1487 task_apply_resource_actions(task_t task, int type)
1488 {
1489 int action = TASK_POLICY_RESOURCE_ATTRIBUTE_NONE;
1490 void * bsdinfo = NULL;
1491
1492 switch (type) {
1493 case TASK_POLICY_CPU_RESOURCE_USAGE:
1494 break;
1495 case TASK_POLICY_WIREDMEM_RESOURCE_USAGE:
1496 case TASK_POLICY_VIRTUALMEM_RESOURCE_USAGE:
1497 case TASK_POLICY_DISK_RESOURCE_USAGE:
1498 case TASK_POLICY_NETWORK_RESOURCE_USAGE:
1499 case TASK_POLICY_POWER_RESOURCE_USAGE:
1500 return(0);
1501
1502 default:
1503 return(1);
1504 };
1505
1506 /* only cpu actions for now */
1507 task_lock(task);
1508
1509 if (task->ext_appliedstate.ru_cpu == TASK_POLICY_RESOURCE_ATTRIBUTE_NONE) {
1510 /* apply action */
1511 task->ext_appliedstate.ru_cpu = task->ext_policystate.ru_cpu;
1512 action = task->ext_appliedstate.ru_cpu;
1513 } else {
1514 action = task->ext_appliedstate.ru_cpu;
1515 }
1516
1517 if (action != TASK_POLICY_RESOURCE_ATTRIBUTE_NONE) {
1518 bsdinfo = task->bsd_info;
1519 task_unlock(task);
1520 proc_apply_resource_actions(bsdinfo, TASK_POLICY_CPU_RESOURCE_USAGE, action);
1521 } else
1522 task_unlock(task);
1523
1524 return(0);
1525 }
1526
1527 /* For ledger hookups */
1528 static int
1529 task_get_cpuusage(task_t task, uint32_t * percentagep, uint64_t * intervalp, uint64_t * deadlinep)
1530 {
1531 *percentagep = task->rusage_cpu_percentage;
1532 *intervalp = task->rusage_cpu_interval;
1533 *deadlinep = task->rusage_cpu_deadline;
1534
1535 return(0);
1536 }
1537
1538 int
1539 task_set_cpuusage(task_t task, uint64_t percentage, uint64_t interval, uint64_t deadline, int scope)
1540 {
1541 uint64_t abstime = 0;
1542 uint64_t save_abstime = 0;
1543 uint64_t limittime = 0;
1544 thread_t thread;
1545
1546 lck_mtx_assert(&task->lock, LCK_MTX_ASSERT_OWNED);
1547
1548 /* By default, refill once per second */
1549 if (interval == 0)
1550 interval = NSEC_PER_SEC;
1551
1552 if (percentage != 0) {
1553 if (percentage > 100)
1554 percentage = 100;
1555 limittime = (interval * percentage)/ 100;
1556 nanoseconds_to_absolutetime(limittime, &abstime);
1557 if (scope == TASK_RUSECPU_FLAGS_PERTHR_LIMIT) {
1558 /*
1559 * A per-thread CPU limit on a task generates an exception
1560 * (LEDGER_ACTION_EXCEPTION) if any one thread in the task
1561 * exceeds the limit.
1562 */
1563 task->rusage_cpu_flags |= TASK_RUSECPU_FLAGS_PERTHR_LIMIT;
1564 task->rusage_cpu_perthr_percentage = percentage;
1565 task->rusage_cpu_perthr_interval = interval;
1566 queue_iterate(&task->threads, thread, thread_t, task_threads) {
1567 set_astledger(thread);
1568 }
1569 } else if (scope == TASK_RUSECPU_FLAGS_PROC_LIMIT) {
1570 /*
1571 * Currently, a proc-wide CPU limit always blocks if the limit is
1572 * exceeded (LEDGER_ACTION_BLOCK).
1573 */
1574 task->rusage_cpu_flags |= TASK_RUSECPU_FLAGS_PROC_LIMIT;
1575 task->rusage_cpu_percentage = percentage;
1576 task->rusage_cpu_interval = interval;
1577
1578 ledger_set_limit(task->ledger, task_ledgers.cpu_time, abstime);
1579 ledger_set_period(task->ledger, task_ledgers.cpu_time, interval);
1580 ledger_set_action(task->ledger, task_ledgers.cpu_time, LEDGER_ACTION_BLOCK);
1581 }
1582 }
1583
1584 if (deadline != 0) {
1585 assert(scope == TASK_RUSECPU_FLAGS_DEADLINE);
1586
1587 /* if already in use, cancel and wait for it to cleanout */
1588 if (task->rusage_cpu_callt != NULL) {
1589 task_unlock(task);
1590 thread_call_cancel_wait(task->rusage_cpu_callt);
1591 task_lock(task);
1592 }
1593 if (task->rusage_cpu_callt == NULL) {
1594 task->rusage_cpu_callt = thread_call_allocate_with_priority(task_action_cpuusage, (thread_call_param_t)task, THREAD_CALL_PRIORITY_KERNEL);
1595 }
1596 /* setup callout */
1597 if (task->rusage_cpu_callt != 0) {
1598 task->rusage_cpu_flags |= TASK_RUSECPU_FLAGS_DEADLINE;
1599 task->rusage_cpu_deadline = deadline;
1600
1601 nanoseconds_to_absolutetime(deadline, &abstime);
1602 save_abstime = abstime;
1603 clock_absolutetime_interval_to_deadline(save_abstime, &abstime);
1604 thread_call_enter_delayed(task->rusage_cpu_callt, abstime);
1605 }
1606 }
1607
1608 return(0);
1609 }
1610
1611 int
1612 task_clear_cpuusage(task_t task)
1613 {
1614 int retval = 0;
1615
1616 task_lock(task);
1617 retval = task_clear_cpuusage_locked(task);
1618 task_unlock(task);
1619
1620 return(retval);
1621 }
1622
1623 int
1624 task_clear_cpuusage_locked(task_t task)
1625 {
1626 thread_call_t savecallt;
1627 thread_t thread;
1628
1629 /* cancel percentage handling if set */
1630 if (task->rusage_cpu_flags & TASK_RUSECPU_FLAGS_PROC_LIMIT) {
1631 task->rusage_cpu_flags &= ~TASK_RUSECPU_FLAGS_PROC_LIMIT;
1632 ledger_set_limit(task->ledger, task_ledgers.cpu_time, LEDGER_LIMIT_INFINITY);
1633 task->rusage_cpu_percentage = 0;
1634 task->rusage_cpu_interval = 0;
1635 }
1636
1637 if (task->rusage_cpu_flags & TASK_RUSECPU_FLAGS_PERTHR_LIMIT) {
1638 task->rusage_cpu_flags &= ~TASK_RUSECPU_FLAGS_PERTHR_LIMIT;
1639 queue_iterate(&task->threads, thread, thread_t, task_threads) {
1640 set_astledger(thread);
1641 }
1642 task->rusage_cpu_perthr_percentage = 0;
1643 task->rusage_cpu_perthr_interval = 0;
1644
1645 }
1646
1647 /* cancel deadline handling if set */
1648 if (task->rusage_cpu_flags & TASK_RUSECPU_FLAGS_DEADLINE) {
1649 task->rusage_cpu_flags &= ~TASK_RUSECPU_FLAGS_DEADLINE;
1650 if (task->rusage_cpu_callt != 0) {
1651 savecallt = task->rusage_cpu_callt;
1652 task->rusage_cpu_callt = NULL;
1653 task->rusage_cpu_deadline = 0;
1654 task_unlock(task);
1655 thread_call_cancel_wait(savecallt);
1656 thread_call_free(savecallt);
1657 task_lock(task);
1658 }
1659 }
1660 return(0);
1661 }
1662
1663 /* called by ledger unit to enforce action due to resource usage criteria being met */
1664 void
1665 task_action_cpuusage(thread_call_param_t param0, __unused thread_call_param_t param1)
1666 {
1667 task_t task = (task_t)param0;
1668 (void)task_apply_resource_actions(task, TASK_POLICY_CPU_RESOURCE_USAGE);
1669 return;
1670 }
1671
1672 #if CONFIG_EMBEDDED
1673 /* return the appstate of a task */
1674 int
1675 proc_lf_getappstate(task_t task)
1676 {
1677 return(task->appstate);
1678
1679 }
1680
1681
1682 /* set appstate of a task and apply approp actions */
1683 int
1684 proc_lf_setappstate(task_t task, int state)
1685 {
1686 int ret = 0, oldstate;
1687 kern_return_t kret = KERN_SUCCESS;
1688 int applywatch = 0, setbg = 0, setnetbg = 0;
1689 int sethib_suspend = 0, sethib_resume=0;
1690
1691 if (state == TASK_APPSTATE_NONE)
1692 goto out;
1693
1694 /* valid states? */
1695 switch (state) {
1696 case TASK_APPSTATE_ACTIVE:
1697 case TASK_APPSTATE_BACKGROUND:
1698 case TASK_APPSTATE_NONUI:
1699 case TASK_APPSTATE_INACTIVE:
1700 break;
1701 default:
1702 ret = EINVAL;
1703 goto out;
1704
1705 }
1706
1707 task_lock(task);
1708 oldstate = task->appstate;
1709 if (oldstate == state) {
1710 /* no changes */
1711 goto out1;
1712 }
1713
1714 switch(oldstate) {
1715 case TASK_APPSTATE_ACTIVE:
1716 switch(state) {
1717 case TASK_APPSTATE_BACKGROUND:
1718 /* moving from active to app background */
1719 task->ext_policystate.hw_bg = TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL;
1720 proc_apply_bgtaskpolicy_internal(task, 1, 1);
1721 /* watchers need update */
1722 applywatch = 1;
1723 setbg = 1;
1724 /* set network part */
1725 setnetbg = 1;
1726 break;
1727
1728 case TASK_APPSTATE_NONUI:
1729 /* set no graphics */
1730 task->ext_policystate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS;
1731 task->ext_appliedstate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS;
1732 break;
1733
1734 case TASK_APPSTATE_INACTIVE:
1735 /* suspend the process */
1736 kret = task_pidsuspend_locked(task);
1737 if (kret != KERN_SUCCESS)
1738 ret = EINVAL;
1739 else
1740 sethib_suspend = 1;
1741
1742 break;
1743 }
1744 break;
1745
1746 case TASK_APPSTATE_BACKGROUND:
1747 switch(state) {
1748 /* watchers need update */
1749 applywatch = 1;
1750 setbg = 0;
1751 /* set network part */
1752 setnetbg = 1;
1753 case TASK_APPSTATE_ACTIVE:
1754 /* remove app background */
1755 ret = proc_restore_bgtaskpolicy_internal(task, 1, 1, BASEPRI_DEFAULT);
1756 /* going from BG to active */
1757 break;
1758
1759 case TASK_APPSTATE_NONUI:
1760 /* remove app background + no graphics */
1761 task->ext_policystate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS;
1762 task->ext_appliedstate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS;
1763 ret = proc_restore_bgtaskpolicy_internal(task, 1, 1, BASEPRI_DEFAULT);
1764 break;
1765
1766 case TASK_APPSTATE_INACTIVE:
1767 /* suspend and then remove app background */
1768 kret = task_pidsuspend_locked(task);
1769 if (kret != KERN_SUCCESS) {
1770 ret = EINVAL;
1771 } else {
1772 ret = proc_restore_bgtaskpolicy_internal(task, 1, 1, BASEPRI_DEFAULT);
1773 sethib_suspend = 1;
1774 }
1775
1776 break;
1777
1778 }
1779 break;
1780
1781 case TASK_APPSTATE_NONUI:
1782 switch(state) {
1783 case TASK_APPSTATE_ACTIVE:
1784 /* restore graphics access */
1785 task->ext_policystate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS;
1786 task->ext_appliedstate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_DEFAULT;
1787 break;
1788
1789 case TASK_APPSTATE_BACKGROUND:
1790 /* set app background */
1791 task->ext_policystate.hw_bg = TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL;
1792
1793 ret = proc_apply_bgtaskpolicy_internal(task, 1, 1);
1794 if (ret == 0) {
1795 task->ext_policystate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_DEFAULT;
1796 task->ext_appliedstate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_DEFAULT;
1797 }
1798 /* watchers need update */
1799 applywatch = 1;
1800 setbg = 1;
1801 /* set network part */
1802 setnetbg = 1;
1803 break;
1804
1805 case TASK_APPSTATE_INACTIVE:
1806 /* suspend & restore graphics access */
1807 kret = task_pidsuspend_locked(task);
1808 if (kret != KERN_SUCCESS) {
1809 ret = EINVAL;
1810 } else {
1811 ret = proc_restore_bgtaskpolicy_internal(task, 1, 1, BASEPRI_DEFAULT);
1812 task->ext_policystate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_DEFAULT;
1813 task->ext_appliedstate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_DEFAULT;
1814 sethib_suspend = 1;
1815 }
1816 break;
1817 }
1818 break;
1819
1820 case TASK_APPSTATE_INACTIVE:
1821 switch(state) {
1822 case TASK_APPSTATE_ACTIVE:
1823 /* resume process */
1824 /* going from inactive to active */
1825 break;
1826
1827 case TASK_APPSTATE_BACKGROUND:
1828 task->ext_policystate.hw_bg = TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL;
1829 ret = proc_apply_bgtaskpolicy_internal(task, 1, 1);
1830 /* put in app background & resume process */
1831 /* watchers need update */
1832 applywatch = 1;
1833 setbg = 1;
1834 /* set network part */
1835 setnetbg = 1;
1836 break;
1837
1838 case TASK_APPSTATE_NONUI:
1839 /* remove graphics access and resume */
1840 task->ext_policystate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS;
1841 task->ext_appliedstate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS;
1842 break;
1843 }
1844 /* pidresume does drop task lock,so no need to have locked version */
1845 task_unlock(task);
1846 kret = task_pidresume(task);
1847 task_lock(task);
1848 sethib_resume = 1;
1849 break;
1850 }
1851 /* set the new app state on the task */
1852 task->appstate = state;
1853 out1:
1854 task_unlock(task);
1855 if (setnetbg != 0) {
1856 /* apply network background */
1857 if (setbg != 0)
1858 proc_apply_task_networkbg_internal(task->bsd_info, NULL);
1859 else
1860 proc_restore_task_networkbg_internal(task->bsd_info, NULL);
1861 }
1862 #if CONFIG_MEMORYSTATUS
1863 if (sethib_suspend != 0)
1864 memorystatus_on_suspend(proc_pid(task->bsd_info));
1865 if (sethib_resume != 0)
1866 memorystatus_on_resume(proc_pid(task->bsd_info));
1867 #endif /* CONFIG_MEMORYSTATUS */
1868 /* if watchers need update, safe point to do that */
1869 if (applywatch != 0)
1870 apply_appstate_watchers(task, setbg);
1871
1872 out:
1873 return(ret);
1874 }
1875
1876 static void
1877 task_watch_lock(void)
1878 {
1879 lck_mtx_lock(&task_watch_mtx);
1880 }
1881
1882 static void
1883 task_watch_unlock(void)
1884 {
1885 lck_mtx_unlock(&task_watch_mtx);
1886 }
1887
1888 static void
1889 add_taskwatch_locked(task_t task, task_watch_t * twp)
1890 {
1891 queue_enter(&task->task_watchers, twp, task_watch_t *, tw_links);
1892 task->num_taskwatchers++;
1893
1894 }
1895
1896 static void
1897 remove_taskwatch_locked(task_t task, task_watch_t * twp)
1898 {
1899 queue_remove(&task->task_watchers, twp, task_watch_t *, tw_links);
1900 task->num_taskwatchers--;
1901 }
1902
1903
1904 int
1905 proc_lf_pidbind(task_t curtask, uint64_t tid, task_t target_task, int bind)
1906 {
1907 thread_t self = current_thread();
1908 thread_t target_thread = NULL;
1909 int selfset = 0, ret = 0, setbg = 0;
1910 task_watch_t *twp = NULL;
1911 task_t task = TASK_NULL;
1912
1913
1914 if ((tid == 0) || (tid == self->thread_id)) {
1915 selfset = 1;
1916 target_thread = self;
1917 thread_reference(target_thread);
1918 } else {
1919 task_lock(curtask);
1920 target_thread = task_findtid(curtask, tid);
1921 if (target_thread != NULL)
1922 thread_reference(target_thread);
1923 else {
1924 ret = ESRCH;
1925 goto out;
1926 }
1927
1928 task_unlock(curtask);
1929 }
1930
1931 if (bind != 0) {
1932 /* task is still active ? */
1933 task_lock(target_task);
1934 if (target_task->active == 0) {
1935 task_unlock(target_task);
1936 ret = ESRCH;
1937 goto out;
1938 }
1939 task_unlock(target_task);
1940
1941 twp = (task_watch_t *)kalloc(sizeof(task_watch_t));
1942 if (twp == NULL) {
1943 task_watch_unlock();
1944 ret = ENOMEM;
1945 goto out;
1946 }
1947
1948 bzero(twp, sizeof(task_watch_t));
1949
1950 task_watch_lock();
1951
1952 if (target_thread->taskwatch != NULL){
1953 /* already bound to another task */
1954 task_watch_unlock();
1955
1956 kfree(twp, sizeof(task_watch_t));
1957 ret = EBUSY;
1958 goto out;
1959 }
1960
1961 task_reference(target_task);
1962
1963 twp->tw_task = target_task; /* holds the task reference */
1964 twp->tw_thread = target_thread; /* holds the thread reference */
1965 twp->tw_state = target_task->appstate;
1966 twp->tw_importance = target_thread->importance;
1967
1968 add_taskwatch_locked(target_task, twp);
1969
1970 target_thread->taskwatch = twp;
1971
1972 if (target_task->appstate == TASK_APPSTATE_BACKGROUND)
1973 setbg = 1;
1974
1975 task_watch_unlock();
1976
1977 if (setbg != 0) {
1978 set_thread_appbg(target_thread, setbg, INT_MIN);
1979 }
1980
1981 /* retain the thread reference as it is in twp */
1982 target_thread = NULL;
1983 } else {
1984 /* unbind */
1985 task_watch_lock();
1986 if ((twp = target_thread->taskwatch) != NULL) {
1987 task = twp->tw_task;
1988 target_thread->taskwatch = NULL;
1989 remove_taskwatch_locked(task, twp);
1990
1991 task_watch_unlock();
1992
1993 task_deallocate(task); /* drop task ref in twp */
1994 set_thread_appbg(target_thread, 0, twp->tw_importance);
1995 thread_deallocate(target_thread); /* drop thread ref in twp */
1996 kfree(twp, sizeof(task_watch_t));
1997 } else {
1998 task_watch_unlock();
1999 ret = 0; /* return success if it not alredy bound */
2000 goto out;
2001 }
2002 }
2003 out:
2004 if (target_thread != NULL)
2005 thread_deallocate(target_thread); /* drop thread ref acquired in this routine */
2006 return(ret);
2007 }
2008
2009 static void
2010 set_thread_appbg(thread_t thread, int setbg,int importance)
2011 {
2012 /* TBD: ensure the proc for network is fine */
2013 if (setbg == 0) {
2014 restore_bgthreadpolicy_locked(thread, 0, importance);
2015 proc_restore_task_networkbg_internal(thread->task->bsd_info, thread);
2016 } else {
2017 apply_bgthreadpolicy_external(thread);
2018 proc_apply_task_networkbg_internal(thread->task->bsd_info, thread);
2019 }
2020 }
2021
2022 static void
2023 apply_appstate_watchers(task_t task, int setbg)
2024 {
2025 int numwatchers = 0, i, j;
2026 thread_watchlist_t * threadlist;
2027 task_watch_t * twp;
2028
2029 retry:
2030 /* if no watchers on the list return */
2031 if ((numwatchers = task->num_taskwatchers) == 0)
2032 return;
2033
2034 threadlist = (thread_watchlist_t *)kalloc(numwatchers*sizeof(thread_watchlist_t));
2035 if (threadlist == NULL)
2036 return;
2037
2038 bzero(threadlist, numwatchers*sizeof(thread_watchlist_t));
2039
2040 task_watch_lock();
2041 /*serialize application of app state changes */
2042 if (task->watchapplying != 0) {
2043 lck_mtx_sleep(&task_watch_mtx, LCK_SLEEP_DEFAULT, &task->watchapplying, THREAD_UNINT);
2044 task_watch_unlock();
2045 kfree(threadlist, numwatchers*sizeof(thread_watchlist_t));
2046 goto retry;
2047 }
2048
2049 if (numwatchers != task->num_taskwatchers) {
2050 task_watch_unlock();
2051 kfree(threadlist, numwatchers*sizeof(thread_watchlist_t));
2052 goto retry;
2053 }
2054
2055 task->watchapplying = 1;
2056 i = 0;
2057 queue_iterate(&task->task_watchers, twp, task_watch_t *, tw_links) {
2058
2059 threadlist[i].thread = twp->tw_thread;
2060 thread_reference(threadlist[i].thread);
2061 if (setbg != 0) {
2062 twp->tw_importance = twp->tw_thread->importance;
2063 threadlist[i].importance = INT_MIN;
2064 } else
2065 threadlist[i].importance = twp->tw_importance;
2066 i++;
2067 if (i > numwatchers)
2068 break;
2069 }
2070 task_watch_unlock();
2071
2072 for (j = 0; j< i; j++) {
2073 set_thread_appbg(threadlist[j].thread, setbg, threadlist[j].importance);
2074 thread_deallocate(threadlist[j].thread);
2075 }
2076 kfree(threadlist, numwatchers*sizeof(thread_watchlist_t));
2077
2078
2079 task_watch_lock();
2080 task->watchapplying = 0;
2081 thread_wakeup_one(&task->watchapplying);
2082 task_watch_unlock();
2083 }
2084
2085 void
2086 thead_remove_taskwatch(thread_t thread)
2087 {
2088 task_watch_t * twp;
2089 int importance = 0;
2090
2091 task_watch_lock();
2092 if ((twp = thread->taskwatch) != NULL) {
2093 thread->taskwatch = NULL;
2094 remove_taskwatch_locked(twp->tw_task, twp);
2095 }
2096 task_watch_unlock();
2097 if (twp != NULL) {
2098 thread_deallocate(twp->tw_thread);
2099 task_deallocate(twp->tw_task);
2100 importance = twp->tw_importance;
2101 kfree(twp, sizeof(task_watch_t));
2102 /* remove the thread and networkbg */
2103 set_thread_appbg(thread, 0, importance);
2104 }
2105 }
2106
2107 void
2108 task_removewatchers(task_t task)
2109 {
2110 int numwatchers = 0, i, j;
2111 task_watch_t ** twplist = NULL;
2112 task_watch_t * twp = NULL;
2113
2114 retry:
2115 if ((numwatchers = task->num_taskwatchers) == 0)
2116 return;
2117
2118 twplist = (task_watch_t **)kalloc(numwatchers*sizeof(task_watch_t *));
2119 if (twplist == NULL)
2120 return;
2121
2122 bzero(twplist, numwatchers*sizeof(task_watch_t *));
2123
2124 task_watch_lock();
2125 if (task->num_taskwatchers == 0) {
2126 task_watch_unlock();
2127 goto out;
2128 }
2129
2130 if (numwatchers != task->num_taskwatchers) {
2131 task_watch_unlock();
2132 kfree(twplist, numwatchers*sizeof(task_watch_t *));
2133 numwatchers = 0;
2134 goto retry;
2135 }
2136
2137 i = 0;
2138 while((twp = (task_watch_t *)dequeue_head(&task->task_watchers)) != NULL)
2139 {
2140 twplist[i] = twp;
2141 task->num_taskwatchers--;
2142
2143 /*
2144 * Since the linkage is removed and thead state cleanup is already set up,
2145 * remove the refernce from the thread.
2146 */
2147 twp->tw_thread->taskwatch = NULL; /* removed linkage, clear thread holding ref */
2148 i++;
2149 if ((task->num_taskwatchers == 0) || (i > numwatchers))
2150 break;
2151 }
2152
2153 task_watch_unlock();
2154
2155 for (j = 0; j< i; j++) {
2156
2157 twp = twplist[j];
2158 /* remove thread and network bg */
2159 set_thread_appbg(twp->tw_thread, 0, twp->tw_importance);
2160 thread_deallocate(twp->tw_thread);
2161 task_deallocate(twp->tw_task);
2162 kfree(twp, sizeof(task_watch_t));
2163 }
2164
2165 out:
2166 kfree(twplist, numwatchers*sizeof(task_watch_t *));
2167
2168 }
2169 #endif /* CONFIG_EMBEDDED */
2170
2171
2172 int
2173 proc_disable_task_apptype(task_t task, int policy_subtype)
2174 {
2175 void * bsdinfo = NULL;
2176 int ret = 0;
2177 int setbg = 0;
2178 #if !CONFIG_EMBEDDED
2179 int maxpri = BASEPRI_DEFAULT;
2180 #endif /* !CONFIG_EMBEDDED */
2181
2182 task_lock(task);
2183
2184 if (task->ext_policystate.apptype != policy_subtype) {
2185 ret = EINVAL;
2186 goto out;
2187 }
2188
2189 #if !CONFIG_EMBEDDED
2190 switch (task->role) {
2191 case TASK_FOREGROUND_APPLICATION:
2192 maxpri = BASEPRI_FOREGROUND;
2193 break;
2194 case TASK_BACKGROUND_APPLICATION:
2195 maxpri = BASEPRI_BACKGROUND;
2196 break;
2197 default:
2198 maxpri = BASEPRI_DEFAULT;
2199 }
2200
2201
2202 #endif /* !CONFIG_EMBEDDED */
2203
2204 /* TAL apps are cleared with BG handling on first foreground application */
2205 if (task->ext_appliedstate.apptype != PROC_POLICY_OSX_APPTYPE_NONE) {
2206 switch (task->ext_appliedstate.apptype) {
2207 #if !CONFIG_EMBEDDED
2208 case PROC_POLICY_OSX_APPTYPE_TAL:
2209 /* disable foreground/background handling */
2210 task->ext_appliedstate.apptype = PROC_POLICY_OSX_APPTYPE_NONE;
2211 /* external BG application removal */
2212 proc_restore_bgtaskpolicy_internal(task, 1, 1, maxpri);
2213 bsdinfo = task->bsd_info;
2214 setbg = 0;
2215 break;
2216
2217 case PROC_POLICY_OSX_APPTYPE_DBCLIENT:
2218 /* disable foreground/background handling */
2219 task->ext_appliedstate.apptype = PROC_POLICY_OSX_APPTYPE_NONE;
2220 /* internal BG application removal */
2221 proc_restore_bgtaskpolicy_internal(task, 1, 0, maxpri);
2222 bsdinfo = task->bsd_info;
2223 setbg = 0;
2224 break;
2225
2226 #endif /* !CONFIG_EMBEDDED */
2227 default:
2228 ret = EINVAL;
2229 break;
2230 }
2231
2232 } else {
2233 ret = EINVAL;
2234 }
2235
2236 out:
2237 task_unlock(task);
2238 /* if backgrounding action ... */
2239 if (bsdinfo != NULL)
2240 proc_set_task_networkbg(bsdinfo, setbg);
2241
2242 return(ret);
2243 }
2244
2245 int
2246 proc_enable_task_apptype(task_t task, int policy_subtype)
2247 {
2248 void * bsdinfo = NULL;
2249 int setbg = 0;
2250 int ret = 0;
2251
2252 task_lock(task);
2253
2254 if (task->ext_policystate.apptype != policy_subtype) {
2255 ret = EINVAL;
2256 goto out;
2257 }
2258
2259 if (task->ext_appliedstate.apptype == PROC_POLICY_OSX_APPTYPE_NONE) {
2260 switch (task->ext_policystate.apptype) {
2261 #if !CONFIG_EMBEDDED
2262 case PROC_POLICY_OSX_APPTYPE_TAL:
2263 /* TAL policy is activated again */
2264 task->ext_appliedstate.apptype = task->ext_policystate.apptype;
2265 if (task->role == TASK_BACKGROUND_APPLICATION) {
2266 if (task->role == TASK_BACKGROUND_APPLICATION) {
2267 proc_apply_bgtaskpolicy_internal(task, 1, 1);
2268 bsdinfo = task->bsd_info;
2269 setbg = 1;
2270 }
2271 }
2272 ret = 0;
2273 break;
2274 #endif /* !CONFIG_EMBEDDED */
2275 default:
2276 ret = EINVAL;
2277 }
2278 } else
2279 ret = EINVAL;
2280
2281 out:
2282 task_unlock(task);
2283 /* if backgrounding action ... */
2284 if (bsdinfo != NULL)
2285 proc_set_task_networkbg(bsdinfo, setbg);
2286
2287 return(ret);
2288 }
2289
2290 #if CONFIG_EMBEDDED
2291 int
2292 proc_setthread_saved_importance(thread_t thread, int importance)
2293 {
2294 if ((thread->task->ext_appliedstate.apptype == PROC_POLICY_IOS_APPLE_DAEMON) &&
2295 (thread->appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL))
2296 {
2297 /* the thread is still backgrounded , save the importance for restore time */
2298 thread->saved_importance = importance;
2299
2300 return(1);
2301 } else
2302 return(0);
2303 }
2304 #endif /* CONFIG_EMBEDDED */