]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/processor.c
xnu-792.21.3.tar.gz
[apple/xnu.git] / osfmk / kern / processor.c
CommitLineData
1c79356b 1/*
91447636 2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
1c79356b 3 *
8f6c56a5 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
8f6c56a5
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.
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
8ad349bb 24 * limitations under the License.
8f6c56a5
A
25 *
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
1c79356b
A
81/*
82 * Exported interface
83 */
84#include <mach/mach_host_server.h>
91447636 85#include <mach/processor_set_server.h>
1c79356b
A
86
87/*
88 * Exported variables.
89 */
91447636 90struct processor_set default_pset;
1c79356b 91
91447636
A
92processor_t processor_list;
93unsigned int processor_count;
94static processor_t processor_list_tail;
95decl_simple_lock_data(,processor_list_lock)
9bccf70c 96
1c79356b 97processor_t master_processor;
91447636 98int master_cpu = 0;
1c79356b
A
99
100/* Forwards */
1c79356b
A
101kern_return_t processor_set_base(
102 processor_set_t pset,
103 policy_t policy,
104 policy_base_t base,
105 boolean_t change);
106
107kern_return_t processor_set_limit(
108 processor_set_t pset,
109 policy_t policy,
110 policy_limit_t limit,
111 boolean_t change);
112
113kern_return_t processor_set_things(
114 processor_set_t pset,
115 mach_port_t **thing_list,
116 mach_msg_type_number_t *count,
117 int type);
118
1c79356b 119void
91447636 120processor_bootstrap(void)
1c79356b 121{
91447636 122 simple_lock_init(&processor_list_lock, 0);
55e303ae 123
1c79356b 124 master_processor = cpu_to_processor(master_cpu);
55e303ae 125
91447636 126 processor_init(master_processor, master_cpu);
1c79356b
A
127}
128
129/*
130 * Initialize the given processor_set structure.
131 */
132
91447636
A
133void
134pset_init(
1c79356b
A
135 register processor_set_t pset)
136{
9bccf70c 137 register int i;
1c79356b 138
9bccf70c 139 /* setup run queue */
55e303ae 140 pset->runq.highq = IDLEPRI;
9bccf70c 141 for (i = 0; i < NRQBM; i++)
1c79356b 142 pset->runq.bitmap[i] = 0;
1c79356b 143 setbit(MAXPRI - IDLEPRI, pset->runq.bitmap);
9bccf70c
A
144 pset->runq.urgency = pset->runq.count = 0;
145 for (i = 0; i < NRQS; i++)
146 queue_init(&pset->runq.queues[i]);
1c79356b
A
147
148 queue_init(&pset->idle_queue);
149 pset->idle_count = 0;
9bccf70c 150 queue_init(&pset->active_queue);
91447636 151 simple_lock_init(&pset->sched_lock, 0);
55e303ae 152 pset->run_count = pset->share_count = 0;
1c79356b 153 pset->mach_factor = pset->load_average = 0;
91447636 154 pset->pri_shift = INT8_MAX;
1c79356b
A
155 queue_init(&pset->processors);
156 pset->processor_count = 0;
1c79356b
A
157 queue_init(&pset->tasks);
158 pset->task_count = 0;
159 queue_init(&pset->threads);
160 pset->thread_count = 0;
161 pset->ref_count = 1;
91447636
A
162 pset->active = TRUE;
163 mutex_init(&pset->lock, 0);
1c79356b
A
164 pset->pset_self = IP_NULL;
165 pset->pset_name_self = IP_NULL;
55e303ae 166 pset->timeshare_quanta = 1;
1c79356b
A
167}
168
169/*
170 * Initialize the given processor structure for the processor in
171 * the slot specified by slot_num.
172 */
173void
174processor_init(
9bccf70c
A
175 register processor_t p,
176 int slot_num)
1c79356b 177{
9bccf70c 178 register int i;
1c79356b 179
9bccf70c 180 /* setup run queue */
55e303ae 181 p->runq.highq = IDLEPRI;
9bccf70c
A
182 for (i = 0; i < NRQBM; i++)
183 p->runq.bitmap[i] = 0;
184 setbit(MAXPRI - IDLEPRI, p->runq.bitmap);
9bccf70c
A
185 p->runq.urgency = p->runq.count = 0;
186 for (i = 0; i < NRQS; i++)
187 queue_init(&p->runq.queues[i]);
188
189 p->state = PROCESSOR_OFF_LINE;
55e303ae
A
190 p->active_thread = p->next_thread = p->idle_thread = THREAD_NULL;
191 p->processor_set = PROCESSOR_SET_NULL;
9bccf70c 192 p->current_pri = MINPRI;
91447636 193 p->deadline = UINT64_MAX;
9bccf70c 194 timer_call_setup(&p->quantum_timer, thread_quantum_expire, p);
55e303ae 195 p->timeslice = 0;
91447636 196 simple_lock_init(&p->lock, 0);
9bccf70c 197 p->processor_self = IP_NULL;
91447636
A
198 processor_data_init(p);
199 PROCESSOR_DATA(p, slot_num) = slot_num;
200
201 simple_lock(&processor_list_lock);
202 if (processor_list == NULL)
203 processor_list = p;
204 else
205 processor_list_tail->processor_list = p;
206 processor_list_tail = p;
207 processor_count++;
208 p->processor_list = NULL;
209 simple_unlock(&processor_list_lock);
9bccf70c 210}
1c79356b 211
9bccf70c
A
212/*
213 * pset_deallocate:
214 *
215 * Remove one reference to the processor set. Destroy processor_set
216 * if this was the last reference.
217 */
218void
219pset_deallocate(
220 processor_set_t pset)
221{
222 if (pset == PROCESSOR_SET_NULL)
223 return;
224
225 assert(pset == &default_pset);
226 return;
1c79356b
A
227}
228
9bccf70c
A
229/*
230 * pset_reference:
231 *
232 * Add one reference to the processor set.
233 */
234void
235pset_reference(
236 processor_set_t pset)
237{
91447636
A
238 if (pset == PROCESSOR_SET_NULL)
239 return;
240
9bccf70c
A
241 assert(pset == &default_pset);
242}
243
244#define pset_reference_locked(pset) assert(pset == &default_pset)
245
1c79356b
A
246/*
247 * pset_remove_processor() removes a processor from a processor_set.
248 * It can only be called on the current processor. Caller must
249 * hold lock on current processor and processor set.
250 */
251void
252pset_remove_processor(
253 processor_set_t pset,
254 processor_t processor)
255{
256 if (pset != processor->processor_set)
257 panic("pset_remove_processor: wrong pset");
258
259 queue_remove(&pset->processors, processor, processor_t, processors);
260 processor->processor_set = PROCESSOR_SET_NULL;
261 pset->processor_count--;
91447636 262 timeshare_quanta_update(pset);
1c79356b
A
263}
264
265/*
266 * pset_add_processor() adds a processor to a processor_set.
267 * It can only be called on the current processor. Caller must
268 * hold lock on curent processor and on pset. No reference counting on
269 * processors. Processor reference to pset is implicit.
270 */
271void
272pset_add_processor(
273 processor_set_t pset,
274 processor_t processor)
275{
276 queue_enter(&pset->processors, processor, processor_t, processors);
277 processor->processor_set = pset;
278 pset->processor_count++;
91447636 279 timeshare_quanta_update(pset);
1c79356b
A
280}
281
282/*
283 * pset_remove_task() removes a task from a processor_set.
9bccf70c
A
284 * Caller must hold locks on pset and task (unless task has
285 * no references left, in which case just the pset lock is
286 * needed). Pset reference count is not decremented;
287 * caller must explicitly pset_deallocate.
1c79356b
A
288 */
289void
290pset_remove_task(
291 processor_set_t pset,
292 task_t task)
293{
294 if (pset != task->processor_set)
295 return;
296
297 queue_remove(&pset->tasks, task, task_t, pset_tasks);
1c79356b
A
298 pset->task_count--;
299}
300
301/*
302 * pset_add_task() adds a task to a processor_set.
303 * Caller must hold locks on pset and task. Pset references to
304 * tasks are implicit.
305 */
306void
307pset_add_task(
308 processor_set_t pset,
309 task_t task)
310{
311 queue_enter(&pset->tasks, task, task_t, pset_tasks);
312 task->processor_set = pset;
313 pset->task_count++;
9bccf70c 314 pset_reference_locked(pset);
1c79356b
A
315}
316
317/*
318 * pset_remove_thread() removes a thread from a processor_set.
9bccf70c
A
319 * Caller must hold locks on pset and thread (but only if thread
320 * has outstanding references that could be used to lookup the pset).
321 * The pset reference count is not decremented; caller must explicitly
322 * pset_deallocate.
1c79356b
A
323 */
324void
325pset_remove_thread(
326 processor_set_t pset,
327 thread_t thread)
328{
329 queue_remove(&pset->threads, thread, thread_t, pset_threads);
1c79356b
A
330 pset->thread_count--;
331}
332
333/*
334 * pset_add_thread() adds a thread to a processor_set.
335 * Caller must hold locks on pset and thread. Pset references to
336 * threads are implicit.
337 */
338void
339pset_add_thread(
340 processor_set_t pset,
341 thread_t thread)
342{
343 queue_enter(&pset->threads, thread, thread_t, pset_threads);
344 thread->processor_set = pset;
345 pset->thread_count++;
9bccf70c 346 pset_reference_locked(pset);
1c79356b
A
347}
348
349/*
350 * thread_change_psets() changes the pset of a thread. Caller must
351 * hold locks on both psets and thread. The old pset must be
352 * explicitly pset_deallocat()'ed by caller.
353 */
354void
355thread_change_psets(
356 thread_t thread,
357 processor_set_t old_pset,
358 processor_set_t new_pset)
359{
360 queue_remove(&old_pset->threads, thread, thread_t, pset_threads);
361 old_pset->thread_count--;
362 queue_enter(&new_pset->threads, thread, thread_t, pset_threads);
363 thread->processor_set = new_pset;
364 new_pset->thread_count++;
9bccf70c 365 pset_reference_locked(new_pset);
1c79356b
A
366}
367
1c79356b
A
368
369kern_return_t
370processor_info_count(
91447636 371 processor_flavor_t flavor,
1c79356b
A
372 mach_msg_type_number_t *count)
373{
1c79356b 374 switch (flavor) {
91447636 375
1c79356b
A
376 case PROCESSOR_BASIC_INFO:
377 *count = PROCESSOR_BASIC_INFO_COUNT;
91447636
A
378 break;
379
1c79356b
A
380 case PROCESSOR_CPU_LOAD_INFO:
381 *count = PROCESSOR_CPU_LOAD_INFO_COUNT;
91447636
A
382 break;
383
1c79356b 384 default:
91447636 385 return (cpu_info_count(flavor, count));
1c79356b 386 }
91447636
A
387
388 return (KERN_SUCCESS);
1c79356b
A
389}
390
391
392kern_return_t
393processor_info(
394 register processor_t processor,
91447636
A
395 processor_flavor_t flavor,
396 host_t *host,
397 processor_info_t info,
1c79356b
A
398 mach_msg_type_number_t *count)
399{
400 register int i, slot_num, state;
91447636 401 kern_return_t result;
1c79356b
A
402
403 if (processor == PROCESSOR_NULL)
91447636 404 return (KERN_INVALID_ARGUMENT);
1c79356b 405
91447636 406 slot_num = PROCESSOR_DATA(processor, slot_num);
1c79356b
A
407
408 switch (flavor) {
409
410 case PROCESSOR_BASIC_INFO:
91447636
A
411 {
412 register processor_basic_info_t basic_info;
413
414 if (*count < PROCESSOR_BASIC_INFO_COUNT)
415 return (KERN_FAILURE);
416
417 basic_info = (processor_basic_info_t) info;
418 basic_info->cpu_type = slot_type(slot_num);
419 basic_info->cpu_subtype = slot_subtype(slot_num);
420 state = processor->state;
421 if (state == PROCESSOR_OFF_LINE)
422 basic_info->running = FALSE;
423 else
424 basic_info->running = TRUE;
425 basic_info->slot_num = slot_num;
426 if (processor == master_processor)
427 basic_info->is_master = TRUE;
428 else
429 basic_info->is_master = FALSE;
430
431 *count = PROCESSOR_BASIC_INFO_COUNT;
432 *host = &realhost;
433
434 return (KERN_SUCCESS);
435 }
436
1c79356b 437 case PROCESSOR_CPU_LOAD_INFO:
91447636
A
438 {
439 register processor_cpu_load_info_t cpu_load_info;
440 register integer_t *cpu_ticks;
441
1c79356b 442 if (*count < PROCESSOR_CPU_LOAD_INFO_COUNT)
91447636 443 return (KERN_FAILURE);
1c79356b
A
444
445 cpu_load_info = (processor_cpu_load_info_t) info;
91447636
A
446 cpu_ticks = PROCESSOR_DATA(processor, cpu_ticks);
447 for (i=0; i < CPU_STATE_MAX; i++)
448 cpu_load_info->cpu_ticks[i] = cpu_ticks[i];
1c79356b
A
449
450 *count = PROCESSOR_CPU_LOAD_INFO_COUNT;
451 *host = &realhost;
91447636
A
452
453 return (KERN_SUCCESS);
454 }
455
1c79356b 456 default:
91447636
A
457 result = cpu_info(flavor, slot_num, info, count);
458 if (result == KERN_SUCCESS)
459 *host = &realhost;
460
461 return (result);
1c79356b
A
462 }
463}
464
465kern_return_t
466processor_start(
467 processor_t processor)
468{
55e303ae 469 kern_return_t result;
91447636 470 thread_t thread;
55e303ae 471 spl_t s;
1c79356b
A
472
473 if (processor == PROCESSOR_NULL)
91447636 474 return (KERN_INVALID_ARGUMENT);
1c79356b 475
0b4e3aa0 476 if (processor == master_processor) {
91447636 477 thread_t self = current_thread();
55e303ae
A
478 processor_t prev;
479
91447636 480 prev = thread_bind(self, processor);
9bccf70c 481 thread_block(THREAD_CONTINUE_NULL);
0b4e3aa0 482
91447636 483 result = cpu_start(PROCESSOR_DATA(processor, slot_num));
55e303ae 484
91447636 485 thread_bind(self, prev);
55e303ae
A
486
487 return (result);
0b4e3aa0 488 }
1c79356b
A
489
490 s = splsched();
491 processor_lock(processor);
55e303ae 492 if (processor->state != PROCESSOR_OFF_LINE) {
1c79356b
A
493 processor_unlock(processor);
494 splx(s);
55e303ae
A
495
496 return (KERN_FAILURE);
1c79356b 497 }
55e303ae 498
1c79356b
A
499 processor->state = PROCESSOR_START;
500 processor_unlock(processor);
501 splx(s);
502
91447636
A
503 /*
504 * Create the idle processor thread.
505 */
506 if (processor->idle_thread == THREAD_NULL) {
507 result = idle_thread_create(processor);
508 if (result != KERN_SUCCESS) {
509 s = splsched();
510 processor_lock(processor);
511 processor->state = PROCESSOR_OFF_LINE;
512 processor_unlock(processor);
513 splx(s);
514
515 return (result);
516 }
517 }
518
519 /*
520 * If there is no active thread, the processor
521 * has never been started. Create a dedicated
522 * start up thread.
523 */
524 if ( processor->active_thread == THREAD_NULL &&
525 processor->next_thread == THREAD_NULL ) {
526 result = kernel_thread_create((thread_continue_t)processor_start_thread, NULL, MAXPRI_KERNEL, &thread);
527 if (result != KERN_SUCCESS) {
528 s = splsched();
529 processor_lock(processor);
530 processor->state = PROCESSOR_OFF_LINE;
531 processor_unlock(processor);
532 splx(s);
533
534 return (result);
535 }
1c79356b
A
536
537 s = splsched();
538 thread_lock(thread);
55e303ae 539 thread->bound_processor = processor;
1c79356b 540 processor->next_thread = thread;
55e303ae 541 thread->state = TH_RUN;
1c79356b
A
542 thread_unlock(thread);
543 splx(s);
91447636
A
544
545 thread_deallocate(thread);
1c79356b
A
546 }
547
55e303ae
A
548 if (processor->processor_self == IP_NULL)
549 ipc_processor_init(processor);
1c79356b 550
91447636 551 result = cpu_start(PROCESSOR_DATA(processor, slot_num));
55e303ae 552 if (result != KERN_SUCCESS) {
1c79356b
A
553 s = splsched();
554 processor_lock(processor);
555 processor->state = PROCESSOR_OFF_LINE;
91447636 556 timer_call_shutdown(processor);
1c79356b
A
557 processor_unlock(processor);
558 splx(s);
55e303ae
A
559
560 return (result);
1c79356b
A
561 }
562
55e303ae
A
563 ipc_processor_enable(processor);
564
565 return (KERN_SUCCESS);
1c79356b
A
566}
567
568kern_return_t
569processor_exit(
570 processor_t processor)
571{
572 if (processor == PROCESSOR_NULL)
573 return(KERN_INVALID_ARGUMENT);
574
575 return(processor_shutdown(processor));
576}
577
578kern_return_t
579processor_control(
580 processor_t processor,
581 processor_info_t info,
582 mach_msg_type_number_t count)
583{
584 if (processor == PROCESSOR_NULL)
585 return(KERN_INVALID_ARGUMENT);
586
91447636 587 return(cpu_control(PROCESSOR_DATA(processor, slot_num), info, count));
1c79356b
A
588}
589
590/*
91447636 591 * Calculate the appropriate timesharing quanta based on set load.
1c79356b
A
592 */
593
594void
91447636 595timeshare_quanta_update(
1c79356b
A
596 processor_set_t pset)
597{
91447636
A
598 int pcount = pset->processor_count;
599 int i = pset->runq.count;
600
601 if (i >= pcount)
602 i = 1;
603 else
604 if (i <= 1)
605 i = pcount;
606 else
607 i = (pcount + (i / 2)) / i;
608
609 pset->timeshare_quanta = i;
1c79356b
A
610}
611
612kern_return_t
613processor_set_create(
91447636
A
614 __unused host_t host,
615 __unused processor_set_t *new_set,
616 __unused processor_set_t *new_name)
1c79356b 617{
1c79356b
A
618 return(KERN_FAILURE);
619}
620
621kern_return_t
622processor_set_destroy(
91447636 623 __unused processor_set_t pset)
1c79356b 624{
1c79356b
A
625 return(KERN_FAILURE);
626}
627
628kern_return_t
629processor_get_assignment(
630 processor_t processor,
631 processor_set_t *pset)
632{
633 int state;
634
635 state = processor->state;
636 if (state == PROCESSOR_SHUTDOWN || state == PROCESSOR_OFF_LINE)
637 return(KERN_FAILURE);
638
639 *pset = processor->processor_set;
640 pset_reference(*pset);
641 return(KERN_SUCCESS);
642}
643
644kern_return_t
645processor_set_info(
646 processor_set_t pset,
647 int flavor,
648 host_t *host,
649 processor_set_info_t info,
650 mach_msg_type_number_t *count)
651{
652 if (pset == PROCESSOR_SET_NULL)
653 return(KERN_INVALID_ARGUMENT);
654
655 if (flavor == PROCESSOR_SET_BASIC_INFO) {
656 register processor_set_basic_info_t basic_info;
657
658 if (*count < PROCESSOR_SET_BASIC_INFO_COUNT)
659 return(KERN_FAILURE);
660
661 basic_info = (processor_set_basic_info_t) info;
1c79356b 662 basic_info->processor_count = pset->processor_count;
0b4e3aa0 663 basic_info->default_policy = POLICY_TIMESHARE;
1c79356b
A
664
665 *count = PROCESSOR_SET_BASIC_INFO_COUNT;
666 *host = &realhost;
667 return(KERN_SUCCESS);
668 }
669 else if (flavor == PROCESSOR_SET_TIMESHARE_DEFAULT) {
670 register policy_timeshare_base_t ts_base;
671
672 if (*count < POLICY_TIMESHARE_BASE_COUNT)
673 return(KERN_FAILURE);
674
675 ts_base = (policy_timeshare_base_t) info;
0b4e3aa0 676 ts_base->base_priority = BASEPRI_DEFAULT;
1c79356b
A
677
678 *count = POLICY_TIMESHARE_BASE_COUNT;
679 *host = &realhost;
680 return(KERN_SUCCESS);
681 }
682 else if (flavor == PROCESSOR_SET_FIFO_DEFAULT) {
683 register policy_fifo_base_t fifo_base;
684
685 if (*count < POLICY_FIFO_BASE_COUNT)
686 return(KERN_FAILURE);
687
688 fifo_base = (policy_fifo_base_t) info;
0b4e3aa0 689 fifo_base->base_priority = BASEPRI_DEFAULT;
1c79356b
A
690
691 *count = POLICY_FIFO_BASE_COUNT;
692 *host = &realhost;
693 return(KERN_SUCCESS);
694 }
695 else if (flavor == PROCESSOR_SET_RR_DEFAULT) {
696 register policy_rr_base_t rr_base;
697
698 if (*count < POLICY_RR_BASE_COUNT)
699 return(KERN_FAILURE);
700
701 rr_base = (policy_rr_base_t) info;
0b4e3aa0
A
702 rr_base->base_priority = BASEPRI_DEFAULT;
703 rr_base->quantum = 1;
1c79356b
A
704
705 *count = POLICY_RR_BASE_COUNT;
706 *host = &realhost;
707 return(KERN_SUCCESS);
708 }
709 else if (flavor == PROCESSOR_SET_TIMESHARE_LIMITS) {
710 register policy_timeshare_limit_t ts_limit;
711
712 if (*count < POLICY_TIMESHARE_LIMIT_COUNT)
713 return(KERN_FAILURE);
714
715 ts_limit = (policy_timeshare_limit_t) info;
91447636 716 ts_limit->max_priority = MAXPRI_KERNEL;
1c79356b
A
717
718 *count = POLICY_TIMESHARE_LIMIT_COUNT;
719 *host = &realhost;
720 return(KERN_SUCCESS);
721 }
722 else if (flavor == PROCESSOR_SET_FIFO_LIMITS) {
723 register policy_fifo_limit_t fifo_limit;
724
725 if (*count < POLICY_FIFO_LIMIT_COUNT)
726 return(KERN_FAILURE);
727
728 fifo_limit = (policy_fifo_limit_t) info;
91447636 729 fifo_limit->max_priority = MAXPRI_KERNEL;
1c79356b
A
730
731 *count = POLICY_FIFO_LIMIT_COUNT;
732 *host = &realhost;
733 return(KERN_SUCCESS);
734 }
735 else if (flavor == PROCESSOR_SET_RR_LIMITS) {
736 register policy_rr_limit_t rr_limit;
737
738 if (*count < POLICY_RR_LIMIT_COUNT)
739 return(KERN_FAILURE);
740
741 rr_limit = (policy_rr_limit_t) info;
91447636 742 rr_limit->max_priority = MAXPRI_KERNEL;
1c79356b
A
743
744 *count = POLICY_RR_LIMIT_COUNT;
745 *host = &realhost;
746 return(KERN_SUCCESS);
747 }
748 else if (flavor == PROCESSOR_SET_ENABLED_POLICIES) {
749 register int *enabled;
750
751 if (*count < (sizeof(*enabled)/sizeof(int)))
752 return(KERN_FAILURE);
753
754 enabled = (int *) info;
0b4e3aa0 755 *enabled = POLICY_TIMESHARE | POLICY_RR | POLICY_FIFO;
1c79356b
A
756
757 *count = sizeof(*enabled)/sizeof(int);
758 *host = &realhost;
759 return(KERN_SUCCESS);
760 }
761
762
763 *host = HOST_NULL;
764 return(KERN_INVALID_ARGUMENT);
765}
766
767/*
768 * processor_set_statistics
769 *
770 * Returns scheduling statistics for a processor set.
771 */
772kern_return_t
773processor_set_statistics(
774 processor_set_t pset,
775 int flavor,
776 processor_set_info_t info,
777 mach_msg_type_number_t *count)
778{
779 if (pset == PROCESSOR_SET_NULL)
780 return (KERN_INVALID_PROCESSOR_SET);
781
782 if (flavor == PROCESSOR_SET_LOAD_INFO) {
783 register processor_set_load_info_t load_info;
784
785 if (*count < PROCESSOR_SET_LOAD_INFO_COUNT)
786 return(KERN_FAILURE);
787
788 load_info = (processor_set_load_info_t) info;
789
790 pset_lock(pset);
791 load_info->task_count = pset->task_count;
792 load_info->thread_count = pset->thread_count;
1c79356b
A
793 load_info->mach_factor = pset->mach_factor;
794 load_info->load_average = pset->load_average;
1c79356b
A
795 pset_unlock(pset);
796
797 *count = PROCESSOR_SET_LOAD_INFO_COUNT;
798 return(KERN_SUCCESS);
799 }
800
801 return(KERN_INVALID_ARGUMENT);
802}
803
804/*
805 * processor_set_max_priority:
806 *
807 * Specify max priority permitted on processor set. This affects
808 * newly created and assigned threads. Optionally change existing
809 * ones.
810 */
811kern_return_t
812processor_set_max_priority(
91447636
A
813 __unused processor_set_t pset,
814 __unused int max_priority,
815 __unused boolean_t change_threads)
1c79356b
A
816{
817 return (KERN_INVALID_ARGUMENT);
818}
819
820/*
821 * processor_set_policy_enable:
822 *
823 * Allow indicated policy on processor set.
824 */
825
826kern_return_t
827processor_set_policy_enable(
91447636
A
828 __unused processor_set_t pset,
829 __unused int policy)
1c79356b
A
830{
831 return (KERN_INVALID_ARGUMENT);
832}
833
834/*
835 * processor_set_policy_disable:
836 *
837 * Forbid indicated policy on processor set. Time sharing cannot
838 * be forbidden.
839 */
840kern_return_t
841processor_set_policy_disable(
91447636
A
842 __unused processor_set_t pset,
843 __unused int policy,
844 __unused boolean_t change_threads)
1c79356b
A
845{
846 return (KERN_INVALID_ARGUMENT);
847}
848
849#define THING_TASK 0
850#define THING_THREAD 1
851
852/*
853 * processor_set_things:
854 *
855 * Common internals for processor_set_{threads,tasks}
856 */
857kern_return_t
858processor_set_things(
91447636
A
859 processor_set_t pset,
860 mach_port_t **thing_list,
1c79356b 861 mach_msg_type_number_t *count,
91447636 862 int type)
1c79356b
A
863{
864 unsigned int actual; /* this many things */
91447636
A
865 unsigned int maxthings;
866 unsigned int i;
1c79356b
A
867
868 vm_size_t size, size_needed;
91447636 869 void *addr;
1c79356b
A
870
871 if (pset == PROCESSOR_SET_NULL)
91447636 872 return (KERN_INVALID_ARGUMENT);
1c79356b
A
873
874 size = 0; addr = 0;
875
876 for (;;) {
877 pset_lock(pset);
878 if (!pset->active) {
879 pset_unlock(pset);
91447636
A
880
881 return (KERN_FAILURE);
1c79356b
A
882 }
883
884 if (type == THING_TASK)
91447636 885 maxthings = pset->task_count;
1c79356b 886 else
91447636 887 maxthings = pset->thread_count;
1c79356b
A
888
889 /* do we have the memory we need? */
890
91447636 891 size_needed = maxthings * sizeof (mach_port_t);
1c79356b
A
892 if (size_needed <= size)
893 break;
894
895 /* unlock the pset and allocate more memory */
896 pset_unlock(pset);
897
898 if (size != 0)
899 kfree(addr, size);
900
901 assert(size_needed > 0);
902 size = size_needed;
903
904 addr = kalloc(size);
905 if (addr == 0)
91447636 906 return (KERN_RESOURCE_SHORTAGE);
1c79356b
A
907 }
908
909 /* OK, have memory and the processor_set is locked & active */
910
91447636 911 actual = 0;
1c79356b 912 switch (type) {
91447636
A
913
914 case THING_TASK:
915 {
916 task_t task, *tasks = (task_t *)addr;
917
918 for (task = (task_t)queue_first(&pset->tasks);
919 !queue_end(&pset->tasks, (queue_entry_t)task);
920 task = (task_t)queue_next(&task->pset_tasks)) {
921 task_reference_internal(task);
922 tasks[actual++] = task;
1c79356b 923 }
91447636 924
1c79356b 925 break;
91447636
A
926 }
927
928 case THING_THREAD:
929 {
930 thread_t thread, *threads = (thread_t *)addr;
931
932 for (i = 0, thread = (thread_t)queue_first(&pset->threads);
933 !queue_end(&pset->threads, (queue_entry_t)thread);
934 thread = (thread_t)queue_next(&thread->pset_threads)) {
935 thread_reference_internal(thread);
936 threads[actual++] = thread;
1c79356b 937 }
91447636 938
1c79356b 939 break;
91447636 940 }
1c79356b 941 }
9bccf70c 942
1c79356b
A
943 pset_unlock(pset);
944
91447636
A
945 if (actual < maxthings)
946 size_needed = actual * sizeof (mach_port_t);
9bccf70c 947
1c79356b
A
948 if (actual == 0) {
949 /* no things, so return null pointer and deallocate memory */
950 *thing_list = 0;
951 *count = 0;
952
953 if (size != 0)
954 kfree(addr, size);
91447636
A
955 }
956 else {
1c79356b
A
957 /* if we allocated too much, must copy */
958
959 if (size_needed < size) {
91447636 960 void *newaddr;
1c79356b
A
961
962 newaddr = kalloc(size_needed);
963 if (newaddr == 0) {
964 switch (type) {
91447636
A
965
966 case THING_TASK:
967 {
968 task_t *tasks = (task_t *)addr;
1c79356b
A
969
970 for (i = 0; i < actual; i++)
971 task_deallocate(tasks[i]);
972 break;
91447636 973 }
1c79356b 974
91447636
A
975 case THING_THREAD:
976 {
977 thread_t *threads = (thread_t *)addr;
1c79356b
A
978
979 for (i = 0; i < actual; i++)
91447636 980 thread_deallocate(threads[i]);
1c79356b 981 break;
1c79356b 982 }
91447636
A
983 }
984
1c79356b 985 kfree(addr, size);
91447636 986 return (KERN_RESOURCE_SHORTAGE);
1c79356b
A
987 }
988
91447636 989 bcopy((void *) addr, (void *) newaddr, size_needed);
1c79356b
A
990 kfree(addr, size);
991 addr = newaddr;
992 }
993
91447636 994 *thing_list = (mach_port_t *)addr;
1c79356b
A
995 *count = actual;
996
997 /* do the conversion that Mig should handle */
998
999 switch (type) {
91447636
A
1000
1001 case THING_TASK:
1002 {
1003 task_t *tasks = (task_t *)addr;
1c79356b
A
1004
1005 for (i = 0; i < actual; i++)
1006 (*thing_list)[i] = convert_task_to_port(tasks[i]);
1007 break;
91447636 1008 }
1c79356b 1009
91447636
A
1010 case THING_THREAD:
1011 {
1012 thread_t *threads = (thread_t *)addr;
1c79356b
A
1013
1014 for (i = 0; i < actual; i++)
91447636 1015 (*thing_list)[i] = convert_thread_to_port(threads[i]);
1c79356b 1016 break;
91447636 1017 }
1c79356b
A
1018 }
1019 }
1020
91447636 1021 return (KERN_SUCCESS);
1c79356b
A
1022}
1023
1024
1025/*
1026 * processor_set_tasks:
1027 *
1028 * List all tasks in the processor set.
1029 */
1030kern_return_t
1031processor_set_tasks(
1032 processor_set_t pset,
1033 task_array_t *task_list,
1034 mach_msg_type_number_t *count)
1035{
1036 return(processor_set_things(pset, (mach_port_t **)task_list, count, THING_TASK));
1037}
1038
1039/*
1040 * processor_set_threads:
1041 *
1042 * List all threads in the processor set.
1043 */
1044kern_return_t
1045processor_set_threads(
1046 processor_set_t pset,
1047 thread_array_t *thread_list,
1048 mach_msg_type_number_t *count)
1049{
1050 return(processor_set_things(pset, (mach_port_t **)thread_list, count, THING_THREAD));
1051}
1052
1053/*
1054 * processor_set_base:
1055 *
1056 * Specify per-policy base priority for a processor set. Set processor
1057 * set default policy to the given policy. This affects newly created
1058 * and assigned threads. Optionally change existing ones.
1059 */
1060kern_return_t
1061processor_set_base(
91447636
A
1062 __unused processor_set_t pset,
1063 __unused policy_t policy,
1064 __unused policy_base_t base,
1065 __unused boolean_t change)
1c79356b
A
1066{
1067 return (KERN_INVALID_ARGUMENT);
1068}
1069
1070/*
1071 * processor_set_limit:
1072 *
1073 * Specify per-policy limits for a processor set. This affects
1074 * newly created and assigned threads. Optionally change existing
1075 * ones.
1076 */
1077kern_return_t
1078processor_set_limit(
91447636
A
1079 __unused processor_set_t pset,
1080 __unused policy_t policy,
1081 __unused policy_limit_t limit,
1082 __unused boolean_t change)
1c79356b
A
1083{
1084 return (KERN_POLICY_LIMIT);
1085}
1086
1087/*
1088 * processor_set_policy_control
1089 *
1090 * Controls the scheduling attributes governing the processor set.
1091 * Allows control of enabled policies, and per-policy base and limit
1092 * priorities.
1093 */
1094kern_return_t
1095processor_set_policy_control(
91447636
A
1096 __unused processor_set_t pset,
1097 __unused int flavor,
1098 __unused processor_set_info_t policy_info,
1099 __unused mach_msg_type_number_t count,
1100 __unused boolean_t change)
1c79356b
A
1101{
1102 return (KERN_INVALID_ARGUMENT);
1103}