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