]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/processor.c
xnu-4570.20.62.tar.gz
[apple/xnu.git] / osfmk / kern / processor.c
1 /*
2 * Copyright (c) 2000-2009 Apple 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 * @OSF_COPYRIGHT@
30 */
31 /*
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University
34 * All Rights Reserved.
35 *
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
41 *
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56 /*
57 */
58
59 /*
60 * processor.c: processor and processor_set manipulation routines.
61 */
62
63 #include <mach/boolean.h>
64 #include <mach/policy.h>
65 #include <mach/processor.h>
66 #include <mach/processor_info.h>
67 #include <mach/vm_param.h>
68 #include <kern/cpu_number.h>
69 #include <kern/host.h>
70 #include <kern/machine.h>
71 #include <kern/misc_protos.h>
72 #include <kern/processor.h>
73 #include <kern/sched.h>
74 #include <kern/task.h>
75 #include <kern/thread.h>
76 #include <kern/ipc_host.h>
77 #include <kern/ipc_tt.h>
78 #include <ipc/ipc_port.h>
79 #include <kern/kalloc.h>
80
81 #include <security/mac_mach_internal.h>
82
83
84 /*
85 * Exported interface
86 */
87 #include <mach/mach_host_server.h>
88 #include <mach/processor_set_server.h>
89
90 struct processor_set pset0;
91 struct pset_node pset_node0;
92 decl_simple_lock_data(static,pset_node_lock)
93
94 queue_head_t tasks;
95 queue_head_t terminated_tasks; /* To be used ONLY for stackshot. */
96 queue_head_t corpse_tasks;
97 int tasks_count;
98 int terminated_tasks_count;
99 queue_head_t threads;
100 int threads_count;
101 decl_lck_mtx_data(,tasks_threads_lock)
102 decl_lck_mtx_data(,tasks_corpse_lock)
103
104 processor_t processor_list;
105 unsigned int processor_count;
106 static processor_t processor_list_tail;
107 decl_simple_lock_data(,processor_list_lock)
108
109 uint32_t processor_avail_count;
110
111 processor_t master_processor;
112 int master_cpu = 0;
113 boolean_t sched_stats_active = FALSE;
114
115 processor_t processor_array[MAX_SCHED_CPUS] = { 0 };
116
117
118
119 void
120 processor_bootstrap(void)
121 {
122 pset_init(&pset0, &pset_node0);
123 pset_node0.psets = &pset0;
124
125 simple_lock_init(&pset_node_lock, 0);
126
127 queue_init(&tasks);
128 queue_init(&terminated_tasks);
129 queue_init(&threads);
130 queue_init(&corpse_tasks);
131
132 simple_lock_init(&processor_list_lock, 0);
133
134 master_processor = cpu_to_processor(master_cpu);
135
136 processor_init(master_processor, master_cpu, &pset0);
137 }
138
139 /*
140 * Initialize the given processor for the cpu
141 * indicated by cpu_id, and assign to the
142 * specified processor set.
143 */
144 void
145 processor_init(
146 processor_t processor,
147 int cpu_id,
148 processor_set_t pset)
149 {
150 spl_t s;
151
152 if (processor != master_processor) {
153 /* Scheduler state for master_processor initialized in sched_init() */
154 SCHED(processor_init)(processor);
155 }
156
157 processor->state = PROCESSOR_OFF_LINE;
158 processor->active_thread = processor->next_thread = processor->idle_thread = THREAD_NULL;
159 processor->processor_set = pset;
160 processor_state_update_idle(processor);
161 processor->starting_pri = MINPRI;
162 processor->cpu_id = cpu_id;
163 timer_call_setup(&processor->quantum_timer, thread_quantum_expire, processor);
164 processor->quantum_end = UINT64_MAX;
165 processor->deadline = UINT64_MAX;
166 processor->first_timeslice = FALSE;
167 processor->processor_primary = processor; /* no SMT relationship known at this point */
168 processor->processor_secondary = NULL;
169 processor->is_SMT = FALSE;
170 processor->is_recommended = (pset->recommended_bitmask & (1ULL << cpu_id)) ? TRUE : FALSE;
171 processor->processor_self = IP_NULL;
172 processor_data_init(processor);
173 processor->processor_list = NULL;
174
175 s = splsched();
176 pset_lock(pset);
177 bit_set(pset->cpu_bitmask, cpu_id);
178 if (pset->cpu_set_count++ == 0)
179 pset->cpu_set_low = pset->cpu_set_hi = cpu_id;
180 else {
181 pset->cpu_set_low = (cpu_id < pset->cpu_set_low)? cpu_id: pset->cpu_set_low;
182 pset->cpu_set_hi = (cpu_id > pset->cpu_set_hi)? cpu_id: pset->cpu_set_hi;
183 }
184 pset_unlock(pset);
185 splx(s);
186
187 simple_lock(&processor_list_lock);
188 if (processor_list == NULL)
189 processor_list = processor;
190 else
191 processor_list_tail->processor_list = processor;
192 processor_list_tail = processor;
193 processor_count++;
194 assert(cpu_id < MAX_SCHED_CPUS);
195 processor_array[cpu_id] = processor;
196 simple_unlock(&processor_list_lock);
197 }
198
199 void
200 processor_set_primary(
201 processor_t processor,
202 processor_t primary)
203 {
204 assert(processor->processor_primary == primary || processor->processor_primary == processor);
205 /* Re-adjust primary point for this (possibly) secondary processor */
206 processor->processor_primary = primary;
207
208 assert(primary->processor_secondary == NULL || primary->processor_secondary == processor);
209 if (primary != processor) {
210 /* Link primary to secondary, assumes a 2-way SMT model
211 * We'll need to move to a queue if any future architecture
212 * requires otherwise.
213 */
214 assert(processor->processor_secondary == NULL);
215 primary->processor_secondary = processor;
216 /* Mark both processors as SMT siblings */
217 primary->is_SMT = TRUE;
218 processor->is_SMT = TRUE;
219 }
220 }
221
222 processor_set_t
223 processor_pset(
224 processor_t processor)
225 {
226 return (processor->processor_set);
227 }
228
229 void
230 processor_state_update_idle(processor_t processor)
231 {
232 processor->current_pri = IDLEPRI;
233 processor->current_sfi_class = SFI_CLASS_KERNEL;
234 processor->current_recommended_pset_type = PSET_SMP;
235 processor->current_perfctl_class = PERFCONTROL_CLASS_IDLE;
236 }
237
238 void
239 processor_state_update_from_thread(processor_t processor, thread_t thread)
240 {
241 processor->current_pri = thread->sched_pri;
242 processor->current_sfi_class = thread->sfi_class;
243 processor->current_recommended_pset_type = recommended_pset_type(thread);
244 processor->current_perfctl_class = thread_get_perfcontrol_class(thread);
245 }
246
247 void
248 processor_state_update_explicit(processor_t processor, int pri, sfi_class_id_t sfi_class,
249 pset_cluster_type_t pset_type, perfcontrol_class_t perfctl_class)
250 {
251 processor->current_pri = pri;
252 processor->current_sfi_class = sfi_class;
253 processor->current_recommended_pset_type = pset_type;
254 processor->current_perfctl_class = perfctl_class;
255 }
256
257 pset_node_t
258 pset_node_root(void)
259 {
260 return &pset_node0;
261 }
262
263 processor_set_t
264 pset_create(
265 pset_node_t node)
266 {
267 /* some schedulers do not support multiple psets */
268 if (SCHED(multiple_psets_enabled) == FALSE)
269 return processor_pset(master_processor);
270
271 processor_set_t *prev, pset = kalloc(sizeof (*pset));
272
273 if (pset != PROCESSOR_SET_NULL) {
274 pset_init(pset, node);
275
276 simple_lock(&pset_node_lock);
277
278 prev = &node->psets;
279 while (*prev != PROCESSOR_SET_NULL)
280 prev = &(*prev)->pset_list;
281
282 *prev = pset;
283
284 simple_unlock(&pset_node_lock);
285 }
286
287 return (pset);
288 }
289
290 /*
291 * Find processor set in specified node with specified cluster_id.
292 * Returns default_pset if not found.
293 */
294 processor_set_t
295 pset_find(
296 uint32_t cluster_id,
297 processor_set_t default_pset)
298 {
299 simple_lock(&pset_node_lock);
300 pset_node_t node = &pset_node0;
301 processor_set_t pset = NULL;
302
303 do {
304 pset = node->psets;
305 while (pset != NULL) {
306 if (pset->pset_cluster_id == cluster_id)
307 break;
308 pset = pset->pset_list;
309 }
310 } while ((node = node->node_list) != NULL);
311 simple_unlock(&pset_node_lock);
312 if (pset == NULL)
313 return default_pset;
314 return (pset);
315 }
316
317 /*
318 * Initialize the given processor_set structure.
319 */
320 void
321 pset_init(
322 processor_set_t pset,
323 pset_node_t node)
324 {
325 if (pset != &pset0) {
326 /* Scheduler state for pset0 initialized in sched_init() */
327 SCHED(pset_init)(pset);
328 SCHED(rt_init)(pset);
329 }
330
331 queue_init(&pset->active_queue);
332 queue_init(&pset->idle_queue);
333 queue_init(&pset->idle_secondary_queue);
334 queue_init(&pset->unused_queue);
335 pset->online_processor_count = 0;
336 pset->active_processor_count = 0;
337 pset->load_average = 0;
338 pset->cpu_set_low = pset->cpu_set_hi = 0;
339 pset->cpu_set_count = 0;
340 pset->cpu_bitmask = 0;
341 pset->recommended_bitmask = ~0ULL;
342 pset->pending_AST_cpu_mask = 0;
343 #if defined(CONFIG_SCHED_DEFERRED_AST)
344 pset->pending_deferred_AST_cpu_mask = 0;
345 #endif
346 pset->pending_spill_cpu_mask = 0;
347 pset_lock_init(pset);
348 pset->pset_self = IP_NULL;
349 pset->pset_name_self = IP_NULL;
350 pset->pset_list = PROCESSOR_SET_NULL;
351 pset->node = node;
352 pset->pset_cluster_type = PSET_SMP;
353 pset->pset_cluster_id = 0;
354 }
355
356 kern_return_t
357 processor_info_count(
358 processor_flavor_t flavor,
359 mach_msg_type_number_t *count)
360 {
361 switch (flavor) {
362
363 case PROCESSOR_BASIC_INFO:
364 *count = PROCESSOR_BASIC_INFO_COUNT;
365 break;
366
367 case PROCESSOR_CPU_LOAD_INFO:
368 *count = PROCESSOR_CPU_LOAD_INFO_COUNT;
369 break;
370
371 default:
372 return (cpu_info_count(flavor, count));
373 }
374
375 return (KERN_SUCCESS);
376 }
377
378
379 kern_return_t
380 processor_info(
381 processor_t processor,
382 processor_flavor_t flavor,
383 host_t *host,
384 processor_info_t info,
385 mach_msg_type_number_t *count)
386 {
387 int cpu_id, state;
388 kern_return_t result;
389
390 if (processor == PROCESSOR_NULL)
391 return (KERN_INVALID_ARGUMENT);
392
393 cpu_id = processor->cpu_id;
394
395 switch (flavor) {
396
397 case PROCESSOR_BASIC_INFO:
398 {
399 processor_basic_info_t basic_info;
400
401 if (*count < PROCESSOR_BASIC_INFO_COUNT)
402 return (KERN_FAILURE);
403
404 basic_info = (processor_basic_info_t) info;
405 basic_info->cpu_type = slot_type(cpu_id);
406 basic_info->cpu_subtype = slot_subtype(cpu_id);
407 state = processor->state;
408 if (state == PROCESSOR_OFF_LINE)
409 basic_info->running = FALSE;
410 else
411 basic_info->running = TRUE;
412 basic_info->slot_num = cpu_id;
413 if (processor == master_processor)
414 basic_info->is_master = TRUE;
415 else
416 basic_info->is_master = FALSE;
417
418 *count = PROCESSOR_BASIC_INFO_COUNT;
419 *host = &realhost;
420
421 return (KERN_SUCCESS);
422 }
423
424 case PROCESSOR_CPU_LOAD_INFO:
425 {
426 processor_cpu_load_info_t cpu_load_info;
427 timer_t idle_state;
428 uint64_t idle_time_snapshot1, idle_time_snapshot2;
429 uint64_t idle_time_tstamp1, idle_time_tstamp2;
430
431 /*
432 * We capture the accumulated idle time twice over
433 * the course of this function, as well as the timestamps
434 * when each were last updated. Since these are
435 * all done using non-atomic racy mechanisms, the
436 * most we can infer is whether values are stable.
437 * timer_grab() is the only function that can be
438 * used reliably on another processor's per-processor
439 * data.
440 */
441
442 if (*count < PROCESSOR_CPU_LOAD_INFO_COUNT)
443 return (KERN_FAILURE);
444
445 cpu_load_info = (processor_cpu_load_info_t) info;
446 if (precise_user_kernel_time) {
447 cpu_load_info->cpu_ticks[CPU_STATE_USER] =
448 (uint32_t)(timer_grab(&PROCESSOR_DATA(processor, user_state)) / hz_tick_interval);
449 cpu_load_info->cpu_ticks[CPU_STATE_SYSTEM] =
450 (uint32_t)(timer_grab(&PROCESSOR_DATA(processor, system_state)) / hz_tick_interval);
451 } else {
452 uint64_t tval = timer_grab(&PROCESSOR_DATA(processor, user_state)) +
453 timer_grab(&PROCESSOR_DATA(processor, system_state));
454
455 cpu_load_info->cpu_ticks[CPU_STATE_USER] = (uint32_t)(tval / hz_tick_interval);
456 cpu_load_info->cpu_ticks[CPU_STATE_SYSTEM] = 0;
457 }
458
459 idle_state = &PROCESSOR_DATA(processor, idle_state);
460 idle_time_snapshot1 = timer_grab(idle_state);
461 idle_time_tstamp1 = idle_state->tstamp;
462
463 /*
464 * Idle processors are not continually updating their
465 * per-processor idle timer, so it may be extremely
466 * out of date, resulting in an over-representation
467 * of non-idle time between two measurement
468 * intervals by e.g. top(1). If we are non-idle, or
469 * have evidence that the timer is being updated
470 * concurrently, we consider its value up-to-date.
471 */
472 if (PROCESSOR_DATA(processor, current_state) != idle_state) {
473 cpu_load_info->cpu_ticks[CPU_STATE_IDLE] =
474 (uint32_t)(idle_time_snapshot1 / hz_tick_interval);
475 } else if ((idle_time_snapshot1 != (idle_time_snapshot2 = timer_grab(idle_state))) ||
476 (idle_time_tstamp1 != (idle_time_tstamp2 = idle_state->tstamp))){
477 /* Idle timer is being updated concurrently, second stamp is good enough */
478 cpu_load_info->cpu_ticks[CPU_STATE_IDLE] =
479 (uint32_t)(idle_time_snapshot2 / hz_tick_interval);
480 } else {
481 /*
482 * Idle timer may be very stale. Fortunately we have established
483 * that idle_time_snapshot1 and idle_time_tstamp1 are unchanging
484 */
485 idle_time_snapshot1 += mach_absolute_time() - idle_time_tstamp1;
486
487 cpu_load_info->cpu_ticks[CPU_STATE_IDLE] =
488 (uint32_t)(idle_time_snapshot1 / hz_tick_interval);
489 }
490
491 cpu_load_info->cpu_ticks[CPU_STATE_NICE] = 0;
492
493 *count = PROCESSOR_CPU_LOAD_INFO_COUNT;
494 *host = &realhost;
495
496 return (KERN_SUCCESS);
497 }
498
499 default:
500 result = cpu_info(flavor, cpu_id, info, count);
501 if (result == KERN_SUCCESS)
502 *host = &realhost;
503
504 return (result);
505 }
506 }
507
508 kern_return_t
509 processor_start(
510 processor_t processor)
511 {
512 processor_set_t pset;
513 thread_t thread;
514 kern_return_t result;
515 spl_t s;
516
517 if (processor == PROCESSOR_NULL || processor->processor_set == PROCESSOR_SET_NULL)
518 return (KERN_INVALID_ARGUMENT);
519
520 if (processor == master_processor) {
521 processor_t prev;
522
523 prev = thread_bind(processor);
524 thread_block(THREAD_CONTINUE_NULL);
525
526 result = cpu_start(processor->cpu_id);
527
528 thread_bind(prev);
529
530 return (result);
531 }
532
533 s = splsched();
534 pset = processor->processor_set;
535 pset_lock(pset);
536 if (processor->state != PROCESSOR_OFF_LINE) {
537 pset_unlock(pset);
538 splx(s);
539
540 return (KERN_FAILURE);
541 }
542
543 processor->state = PROCESSOR_START;
544 pset_unlock(pset);
545 splx(s);
546
547 /*
548 * Create the idle processor thread.
549 */
550 if (processor->idle_thread == THREAD_NULL) {
551 result = idle_thread_create(processor);
552 if (result != KERN_SUCCESS) {
553 s = splsched();
554 pset_lock(pset);
555 processor->state = PROCESSOR_OFF_LINE;
556 pset_unlock(pset);
557 splx(s);
558
559 return (result);
560 }
561 }
562
563 /*
564 * If there is no active thread, the processor
565 * has never been started. Create a dedicated
566 * start up thread.
567 */
568 if ( processor->active_thread == THREAD_NULL &&
569 processor->next_thread == THREAD_NULL ) {
570 result = kernel_thread_create((thread_continue_t)processor_start_thread, NULL, MAXPRI_KERNEL, &thread);
571 if (result != KERN_SUCCESS) {
572 s = splsched();
573 pset_lock(pset);
574 processor->state = PROCESSOR_OFF_LINE;
575 pset_unlock(pset);
576 splx(s);
577
578 return (result);
579 }
580
581 s = splsched();
582 thread_lock(thread);
583 thread->bound_processor = processor;
584 processor->next_thread = thread;
585 thread->state = TH_RUN;
586 thread->last_made_runnable_time = mach_absolute_time();
587 thread_unlock(thread);
588 splx(s);
589
590 thread_deallocate(thread);
591 }
592
593 if (processor->processor_self == IP_NULL)
594 ipc_processor_init(processor);
595
596 result = cpu_start(processor->cpu_id);
597 if (result != KERN_SUCCESS) {
598 s = splsched();
599 pset_lock(pset);
600 processor->state = PROCESSOR_OFF_LINE;
601 pset_unlock(pset);
602 splx(s);
603
604 return (result);
605 }
606
607 ipc_processor_enable(processor);
608
609 return (KERN_SUCCESS);
610 }
611
612 kern_return_t
613 processor_exit(
614 processor_t processor)
615 {
616 if (processor == PROCESSOR_NULL)
617 return(KERN_INVALID_ARGUMENT);
618
619 return(processor_shutdown(processor));
620 }
621
622 kern_return_t
623 processor_control(
624 processor_t processor,
625 processor_info_t info,
626 mach_msg_type_number_t count)
627 {
628 if (processor == PROCESSOR_NULL)
629 return(KERN_INVALID_ARGUMENT);
630
631 return(cpu_control(processor->cpu_id, info, count));
632 }
633
634 kern_return_t
635 processor_set_create(
636 __unused host_t host,
637 __unused processor_set_t *new_set,
638 __unused processor_set_t *new_name)
639 {
640 return(KERN_FAILURE);
641 }
642
643 kern_return_t
644 processor_set_destroy(
645 __unused processor_set_t pset)
646 {
647 return(KERN_FAILURE);
648 }
649
650 kern_return_t
651 processor_get_assignment(
652 processor_t processor,
653 processor_set_t *pset)
654 {
655 int state;
656
657 if (processor == PROCESSOR_NULL)
658 return(KERN_INVALID_ARGUMENT);
659
660 state = processor->state;
661 if (state == PROCESSOR_SHUTDOWN || state == PROCESSOR_OFF_LINE)
662 return(KERN_FAILURE);
663
664 *pset = &pset0;
665
666 return(KERN_SUCCESS);
667 }
668
669 kern_return_t
670 processor_set_info(
671 processor_set_t pset,
672 int flavor,
673 host_t *host,
674 processor_set_info_t info,
675 mach_msg_type_number_t *count)
676 {
677 if (pset == PROCESSOR_SET_NULL)
678 return(KERN_INVALID_ARGUMENT);
679
680 if (flavor == PROCESSOR_SET_BASIC_INFO) {
681 processor_set_basic_info_t basic_info;
682
683 if (*count < PROCESSOR_SET_BASIC_INFO_COUNT)
684 return(KERN_FAILURE);
685
686 basic_info = (processor_set_basic_info_t) info;
687 basic_info->processor_count = processor_avail_count;
688 basic_info->default_policy = POLICY_TIMESHARE;
689
690 *count = PROCESSOR_SET_BASIC_INFO_COUNT;
691 *host = &realhost;
692 return(KERN_SUCCESS);
693 }
694 else if (flavor == PROCESSOR_SET_TIMESHARE_DEFAULT) {
695 policy_timeshare_base_t ts_base;
696
697 if (*count < POLICY_TIMESHARE_BASE_COUNT)
698 return(KERN_FAILURE);
699
700 ts_base = (policy_timeshare_base_t) info;
701 ts_base->base_priority = BASEPRI_DEFAULT;
702
703 *count = POLICY_TIMESHARE_BASE_COUNT;
704 *host = &realhost;
705 return(KERN_SUCCESS);
706 }
707 else if (flavor == PROCESSOR_SET_FIFO_DEFAULT) {
708 policy_fifo_base_t fifo_base;
709
710 if (*count < POLICY_FIFO_BASE_COUNT)
711 return(KERN_FAILURE);
712
713 fifo_base = (policy_fifo_base_t) info;
714 fifo_base->base_priority = BASEPRI_DEFAULT;
715
716 *count = POLICY_FIFO_BASE_COUNT;
717 *host = &realhost;
718 return(KERN_SUCCESS);
719 }
720 else if (flavor == PROCESSOR_SET_RR_DEFAULT) {
721 policy_rr_base_t rr_base;
722
723 if (*count < POLICY_RR_BASE_COUNT)
724 return(KERN_FAILURE);
725
726 rr_base = (policy_rr_base_t) info;
727 rr_base->base_priority = BASEPRI_DEFAULT;
728 rr_base->quantum = 1;
729
730 *count = POLICY_RR_BASE_COUNT;
731 *host = &realhost;
732 return(KERN_SUCCESS);
733 }
734 else if (flavor == PROCESSOR_SET_TIMESHARE_LIMITS) {
735 policy_timeshare_limit_t ts_limit;
736
737 if (*count < POLICY_TIMESHARE_LIMIT_COUNT)
738 return(KERN_FAILURE);
739
740 ts_limit = (policy_timeshare_limit_t) info;
741 ts_limit->max_priority = MAXPRI_KERNEL;
742
743 *count = POLICY_TIMESHARE_LIMIT_COUNT;
744 *host = &realhost;
745 return(KERN_SUCCESS);
746 }
747 else if (flavor == PROCESSOR_SET_FIFO_LIMITS) {
748 policy_fifo_limit_t fifo_limit;
749
750 if (*count < POLICY_FIFO_LIMIT_COUNT)
751 return(KERN_FAILURE);
752
753 fifo_limit = (policy_fifo_limit_t) info;
754 fifo_limit->max_priority = MAXPRI_KERNEL;
755
756 *count = POLICY_FIFO_LIMIT_COUNT;
757 *host = &realhost;
758 return(KERN_SUCCESS);
759 }
760 else if (flavor == PROCESSOR_SET_RR_LIMITS) {
761 policy_rr_limit_t rr_limit;
762
763 if (*count < POLICY_RR_LIMIT_COUNT)
764 return(KERN_FAILURE);
765
766 rr_limit = (policy_rr_limit_t) info;
767 rr_limit->max_priority = MAXPRI_KERNEL;
768
769 *count = POLICY_RR_LIMIT_COUNT;
770 *host = &realhost;
771 return(KERN_SUCCESS);
772 }
773 else if (flavor == PROCESSOR_SET_ENABLED_POLICIES) {
774 int *enabled;
775
776 if (*count < (sizeof(*enabled)/sizeof(int)))
777 return(KERN_FAILURE);
778
779 enabled = (int *) info;
780 *enabled = POLICY_TIMESHARE | POLICY_RR | POLICY_FIFO;
781
782 *count = sizeof(*enabled)/sizeof(int);
783 *host = &realhost;
784 return(KERN_SUCCESS);
785 }
786
787
788 *host = HOST_NULL;
789 return(KERN_INVALID_ARGUMENT);
790 }
791
792 /*
793 * processor_set_statistics
794 *
795 * Returns scheduling statistics for a processor set.
796 */
797 kern_return_t
798 processor_set_statistics(
799 processor_set_t pset,
800 int flavor,
801 processor_set_info_t info,
802 mach_msg_type_number_t *count)
803 {
804 if (pset == PROCESSOR_SET_NULL || pset != &pset0)
805 return (KERN_INVALID_PROCESSOR_SET);
806
807 if (flavor == PROCESSOR_SET_LOAD_INFO) {
808 processor_set_load_info_t load_info;
809
810 if (*count < PROCESSOR_SET_LOAD_INFO_COUNT)
811 return(KERN_FAILURE);
812
813 load_info = (processor_set_load_info_t) info;
814
815 load_info->mach_factor = sched_mach_factor;
816 load_info->load_average = sched_load_average;
817
818 load_info->task_count = tasks_count;
819 load_info->thread_count = threads_count;
820
821 *count = PROCESSOR_SET_LOAD_INFO_COUNT;
822 return(KERN_SUCCESS);
823 }
824
825 return(KERN_INVALID_ARGUMENT);
826 }
827
828 /*
829 * processor_set_max_priority:
830 *
831 * Specify max priority permitted on processor set. This affects
832 * newly created and assigned threads. Optionally change existing
833 * ones.
834 */
835 kern_return_t
836 processor_set_max_priority(
837 __unused processor_set_t pset,
838 __unused int max_priority,
839 __unused boolean_t change_threads)
840 {
841 return (KERN_INVALID_ARGUMENT);
842 }
843
844 /*
845 * processor_set_policy_enable:
846 *
847 * Allow indicated policy on processor set.
848 */
849
850 kern_return_t
851 processor_set_policy_enable(
852 __unused processor_set_t pset,
853 __unused int policy)
854 {
855 return (KERN_INVALID_ARGUMENT);
856 }
857
858 /*
859 * processor_set_policy_disable:
860 *
861 * Forbid indicated policy on processor set. Time sharing cannot
862 * be forbidden.
863 */
864 kern_return_t
865 processor_set_policy_disable(
866 __unused processor_set_t pset,
867 __unused int policy,
868 __unused boolean_t change_threads)
869 {
870 return (KERN_INVALID_ARGUMENT);
871 }
872
873 /*
874 * processor_set_things:
875 *
876 * Common internals for processor_set_{threads,tasks}
877 */
878 kern_return_t
879 processor_set_things(
880 processor_set_t pset,
881 void **thing_list,
882 mach_msg_type_number_t *count,
883 int type)
884 {
885 unsigned int i;
886 task_t task;
887 thread_t thread;
888
889 task_t *task_list;
890 unsigned int actual_tasks;
891 vm_size_t task_size, task_size_needed;
892
893 thread_t *thread_list;
894 unsigned int actual_threads;
895 vm_size_t thread_size, thread_size_needed;
896
897 void *addr, *newaddr;
898 vm_size_t size, size_needed;
899
900 if (pset == PROCESSOR_SET_NULL || pset != &pset0)
901 return (KERN_INVALID_ARGUMENT);
902
903 task_size = 0;
904 task_size_needed = 0;
905 task_list = NULL;
906 actual_tasks = 0;
907
908 thread_size = 0;
909 thread_size_needed = 0;
910 thread_list = NULL;
911 actual_threads = 0;
912
913 for (;;) {
914 lck_mtx_lock(&tasks_threads_lock);
915
916 /* do we have the memory we need? */
917 if (type == PSET_THING_THREAD)
918 thread_size_needed = threads_count * sizeof(void *);
919 #if !CONFIG_MACF
920 else
921 #endif
922 task_size_needed = tasks_count * sizeof(void *);
923
924 if (task_size_needed <= task_size &&
925 thread_size_needed <= thread_size)
926 break;
927
928 /* unlock and allocate more memory */
929 lck_mtx_unlock(&tasks_threads_lock);
930
931 /* grow task array */
932 if (task_size_needed > task_size) {
933 if (task_size != 0)
934 kfree(task_list, task_size);
935
936 assert(task_size_needed > 0);
937 task_size = task_size_needed;
938
939 task_list = (task_t *)kalloc(task_size);
940 if (task_list == NULL) {
941 if (thread_size != 0)
942 kfree(thread_list, thread_size);
943 return (KERN_RESOURCE_SHORTAGE);
944 }
945 }
946
947 /* grow thread array */
948 if (thread_size_needed > thread_size) {
949 if (thread_size != 0)
950 kfree(thread_list, thread_size);
951
952 assert(thread_size_needed > 0);
953 thread_size = thread_size_needed;
954
955 thread_list = (thread_t *)kalloc(thread_size);
956 if (thread_list == 0) {
957 if (task_size != 0)
958 kfree(task_list, task_size);
959 return (KERN_RESOURCE_SHORTAGE);
960 }
961 }
962 }
963
964 /* OK, have memory and the list locked */
965
966 /* If we need it, get the thread list */
967 if (type == PSET_THING_THREAD) {
968 for (thread = (thread_t)queue_first(&threads);
969 !queue_end(&threads, (queue_entry_t)thread);
970 thread = (thread_t)queue_next(&thread->threads)) {
971 #if defined(SECURE_KERNEL)
972 if (thread->task != kernel_task) {
973 #endif
974 thread_reference_internal(thread);
975 thread_list[actual_threads++] = thread;
976 #if defined(SECURE_KERNEL)
977 }
978 #endif
979 }
980 }
981 #if !CONFIG_MACF
982 else {
983 #endif
984 /* get a list of the tasks */
985 for (task = (task_t)queue_first(&tasks);
986 !queue_end(&tasks, (queue_entry_t)task);
987 task = (task_t)queue_next(&task->tasks)) {
988 #if defined(SECURE_KERNEL)
989 if (task != kernel_task) {
990 #endif
991 task_reference_internal(task);
992 task_list[actual_tasks++] = task;
993 #if defined(SECURE_KERNEL)
994 }
995 #endif
996 }
997 #if !CONFIG_MACF
998 }
999 #endif
1000
1001 lck_mtx_unlock(&tasks_threads_lock);
1002
1003 #if CONFIG_MACF
1004 unsigned int j, used;
1005
1006 /* for each task, make sure we are allowed to examine it */
1007 for (i = used = 0; i < actual_tasks; i++) {
1008 if (mac_task_check_expose_task(task_list[i])) {
1009 task_deallocate(task_list[i]);
1010 continue;
1011 }
1012 task_list[used++] = task_list[i];
1013 }
1014 actual_tasks = used;
1015 task_size_needed = actual_tasks * sizeof(void *);
1016
1017 if (type == PSET_THING_THREAD) {
1018
1019 /* for each thread (if any), make sure it's task is in the allowed list */
1020 for (i = used = 0; i < actual_threads; i++) {
1021 boolean_t found_task = FALSE;
1022
1023 task = thread_list[i]->task;
1024 for (j = 0; j < actual_tasks; j++) {
1025 if (task_list[j] == task) {
1026 found_task = TRUE;
1027 break;
1028 }
1029 }
1030 if (found_task)
1031 thread_list[used++] = thread_list[i];
1032 else
1033 thread_deallocate(thread_list[i]);
1034 }
1035 actual_threads = used;
1036 thread_size_needed = actual_threads * sizeof(void *);
1037
1038 /* done with the task list */
1039 for (i = 0; i < actual_tasks; i++)
1040 task_deallocate(task_list[i]);
1041 kfree(task_list, task_size);
1042 task_size = 0;
1043 actual_tasks = 0;
1044 task_list = NULL;
1045 }
1046 #endif
1047
1048 if (type == PSET_THING_THREAD) {
1049 if (actual_threads == 0) {
1050 /* no threads available to return */
1051 assert(task_size == 0);
1052 if (thread_size != 0)
1053 kfree(thread_list, thread_size);
1054 *thing_list = NULL;
1055 *count = 0;
1056 return KERN_SUCCESS;
1057 }
1058 size_needed = actual_threads * sizeof(void *);
1059 size = thread_size;
1060 addr = thread_list;
1061 } else {
1062 if (actual_tasks == 0) {
1063 /* no tasks available to return */
1064 assert(thread_size == 0);
1065 if (task_size != 0)
1066 kfree(task_list, task_size);
1067 *thing_list = NULL;
1068 *count = 0;
1069 return KERN_SUCCESS;
1070 }
1071 size_needed = actual_tasks * sizeof(void *);
1072 size = task_size;
1073 addr = task_list;
1074 }
1075
1076 /* if we allocated too much, must copy */
1077 if (size_needed < size) {
1078 newaddr = kalloc(size_needed);
1079 if (newaddr == 0) {
1080 for (i = 0; i < actual_tasks; i++) {
1081 if (type == PSET_THING_THREAD)
1082 thread_deallocate(thread_list[i]);
1083 else
1084 task_deallocate(task_list[i]);
1085 }
1086 if (size)
1087 kfree(addr, size);
1088 return (KERN_RESOURCE_SHORTAGE);
1089 }
1090
1091 bcopy((void *) addr, (void *) newaddr, size_needed);
1092 kfree(addr, size);
1093
1094 addr = newaddr;
1095 size = size_needed;
1096 }
1097
1098 *thing_list = (void **)addr;
1099 *count = (unsigned int)size / sizeof(void *);
1100
1101 return (KERN_SUCCESS);
1102 }
1103
1104
1105 /*
1106 * processor_set_tasks:
1107 *
1108 * List all tasks in the processor set.
1109 */
1110 kern_return_t
1111 processor_set_tasks(
1112 processor_set_t pset,
1113 task_array_t *task_list,
1114 mach_msg_type_number_t *count)
1115 {
1116 kern_return_t ret;
1117 mach_msg_type_number_t i;
1118
1119 ret = processor_set_things(pset, (void **)task_list, count, PSET_THING_TASK);
1120 if (ret != KERN_SUCCESS)
1121 return ret;
1122
1123 /* do the conversion that Mig should handle */
1124 for (i = 0; i < *count; i++)
1125 (*task_list)[i] = (task_t)convert_task_to_port((*task_list)[i]);
1126 return KERN_SUCCESS;
1127 }
1128
1129 /*
1130 * processor_set_threads:
1131 *
1132 * List all threads in the processor set.
1133 */
1134 #if defined(SECURE_KERNEL)
1135 kern_return_t
1136 processor_set_threads(
1137 __unused processor_set_t pset,
1138 __unused thread_array_t *thread_list,
1139 __unused mach_msg_type_number_t *count)
1140 {
1141 return KERN_FAILURE;
1142 }
1143 #elif defined(CONFIG_EMBEDDED)
1144 kern_return_t
1145 processor_set_threads(
1146 __unused processor_set_t pset,
1147 __unused thread_array_t *thread_list,
1148 __unused mach_msg_type_number_t *count)
1149 {
1150 return KERN_NOT_SUPPORTED;
1151 }
1152 #else
1153 kern_return_t
1154 processor_set_threads(
1155 processor_set_t pset,
1156 thread_array_t *thread_list,
1157 mach_msg_type_number_t *count)
1158 {
1159 kern_return_t ret;
1160 mach_msg_type_number_t i;
1161
1162 ret = processor_set_things(pset, (void **)thread_list, count, PSET_THING_THREAD);
1163 if (ret != KERN_SUCCESS)
1164 return ret;
1165
1166 /* do the conversion that Mig should handle */
1167 for (i = 0; i < *count; i++)
1168 (*thread_list)[i] = (thread_t)convert_thread_to_port((*thread_list)[i]);
1169 return KERN_SUCCESS;
1170 }
1171 #endif
1172
1173 /*
1174 * processor_set_policy_control
1175 *
1176 * Controls the scheduling attributes governing the processor set.
1177 * Allows control of enabled policies, and per-policy base and limit
1178 * priorities.
1179 */
1180 kern_return_t
1181 processor_set_policy_control(
1182 __unused processor_set_t pset,
1183 __unused int flavor,
1184 __unused processor_set_info_t policy_info,
1185 __unused mach_msg_type_number_t count,
1186 __unused boolean_t change)
1187 {
1188 return (KERN_INVALID_ARGUMENT);
1189 }
1190
1191 #undef pset_deallocate
1192 void pset_deallocate(processor_set_t pset);
1193 void
1194 pset_deallocate(
1195 __unused processor_set_t pset)
1196 {
1197 return;
1198 }
1199
1200 #undef pset_reference
1201 void pset_reference(processor_set_t pset);
1202 void
1203 pset_reference(
1204 __unused processor_set_t pset)
1205 {
1206 return;
1207 }
1208
1209 pset_cluster_type_t
1210 recommended_pset_type(thread_t thread)
1211 {
1212 (void)thread;
1213 return PSET_SMP;
1214 }