]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/mk_sp.c
xnu-201.5.tar.gz
[apple/xnu.git] / osfmk / kern / mk_sp.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * @OSF_COPYRIGHT@
24 *
25 */
26
27 /***
28 *** ??? The following lines were picked up when code was incorporated
29 *** into this file from `kern/syscall_subr.c.' These should be moved
30 *** with the code if it moves again. Otherwise, they should be trimmed,
31 *** based on the files included above.
32 ***/
33
34 #include <mach/boolean.h>
35 #include <mach/thread_switch.h>
36 #include <ipc/ipc_port.h>
37 #include <ipc/ipc_space.h>
38 #include <kern/ipc_kobject.h>
39 #include <kern/processor.h>
40 #include <kern/sched.h>
41 #include <kern/sched_prim.h>
42 #include <kern/spl.h>
43 #include <kern/task.h>
44 #include <kern/thread.h>
45 #include <kern/ast.h>
46 #include <mach/policy.h>
47
48 #include <kern/syscall_subr.h>
49 #include <mach/mach_host_server.h>
50 #include <mach/mach_syscalls.h>
51
52 /***
53 *** ??? End of lines picked up when code was incorporated
54 *** into this file from `kern/syscall_subr.c.'
55 ***/
56
57 #include <kern/mk_sp.h>
58 #include <kern/misc_protos.h>
59 #include <kern/spl.h>
60 #include <kern/sched.h>
61 #include <kern/sched_prim.h>
62 #include <kern/assert.h>
63 #include <kern/thread.h>
64 #include <mach/mach_host_server.h>
65
66 /***
67 *** ??? The next two files supply the prototypes for `thread_set_policy()'
68 *** and `thread_policy.' These routines cannot stay here if they are
69 *** exported Mach system calls.
70 ***/
71 #include <mach/thread_act_server.h>
72 #include <mach/host_priv_server.h>
73 #include <sys/kdebug.h>
74
75 void
76 _mk_sp_thread_unblock(
77 thread_t thread)
78 {
79 if (!(thread->state & TH_IDLE))
80 thread_setrun(thread, TRUE, TAIL_Q);
81
82 thread->current_quantum = 0;
83 thread->metered_computation = 0;
84 thread->reason = AST_NONE;
85
86 KERNEL_DEBUG_CONSTANT(
87 MACHDBG_CODE(DBG_MACH_SCHED,MACH_MAKE_RUNNABLE) | DBG_FUNC_NONE,
88 (int)thread, (int)thread->sched_pri, 0, 0, 0);
89 }
90
91 void
92 _mk_sp_thread_done(
93 thread_t thread)
94 {
95 processor_t myprocessor = cpu_to_processor(cpu_number());
96
97 /*
98 * A running thread is being taken off a processor:
99 */
100 clock_get_uptime(&myprocessor->last_dispatch);
101 if (!(thread->state & TH_IDLE)) {
102 if ( first_quantum(myprocessor) &&
103 myprocessor->quantum_end > myprocessor->last_dispatch )
104 thread->current_quantum =
105 (myprocessor->quantum_end - myprocessor->last_dispatch);
106 else
107 thread->current_quantum = 0;
108
109 if (!(thread->sched_mode & TH_MODE_REALTIME)) {
110 if (thread->current_quantum < min_std_quantum) {
111 thread->reason |= AST_QUANTUM;
112 thread->current_quantum += std_quantum;
113 }
114 }
115 else
116 if (thread->current_quantum == 0)
117 thread->reason |= AST_QUANTUM;
118
119 thread->metered_computation +=
120 (myprocessor->last_dispatch - thread->computation_epoch);
121 }
122 }
123
124 void
125 _mk_sp_thread_begin(
126 thread_t thread)
127 {
128 processor_t myprocessor = cpu_to_processor(cpu_number());
129
130 /*
131 * The designated thread is beginning execution:
132 */
133 if (!(thread->state & TH_IDLE)) {
134 if (thread->current_quantum == 0)
135 thread->current_quantum =
136 (thread->sched_mode & TH_MODE_REALTIME)?
137 thread->realtime.computation: std_quantum;
138
139 myprocessor->quantum_end =
140 (myprocessor->last_dispatch + thread->current_quantum);
141 timer_call_enter1(&myprocessor->quantum_timer,
142 thread, myprocessor->quantum_end);
143
144 myprocessor->slice_quanta =
145 (thread->sched_mode & TH_MODE_TIMESHARE)?
146 myprocessor->processor_set->set_quanta: 1;
147
148 thread->computation_epoch = myprocessor->last_dispatch;
149 }
150 else {
151 timer_call_cancel(&myprocessor->quantum_timer);
152
153 myprocessor->slice_quanta = 1;
154 }
155 }
156
157 void
158 _mk_sp_thread_dispatch(
159 thread_t old_thread)
160 {
161 if (old_thread->reason & AST_QUANTUM)
162 thread_setrun(old_thread, FALSE, TAIL_Q);
163 else
164 thread_setrun(old_thread, FALSE, HEAD_Q);
165
166 old_thread->reason = AST_NONE;
167 }
168
169 /*
170 * thread_policy_common:
171 *
172 * Set scheduling policy & priority for thread.
173 */
174 static kern_return_t
175 thread_policy_common(
176 thread_t thread,
177 integer_t policy,
178 integer_t priority)
179 {
180 spl_t s;
181
182 if ( thread == THREAD_NULL ||
183 invalid_policy(policy) )
184 return(KERN_INVALID_ARGUMENT);
185
186 s = splsched();
187 thread_lock(thread);
188
189 if ( !(thread->sched_mode & TH_MODE_REALTIME) &&
190 !(thread->safe_mode & TH_MODE_REALTIME) ) {
191 if (!(thread->sched_mode & TH_MODE_FAILSAFE)) {
192 if (policy == POLICY_TIMESHARE)
193 thread->sched_mode |= TH_MODE_TIMESHARE;
194 else
195 thread->sched_mode &= ~TH_MODE_TIMESHARE;
196 }
197 else {
198 if (policy == POLICY_TIMESHARE)
199 thread->safe_mode |= TH_MODE_TIMESHARE;
200 else
201 thread->safe_mode &= ~TH_MODE_TIMESHARE;
202 }
203
204 if (priority >= thread->max_priority)
205 priority = thread->max_priority - thread->task_priority;
206 else
207 if (priority >= MINPRI_KERNEL)
208 priority -= MINPRI_KERNEL;
209 else
210 if (priority >= MINPRI_SYSTEM)
211 priority -= MINPRI_SYSTEM;
212 else
213 priority -= BASEPRI_DEFAULT;
214
215 priority += thread->task_priority;
216
217 if (priority > thread->max_priority)
218 priority = thread->max_priority;
219
220 thread->importance = priority - thread->task_priority;
221
222 /*
223 * Set priorities. If a depression is in progress,
224 * change the priority to restore.
225 */
226 if (thread->depress_priority >= 0)
227 thread->depress_priority = priority;
228 else {
229 thread->priority = priority;
230 compute_priority(thread, TRUE);
231
232 /*
233 * If the current thread has changed its
234 * priority let the ast code decide whether
235 * a different thread should run.
236 */
237 if (thread == current_thread())
238 ast_on(AST_BLOCK);
239 }
240 }
241
242 thread_unlock(thread);
243 splx(s);
244
245 return (KERN_SUCCESS);
246 }
247
248 /*
249 * thread_set_policy
250 *
251 * Set scheduling policy and parameters, both base and limit, for
252 * the given thread. Policy can be any policy implemented by the
253 * processor set, whether enabled or not.
254 */
255 kern_return_t
256 thread_set_policy(
257 thread_act_t thr_act,
258 processor_set_t pset,
259 policy_t policy,
260 policy_base_t base,
261 mach_msg_type_number_t base_count,
262 policy_limit_t limit,
263 mach_msg_type_number_t limit_count)
264 {
265 thread_t thread;
266 int max, bas;
267 kern_return_t result = KERN_SUCCESS;
268
269 if ( thr_act == THR_ACT_NULL ||
270 pset == PROCESSOR_SET_NULL )
271 return (KERN_INVALID_ARGUMENT);
272
273 thread = act_lock_thread(thr_act);
274 if (thread == THREAD_NULL) {
275 act_unlock_thread(thr_act);
276
277 return(KERN_INVALID_ARGUMENT);
278 }
279
280 if (pset != thread->processor_set) {
281 act_unlock_thread(thr_act);
282
283 return(KERN_FAILURE);
284 }
285
286 switch (policy) {
287
288 case POLICY_RR:
289 {
290 policy_rr_base_t rr_base = (policy_rr_base_t) base;
291 policy_rr_limit_t rr_limit = (policy_rr_limit_t) limit;
292
293 if ( base_count != POLICY_RR_BASE_COUNT ||
294 limit_count != POLICY_RR_LIMIT_COUNT ) {
295 result = KERN_INVALID_ARGUMENT;
296 break;
297 }
298
299 bas = rr_base->base_priority;
300 max = rr_limit->max_priority;
301 if (invalid_pri(bas) || invalid_pri(max)) {
302 result = KERN_INVALID_ARGUMENT;
303 break;
304 }
305
306 break;
307 }
308
309 case POLICY_FIFO:
310 {
311 policy_fifo_base_t fifo_base = (policy_fifo_base_t) base;
312 policy_fifo_limit_t fifo_limit = (policy_fifo_limit_t) limit;
313
314 if ( base_count != POLICY_FIFO_BASE_COUNT ||
315 limit_count != POLICY_FIFO_LIMIT_COUNT) {
316 result = KERN_INVALID_ARGUMENT;
317 break;
318 }
319
320 bas = fifo_base->base_priority;
321 max = fifo_limit->max_priority;
322 if (invalid_pri(bas) || invalid_pri(max)) {
323 result = KERN_INVALID_ARGUMENT;
324 break;
325 }
326
327 break;
328 }
329
330 case POLICY_TIMESHARE:
331 {
332 policy_timeshare_base_t ts_base = (policy_timeshare_base_t) base;
333 policy_timeshare_limit_t ts_limit =
334 (policy_timeshare_limit_t) limit;
335
336 if ( base_count != POLICY_TIMESHARE_BASE_COUNT ||
337 limit_count != POLICY_TIMESHARE_LIMIT_COUNT ) {
338 result = KERN_INVALID_ARGUMENT;
339 break;
340 }
341
342 bas = ts_base->base_priority;
343 max = ts_limit->max_priority;
344 if (invalid_pri(bas) || invalid_pri(max)) {
345 result = KERN_INVALID_ARGUMENT;
346 break;
347 }
348
349 break;
350 }
351
352 default:
353 result = KERN_INVALID_POLICY;
354 }
355
356 if (result != KERN_SUCCESS) {
357 act_unlock_thread(thr_act);
358
359 return(result);
360 }
361
362 result = thread_policy_common(thread, policy, bas);
363 act_unlock_thread(thr_act);
364
365 return(result);
366 }
367
368
369 /*
370 * thread_policy
371 *
372 * Set scheduling policy and parameters, both base and limit, for
373 * the given thread. Policy must be a policy which is enabled for the
374 * processor set. Change contained threads if requested.
375 */
376 kern_return_t
377 thread_policy(
378 thread_act_t thr_act,
379 policy_t policy,
380 policy_base_t base,
381 mach_msg_type_number_t count,
382 boolean_t set_limit)
383 {
384 thread_t thread;
385 processor_set_t pset;
386 kern_return_t result = KERN_SUCCESS;
387 policy_limit_t limit;
388 int limcount;
389 policy_rr_limit_data_t rr_limit;
390 policy_fifo_limit_data_t fifo_limit;
391 policy_timeshare_limit_data_t ts_limit;
392
393 if (thr_act == THR_ACT_NULL)
394 return (KERN_INVALID_ARGUMENT);
395
396 thread = act_lock_thread(thr_act);
397 pset = thread->processor_set;
398 if ( thread == THREAD_NULL ||
399 pset == PROCESSOR_SET_NULL ){
400 act_unlock_thread(thr_act);
401
402 return(KERN_INVALID_ARGUMENT);
403 }
404
405 if ( invalid_policy(policy) ||
406 ((POLICY_TIMESHARE | POLICY_RR | POLICY_FIFO) & policy) == 0 ) {
407 act_unlock_thread(thr_act);
408
409 return(KERN_INVALID_POLICY);
410 }
411
412 if (set_limit) {
413 /*
414 * Set scheduling limits to base priority.
415 */
416 switch (policy) {
417
418 case POLICY_RR:
419 {
420 policy_rr_base_t rr_base;
421
422 if (count != POLICY_RR_BASE_COUNT) {
423 result = KERN_INVALID_ARGUMENT;
424 break;
425 }
426
427 limcount = POLICY_RR_LIMIT_COUNT;
428 rr_base = (policy_rr_base_t) base;
429 rr_limit.max_priority = rr_base->base_priority;
430 limit = (policy_limit_t) &rr_limit;
431
432 break;
433 }
434
435 case POLICY_FIFO:
436 {
437 policy_fifo_base_t fifo_base;
438
439 if (count != POLICY_FIFO_BASE_COUNT) {
440 result = KERN_INVALID_ARGUMENT;
441 break;
442 }
443
444 limcount = POLICY_FIFO_LIMIT_COUNT;
445 fifo_base = (policy_fifo_base_t) base;
446 fifo_limit.max_priority = fifo_base->base_priority;
447 limit = (policy_limit_t) &fifo_limit;
448
449 break;
450 }
451
452 case POLICY_TIMESHARE:
453 {
454 policy_timeshare_base_t ts_base;
455
456 if (count != POLICY_TIMESHARE_BASE_COUNT) {
457 result = KERN_INVALID_ARGUMENT;
458 break;
459 }
460
461 limcount = POLICY_TIMESHARE_LIMIT_COUNT;
462 ts_base = (policy_timeshare_base_t) base;
463 ts_limit.max_priority = ts_base->base_priority;
464 limit = (policy_limit_t) &ts_limit;
465
466 break;
467 }
468
469 default:
470 result = KERN_INVALID_POLICY;
471 break;
472 }
473
474 }
475 else {
476 /*
477 * Use current scheduling limits. Ensure that the
478 * new base priority will not exceed current limits.
479 */
480 switch (policy) {
481
482 case POLICY_RR:
483 {
484 policy_rr_base_t rr_base;
485
486 if (count != POLICY_RR_BASE_COUNT) {
487 result = KERN_INVALID_ARGUMENT;
488 break;
489 }
490
491 limcount = POLICY_RR_LIMIT_COUNT;
492 rr_base = (policy_rr_base_t) base;
493 if (rr_base->base_priority > thread->max_priority) {
494 result = KERN_POLICY_LIMIT;
495 break;
496 }
497
498 rr_limit.max_priority = thread->max_priority;
499 limit = (policy_limit_t) &rr_limit;
500
501 break;
502 }
503
504 case POLICY_FIFO:
505 {
506 policy_fifo_base_t fifo_base;
507
508 if (count != POLICY_FIFO_BASE_COUNT) {
509 result = KERN_INVALID_ARGUMENT;
510 break;
511 }
512
513 limcount = POLICY_FIFO_LIMIT_COUNT;
514 fifo_base = (policy_fifo_base_t) base;
515 if (fifo_base->base_priority > thread->max_priority) {
516 result = KERN_POLICY_LIMIT;
517 break;
518 }
519
520 fifo_limit.max_priority = thread->max_priority;
521 limit = (policy_limit_t) &fifo_limit;
522
523 break;
524 }
525
526 case POLICY_TIMESHARE:
527 {
528 policy_timeshare_base_t ts_base;
529
530 if (count != POLICY_TIMESHARE_BASE_COUNT) {
531 result = KERN_INVALID_ARGUMENT;
532 break;
533 }
534
535 limcount = POLICY_TIMESHARE_LIMIT_COUNT;
536 ts_base = (policy_timeshare_base_t) base;
537 if (ts_base->base_priority > thread->max_priority) {
538 result = KERN_POLICY_LIMIT;
539 break;
540 }
541
542 ts_limit.max_priority = thread->max_priority;
543 limit = (policy_limit_t) &ts_limit;
544
545 break;
546 }
547
548 default:
549 result = KERN_INVALID_POLICY;
550 break;
551 }
552
553 }
554
555 act_unlock_thread(thr_act);
556
557 if (result == KERN_SUCCESS)
558 result = thread_set_policy(thr_act, pset,
559 policy, base, count, limit, limcount);
560
561 return(result);
562 }
563
564 /*
565 * Define shifts for simulating (5/8)**n
566 */
567
568 shift_data_t wait_shift[32] = {
569 {1,1},{1,3},{1,-3},{2,-7},{3,5},{3,-5},{4,-8},{5,7},
570 {5,-7},{6,-10},{7,10},{7,-9},{8,-11},{9,12},{9,-11},{10,-13},
571 {11,14},{11,-13},{12,-15},{13,17},{13,-15},{14,-17},{15,19},{16,18},
572 {16,-19},{17,22},{18,20},{18,-20},{19,26},{20,22},{20,-22},{21,-27}};
573
574 /*
575 * do_priority_computation:
576 *
577 * Calculate new priority for thread based on its base priority plus
578 * accumulated usage. PRI_SHIFT and PRI_SHIFT_2 convert from
579 * usage to priorities. SCHED_SHIFT converts for the scaling
580 * of the sched_usage field by SCHED_SCALE. This scaling comes
581 * from the multiplication by sched_load (thread_timer_delta)
582 * in sched.h. sched_load is calculated as a scaled overload
583 * factor in compute_mach_factor (mach_factor.c).
584 */
585 #ifdef PRI_SHIFT_2
586 #if PRI_SHIFT_2 > 0
587 #define do_priority_computation(thread, pri) \
588 MACRO_BEGIN \
589 (pri) = (thread)->priority /* start with base priority */ \
590 - ((thread)->sched_usage >> (PRI_SHIFT + SCHED_SHIFT)) \
591 - ((thread)->sched_usage >> (PRI_SHIFT_2 + SCHED_SHIFT)); \
592 if ((pri) < MINPRI_STANDARD) \
593 (pri) = MINPRI_STANDARD; \
594 else \
595 if ((pri) > MAXPRI_STANDARD) \
596 (pri) = MAXPRI_STANDARD; \
597 MACRO_END
598 #else /* PRI_SHIFT_2 */
599 #define do_priority_computation(thread, pri) \
600 MACRO_BEGIN \
601 (pri) = (thread)->priority /* start with base priority */ \
602 - ((thread)->sched_usage >> (PRI_SHIFT + SCHED_SHIFT)) \
603 + ((thread)->sched_usage >> (SCHED_SHIFT - PRI_SHIFT_2)); \
604 if ((pri) < MINPRI_STANDARD) \
605 (pri) = MINPRI_STANDARD; \
606 else \
607 if ((pri) > MAXPRI_STANDARD) \
608 (pri) = MAXPRI_STANDARD; \
609 MACRO_END
610 #endif /* PRI_SHIFT_2 */
611 #else /* defined(PRI_SHIFT_2) */
612 #define do_priority_computation(thread, pri) \
613 MACRO_BEGIN \
614 (pri) = (thread)->priority /* start with base priority */ \
615 - ((thread)->sched_usage >> (PRI_SHIFT + SCHED_SHIFT)); \
616 if ((pri) < MINPRI_STANDARD) \
617 (pri) = MINPRI_STANDARD; \
618 else \
619 if ((pri) > MAXPRI_STANDARD) \
620 (pri) = MAXPRI_STANDARD; \
621 MACRO_END
622 #endif /* defined(PRI_SHIFT_2) */
623
624 /*
625 * compute_priority:
626 *
627 * Compute the effective priority of the specified thread.
628 * The effective priority computation is as follows:
629 *
630 * Take the base priority for this thread and add
631 * to it an increment derived from its cpu_usage.
632 *
633 * The thread *must* be locked by the caller.
634 */
635
636 void
637 compute_priority(
638 register thread_t thread,
639 boolean_t resched)
640 {
641 register int pri;
642
643 if (thread->sched_mode & TH_MODE_TIMESHARE) {
644 do_priority_computation(thread, pri);
645 if (thread->depress_priority < 0)
646 set_pri(thread, pri, resched);
647 else
648 thread->depress_priority = pri;
649 }
650 else
651 set_pri(thread, thread->priority, resched);
652 }
653
654 /*
655 * compute_my_priority:
656 *
657 * Version of compute priority for current thread or thread
658 * being manipulated by scheduler (going on or off a runq).
659 * Only used for priority updates. Policy or priority changes
660 * must call compute_priority above. Caller must have thread
661 * locked and know it is timesharing and not depressed.
662 */
663
664 void
665 compute_my_priority(
666 register thread_t thread)
667 {
668 register int pri;
669
670 do_priority_computation(thread, pri);
671 assert(thread->runq == RUN_QUEUE_NULL);
672 thread->sched_pri = pri;
673 }
674
675 /*
676 * update_priority
677 *
678 * Cause the priority computation of a thread that has been
679 * sleeping or suspended to "catch up" with the system. Thread
680 * *MUST* be locked by caller. If thread is running, then this
681 * can only be called by the thread on itself.
682 */
683 void
684 update_priority(
685 register thread_t thread)
686 {
687 register unsigned int ticks;
688 register shift_t shiftp;
689
690 ticks = sched_tick - thread->sched_stamp;
691 assert(ticks != 0);
692
693 /*
694 * If asleep for more than 30 seconds forget all
695 * cpu_usage, else catch up on missed aging.
696 * 5/8 ** n is approximated by the two shifts
697 * in the wait_shift array.
698 */
699 thread->sched_stamp += ticks;
700 thread_timer_delta(thread);
701 if (ticks > 30) {
702 thread->cpu_usage = 0;
703 thread->sched_usage = 0;
704 }
705 else {
706 thread->cpu_usage += thread->cpu_delta;
707 thread->sched_usage += thread->sched_delta;
708
709 shiftp = &wait_shift[ticks];
710 if (shiftp->shift2 > 0) {
711 thread->cpu_usage =
712 (thread->cpu_usage >> shiftp->shift1) +
713 (thread->cpu_usage >> shiftp->shift2);
714 thread->sched_usage =
715 (thread->sched_usage >> shiftp->shift1) +
716 (thread->sched_usage >> shiftp->shift2);
717 }
718 else {
719 thread->cpu_usage =
720 (thread->cpu_usage >> shiftp->shift1) -
721 (thread->cpu_usage >> -(shiftp->shift2));
722 thread->sched_usage =
723 (thread->sched_usage >> shiftp->shift1) -
724 (thread->sched_usage >> -(shiftp->shift2));
725 }
726 }
727
728 thread->cpu_delta = 0;
729 thread->sched_delta = 0;
730
731 if ( (thread->sched_mode & TH_MODE_FAILSAFE) &&
732 thread->sched_stamp >= thread->safe_release ) {
733 if (!(thread->safe_mode & TH_MODE_TIMESHARE)) {
734 if (thread->safe_mode & TH_MODE_REALTIME) {
735 if (thread->depress_priority < 0)
736 thread->priority = BASEPRI_REALTIME;
737 else
738 thread->depress_priority = BASEPRI_REALTIME;
739
740 thread->sched_mode |= TH_MODE_REALTIME;
741 }
742
743 if ( thread->depress_priority < 0 &&
744 thread->sched_pri != thread->priority ) {
745 run_queue_t runq;
746
747 runq = rem_runq(thread);
748 thread->sched_pri = thread->priority;
749 if (runq != RUN_QUEUE_NULL)
750 thread_setrun(thread, TRUE, TAIL_Q);
751 }
752
753 thread->sched_mode &= ~TH_MODE_TIMESHARE;
754 }
755
756 thread->safe_mode = 0;
757 thread->sched_mode &= ~TH_MODE_FAILSAFE;
758 }
759
760 /*
761 * Recompute priority if appropriate.
762 */
763 if ( (thread->sched_mode & TH_MODE_TIMESHARE) &&
764 thread->depress_priority < 0 ) {
765 register int new_pri;
766
767 do_priority_computation(thread, new_pri);
768 if (new_pri != thread->sched_pri) {
769 run_queue_t runq;
770
771 runq = rem_runq(thread);
772 thread->sched_pri = new_pri;
773 if (runq != RUN_QUEUE_NULL)
774 thread_setrun(thread, TRUE, TAIL_Q);
775 }
776 }
777 }
778
779 /*
780 * thread_switch_continue:
781 *
782 * Continuation routine for a thread switch.
783 *
784 * Just need to arrange the return value gets sent out correctly and that
785 * we cancel the timer or the depression called for by the options to the
786 * thread_switch call.
787 */
788 void
789 _mk_sp_thread_switch_continue(void)
790 {
791 register thread_t self = current_thread();
792 int wait_result = self->wait_result;
793 int option = self->saved.swtch.option;
794
795 if (option == SWITCH_OPTION_WAIT && wait_result != THREAD_TIMED_OUT)
796 thread_cancel_timer();
797 else
798 if (option == SWITCH_OPTION_DEPRESS)
799 _mk_sp_thread_depress_abort(self, FALSE);
800
801 thread_syscall_return(KERN_SUCCESS);
802 /*NOTREACHED*/
803 }
804
805 /*
806 * thread_switch:
807 *
808 * Context switch. User may supply thread hint.
809 *
810 * Fixed priority threads that call this get what they asked for
811 * even if that violates priority order.
812 */
813 kern_return_t
814 _mk_sp_thread_switch(
815 thread_act_t hint_act,
816 int option,
817 mach_msg_timeout_t option_time)
818 {
819 register thread_t self = current_thread();
820 register processor_t myprocessor;
821 int s;
822
823 /*
824 * Check and use thr_act hint if appropriate. It is not
825 * appropriate to give a hint that shares the current shuttle.
826 */
827 if (hint_act != THR_ACT_NULL) {
828 register thread_t thread = act_lock_thread(hint_act);
829
830 if ( thread != THREAD_NULL &&
831 thread != self &&
832 thread->top_act == hint_act ) {
833 s = splsched();
834 thread_lock(thread);
835
836 /*
837 * Check if the thread is in the right pset. Then
838 * pull it off its run queue. If it
839 * doesn't come, then it's not eligible.
840 */
841 if ( thread->processor_set == self->processor_set &&
842 rem_runq(thread) != RUN_QUEUE_NULL ) {
843 /*
844 * Hah, got it!!
845 */
846 thread_unlock(thread);
847
848 act_unlock_thread(hint_act);
849 act_deallocate(hint_act);
850
851 if (option == SWITCH_OPTION_WAIT)
852 assert_wait_timeout(option_time, THREAD_ABORTSAFE);
853 else
854 if (option == SWITCH_OPTION_DEPRESS)
855 _mk_sp_thread_depress_ms(option_time);
856
857 self->saved.swtch.option = option;
858
859 thread_run(self, _mk_sp_thread_switch_continue, thread);
860 splx(s);
861
862 goto out;
863 }
864
865 thread_unlock(thread);
866 splx(s);
867 }
868
869 act_unlock_thread(hint_act);
870 act_deallocate(hint_act);
871 }
872
873 /*
874 * No handoff hint supplied, or hint was wrong. Call thread_block() in
875 * hopes of running something else. If nothing else is runnable,
876 * thread_block will detect this. WARNING: thread_switch with no
877 * option will not do anything useful if the thread calling it is the
878 * highest priority thread (can easily happen with a collection
879 * of timesharing threads).
880 */
881 mp_disable_preemption();
882 myprocessor = current_processor();
883 if ( option != SWITCH_OPTION_NONE ||
884 myprocessor->processor_set->runq.count > 0 ||
885 myprocessor->runq.count > 0 ) {
886 mp_enable_preemption();
887
888 if (option == SWITCH_OPTION_WAIT)
889 assert_wait_timeout(option_time, THREAD_ABORTSAFE);
890 else
891 if (option == SWITCH_OPTION_DEPRESS)
892 _mk_sp_thread_depress_ms(option_time);
893
894 self->saved.swtch.option = option;
895
896 thread_block(_mk_sp_thread_switch_continue);
897 }
898 else
899 mp_enable_preemption();
900
901 out:
902 if (option == SWITCH_OPTION_WAIT)
903 thread_cancel_timer();
904 else
905 if (option == SWITCH_OPTION_DEPRESS)
906 _mk_sp_thread_depress_abort(self, FALSE);
907
908 return (KERN_SUCCESS);
909 }
910
911 /*
912 * Depress thread's priority to lowest possible for the specified interval,
913 * with a value of zero resulting in no timeout being scheduled.
914 */
915 void
916 _mk_sp_thread_depress_abstime(
917 uint64_t interval)
918 {
919 register thread_t self = current_thread();
920 uint64_t deadline;
921 spl_t s;
922
923 s = splsched();
924 wake_lock(self);
925 thread_lock(self);
926 if (self->depress_priority < 0) {
927 self->depress_priority = self->priority;
928 self->sched_pri = self->priority = DEPRESSPRI;
929 thread_unlock(self);
930
931 if (interval != 0) {
932 clock_absolutetime_interval_to_deadline(interval, &deadline);
933 if (!timer_call_enter(&self->depress_timer, deadline))
934 self->depress_timer_active++;
935 }
936 }
937 else
938 thread_unlock(self);
939 wake_unlock(self);
940 splx(s);
941 }
942
943 void
944 _mk_sp_thread_depress_ms(
945 mach_msg_timeout_t interval)
946 {
947 uint64_t abstime;
948
949 clock_interval_to_absolutetime_interval(
950 interval, 1000*NSEC_PER_USEC, &abstime);
951 _mk_sp_thread_depress_abstime(abstime);
952 }
953
954 /*
955 * Priority depression expiration.
956 */
957 void
958 thread_depress_expire(
959 timer_call_param_t p0,
960 timer_call_param_t p1)
961 {
962 thread_t thread = p0;
963 spl_t s;
964
965 s = splsched();
966 wake_lock(thread);
967 if (--thread->depress_timer_active == 1) {
968 thread_lock(thread);
969 if (thread->depress_priority >= 0) {
970 thread->priority = thread->depress_priority;
971 thread->depress_priority = -1;
972 compute_priority(thread, TRUE);
973 }
974 else
975 if (thread->depress_priority == -2) {
976 /*
977 * Thread was temporarily undepressed by thread_suspend, to
978 * be redepressed in special_handler as it blocks. We need to
979 * prevent special_handler from redepressing it, since depression
980 * has timed out:
981 */
982 thread->depress_priority = -1;
983 }
984 thread->sched_mode &= ~TH_MODE_POLLDEPRESS;
985 thread_unlock(thread);
986 }
987 else
988 if (thread->depress_timer_active == 0)
989 thread_wakeup_one(&thread->depress_timer_active);
990 wake_unlock(thread);
991 splx(s);
992 }
993
994 /*
995 * Prematurely abort priority depression if there is one.
996 */
997 kern_return_t
998 _mk_sp_thread_depress_abort(
999 register thread_t thread,
1000 boolean_t abortall)
1001 {
1002 kern_return_t result = KERN_NOT_DEPRESSED;
1003 spl_t s;
1004
1005 s = splsched();
1006 wake_lock(thread);
1007 thread_lock(thread);
1008 if (abortall || !(thread->sched_mode & TH_MODE_POLLDEPRESS)) {
1009 if (thread->depress_priority >= 0) {
1010 thread->priority = thread->depress_priority;
1011 thread->depress_priority = -1;
1012 compute_priority(thread, TRUE);
1013 result = KERN_SUCCESS;
1014 }
1015
1016 thread->sched_mode &= ~TH_MODE_POLLDEPRESS;
1017 thread_unlock(thread);
1018
1019 if (timer_call_cancel(&thread->depress_timer))
1020 thread->depress_timer_active--;
1021 }
1022 else
1023 thread_unlock(thread);
1024 wake_unlock(thread);
1025 splx(s);
1026
1027 return (result);
1028 }
1029
1030 void
1031 _mk_sp_thread_perhaps_yield(
1032 thread_t self)
1033 {
1034 spl_t s;
1035
1036 assert(self == current_thread());
1037
1038 s = splsched();
1039 thread_lock(self);
1040 if (!(self->sched_mode & (TH_MODE_REALTIME|TH_MODE_TIMESHARE))) {
1041 extern uint64_t max_poll_computation;
1042 extern int sched_poll_yield_shift;
1043 uint64_t abstime, total_computation;
1044
1045 clock_get_uptime(&abstime);
1046 total_computation = abstime - self->computation_epoch;
1047 total_computation += self->metered_computation;
1048 if (total_computation >= max_poll_computation) {
1049 processor_t myprocessor;
1050
1051 thread_unlock(self);
1052
1053 wake_lock(self);
1054 thread_lock(self);
1055 if (self->depress_priority < 0) {
1056 self->depress_priority = self->priority;
1057 self->sched_pri = self->priority = DEPRESSPRI;
1058 }
1059 self->computation_epoch = abstime;
1060 self->metered_computation = 0;
1061 self->sched_mode |= TH_MODE_POLLDEPRESS;
1062 thread_unlock(self);
1063
1064 abstime += (total_computation >> sched_poll_yield_shift);
1065 if (!timer_call_enter(&self->depress_timer, abstime))
1066 self->depress_timer_active++;
1067 wake_unlock(self);
1068
1069 myprocessor = current_processor();
1070 if (csw_needed(self, myprocessor))
1071 ast_on(AST_BLOCK);
1072 }
1073 else
1074 thread_unlock(self);
1075 }
1076 else
1077 thread_unlock(self);
1078
1079 splx(s);
1080 }