]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/sched_proto.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / osfmk / kern / sched_proto.c
CommitLineData
6d2010ae
A
1/*
2 * Copyright (c) 2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
6d2010ae
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
0a7de745 14 *
6d2010ae
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
6d2010ae
A
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
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.
0a7de745 25 *
6d2010ae
A
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#include <mach/mach_types.h>
30#include <mach/machine.h>
31#include <mach/policy.h>
32#include <mach/sync_policy.h>
33#include <mach/thread_act.h>
34
35#include <machine/machine_routines.h>
36#include <machine/sched_param.h>
37#include <machine/machine_cpu.h>
38
39#include <kern/kern_types.h>
40#include <kern/clock.h>
41#include <kern/counters.h>
42#include <kern/cpu_number.h>
43#include <kern/cpu_data.h>
44#include <kern/debug.h>
6d2010ae
A
45#include <kern/macro_help.h>
46#include <kern/machine.h>
47#include <kern/misc_protos.h>
48#include <kern/processor.h>
49#include <kern/queue.h>
50#include <kern/sched.h>
51#include <kern/sched_prim.h>
52#include <kern/syscall_subr.h>
53#include <kern/task.h>
54#include <kern/thread.h>
6d2010ae
A
55
56#include <vm/pmap.h>
57#include <vm/vm_kern.h>
58#include <vm/vm_map.h>
59
60#include <mach/sdt.h>
61
62#include <sys/kdebug.h>
63
64static void
65sched_proto_init(void);
66
67static void
68sched_proto_timebase_init(void);
69
70static void
71sched_proto_processor_init(processor_t processor);
72
73static void
74sched_proto_pset_init(processor_set_t pset);
75
76static void
77sched_proto_maintenance_continuation(void);
78
79static thread_t
0a7de745
A
80sched_proto_choose_thread(processor_t processor,
81 int priority,
82 ast_t reason);
6d2010ae
A
83
84static thread_t
0a7de745 85sched_proto_steal_thread(processor_set_t pset);
6d2010ae 86
3e170ce0
A
87static int
88sched_proto_compute_priority(thread_t thread);
6d2010ae
A
89
90static processor_t
0a7de745
A
91sched_proto_choose_processor( processor_set_t pset,
92 processor_t processor,
93 thread_t thread);
6d2010ae
A
94
95
96static boolean_t
97sched_proto_processor_enqueue(
0a7de745
A
98 processor_t processor,
99 thread_t thread,
cb323159 100 sched_options_t options);
6d2010ae
A
101
102static void
103sched_proto_processor_queue_shutdown(
0a7de745 104 processor_t processor);
6d2010ae
A
105
106static boolean_t
107sched_proto_processor_queue_remove(
0a7de745
A
108 processor_t processor,
109 thread_t thread);
6d2010ae
A
110
111static boolean_t
0a7de745 112sched_proto_processor_queue_empty(processor_t processor);
6d2010ae
A
113
114static boolean_t
0a7de745
A
115sched_proto_processor_queue_has_priority(processor_t processor,
116 int priority,
117 boolean_t gte);
6d2010ae
A
118
119static boolean_t
120sched_proto_priority_is_urgent(int priority);
121
122static ast_t
123sched_proto_processor_csw_check(processor_t processor);
124
125static uint32_t
126sched_proto_initial_quantum_size(thread_t thread);
127
128static sched_mode_t
129sched_proto_initial_thread_sched_mode(task_t parent_task);
130
6d2010ae 131static boolean_t
0a7de745 132sched_proto_can_update_priority(thread_t thread);
6d2010ae
A
133
134static void
0a7de745 135sched_proto_update_priority(thread_t thread);
6d2010ae
A
136
137static void
0a7de745 138sched_proto_lightweight_update_priority(thread_t thread);
6d2010ae
A
139
140static void
0a7de745 141sched_proto_quantum_expire(thread_t thread);
6d2010ae 142
6d2010ae
A
143static int
144sched_proto_processor_runq_count(processor_t processor);
145
146static uint64_t
147sched_proto_processor_runq_stats_count_sum(processor_t processor);
148
fe8ab488
A
149static int
150sched_proto_processor_bound_count(processor_t processor);
151
152static void
3e170ce0 153sched_proto_thread_update_scan(sched_update_scan_context_t scan_context);
fe8ab488
A
154
155
6d2010ae 156const struct sched_dispatch_table sched_proto_dispatch = {
3e170ce0 157 .sched_name = "proto",
fe8ab488
A
158 .init = sched_proto_init,
159 .timebase_init = sched_proto_timebase_init,
160 .processor_init = sched_proto_processor_init,
161 .pset_init = sched_proto_pset_init,
162 .maintenance_continuation = sched_proto_maintenance_continuation,
163 .choose_thread = sched_proto_choose_thread,
0a7de745 164 .steal_thread_enabled = sched_steal_thread_DISABLED,
fe8ab488 165 .steal_thread = sched_proto_steal_thread,
3e170ce0 166 .compute_timeshare_priority = sched_proto_compute_priority,
f427ee49 167 .choose_node = sched_choose_node,
fe8ab488
A
168 .choose_processor = sched_proto_choose_processor,
169 .processor_enqueue = sched_proto_processor_enqueue,
170 .processor_queue_shutdown = sched_proto_processor_queue_shutdown,
171 .processor_queue_remove = sched_proto_processor_queue_remove,
172 .processor_queue_empty = sched_proto_processor_queue_empty,
173 .priority_is_urgent = sched_proto_priority_is_urgent,
174 .processor_csw_check = sched_proto_processor_csw_check,
175 .processor_queue_has_priority = sched_proto_processor_queue_has_priority,
176 .initial_quantum_size = sched_proto_initial_quantum_size,
177 .initial_thread_sched_mode = sched_proto_initial_thread_sched_mode,
178 .can_update_priority = sched_proto_can_update_priority,
179 .update_priority = sched_proto_update_priority,
180 .lightweight_update_priority = sched_proto_lightweight_update_priority,
181 .quantum_expire = sched_proto_quantum_expire,
fe8ab488
A
182 .processor_runq_count = sched_proto_processor_runq_count,
183 .processor_runq_stats_count_sum = sched_proto_processor_runq_stats_count_sum,
fe8ab488
A
184 .processor_bound_count = sched_proto_processor_bound_count,
185 .thread_update_scan = sched_proto_thread_update_scan,
3e170ce0
A
186 .multiple_psets_enabled = TRUE,
187 .sched_groups_enabled = FALSE,
5ba3f43e
A
188 .avoid_processor_enabled = FALSE,
189 .thread_avoid_processor = NULL,
190 .processor_balance = sched_SMT_balance,
191
f427ee49
A
192 .rt_runq = sched_rtlocal_runq,
193 .rt_init = sched_rtlocal_init,
194 .rt_queue_shutdown = sched_rtlocal_queue_shutdown,
195 .rt_runq_scan = sched_rtlocal_runq_scan,
196 .rt_runq_count_sum = sched_rtlocal_runq_count_sum,
5ba3f43e
A
197
198 .qos_max_parallelism = sched_qos_max_parallelism,
199 .check_spill = sched_check_spill,
200 .ipi_policy = sched_ipi_policy,
201 .thread_should_yield = sched_thread_should_yield,
cb323159
A
202 .run_count_incr = sched_run_incr,
203 .run_count_decr = sched_run_decr,
204 .update_thread_bucket = sched_update_thread_bucket,
205 .pset_made_schedulable = sched_pset_made_schedulable,
6d2010ae
A
206};
207
0a7de745
A
208static struct run_queue *global_runq;
209static struct run_queue global_runq_storage;
6d2010ae 210
0a7de745
A
211#define GLOBAL_RUNQ ((processor_t)-2)
212decl_simple_lock_data(static, global_runq_lock);
6d2010ae 213
0a7de745 214extern int max_unsafe_quanta;
6d2010ae
A
215
216static uint32_t proto_quantum_us;
217static uint32_t proto_quantum;
218
0a7de745 219static uint32_t runqueue_generation;
6d2010ae
A
220
221static processor_t proto_processor;
222
0a7de745
A
223static uint64_t sched_proto_tick_deadline;
224static uint32_t sched_proto_tick;
6d2010ae
A
225
226static void
227sched_proto_init(void)
228{
0a7de745
A
229 proto_quantum_us = 10 * 1000;
230
6d2010ae
A
231 printf("standard proto timeslicing quantum is %d us\n", proto_quantum_us);
232
233 simple_lock_init(&global_runq_lock, 0);
234 global_runq = &global_runq_storage;
235 run_queue_init(global_runq);
236 runqueue_generation = 0;
0a7de745 237
6d2010ae
A
238 proto_processor = master_processor;
239}
240
241static void
242sched_proto_timebase_init(void)
243{
0a7de745 244 uint64_t abstime;
6d2010ae
A
245
246 /* standard timeslicing quantum */
247 clock_interval_to_absolutetime_interval(
0a7de745 248 proto_quantum_us, NSEC_PER_USEC, &abstime);
6d2010ae
A
249 assert((abstime >> 32) == 0 && (uint32_t)abstime != 0);
250 proto_quantum = (uint32_t)abstime;
0a7de745 251
6d2010ae
A
252 thread_depress_time = 1 * proto_quantum;
253 default_timeshare_computation = proto_quantum / 2;
254 default_timeshare_constraint = proto_quantum;
0a7de745 255
6d2010ae
A
256 max_unsafe_computation = max_unsafe_quanta * proto_quantum;
257 sched_safe_duration = 2 * max_unsafe_quanta * proto_quantum;
6d2010ae
A
258}
259
260static void
261sched_proto_processor_init(processor_t processor __unused)
262{
263 /* No per-processor state */
264}
265
266static void
267sched_proto_pset_init(processor_set_t pset __unused)
268{
269}
270
271static void
272sched_proto_maintenance_continuation(void)
273{
0a7de745
A
274 uint64_t abstime = mach_absolute_time();
275
6d2010ae 276 sched_proto_tick++;
0a7de745 277
6d2010ae
A
278 /* Every 8 seconds, switch to another processor */
279 if ((sched_proto_tick & 0x7) == 0) {
280 processor_t new_processor;
0a7de745 281
6d2010ae 282 new_processor = proto_processor->processor_list;
0a7de745 283 if (new_processor == PROCESSOR_NULL) {
6d2010ae 284 proto_processor = master_processor;
0a7de745 285 } else {
6d2010ae 286 proto_processor = new_processor;
0a7de745 287 }
6d2010ae 288 }
0a7de745
A
289
290
6d2010ae
A
291 /*
292 * Compute various averages.
293 */
39236c6e 294 compute_averages(1);
0a7de745
A
295
296 if (sched_proto_tick_deadline == 0) {
6d2010ae 297 sched_proto_tick_deadline = abstime;
0a7de745
A
298 }
299
6d2010ae 300 clock_deadline_for_periodic_event(sched_one_second_interval, abstime,
0a7de745
A
301 &sched_proto_tick_deadline);
302
6d2010ae
A
303 assert_wait_deadline((event_t)sched_proto_maintenance_continuation, THREAD_UNINT, sched_proto_tick_deadline);
304 thread_block((thread_continue_t)sched_proto_maintenance_continuation);
305 /*NOTREACHED*/
306}
307
308static thread_t
0a7de745
A
309sched_proto_choose_thread(processor_t processor,
310 int priority,
311 ast_t reason __unused)
6d2010ae 312{
0a7de745 313 run_queue_t rq = global_runq;
cb323159 314 circle_queue_t queue;
0a7de745
A
315 int pri, count;
316 thread_t thread;
317
318
319 simple_lock(&global_runq_lock, LCK_GRP_NULL);
320
6d2010ae
A
321 queue = rq->queues + rq->highq;
322 pri = rq->highq;
323 count = rq->count;
0a7de745 324
6d2010ae
A
325 /*
326 * Since we don't depress priorities, a high priority thread
327 * may get selected over and over again. Put a runqueue
328 * generation number in the thread structure so that we
329 * can ensure that we've cycled through all runnable tasks
330 * before coming back to a high priority thread. This isn't
331 * perfect, especially if the number of runnable threads always
332 * stays high, but is a workable approximation
333 */
0a7de745 334
6d2010ae 335 while (count > 0 && pri >= priority) {
cb323159 336 cqe_foreach_element_safe(thread, queue, runq_links) {
6d2010ae 337 if ((thread->bound_processor == PROCESSOR_NULL ||
0a7de745
A
338 thread->bound_processor == processor) &&
339 runqueue_generation != thread->runqueue_generation) {
cb323159 340 circle_dequeue(queue, &thread->runq_links);
0a7de745 341
6d2010ae
A
342 thread->runq = PROCESSOR_NULL;
343 thread->runqueue_generation = runqueue_generation;
344 SCHED_STATS_RUNQ_CHANGE(&rq->runq_stats, rq->count);
345 rq->count--;
cb323159 346 if (circle_queue_empty(queue)) {
39037602
A
347 bitmap_clear(rq->bitmap, pri);
348 rq->highq = bitmap_first(rq->bitmap, NRQS);
6d2010ae 349 }
0a7de745 350
6d2010ae 351 simple_unlock(&global_runq_lock);
0a7de745 352 return thread;
6d2010ae
A
353 }
354 count--;
0a7de745 355
6d2010ae
A
356 thread = (thread_t)queue_next((queue_entry_t)thread);
357 }
0a7de745 358
6d2010ae
A
359 queue--; pri--;
360 }
0a7de745 361
6d2010ae 362 runqueue_generation++;
0a7de745 363
6d2010ae 364 simple_unlock(&global_runq_lock);
0a7de745 365 return THREAD_NULL;
6d2010ae
A
366}
367
368static thread_t
0a7de745 369sched_proto_steal_thread(processor_set_t pset)
6d2010ae
A
370{
371 pset_unlock(pset);
0a7de745
A
372
373 return THREAD_NULL;
6d2010ae
A
374}
375
3e170ce0
A
376static int
377sched_proto_compute_priority(thread_t thread)
6d2010ae 378{
3e170ce0 379 return thread->base_pri;
6d2010ae
A
380}
381
382static processor_t
0a7de745
A
383sched_proto_choose_processor( processor_set_t pset,
384 processor_t processor,
385 thread_t thread __unused)
6d2010ae
A
386{
387 processor = proto_processor;
0a7de745 388
6d2010ae
A
389 /*
390 * Check that the correct processor set is
391 * returned locked.
392 */
393 if (pset != processor->processor_set) {
394 pset_unlock(pset);
0a7de745 395
6d2010ae
A
396 pset = processor->processor_set;
397 pset_lock(pset);
398 }
0a7de745
A
399
400 return processor;
6d2010ae
A
401}
402
403static boolean_t
404sched_proto_processor_enqueue(
0a7de745
A
405 processor_t processor __unused,
406 thread_t thread,
cb323159 407 sched_options_t options)
6d2010ae 408{
0a7de745
A
409 run_queue_t rq = global_runq;
410 boolean_t result;
411
412 simple_lock(&global_runq_lock, LCK_GRP_NULL);
6d2010ae
A
413 result = run_queue_enqueue(rq, thread, options);
414 thread->runq = GLOBAL_RUNQ;
415 simple_unlock(&global_runq_lock);
0a7de745
A
416
417 return result;
6d2010ae
A
418}
419
420static void
421sched_proto_processor_queue_shutdown(
0a7de745 422 processor_t processor)
6d2010ae
A
423{
424 /* With a global runqueue, just stop choosing this processor */
425 (void)processor;
426}
427
428static boolean_t
429sched_proto_processor_queue_remove(
0a7de745
A
430 processor_t processor,
431 thread_t thread)
6d2010ae 432{
0a7de745
A
433 void * rqlock;
434 run_queue_t rq;
3e170ce0 435
6d2010ae
A
436 rqlock = &global_runq_lock;
437 rq = global_runq;
0a7de745
A
438
439 simple_lock(rqlock, LCK_GRP_NULL);
6d2010ae
A
440 if (processor == thread->runq) {
441 /*
442 * Thread is on a run queue and we have a lock on
443 * that run queue.
444 */
cb323159 445 run_queue_remove(rq, thread);
0a7de745 446 } else {
6d2010ae
A
447 /*
448 * The thread left the run queue before we could
0a7de745 449 * lock the run queue.
6d2010ae
A
450 */
451 assert(thread->runq == PROCESSOR_NULL);
452 processor = PROCESSOR_NULL;
453 }
0a7de745 454
6d2010ae 455 simple_unlock(rqlock);
0a7de745
A
456
457 return processor != PROCESSOR_NULL;
6d2010ae
A
458}
459
460static boolean_t
0a7de745 461sched_proto_processor_queue_empty(processor_t processor __unused)
6d2010ae
A
462{
463 boolean_t result;
0a7de745 464
6d2010ae 465 result = (global_runq->count == 0);
0a7de745 466
6d2010ae
A
467 return result;
468}
469
470static boolean_t
0a7de745
A
471sched_proto_processor_queue_has_priority(processor_t processor __unused,
472 int priority,
473 boolean_t gte)
6d2010ae
A
474{
475 boolean_t result;
6d2010ae 476
0a7de745
A
477 simple_lock(&global_runq_lock, LCK_GRP_NULL);
478
479 if (gte) {
6d2010ae 480 result = global_runq->highq >= priority;
0a7de745 481 } else {
5ba3f43e 482 result = global_runq->highq > priority;
0a7de745 483 }
6d2010ae
A
484
485 simple_unlock(&global_runq_lock);
0a7de745 486
6d2010ae
A
487 return result;
488}
489
490/* Implement sched_preempt_pri in code */
491static boolean_t
492sched_proto_priority_is_urgent(int priority)
493{
0a7de745 494 if (priority <= BASEPRI_FOREGROUND) {
6d2010ae 495 return FALSE;
0a7de745
A
496 }
497
498 if (priority < MINPRI_KERNEL) {
6d2010ae 499 return TRUE;
0a7de745 500 }
6d2010ae 501
0a7de745 502 if (priority >= BASEPRI_PREEMPT) {
6d2010ae 503 return TRUE;
0a7de745
A
504 }
505
6d2010ae
A
506 return FALSE;
507}
508
509static ast_t
3e170ce0 510sched_proto_processor_csw_check(processor_t processor)
6d2010ae 511{
0a7de745
A
512 run_queue_t runq;
513 int count, urgency;
514
6d2010ae
A
515 runq = global_runq;
516 count = runq->count;
517 urgency = runq->urgency;
0a7de745 518
6d2010ae 519 if (count > 0) {
0a7de745
A
520 if (urgency > 0) {
521 return AST_PREEMPT | AST_URGENT;
522 }
523
6d2010ae
A
524 return AST_PREEMPT;
525 }
3e170ce0 526
0a7de745 527 if (proto_processor != processor) {
3e170ce0 528 return AST_PREEMPT;
0a7de745 529 }
3e170ce0 530
6d2010ae
A
531 return AST_NONE;
532}
533
534static uint32_t
535sched_proto_initial_quantum_size(thread_t thread __unused)
536{
537 return proto_quantum;
538}
539
540static sched_mode_t
541sched_proto_initial_thread_sched_mode(task_t parent_task)
542{
0a7de745 543 if (parent_task == kernel_task) {
6d2010ae 544 return TH_MODE_FIXED;
0a7de745
A
545 } else {
546 return TH_MODE_TIMESHARE;
547 }
6d2010ae
A
548}
549
6d2010ae 550static boolean_t
0a7de745 551sched_proto_can_update_priority(thread_t thread __unused)
6d2010ae
A
552{
553 return FALSE;
554}
555
556static void
0a7de745 557sched_proto_update_priority(thread_t thread __unused)
6d2010ae 558{
6d2010ae
A
559}
560
561static void
0a7de745 562sched_proto_lightweight_update_priority(thread_t thread __unused)
6d2010ae 563{
6d2010ae
A
564}
565
566static void
3e170ce0 567sched_proto_quantum_expire(thread_t thread __unused)
6d2010ae 568{
6d2010ae
A
569}
570
6d2010ae
A
571static int
572sched_proto_processor_runq_count(processor_t processor)
573{
574 if (master_processor == processor) {
575 return global_runq->count;
576 } else {
577 return 0;
0a7de745 578 }
6d2010ae
A
579}
580
581static uint64_t
582sched_proto_processor_runq_stats_count_sum(processor_t processor)
583{
584 if (master_processor == processor) {
585 return global_runq->runq_stats.count_sum;
586 } else {
587 return 0ULL;
588 }
589}
590
fe8ab488
A
591static int
592sched_proto_processor_bound_count(__unused processor_t processor)
593{
594 return 0;
595}
596
597static void
3e170ce0 598sched_proto_thread_update_scan(__unused sched_update_scan_context_t scan_context)
fe8ab488 599{
fe8ab488 600}