]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/task_policy.c
xnu-1699.22.81.tar.gz
[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
39 static int proc_apply_bgtaskpolicy_locked(task_t task, int, int);
40 static int proc_restore_bgtaskpolicy_locked(task_t, int, int, int);
41 static int task_get_cpuusage(task_t task, uint32_t * percentagep, uint64_t * intervalp, uint64_t * deadlinep);
42 static int task_set_cpuusage(task_t task, uint32_t percentage, uint64_t interval, uint64_t deadline);
43 static int task_apply_resource_actions(task_t task, int type);
44 static int proc_apply_bgthreadpolicy_locked(thread_t thread, int selfset);
45 static void restore_bgthreadpolicy_locked(thread_t thread, int selfset);
46
47 process_policy_t default_task_proc_policy = {0,
48 0,
49 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
50 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
51 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
52 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
53 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
54 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
55 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
56 0,
57 TASK_POLICY_HWACCESS_CPU_ATTRIBUTE_ALL,
58 TASK_POLICY_HWACCESS_NET_ATTRIBUTE_NORMAL,
59 TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_FULLACCESS,
60 TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_NORMAL,
61 TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL
62 };
63
64 process_policy_t default_task_null_policy = {0,
65 0,
66 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
67 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
68 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
69 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
70 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
71 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
72 TASK_POLICY_RESOURCE_ATTRIBUTE_NONE,
73 0,
74 TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NONE,
75 TASK_POLICY_HWACCESS_NET_ATTRIBUTE_NONE,
76 TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NONE,
77 TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_NORMAL,
78 TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE
79 };
80
81
82 static void
83 task_priority(
84 task_t task,
85 integer_t priority,
86 integer_t max_priority);
87
88 kern_return_t
89 task_policy_set(
90 task_t task,
91 task_policy_flavor_t flavor,
92 task_policy_t policy_info,
93 mach_msg_type_number_t count)
94 {
95 kern_return_t result = KERN_SUCCESS;
96 void * bsdinfo = NULL;
97 int setbg = 0;
98
99 if (task == TASK_NULL || task == kernel_task)
100 return (KERN_INVALID_ARGUMENT);
101
102 switch (flavor) {
103
104 case TASK_CATEGORY_POLICY:
105 {
106 task_category_policy_t info = (task_category_policy_t)policy_info;
107
108 if (count < TASK_CATEGORY_POLICY_COUNT)
109 return (KERN_INVALID_ARGUMENT);
110
111 #if CONFIG_EMBEDDED
112 if ((current_task() == task) && (info != NULL) &&
113 (info->role != TASK_THROTTLE_APPLICATION))
114 return (KERN_INVALID_ARGUMENT);
115 #endif
116
117 task_lock(task);
118 if ( info->role == TASK_FOREGROUND_APPLICATION ||
119 info->role == TASK_BACKGROUND_APPLICATION) {
120 #if !CONFIG_EMBEDDED
121 if (task->ext_actionstate.apptype != PROC_POLICY_OSX_APPTYPE_NONE) {
122 switch (info->role) {
123 case TASK_FOREGROUND_APPLICATION:
124 switch (task->ext_actionstate.apptype) {
125 case PROC_POLICY_OSX_APPTYPE_TAL:
126 /* Move the app to foreground with no DarwinBG */
127 proc_restore_bgtaskpolicy_locked(task, 1, 1, BASEPRI_FOREGROUND);
128 bsdinfo = task->bsd_info;
129 setbg = 0;
130 break;
131
132 case PROC_POLICY_OSX_APPTYPE_DBCLIENT:
133 /* reset the apptype so enforcement on background/foregound */
134 task->ext_actionstate.apptype = PROC_POLICY_OSX_APPTYPE_NONE;
135 /* Internal application and make it foreground pri */
136 proc_restore_bgtaskpolicy_locked(task, 1, 0, BASEPRI_FOREGROUND);
137 bsdinfo = task->bsd_info;
138 setbg = 0;
139 break;
140
141 default:
142 /* the app types cannot be in CONTROL, GRAPHICS STATE, so it will de default state here */
143 task_priority(task,
144 ((info->role == TASK_FOREGROUND_APPLICATION)?
145 BASEPRI_FOREGROUND: BASEPRI_BACKGROUND),
146 task->max_priority);
147 break;
148 }
149 task->role = TASK_FOREGROUND_APPLICATION;
150 break;
151
152 case TASK_BACKGROUND_APPLICATION:
153 switch (task->ext_actionstate.apptype) {
154 case PROC_POLICY_OSX_APPTYPE_TAL:
155 /* TAL apps will get Darwin backgrounded if not already set */
156 if (task->ext_actionstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) {
157 /* external application of Darwin BG */
158 proc_apply_bgtaskpolicy_locked(task, 1, 1);
159 bsdinfo = task->bsd_info;
160 setbg = 1;
161 }
162 break;
163
164 default:
165 task_priority(task,
166 ((info->role == TASK_FOREGROUND_APPLICATION)?
167 BASEPRI_FOREGROUND: BASEPRI_BACKGROUND),
168 task->max_priority);
169 break;
170 }
171 task->role = TASK_BACKGROUND_APPLICATION;
172 break;
173
174 default:
175 /* do nothing */
176 break;
177
178 } /* switch info->role */
179 } else { /* apptype != PROC_POLICY_OSX_APPTYPE_NONE */
180 #endif /* !CONFIG_EMBEDDED */
181 switch (task->role) {
182
183 case TASK_FOREGROUND_APPLICATION:
184 case TASK_BACKGROUND_APPLICATION:
185 case TASK_UNSPECIFIED:
186 /* if there are no process wide backgrounding ... */
187 if ((task->ext_actionstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) &&
188 (task->actionstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE)) {
189 task_priority(task,
190 ((info->role == TASK_FOREGROUND_APPLICATION)?
191 BASEPRI_FOREGROUND: BASEPRI_BACKGROUND),
192 task->max_priority);
193 }
194 task->role = info->role;
195 break;
196
197 case TASK_CONTROL_APPLICATION:
198 case TASK_RENICED:
199 /* else fail silently */
200 break;
201
202 default:
203 result = KERN_INVALID_ARGUMENT;
204 break;
205 }
206 #if !CONFIG_EMBEDDED
207 } /* apptype != PROC_POLICY_OSX_APPTYPE_NONE */
208 #endif /* !CONFIG_EMBEDDED */
209
210 } else if (info->role == TASK_CONTROL_APPLICATION) {
211 if (task != current_task()||
212 task->sec_token.val[0] != 0)
213 result = KERN_INVALID_ARGUMENT;
214 else {
215 task_priority(task, BASEPRI_CONTROL, task->max_priority);
216 task->role = info->role;
217 }
218 } else if (info->role == TASK_GRAPHICS_SERVER) {
219 if (task != current_task() ||
220 task->sec_token.val[0] != 0)
221 result = KERN_INVALID_ARGUMENT;
222 else {
223 task_priority(task, MAXPRI_RESERVED - 3, MAXPRI_RESERVED);
224 task->role = info->role;
225 }
226 } else
227 #if CONFIG_EMBEDDED
228 if (info->role == TASK_THROTTLE_APPLICATION) {
229 task_priority(task, MAXPRI_THROTTLE, MAXPRI_THROTTLE);
230 task->role = info->role;
231 } else if (info->role == TASK_DEFAULT_APPLICATION || info->role == TASK_NONUI_APPLICATION)
232 {
233 task_priority(task, BASEPRI_DEFAULT, MAXPRI_USER);
234 task->role = info->role;
235 } else
236 #else /* CONFIG_EMBEDDED */
237 if (info->role == TASK_DEFAULT_APPLICATION)
238 {
239 task_priority(task, BASEPRI_DEFAULT, MAXPRI_USER);
240 task->role = info->role;
241 } else
242 #endif /* CONFIG_EMBEDDED */
243 result = KERN_INVALID_ARGUMENT;
244
245 task_unlock(task);
246
247 /* if backgrounding action ... */
248 if (bsdinfo != NULL)
249 proc_set_task_networkbg(bsdinfo, setbg);
250
251 break;
252 }
253
254 default:
255 result = KERN_INVALID_ARGUMENT;
256 break;
257 }
258
259 return (result);
260 }
261
262 static void
263 task_priority(
264 task_t task,
265 integer_t priority,
266 integer_t max_priority)
267 {
268 thread_t thread;
269
270 task->max_priority = max_priority;
271
272 if (priority > task->max_priority)
273 priority = task->max_priority;
274 else
275 if (priority < MINPRI)
276 priority = MINPRI;
277
278 task->priority = priority;
279
280 queue_iterate(&task->threads, thread, thread_t, task_threads) {
281 thread_mtx_lock(thread);
282
283 if (thread->active)
284 thread_task_priority(thread, priority, max_priority);
285
286 thread_mtx_unlock(thread);
287 }
288 }
289
290 kern_return_t
291 task_importance(
292 task_t task,
293 integer_t importance)
294 {
295 if (task == TASK_NULL || task == kernel_task)
296 return (KERN_INVALID_ARGUMENT);
297
298 task_lock(task);
299
300 if (!task->active) {
301 task_unlock(task);
302
303 return (KERN_TERMINATED);
304 }
305
306 if (task->role >= TASK_CONTROL_APPLICATION) {
307 task_unlock(task);
308
309 return (KERN_INVALID_ARGUMENT);
310 }
311
312 task_priority(task, importance + BASEPRI_DEFAULT, task->max_priority);
313 task->role = TASK_RENICED;
314
315 task_unlock(task);
316
317 return (KERN_SUCCESS);
318 }
319
320 kern_return_t
321 task_policy_get(
322 task_t task,
323 task_policy_flavor_t flavor,
324 task_policy_t policy_info,
325 mach_msg_type_number_t *count,
326 boolean_t *get_default)
327 {
328 if (task == TASK_NULL || task == kernel_task)
329 return (KERN_INVALID_ARGUMENT);
330
331 switch (flavor) {
332
333 case TASK_CATEGORY_POLICY:
334 {
335 task_category_policy_t info = (task_category_policy_t)policy_info;
336
337 if (*count < TASK_CATEGORY_POLICY_COUNT)
338 return (KERN_INVALID_ARGUMENT);
339
340 if (*get_default)
341 info->role = TASK_UNSPECIFIED;
342 else {
343 task_lock(task);
344 info->role = task->role;
345 task_unlock(task);
346 }
347 break;
348 }
349
350 default:
351 return (KERN_INVALID_ARGUMENT);
352 }
353
354 return (KERN_SUCCESS);
355 }
356
357 /* task Darwin BG enforcement/settings related routines */
358 int
359 proc_get_task_bg_policy(task_t task)
360 {
361
362 int selfset = 0;
363 int val = 0;
364
365 if (current_task() == task)
366 selfset = 1;
367
368 if (selfset == 0) {
369 val = task->ext_policystate.hw_bg;
370 } else {
371 val = task->policystate.hw_bg;
372 }
373
374 return(val);
375 }
376
377
378 int
379 proc_get_thread_bg_policy(task_t task, uint64_t tid)
380 {
381 thread_t self = current_thread();
382 thread_t thread = THREAD_NULL;
383 int val = 0;
384
385 if (tid == self->thread_id) {
386 val = self->policystate.hw_bg;
387 } else {
388 task_lock(task);
389 thread = task_findtid(task, tid);
390 if (thread != NULL)
391 val = thread->ext_policystate.hw_bg;
392 task_unlock(task);
393 }
394
395 return(val);
396 }
397
398 int
399 proc_get_self_isbackground(void)
400 {
401 task_t task = current_task();;
402 thread_t thread = current_thread();
403
404 if ((task->ext_actionstate.hw_bg != TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) ||
405 (task->actionstate.hw_bg != TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) ||
406 (thread->ext_actionstate.hw_bg != TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) ||
407 (thread->actionstate.hw_bg != TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE))
408 return(1);
409 else
410 return(0);
411
412 }
413
414 int proc_get_selfthread_isbackground(void)
415 {
416 thread_t thread = current_thread();
417
418 if ((thread->ext_actionstate.hw_bg != TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) ||
419 (thread->actionstate.hw_bg != TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE))
420 return(1);
421 else
422 return(0);
423 }
424
425
426 int
427 proc_set_bgtaskpolicy(task_t task, int intval)
428 {
429
430 int selfset = 0;
431
432 if (current_task() == task)
433 selfset = 1;
434
435 task_lock(task);
436
437 if (selfset == 0) {
438 /* allready set? */
439 if (task->ext_policystate.hw_bg != intval)
440 task->ext_policystate.hw_bg = intval;
441 } else {
442 if (task->policystate.hw_bg != intval)
443 task->policystate.hw_bg = intval;
444 }
445
446 task_unlock(task);
447 return(0);
448 }
449
450 /* set and apply as well */
451 int proc_set1_bgtaskpolicy(task_t task, int prio)
452 {
453 int error = 0;
454
455 if (prio == PRIO_DARWIN_BG) {
456 error = proc_set_bgtaskpolicy(task, TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL);
457 if (error == 0)
458 error = proc_apply_bgtaskpolicy(task);
459 } else {
460 error = proc_restore_bgtaskpolicy(task);
461 }
462
463 return(error);
464 }
465
466
467 int
468 proc_set_bgthreadpolicy(task_t task, uint64_t tid, int prio)
469 {
470 thread_t self = current_thread();
471 thread_t thread = THREAD_NULL;
472 int reset;
473
474 if (prio == 0)
475 reset = 1;
476 task_lock(task);
477 if (tid == self->thread_id) {
478 self->policystate.hw_bg = prio;
479 } else {
480 thread = task_findtid(task, tid);
481 if (thread != NULL)
482 thread->ext_policystate.hw_bg = prio;
483 }
484
485 task_unlock(task);
486
487 return(0);
488 }
489
490 int
491 proc_set1_bgthreadpolicy(task_t task, uint64_t tid, int prio)
492 {
493 int error = 0;
494
495 if (prio == PRIO_DARWIN_BG) {
496 error = proc_set_bgthreadpolicy(task, tid, TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL);
497 if (error == 0)
498 error = proc_apply_bgthreadpolicy(task, tid);
499 } else {
500 error = proc_restore_bgthreadpolicy(task, tid);
501 }
502
503 return(error);
504 }
505
506 int
507 proc_add_bgtaskpolicy(task_t task, int val)
508 {
509 int selfset = 0;
510
511 if (current_task() == task)
512 selfset = 1;
513
514 task_lock(task);
515
516 if (selfset == 0) {
517 task->policystate.hw_bg |= val;
518 } else {
519 task->ext_policystate.hw_bg |= val;
520 }
521
522 task_unlock(task);
523 return(0);
524 }
525
526 int
527 proc_add_bgthreadpolicy(task_t task, uint64_t tid, int val)
528 {
529 thread_t self = current_thread();
530 thread_t thread = THREAD_NULL;
531 int reset;
532
533 if (val == 0)
534 reset = 1;
535 task_lock(task);
536 if (tid == self->thread_id) {
537 self->policystate.hw_bg |= val;
538 } else {
539 thread = task_findtid(task, tid);
540 if (thread != NULL)
541 thread->ext_policystate.hw_bg |= val;
542 }
543
544 task_unlock(task);
545
546 return(val);
547 }
548
549 int
550 proc_remove_bgtaskpolicy(task_t task, int intval)
551 {
552 int selfset = 0;
553
554 if (current_task() == task)
555 selfset = 1;
556
557 task_lock(task);
558
559 if (selfset == 0) {
560 task->policystate.hw_bg &= ~intval;
561 } else {
562 task->ext_policystate.hw_bg &= ~intval;
563 }
564
565 task_unlock(task);
566 return(0);
567 }
568
569 int
570 proc_remove_bgthreadpolicy(task_t task, uint64_t tid, int val)
571 {
572 thread_t self = current_thread();
573 thread_t thread = THREAD_NULL;
574 int reset;
575
576 if (val == 0)
577 reset = 1;
578 task_lock(task);
579 if (tid == self->thread_id) {
580 self->policystate.hw_bg &= ~val;
581 } else {
582 thread = task_findtid(task, tid);
583 if (thread != NULL)
584 thread->ext_policystate.hw_bg &= ~val;
585 }
586
587 task_unlock(task);
588
589 return(val);
590 }
591
592 int
593 proc_apply_bgtask_selfpolicy(void)
594 {
595 return(proc_apply_bgtaskpolicy(current_task()));
596 }
597
598 int
599 proc_apply_bgtaskpolicy(task_t task)
600 {
601 int external = 1;
602
603 if (task == current_task())
604 external = 0;
605
606 return(proc_apply_bgtaskpolicy_locked(task, 0, external));
607 }
608
609 int
610 proc_apply_bgtaskpolicy_external(task_t task)
611 {
612 return(proc_apply_bgtaskpolicy_locked(task, 0, 1));
613
614 }
615
616 int
617 proc_apply_bgtaskpolicy_internal(task_t task)
618 {
619 return(proc_apply_bgtaskpolicy_locked(task, 0, 0));
620 }
621
622
623 static int
624 proc_apply_bgtaskpolicy_locked(task_t task, int locked, int external)
625 {
626 if (locked == 0)
627 task_lock(task);
628
629 if (external != 0) {
630 /* allready set? */
631 if (task->ext_actionstate.hw_bg != task->ext_policystate.hw_bg) {
632 task->ext_actionstate.hw_bg = task->ext_policystate.hw_bg;
633 task_priority(task, MAXPRI_THROTTLE, MAXPRI_THROTTLE);
634 /* background state applied */
635 }
636 } else {
637 if (task->actionstate.hw_bg != task->policystate.hw_bg) {
638 task->actionstate.hw_bg = task->policystate.hw_bg;
639 task_priority(task, MAXPRI_THROTTLE, MAXPRI_THROTTLE);
640 }
641 }
642 if (locked == 0)
643 task_unlock(task);
644 return(0);
645 }
646
647 /* apply the self backgrounding even if the thread is not current thread/task(timer threads) */
648 int
649 proc_apply_workq_bgthreadpolicy(thread_t thread)
650 {
651 int error;
652 task_t wqtask = TASK_NULL;
653
654 if (thread != THREAD_NULL) {
655 wqtask = thread->task;
656 task_lock(wqtask);
657 /* apply the background as selfset internal one */
658 error = proc_apply_bgthreadpolicy_locked(thread, 1);
659 task_unlock(wqtask);
660 } else
661 error = ESRCH;
662
663 return(error);
664 }
665
666 int
667 proc_apply_bgthreadpolicy(task_t task, uint64_t tid)
668 {
669 thread_t self = current_thread();
670 thread_t thread = THREAD_NULL;
671 int selfset = 0, error = 0;
672 task_t localtask = TASK_NULL;
673
674 if (tid == self->thread_id) {
675 selfset = 1;
676 localtask = current_task();
677 } else {
678 localtask = task;
679 }
680
681 task_lock(localtask);
682 if (selfset != 0) {
683 thread = self;
684 } else {
685 thread = task_findtid(task, tid);
686 }
687
688 error = proc_apply_bgthreadpolicy_locked(thread, selfset);
689 task_unlock(localtask);
690
691 return(error);
692 }
693
694 static int
695 proc_apply_bgthreadpolicy_locked(thread_t thread, int selfset)
696 {
697 int set = 0;
698 thread_precedence_policy_data_t policy;
699
700 if (thread != NULL) {
701 if (selfset != 0) {
702 /* internal application */
703 if (thread->actionstate.hw_bg != thread->policystate.hw_bg) {
704 thread->actionstate.hw_bg = thread->policystate.hw_bg;
705 if (thread->ext_actionstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE)
706 set = 1;
707
708 }
709 } else {
710 /* external application */
711 if (thread->ext_actionstate.hw_bg != thread->ext_policystate.hw_bg) {
712 thread->ext_actionstate.hw_bg = thread->ext_policystate.hw_bg;
713 if (thread->actionstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE)
714 set = 1;
715 }
716 }
717
718 if (set != 0) {
719 /* set thread priority (we did not save previous value) */
720 policy.importance = INT_MIN;
721
722 thread_policy_set_internal(thread, THREAD_PRECEDENCE_POLICY,
723 (thread_policy_t)&policy,
724 THREAD_PRECEDENCE_POLICY_COUNT );
725
726 }
727 } else
728 return(ESRCH);
729
730 return(0);
731 }
732
733 int
734 proc_apply_bgthread_selfpolicy(void)
735 {
736 return(proc_apply_bgthreadpolicy(current_task(), current_thread()->thread_id));
737 }
738
739
740 int
741 proc_restore_bgtaskpolicy(task_t task)
742 {
743 int external = 1;
744
745 if (current_task() == task)
746 external = 0;
747 return(proc_restore_bgtaskpolicy_locked(task, 0, external, BASEPRI_DEFAULT));
748 }
749
750 static int
751 proc_restore_bgtaskpolicy_locked(task_t task, int locked, int external, int pri)
752 {
753 if (locked == 0)
754 task_lock(task);
755
756 if (external != 0) {
757 task->ext_actionstate.hw_bg = TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE;
758 /* self BG in flight? */
759 if (task->actionstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) {
760 task_priority(task, pri, MAXPRI_USER);
761 #if CONFIG_EMBEDDED
762 /* non embedded users need role for policy reapplication */
763 task->role = TASK_DEFAULT_APPLICATION;
764 #endif /* CONFIG_EMBEDDED */
765 }
766 } else {
767 task->actionstate.hw_bg = TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE;
768 /* external BG in flight? */
769 if (task->ext_actionstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) {
770 task_priority(task, pri, MAXPRI_USER);
771 #if CONFIG_EMBEDDED
772 /* non embedded users need role for policy reapplication */
773 task->role = TASK_DEFAULT_APPLICATION;
774 #endif /* CONFIG_EMBEDDED */
775 }
776 }
777
778 if (locked == 0)
779 task_unlock(task);
780
781 return(0);
782 }
783
784 /* restore the self backgrounding even if the thread is not current thread */
785 int
786 proc_restore_workq_bgthreadpolicy(thread_t thread)
787 {
788 int error = 0;
789 task_t wqtask = TASK_NULL;
790
791 if (thread != THREAD_NULL) {
792 wqtask = thread->task;
793 task_lock(wqtask);
794 /* remove the background and restore default importance as self(internal) removal */
795 restore_bgthreadpolicy_locked(thread, 1);
796 task_unlock(wqtask);
797 } else
798 error = ESRCH;
799
800 return(error);
801 }
802
803 int proc_restore_bgthread_selfpolicy(void)
804 {
805 return(proc_restore_bgthreadpolicy(current_task(), thread_tid(current_thread())));
806
807 }
808
809
810 int
811 proc_restore_bgthreadpolicy(task_t task, uint64_t tid)
812 {
813 int selfset = 0;
814 thread_t self = current_thread();
815 thread_t thread = THREAD_NULL;
816
817 task_lock(task);
818 if (tid == self->thread_id) {
819 thread = self;
820 selfset = 1;
821 } else {
822 thread = task_findtid(task, tid);
823 }
824
825 if (thread != NULL)
826 restore_bgthreadpolicy_locked(thread, selfset);
827
828 task_unlock(task);
829
830 if (thread != NULL)
831 return(0);
832 else
833 return(1);
834 }
835
836 static void
837 restore_bgthreadpolicy_locked(thread_t thread, int selfset)
838 {
839 thread_precedence_policy_data_t policy;
840 int reset = 0;
841
842 if (thread != NULL) {
843 if (selfset != 0) {
844 thread->actionstate.hw_bg = TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE;
845 /* external BG in flight? */
846 if (thread->ext_actionstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE)
847 reset = 1;
848
849 } else {
850 thread->ext_actionstate.hw_bg = TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE;
851 /* self BG in flight? */
852 if (thread->actionstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE)
853 reset = 1;
854 }
855
856 if (reset != 0) {
857 /* reset thread priority (we did not save previous value) */
858 policy.importance = 0;
859 thread_policy_set_internal(thread, THREAD_PRECEDENCE_POLICY,
860 (thread_policy_t)&policy,
861 THREAD_PRECEDENCE_POLICY_COUNT );
862 }
863 }
864 }
865
866 void
867 proc_set_task_apptype(task_t task, int type)
868 {
869 switch (type) {
870 case PROC_POLICY_OSX_APPTYPE_TAL:
871 task->ext_policystate.apptype = type;
872 task->policystate.apptype = type;
873 proc_apply_bgtaskpolicy_external(task);
874 /* indicate that BG is set and next foreground needs to reset */
875 task->ext_actionstate.apptype = type;
876 break;
877
878 case PROC_POLICY_OSX_APPTYPE_DBCLIENT:
879 task->ext_policystate.apptype = type;
880 task->policystate.apptype = type;
881 proc_apply_bgtaskpolicy_internal(task);
882 /* indicate that BG is set and next foreground needs to reset */
883 task->ext_actionstate.apptype = type;
884 break;
885
886 case PROC_POLICY_IOS_APPTYPE:
887 task->ext_policystate.apptype = type;
888 task->policystate.apptype = type;
889 break;
890 case PROC_POLICY_IOS_NONUITYPE:
891 task->ext_policystate.apptype = type;
892 task->policystate.apptype = type;
893 /* set to deny access to gpu */
894 task->ext_actionstate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS;
895 task->ext_policystate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS;
896 break;
897
898 default:
899 break;
900 }
901 }
902
903 /* update the darwin backdground action state in the flags field for libproc */
904 #define PROC_FLAG_DARWINBG 0x8000 /* process in darwin background */
905 #define PROC_FLAG_EXT_DARWINBG 0x10000 /* process in darwin background - external enforcement */
906
907 int
908 proc_get_darwinbgstate(task_t task, uint32_t * flagsp)
909 {
910 if (task->ext_actionstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL){
911 *flagsp |= PROC_FLAG_EXT_DARWINBG;
912 }
913 if (task->actionstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL){
914 *flagsp |= PROC_FLAG_DARWINBG;
915 }
916
917 return(0);
918 }
919
920 /*
921 * HW disk access realted routines, they need to return
922 * IOPOL_XXX equivalents for spec_xxx/throttle updates.
923 */
924
925 int
926 proc_get_task_disacc(task_t task)
927 {
928 if ((task->ext_actionstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0)
929 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE);
930 if (task->ext_actionstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_NORMAL)
931 return(task->ext_actionstate.hw_disk);
932 if ((task->actionstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0)
933 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE);
934 if (task->actionstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_NORMAL)
935 return(task->actionstate.hw_disk);
936 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_NORMAL);
937 }
938
939 int
940 proc_get_task_selfdiskacc(void)
941 {
942 task_t task = current_task();
943 thread_t thread= current_thread();
944
945 /*
946 * As per defined iopolicysys behavior, thread trumps task.
947 * Do we need to follow that for external enforcements of BG or hw access?
948 * Status quo for now..
949 */
950 if((thread->ext_actionstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0)
951 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE);
952 if (thread->ext_actionstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_NORMAL)
953 return(thread->ext_actionstate.hw_disk);
954 if((thread->actionstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0)
955 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE);
956 if (thread->actionstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_NORMAL)
957 return(thread->actionstate.hw_disk);
958
959 if ((task->ext_actionstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0)
960 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE);
961 if (task->ext_actionstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_NORMAL)
962 return(task->ext_actionstate.hw_disk);
963 if ((task->actionstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0)
964 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE);
965 if (task->actionstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_NORMAL)
966 return(task->actionstate.hw_disk);
967 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_NORMAL);
968 }
969
970 int
971 proc_get_thread_selfdiskacc(void)
972 {
973 thread_t thread = current_thread();
974
975 if((thread->ext_actionstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0)
976 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE);
977 if (thread->ext_actionstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_NORMAL)
978 return(thread->ext_actionstate.hw_disk);
979 if((thread->actionstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0)
980 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE);
981 if (thread->actionstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_NORMAL)
982 return(thread->actionstate.hw_disk);
983 return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_NORMAL);
984 }
985
986 int proc_apply_task_diskacc(task_t task, int policy)
987 {
988 task_t self = current_task();
989
990 task_lock(task);
991 if (task == self) {
992 task->actionstate.hw_disk = policy;
993 task->policystate.hw_disk = policy;
994 } else {
995 task->ext_actionstate.hw_disk = policy;
996 task->ext_policystate.hw_disk = policy;
997 }
998 task_unlock(task);
999 return(0);
1000 }
1001
1002 int proc_apply_thread_diskacc(task_t task, uint64_t tid, int policy)
1003 {
1004 thread_t thread;
1005
1006 if (tid == TID_NULL) {
1007 thread = current_thread();
1008 proc_apply_thread_selfdiskacc(policy);
1009 } else {
1010 task_lock(task);
1011 thread = task_findtid(task, tid);
1012 if (thread != NULL) {
1013 thread->ext_actionstate.hw_disk = policy;
1014 thread->ext_policystate.hw_disk = policy;
1015 }
1016 task_unlock(task);
1017 }
1018 if (thread != NULL)
1019 return(0);
1020 else
1021 return(0);
1022 }
1023
1024 int
1025 proc_apply_thread_selfdiskacc(int policy)
1026 {
1027 task_t task = current_task();
1028 thread_t thread = current_thread();
1029
1030 task_lock(task);
1031 thread->actionstate.hw_disk = policy;
1032 thread->policystate.hw_disk = policy;
1033 task_unlock(task);
1034 return(0);
1035 }
1036
1037 int
1038 proc_denyinherit_policy(__unused task_t task)
1039 {
1040 return(0);
1041 }
1042
1043 int
1044 proc_denyselfset_policy(__unused task_t task)
1045 {
1046 return(0);
1047 }
1048
1049 /* HW GPU access related routines */
1050 int
1051 proc_get_task_selfgpuacc_deny(void)
1052 {
1053 task_t task = current_task();
1054 thread_t thread = current_thread();
1055
1056 if (((task->ext_actionstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_NOGPU) != 0) || (task->ext_actionstate.hw_gpu == TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS))
1057 return(TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS);
1058 if (((task->actionstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_NOGPU) != 0) || (task->actionstate.hw_gpu == TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS))
1059 return(TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS);
1060 if (((thread->ext_actionstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_NOGPU) != 0) || (thread->ext_actionstate.hw_gpu == TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS))
1061 return(TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS);
1062 if (((thread->actionstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_NOGPU) != 0) || (thread->actionstate.hw_gpu == TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS))
1063 return(TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS);
1064
1065 return(TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NORMAL);
1066 }
1067
1068 int
1069 proc_apply_task_gpuacc(task_t task, int policy)
1070 {
1071
1072 task_t self = current_task();
1073
1074 task_lock(task);
1075 if (task == self) {
1076 task->actionstate.hw_gpu = policy;
1077 task->policystate.hw_gpu = policy;
1078 } else {
1079 task->ext_actionstate.hw_gpu = policy;
1080 task->ext_policystate.hw_gpu = policy;
1081 }
1082 task_unlock(task);
1083
1084 return(0);
1085 }
1086
1087 /* Resource usage , CPU realted routines */
1088 int
1089 proc_get_task_ruse_cpu(task_t task, uint32_t * policyp, uint32_t * percentagep, uint64_t * intervalp, uint64_t * deadlinep)
1090 {
1091
1092 int error = 0;
1093
1094 task_lock(task);
1095 if (task != current_task()) {
1096 *policyp = task->ext_policystate.ru_cpu;
1097 } else {
1098 *policyp = task->policystate.ru_cpu;
1099 }
1100
1101 error = task_get_cpuusage(task, percentagep, intervalp, deadlinep);
1102
1103 return(error);
1104 }
1105
1106 int
1107 proc_set_task_ruse_cpu(task_t task, uint32_t policy, uint32_t percentage, uint64_t interval, uint64_t deadline)
1108 {
1109 int error = 0;
1110
1111 task_lock(task);
1112 if (task != current_task()) {
1113 task->ext_policystate.ru_cpu = policy;
1114 } else {
1115 task->policystate.ru_cpu = policy;
1116 }
1117 error = task_set_cpuusage(task, percentage, interval, deadline);
1118 task_unlock(task);
1119 return(error);
1120 }
1121
1122
1123 /* used to apply resource limit related actions */
1124 static int
1125 task_apply_resource_actions(task_t task, int type)
1126 {
1127 int action = TASK_POLICY_RESOURCE_ATTRIBUTE_NONE;
1128 void * bsdinfo = NULL;
1129
1130 switch (type) {
1131 case TASK_POLICY_CPU_RESOURCE_USAGE:
1132 break;
1133 case TASK_POLICY_WIREDMEM_RESOURCE_USAGE:
1134 case TASK_POLICY_VIRTUALMEM_RESOURCE_USAGE:
1135 case TASK_POLICY_DISK_RESOURCE_USAGE:
1136 case TASK_POLICY_NETWORK_RESOURCE_USAGE:
1137 case TASK_POLICY_POWER_RESOURCE_USAGE:
1138 return(0);
1139
1140 default:
1141 return(1);
1142 };
1143
1144 /* only cpu actions for now */
1145 task_lock(task);
1146
1147 if (task->ext_actionstate.ru_cpu == TASK_POLICY_RESOURCE_ATTRIBUTE_NONE) {
1148 /* apply action */
1149 task->ext_actionstate.ru_cpu = task->ext_policystate.ru_cpu;
1150 action = task->ext_actionstate.ru_cpu;
1151 }
1152 if (action != TASK_POLICY_RESOURCE_ATTRIBUTE_NONE) {
1153 bsdinfo = task->bsd_info;
1154 task_unlock(task);
1155 proc_apply_resource_actions(bsdinfo, TASK_POLICY_CPU_RESOURCE_USAGE, action);
1156 } else
1157 task_unlock(task);
1158
1159 return(0);
1160 }
1161
1162 int
1163 task_restore_resource_actions(task_t task, int type)
1164 {
1165 int action;
1166 void * bsdinfo = NULL;
1167
1168 switch (type) {
1169 case TASK_POLICY_CPU_RESOURCE_USAGE:
1170 break;
1171 case TASK_POLICY_WIREDMEM_RESOURCE_USAGE:
1172 case TASK_POLICY_VIRTUALMEM_RESOURCE_USAGE:
1173 case TASK_POLICY_DISK_RESOURCE_USAGE:
1174 case TASK_POLICY_NETWORK_RESOURCE_USAGE:
1175 case TASK_POLICY_POWER_RESOURCE_USAGE:
1176 return(0);
1177
1178 default:
1179 return(1);
1180 };
1181
1182 /* only cpu actions for now */
1183 task_lock(task);
1184
1185 action = task->ext_actionstate.ru_cpu;
1186 if (task->ext_actionstate.ru_cpu != TASK_POLICY_RESOURCE_ATTRIBUTE_NONE) {
1187 /* reset action */
1188 task->ext_actionstate.ru_cpu = TASK_POLICY_RESOURCE_ATTRIBUTE_NONE;
1189 }
1190 if (action != TASK_POLICY_RESOURCE_ATTRIBUTE_NONE) {
1191 bsdinfo = task->bsd_info;
1192 task_unlock(task);
1193 proc_restore_resource_actions(bsdinfo, TASK_POLICY_CPU_RESOURCE_USAGE, action);
1194 } else
1195 task_unlock(task);
1196
1197 return(0);
1198
1199 }
1200
1201 /* For ledger hookups */
1202 static int
1203 task_get_cpuusage(__unused task_t task, uint32_t * percentagep, uint64_t * intervalp, uint64_t * deadlinep)
1204 {
1205 *percentagep = 0;
1206 *intervalp = 0;
1207 *deadlinep = 0;
1208
1209 return(0);
1210 }
1211
1212 static int
1213 task_set_cpuusage(__unused task_t task, __unused uint32_t percentage, __unused uint64_t interval, __unused uint64_t deadline)
1214 {
1215 return(0);
1216 }
1217
1218 /* called by ledger unit to enforce action due to resource usage criteria being met */
1219 int
1220 task_action_cpuusage(task_t task)
1221 {
1222 return(task_apply_resource_actions(task, TASK_POLICY_CPU_RESOURCE_USAGE));
1223 }
1224
1225 int
1226 proc_disable_task_apptype(task_t task, int policy_subtype)
1227 {
1228 void * bsdinfo = NULL;
1229 int setbg = 0;
1230 int ret = 0;
1231 int maxpri = BASEPRI_DEFAULT;
1232
1233 task_lock(task);
1234
1235 if (task->ext_policystate.apptype != policy_subtype) {
1236 ret = EINVAL;
1237 goto out;
1238 }
1239
1240 #if !CONFIG_EMBEDDED
1241 switch (task->role) {
1242 case TASK_FOREGROUND_APPLICATION:
1243 maxpri = BASEPRI_FOREGROUND;
1244 break;
1245 case TASK_BACKGROUND_APPLICATION:
1246 maxpri = BASEPRI_BACKGROUND;
1247 break;
1248 default:
1249 maxpri = BASEPRI_DEFAULT;
1250 }
1251 #endif
1252
1253 if (task->ext_actionstate.apptype != PROC_POLICY_OSX_APPTYPE_NONE) {
1254 switch (task->ext_actionstate.apptype) {
1255 case PROC_POLICY_OSX_APPTYPE_TAL:
1256 /* disable foreground/background handling */
1257 task->ext_actionstate.apptype = PROC_POLICY_OSX_APPTYPE_NONE;
1258 /* external BG application removal */
1259 proc_restore_bgtaskpolicy_locked(task, 1, 1, maxpri);
1260 bsdinfo = task->bsd_info;
1261 setbg = 0;
1262 break;
1263
1264 case PROC_POLICY_OSX_APPTYPE_DBCLIENT:
1265 /* disable foreground/background handling */
1266 task->ext_actionstate.apptype = PROC_POLICY_OSX_APPTYPE_NONE;
1267 /* internal BG application removal */
1268 proc_restore_bgtaskpolicy_locked(task, 1, 0, maxpri);
1269 bsdinfo = task->bsd_info;
1270 setbg = 0;
1271 break;
1272
1273 default:
1274 ret = EINVAL;
1275 break;
1276 }
1277 } else
1278 ret = EINVAL;
1279
1280 out:
1281 task_unlock(task);
1282 /* if backgrounding action ... */
1283 if (bsdinfo != NULL)
1284 proc_set_task_networkbg(bsdinfo, setbg);
1285
1286 return(ret);
1287 }
1288
1289 int
1290 proc_enable_task_apptype(task_t task, int policy_subtype)
1291 {
1292 void * bsdinfo = NULL;
1293 int setbg = 0;
1294 int ret = 0;
1295
1296 task_lock(task);
1297
1298 if (task->ext_policystate.apptype != policy_subtype) {
1299 ret = EINVAL;
1300 goto out;
1301 }
1302
1303 if (task->ext_actionstate.apptype == PROC_POLICY_OSX_APPTYPE_NONE) {
1304 switch (task->ext_policystate.apptype) {
1305 case PROC_POLICY_OSX_APPTYPE_TAL:
1306 /* TAL policy is activated again */
1307 task->ext_actionstate.apptype = task->ext_policystate.apptype;
1308 if (task->role == TASK_BACKGROUND_APPLICATION) {
1309 if (task->role == TASK_BACKGROUND_APPLICATION) {
1310 proc_apply_bgtaskpolicy_locked(task, 1, 1);
1311 bsdinfo = task->bsd_info;
1312 setbg = 1;
1313 }
1314 }
1315 ret = 0;
1316 break;
1317 default:
1318 ret = EINVAL;
1319 }
1320 } else
1321 ret = EINVAL;
1322
1323 out:
1324 task_unlock(task);
1325 /* if backgrounding action ... */
1326 if (bsdinfo != NULL)
1327 proc_set_task_networkbg(bsdinfo, setbg);
1328
1329 return(ret);
1330 }
1331