]>
Commit | Line | Data |
---|---|---|
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 | ||
1c79356b A |
81 | /* |
82 | * Exported interface | |
83 | */ | |
84 | #include <mach/mach_host_server.h> | |
91447636 | 85 | #include <mach/processor_set_server.h> |
1c79356b | 86 | |
2d21ac55 A |
87 | struct processor_set pset0; |
88 | struct pset_node pset_node0; | |
89 | decl_simple_lock_data(static,pset_node_lock) | |
90 | ||
91 | queue_head_t tasks; | |
6d2010ae | 92 | queue_head_t terminated_tasks; /* To be used ONLY for stackshot. */ |
2d21ac55 A |
93 | int tasks_count; |
94 | queue_head_t threads; | |
95 | int threads_count; | |
b0d623f7 | 96 | decl_lck_mtx_data(,tasks_threads_lock) |
1c79356b | 97 | |
91447636 A |
98 | processor_t processor_list; |
99 | unsigned int processor_count; | |
100 | static processor_t processor_list_tail; | |
101 | decl_simple_lock_data(,processor_list_lock) | |
9bccf70c | 102 | |
2d21ac55 A |
103 | uint32_t processor_avail_count; |
104 | ||
b0d623f7 A |
105 | processor_t master_processor; |
106 | int master_cpu = 0; | |
6d2010ae | 107 | boolean_t sched_stats_active = FALSE; |
1c79356b A |
108 | |
109 | /* Forwards */ | |
1c79356b A |
110 | kern_return_t processor_set_things( |
111 | processor_set_t pset, | |
112 | mach_port_t **thing_list, | |
113 | mach_msg_type_number_t *count, | |
114 | int type); | |
115 | ||
1c79356b | 116 | void |
91447636 | 117 | processor_bootstrap(void) |
1c79356b | 118 | { |
2d21ac55 A |
119 | pset_init(&pset0, &pset_node0); |
120 | pset_node0.psets = &pset0; | |
55e303ae | 121 | |
2d21ac55 | 122 | simple_lock_init(&pset_node_lock, 0); |
55e303ae | 123 | |
2d21ac55 | 124 | queue_init(&tasks); |
6d2010ae | 125 | queue_init(&terminated_tasks); |
2d21ac55 | 126 | queue_init(&threads); |
1c79356b | 127 | |
2d21ac55 | 128 | simple_lock_init(&processor_list_lock, 0); |
1c79356b | 129 | |
2d21ac55 | 130 | master_processor = cpu_to_processor(master_cpu); |
1c79356b | 131 | |
2d21ac55 | 132 | processor_init(master_processor, master_cpu, &pset0); |
1c79356b A |
133 | } |
134 | ||
135 | /* | |
2d21ac55 | 136 | * Initialize the given processor for the cpu |
b0d623f7 | 137 | * indicated by cpu_id, and assign to the |
2d21ac55 | 138 | * specified processor set. |
1c79356b A |
139 | */ |
140 | void | |
141 | processor_init( | |
c910b4d9 | 142 | processor_t processor, |
b0d623f7 | 143 | int cpu_id, |
c910b4d9 | 144 | processor_set_t pset) |
1c79356b | 145 | { |
6d2010ae A |
146 | if (processor != master_processor) { |
147 | /* Scheduler state deferred until sched_init() */ | |
148 | SCHED(processor_init)(processor); | |
149 | } | |
c910b4d9 A |
150 | |
151 | processor->state = PROCESSOR_OFF_LINE; | |
152 | processor->active_thread = processor->next_thread = processor->idle_thread = THREAD_NULL; | |
153 | processor->processor_set = pset; | |
154 | processor->current_pri = MINPRI; | |
6d2010ae | 155 | processor->current_thmode = TH_MODE_NONE; |
b0d623f7 | 156 | processor->cpu_id = cpu_id; |
c910b4d9 A |
157 | timer_call_setup(&processor->quantum_timer, thread_quantum_expire, processor); |
158 | processor->deadline = UINT64_MAX; | |
159 | processor->timeslice = 0; | |
b0d623f7 | 160 | processor->processor_meta = PROCESSOR_META_NULL; |
c910b4d9 | 161 | processor->processor_self = IP_NULL; |
c910b4d9 A |
162 | processor_data_init(processor); |
163 | processor->processor_list = NULL; | |
91447636 | 164 | |
b7266188 A |
165 | pset_lock(pset); |
166 | if (pset->cpu_set_count++ == 0) | |
167 | pset->cpu_set_low = pset->cpu_set_hi = cpu_id; | |
168 | else { | |
169 | pset->cpu_set_low = (cpu_id < pset->cpu_set_low)? cpu_id: pset->cpu_set_low; | |
170 | pset->cpu_set_hi = (cpu_id > pset->cpu_set_hi)? cpu_id: pset->cpu_set_hi; | |
171 | } | |
172 | pset_unlock(pset); | |
173 | ||
91447636 A |
174 | simple_lock(&processor_list_lock); |
175 | if (processor_list == NULL) | |
c910b4d9 | 176 | processor_list = processor; |
91447636 | 177 | else |
c910b4d9 A |
178 | processor_list_tail->processor_list = processor; |
179 | processor_list_tail = processor; | |
91447636 | 180 | processor_count++; |
91447636 | 181 | simple_unlock(&processor_list_lock); |
9bccf70c | 182 | } |
1c79356b | 183 | |
b0d623f7 A |
184 | void |
185 | processor_meta_init( | |
186 | processor_t processor, | |
187 | processor_t primary) | |
188 | { | |
189 | processor_meta_t pmeta = primary->processor_meta; | |
190 | ||
191 | if (pmeta == PROCESSOR_META_NULL) { | |
192 | pmeta = kalloc(sizeof (*pmeta)); | |
193 | ||
194 | queue_init(&pmeta->idle_queue); | |
195 | ||
196 | pmeta->primary = primary; | |
197 | } | |
198 | ||
199 | processor->processor_meta = pmeta; | |
200 | } | |
201 | ||
2d21ac55 A |
202 | processor_set_t |
203 | processor_pset( | |
204 | processor_t processor) | |
9bccf70c | 205 | { |
2d21ac55 | 206 | return (processor->processor_set); |
1c79356b A |
207 | } |
208 | ||
2d21ac55 A |
209 | pset_node_t |
210 | pset_node_root(void) | |
9bccf70c | 211 | { |
2d21ac55 | 212 | return &pset_node0; |
9bccf70c A |
213 | } |
214 | ||
2d21ac55 A |
215 | processor_set_t |
216 | pset_create( | |
217 | pset_node_t node) | |
1c79356b | 218 | { |
2d21ac55 | 219 | processor_set_t *prev, pset = kalloc(sizeof (*pset)); |
1c79356b | 220 | |
2d21ac55 A |
221 | if (pset != PROCESSOR_SET_NULL) { |
222 | pset_init(pset, node); | |
1c79356b | 223 | |
2d21ac55 | 224 | simple_lock(&pset_node_lock); |
1c79356b | 225 | |
2d21ac55 A |
226 | prev = &node->psets; |
227 | while (*prev != PROCESSOR_SET_NULL) | |
228 | prev = &(*prev)->pset_list; | |
1c79356b | 229 | |
2d21ac55 | 230 | *prev = pset; |
1c79356b | 231 | |
2d21ac55 A |
232 | simple_unlock(&pset_node_lock); |
233 | } | |
1c79356b | 234 | |
2d21ac55 | 235 | return (pset); |
1c79356b A |
236 | } |
237 | ||
238 | /* | |
2d21ac55 | 239 | * Initialize the given processor_set structure. |
1c79356b A |
240 | */ |
241 | void | |
2d21ac55 A |
242 | pset_init( |
243 | processor_set_t pset, | |
244 | pset_node_t node) | |
1c79356b | 245 | { |
6d2010ae A |
246 | if (pset != &pset0) { |
247 | /* Scheduler state deferred until sched_init() */ | |
248 | SCHED(pset_init)(pset); | |
249 | } | |
250 | ||
2d21ac55 A |
251 | queue_init(&pset->active_queue); |
252 | queue_init(&pset->idle_queue); | |
6d2010ae A |
253 | pset->online_processor_count = 0; |
254 | pset_pri_init_hint(pset, PROCESSOR_NULL); | |
255 | pset_count_init_hint(pset, PROCESSOR_NULL); | |
b7266188 A |
256 | pset->cpu_set_low = pset->cpu_set_hi = 0; |
257 | pset->cpu_set_count = 0; | |
2d21ac55 A |
258 | pset_lock_init(pset); |
259 | pset->pset_self = IP_NULL; | |
260 | pset->pset_name_self = IP_NULL; | |
261 | pset->pset_list = PROCESSOR_SET_NULL; | |
262 | pset->node = node; | |
1c79356b A |
263 | } |
264 | ||
1c79356b A |
265 | kern_return_t |
266 | processor_info_count( | |
91447636 | 267 | processor_flavor_t flavor, |
1c79356b A |
268 | mach_msg_type_number_t *count) |
269 | { | |
1c79356b | 270 | switch (flavor) { |
91447636 | 271 | |
1c79356b A |
272 | case PROCESSOR_BASIC_INFO: |
273 | *count = PROCESSOR_BASIC_INFO_COUNT; | |
91447636 A |
274 | break; |
275 | ||
1c79356b A |
276 | case PROCESSOR_CPU_LOAD_INFO: |
277 | *count = PROCESSOR_CPU_LOAD_INFO_COUNT; | |
91447636 A |
278 | break; |
279 | ||
1c79356b | 280 | default: |
91447636 | 281 | return (cpu_info_count(flavor, count)); |
1c79356b | 282 | } |
91447636 A |
283 | |
284 | return (KERN_SUCCESS); | |
1c79356b A |
285 | } |
286 | ||
287 | ||
288 | kern_return_t | |
289 | processor_info( | |
290 | register processor_t processor, | |
91447636 A |
291 | processor_flavor_t flavor, |
292 | host_t *host, | |
293 | processor_info_t info, | |
1c79356b A |
294 | mach_msg_type_number_t *count) |
295 | { | |
b0d623f7 | 296 | register int cpu_id, state; |
91447636 | 297 | kern_return_t result; |
1c79356b A |
298 | |
299 | if (processor == PROCESSOR_NULL) | |
91447636 | 300 | return (KERN_INVALID_ARGUMENT); |
1c79356b | 301 | |
b0d623f7 | 302 | cpu_id = processor->cpu_id; |
1c79356b A |
303 | |
304 | switch (flavor) { | |
305 | ||
306 | case PROCESSOR_BASIC_INFO: | |
91447636 A |
307 | { |
308 | register processor_basic_info_t basic_info; | |
309 | ||
310 | if (*count < PROCESSOR_BASIC_INFO_COUNT) | |
311 | return (KERN_FAILURE); | |
312 | ||
313 | basic_info = (processor_basic_info_t) info; | |
b0d623f7 A |
314 | basic_info->cpu_type = slot_type(cpu_id); |
315 | basic_info->cpu_subtype = slot_subtype(cpu_id); | |
91447636 A |
316 | state = processor->state; |
317 | if (state == PROCESSOR_OFF_LINE) | |
318 | basic_info->running = FALSE; | |
319 | else | |
320 | basic_info->running = TRUE; | |
b0d623f7 | 321 | basic_info->slot_num = cpu_id; |
91447636 A |
322 | if (processor == master_processor) |
323 | basic_info->is_master = TRUE; | |
324 | else | |
325 | basic_info->is_master = FALSE; | |
326 | ||
327 | *count = PROCESSOR_BASIC_INFO_COUNT; | |
328 | *host = &realhost; | |
329 | ||
330 | return (KERN_SUCCESS); | |
331 | } | |
332 | ||
1c79356b | 333 | case PROCESSOR_CPU_LOAD_INFO: |
91447636 A |
334 | { |
335 | register processor_cpu_load_info_t cpu_load_info; | |
91447636 | 336 | |
6d2010ae | 337 | if (*count < PROCESSOR_CPU_LOAD_INFO_COUNT) |
91447636 | 338 | return (KERN_FAILURE); |
1c79356b | 339 | |
6d2010ae | 340 | cpu_load_info = (processor_cpu_load_info_t) info; |
2d21ac55 | 341 | cpu_load_info->cpu_ticks[CPU_STATE_USER] = |
b0d623f7 | 342 | (uint32_t)(timer_grab(&PROCESSOR_DATA(processor, user_state)) / hz_tick_interval); |
2d21ac55 | 343 | cpu_load_info->cpu_ticks[CPU_STATE_SYSTEM] = |
b0d623f7 | 344 | (uint32_t)(timer_grab(&PROCESSOR_DATA(processor, system_state)) / hz_tick_interval); |
6d2010ae A |
345 | { |
346 | timer_data_t idle_temp; | |
347 | timer_t idle_state; | |
348 | ||
349 | idle_state = &PROCESSOR_DATA(processor, idle_state); | |
350 | idle_temp = *idle_state; | |
351 | ||
352 | if (PROCESSOR_DATA(processor, current_state) != idle_state || | |
353 | timer_grab(&idle_temp) != timer_grab(idle_state)) | |
354 | cpu_load_info->cpu_ticks[CPU_STATE_IDLE] = | |
b0d623f7 | 355 | (uint32_t)(timer_grab(&PROCESSOR_DATA(processor, idle_state)) / hz_tick_interval); |
6d2010ae A |
356 | else { |
357 | timer_advance(&idle_temp, mach_absolute_time() - idle_temp.tstamp); | |
358 | ||
359 | cpu_load_info->cpu_ticks[CPU_STATE_IDLE] = | |
360 | (uint32_t)(timer_grab(&idle_temp) / hz_tick_interval); | |
361 | } | |
362 | } | |
2d21ac55 | 363 | cpu_load_info->cpu_ticks[CPU_STATE_NICE] = 0; |
1c79356b A |
364 | |
365 | *count = PROCESSOR_CPU_LOAD_INFO_COUNT; | |
366 | *host = &realhost; | |
91447636 A |
367 | |
368 | return (KERN_SUCCESS); | |
369 | } | |
370 | ||
1c79356b | 371 | default: |
b0d623f7 | 372 | result = cpu_info(flavor, cpu_id, info, count); |
91447636 A |
373 | if (result == KERN_SUCCESS) |
374 | *host = &realhost; | |
375 | ||
376 | return (result); | |
1c79356b A |
377 | } |
378 | } | |
379 | ||
380 | kern_return_t | |
381 | processor_start( | |
2d21ac55 | 382 | processor_t processor) |
1c79356b | 383 | { |
2d21ac55 A |
384 | processor_set_t pset; |
385 | thread_t thread; | |
386 | kern_return_t result; | |
387 | spl_t s; | |
1c79356b | 388 | |
2d21ac55 | 389 | if (processor == PROCESSOR_NULL || processor->processor_set == PROCESSOR_SET_NULL) |
91447636 | 390 | return (KERN_INVALID_ARGUMENT); |
1c79356b | 391 | |
0b4e3aa0 | 392 | if (processor == master_processor) { |
55e303ae A |
393 | processor_t prev; |
394 | ||
2d21ac55 | 395 | prev = thread_bind(processor); |
9bccf70c | 396 | thread_block(THREAD_CONTINUE_NULL); |
0b4e3aa0 | 397 | |
b0d623f7 | 398 | result = cpu_start(processor->cpu_id); |
55e303ae | 399 | |
2d21ac55 | 400 | thread_bind(prev); |
55e303ae A |
401 | |
402 | return (result); | |
0b4e3aa0 | 403 | } |
1c79356b A |
404 | |
405 | s = splsched(); | |
2d21ac55 A |
406 | pset = processor->processor_set; |
407 | pset_lock(pset); | |
55e303ae | 408 | if (processor->state != PROCESSOR_OFF_LINE) { |
2d21ac55 | 409 | pset_unlock(pset); |
1c79356b | 410 | splx(s); |
55e303ae A |
411 | |
412 | return (KERN_FAILURE); | |
1c79356b | 413 | } |
55e303ae | 414 | |
1c79356b | 415 | processor->state = PROCESSOR_START; |
2d21ac55 | 416 | pset_unlock(pset); |
1c79356b A |
417 | splx(s); |
418 | ||
91447636 A |
419 | /* |
420 | * Create the idle processor thread. | |
421 | */ | |
422 | if (processor->idle_thread == THREAD_NULL) { | |
423 | result = idle_thread_create(processor); | |
424 | if (result != KERN_SUCCESS) { | |
425 | s = splsched(); | |
2d21ac55 | 426 | pset_lock(pset); |
91447636 | 427 | processor->state = PROCESSOR_OFF_LINE; |
2d21ac55 | 428 | pset_unlock(pset); |
91447636 A |
429 | splx(s); |
430 | ||
431 | return (result); | |
432 | } | |
433 | } | |
434 | ||
435 | /* | |
436 | * If there is no active thread, the processor | |
437 | * has never been started. Create a dedicated | |
438 | * start up thread. | |
439 | */ | |
440 | if ( processor->active_thread == THREAD_NULL && | |
441 | processor->next_thread == THREAD_NULL ) { | |
442 | result = kernel_thread_create((thread_continue_t)processor_start_thread, NULL, MAXPRI_KERNEL, &thread); | |
443 | if (result != KERN_SUCCESS) { | |
444 | s = splsched(); | |
2d21ac55 | 445 | pset_lock(pset); |
91447636 | 446 | processor->state = PROCESSOR_OFF_LINE; |
2d21ac55 | 447 | pset_unlock(pset); |
91447636 A |
448 | splx(s); |
449 | ||
450 | return (result); | |
451 | } | |
1c79356b A |
452 | |
453 | s = splsched(); | |
454 | thread_lock(thread); | |
55e303ae | 455 | thread->bound_processor = processor; |
1c79356b | 456 | processor->next_thread = thread; |
55e303ae | 457 | thread->state = TH_RUN; |
1c79356b A |
458 | thread_unlock(thread); |
459 | splx(s); | |
91447636 A |
460 | |
461 | thread_deallocate(thread); | |
1c79356b A |
462 | } |
463 | ||
55e303ae A |
464 | if (processor->processor_self == IP_NULL) |
465 | ipc_processor_init(processor); | |
1c79356b | 466 | |
b0d623f7 | 467 | result = cpu_start(processor->cpu_id); |
55e303ae | 468 | if (result != KERN_SUCCESS) { |
1c79356b | 469 | s = splsched(); |
2d21ac55 | 470 | pset_lock(pset); |
1c79356b | 471 | processor->state = PROCESSOR_OFF_LINE; |
2d21ac55 | 472 | pset_unlock(pset); |
1c79356b | 473 | splx(s); |
55e303ae A |
474 | |
475 | return (result); | |
1c79356b A |
476 | } |
477 | ||
55e303ae A |
478 | ipc_processor_enable(processor); |
479 | ||
480 | return (KERN_SUCCESS); | |
1c79356b A |
481 | } |
482 | ||
483 | kern_return_t | |
484 | processor_exit( | |
485 | processor_t processor) | |
486 | { | |
487 | if (processor == PROCESSOR_NULL) | |
488 | return(KERN_INVALID_ARGUMENT); | |
489 | ||
490 | return(processor_shutdown(processor)); | |
491 | } | |
492 | ||
493 | kern_return_t | |
494 | processor_control( | |
495 | processor_t processor, | |
496 | processor_info_t info, | |
497 | mach_msg_type_number_t count) | |
498 | { | |
499 | if (processor == PROCESSOR_NULL) | |
500 | return(KERN_INVALID_ARGUMENT); | |
501 | ||
b0d623f7 | 502 | return(cpu_control(processor->cpu_id, info, count)); |
1c79356b | 503 | } |
1c79356b A |
504 | |
505 | kern_return_t | |
506 | processor_set_create( | |
91447636 A |
507 | __unused host_t host, |
508 | __unused processor_set_t *new_set, | |
509 | __unused processor_set_t *new_name) | |
1c79356b | 510 | { |
1c79356b A |
511 | return(KERN_FAILURE); |
512 | } | |
513 | ||
514 | kern_return_t | |
515 | processor_set_destroy( | |
91447636 | 516 | __unused processor_set_t pset) |
1c79356b | 517 | { |
1c79356b A |
518 | return(KERN_FAILURE); |
519 | } | |
520 | ||
521 | kern_return_t | |
522 | processor_get_assignment( | |
523 | processor_t processor, | |
524 | processor_set_t *pset) | |
525 | { | |
2d21ac55 | 526 | int state; |
1c79356b A |
527 | |
528 | state = processor->state; | |
529 | if (state == PROCESSOR_SHUTDOWN || state == PROCESSOR_OFF_LINE) | |
530 | return(KERN_FAILURE); | |
531 | ||
2d21ac55 A |
532 | *pset = &pset0; |
533 | ||
1c79356b A |
534 | return(KERN_SUCCESS); |
535 | } | |
536 | ||
537 | kern_return_t | |
538 | processor_set_info( | |
539 | processor_set_t pset, | |
540 | int flavor, | |
541 | host_t *host, | |
542 | processor_set_info_t info, | |
543 | mach_msg_type_number_t *count) | |
544 | { | |
545 | if (pset == PROCESSOR_SET_NULL) | |
546 | return(KERN_INVALID_ARGUMENT); | |
547 | ||
548 | if (flavor == PROCESSOR_SET_BASIC_INFO) { | |
549 | register processor_set_basic_info_t basic_info; | |
550 | ||
551 | if (*count < PROCESSOR_SET_BASIC_INFO_COUNT) | |
552 | return(KERN_FAILURE); | |
553 | ||
554 | basic_info = (processor_set_basic_info_t) info; | |
2d21ac55 | 555 | basic_info->processor_count = processor_avail_count; |
0b4e3aa0 | 556 | basic_info->default_policy = POLICY_TIMESHARE; |
1c79356b A |
557 | |
558 | *count = PROCESSOR_SET_BASIC_INFO_COUNT; | |
559 | *host = &realhost; | |
560 | return(KERN_SUCCESS); | |
561 | } | |
562 | else if (flavor == PROCESSOR_SET_TIMESHARE_DEFAULT) { | |
563 | register policy_timeshare_base_t ts_base; | |
564 | ||
565 | if (*count < POLICY_TIMESHARE_BASE_COUNT) | |
566 | return(KERN_FAILURE); | |
567 | ||
568 | ts_base = (policy_timeshare_base_t) info; | |
0b4e3aa0 | 569 | ts_base->base_priority = BASEPRI_DEFAULT; |
1c79356b A |
570 | |
571 | *count = POLICY_TIMESHARE_BASE_COUNT; | |
572 | *host = &realhost; | |
573 | return(KERN_SUCCESS); | |
574 | } | |
575 | else if (flavor == PROCESSOR_SET_FIFO_DEFAULT) { | |
576 | register policy_fifo_base_t fifo_base; | |
577 | ||
578 | if (*count < POLICY_FIFO_BASE_COUNT) | |
579 | return(KERN_FAILURE); | |
580 | ||
581 | fifo_base = (policy_fifo_base_t) info; | |
0b4e3aa0 | 582 | fifo_base->base_priority = BASEPRI_DEFAULT; |
1c79356b A |
583 | |
584 | *count = POLICY_FIFO_BASE_COUNT; | |
585 | *host = &realhost; | |
586 | return(KERN_SUCCESS); | |
587 | } | |
588 | else if (flavor == PROCESSOR_SET_RR_DEFAULT) { | |
589 | register policy_rr_base_t rr_base; | |
590 | ||
591 | if (*count < POLICY_RR_BASE_COUNT) | |
592 | return(KERN_FAILURE); | |
593 | ||
594 | rr_base = (policy_rr_base_t) info; | |
0b4e3aa0 A |
595 | rr_base->base_priority = BASEPRI_DEFAULT; |
596 | rr_base->quantum = 1; | |
1c79356b A |
597 | |
598 | *count = POLICY_RR_BASE_COUNT; | |
599 | *host = &realhost; | |
600 | return(KERN_SUCCESS); | |
601 | } | |
602 | else if (flavor == PROCESSOR_SET_TIMESHARE_LIMITS) { | |
603 | register policy_timeshare_limit_t ts_limit; | |
604 | ||
605 | if (*count < POLICY_TIMESHARE_LIMIT_COUNT) | |
606 | return(KERN_FAILURE); | |
607 | ||
608 | ts_limit = (policy_timeshare_limit_t) info; | |
91447636 | 609 | ts_limit->max_priority = MAXPRI_KERNEL; |
1c79356b A |
610 | |
611 | *count = POLICY_TIMESHARE_LIMIT_COUNT; | |
612 | *host = &realhost; | |
613 | return(KERN_SUCCESS); | |
614 | } | |
615 | else if (flavor == PROCESSOR_SET_FIFO_LIMITS) { | |
616 | register policy_fifo_limit_t fifo_limit; | |
617 | ||
618 | if (*count < POLICY_FIFO_LIMIT_COUNT) | |
619 | return(KERN_FAILURE); | |
620 | ||
621 | fifo_limit = (policy_fifo_limit_t) info; | |
91447636 | 622 | fifo_limit->max_priority = MAXPRI_KERNEL; |
1c79356b A |
623 | |
624 | *count = POLICY_FIFO_LIMIT_COUNT; | |
625 | *host = &realhost; | |
626 | return(KERN_SUCCESS); | |
627 | } | |
628 | else if (flavor == PROCESSOR_SET_RR_LIMITS) { | |
629 | register policy_rr_limit_t rr_limit; | |
630 | ||
631 | if (*count < POLICY_RR_LIMIT_COUNT) | |
632 | return(KERN_FAILURE); | |
633 | ||
634 | rr_limit = (policy_rr_limit_t) info; | |
91447636 | 635 | rr_limit->max_priority = MAXPRI_KERNEL; |
1c79356b A |
636 | |
637 | *count = POLICY_RR_LIMIT_COUNT; | |
638 | *host = &realhost; | |
639 | return(KERN_SUCCESS); | |
640 | } | |
641 | else if (flavor == PROCESSOR_SET_ENABLED_POLICIES) { | |
642 | register int *enabled; | |
643 | ||
644 | if (*count < (sizeof(*enabled)/sizeof(int))) | |
645 | return(KERN_FAILURE); | |
646 | ||
647 | enabled = (int *) info; | |
0b4e3aa0 | 648 | *enabled = POLICY_TIMESHARE | POLICY_RR | POLICY_FIFO; |
1c79356b A |
649 | |
650 | *count = sizeof(*enabled)/sizeof(int); | |
651 | *host = &realhost; | |
652 | return(KERN_SUCCESS); | |
653 | } | |
654 | ||
655 | ||
656 | *host = HOST_NULL; | |
657 | return(KERN_INVALID_ARGUMENT); | |
658 | } | |
659 | ||
660 | /* | |
661 | * processor_set_statistics | |
662 | * | |
663 | * Returns scheduling statistics for a processor set. | |
664 | */ | |
665 | kern_return_t | |
666 | processor_set_statistics( | |
667 | processor_set_t pset, | |
668 | int flavor, | |
669 | processor_set_info_t info, | |
670 | mach_msg_type_number_t *count) | |
671 | { | |
2d21ac55 A |
672 | if (pset == PROCESSOR_SET_NULL || pset != &pset0) |
673 | return (KERN_INVALID_PROCESSOR_SET); | |
674 | ||
675 | if (flavor == PROCESSOR_SET_LOAD_INFO) { | |
676 | register processor_set_load_info_t load_info; | |
1c79356b | 677 | |
2d21ac55 A |
678 | if (*count < PROCESSOR_SET_LOAD_INFO_COUNT) |
679 | return(KERN_FAILURE); | |
1c79356b | 680 | |
2d21ac55 | 681 | load_info = (processor_set_load_info_t) info; |
1c79356b | 682 | |
2d21ac55 A |
683 | load_info->mach_factor = sched_mach_factor; |
684 | load_info->load_average = sched_load_average; | |
1c79356b | 685 | |
2d21ac55 A |
686 | load_info->task_count = tasks_count; |
687 | load_info->thread_count = threads_count; | |
1c79356b | 688 | |
2d21ac55 A |
689 | *count = PROCESSOR_SET_LOAD_INFO_COUNT; |
690 | return(KERN_SUCCESS); | |
691 | } | |
1c79356b | 692 | |
2d21ac55 | 693 | return(KERN_INVALID_ARGUMENT); |
1c79356b A |
694 | } |
695 | ||
696 | /* | |
697 | * processor_set_max_priority: | |
698 | * | |
699 | * Specify max priority permitted on processor set. This affects | |
700 | * newly created and assigned threads. Optionally change existing | |
701 | * ones. | |
702 | */ | |
703 | kern_return_t | |
704 | processor_set_max_priority( | |
91447636 A |
705 | __unused processor_set_t pset, |
706 | __unused int max_priority, | |
707 | __unused boolean_t change_threads) | |
1c79356b A |
708 | { |
709 | return (KERN_INVALID_ARGUMENT); | |
710 | } | |
711 | ||
712 | /* | |
713 | * processor_set_policy_enable: | |
714 | * | |
715 | * Allow indicated policy on processor set. | |
716 | */ | |
717 | ||
718 | kern_return_t | |
719 | processor_set_policy_enable( | |
91447636 A |
720 | __unused processor_set_t pset, |
721 | __unused int policy) | |
1c79356b A |
722 | { |
723 | return (KERN_INVALID_ARGUMENT); | |
724 | } | |
725 | ||
726 | /* | |
727 | * processor_set_policy_disable: | |
728 | * | |
729 | * Forbid indicated policy on processor set. Time sharing cannot | |
730 | * be forbidden. | |
731 | */ | |
732 | kern_return_t | |
733 | processor_set_policy_disable( | |
91447636 A |
734 | __unused processor_set_t pset, |
735 | __unused int policy, | |
736 | __unused boolean_t change_threads) | |
1c79356b A |
737 | { |
738 | return (KERN_INVALID_ARGUMENT); | |
739 | } | |
740 | ||
741 | #define THING_TASK 0 | |
742 | #define THING_THREAD 1 | |
743 | ||
744 | /* | |
745 | * processor_set_things: | |
746 | * | |
747 | * Common internals for processor_set_{threads,tasks} | |
748 | */ | |
749 | kern_return_t | |
750 | processor_set_things( | |
91447636 A |
751 | processor_set_t pset, |
752 | mach_port_t **thing_list, | |
1c79356b | 753 | mach_msg_type_number_t *count, |
91447636 | 754 | int type) |
1c79356b A |
755 | { |
756 | unsigned int actual; /* this many things */ | |
91447636 A |
757 | unsigned int maxthings; |
758 | unsigned int i; | |
1c79356b A |
759 | |
760 | vm_size_t size, size_needed; | |
91447636 | 761 | void *addr; |
1c79356b | 762 | |
2d21ac55 | 763 | if (pset == PROCESSOR_SET_NULL || pset != &pset0) |
91447636 | 764 | return (KERN_INVALID_ARGUMENT); |
1c79356b | 765 | |
2d21ac55 A |
766 | size = 0; |
767 | addr = NULL; | |
1c79356b A |
768 | |
769 | for (;;) { | |
b0d623f7 | 770 | lck_mtx_lock(&tasks_threads_lock); |
1c79356b A |
771 | |
772 | if (type == THING_TASK) | |
2d21ac55 | 773 | maxthings = tasks_count; |
1c79356b | 774 | else |
2d21ac55 | 775 | maxthings = threads_count; |
1c79356b A |
776 | |
777 | /* do we have the memory we need? */ | |
778 | ||
91447636 | 779 | size_needed = maxthings * sizeof (mach_port_t); |
1c79356b A |
780 | if (size_needed <= size) |
781 | break; | |
782 | ||
2d21ac55 | 783 | /* unlock and allocate more memory */ |
b0d623f7 | 784 | lck_mtx_unlock(&tasks_threads_lock); |
1c79356b A |
785 | |
786 | if (size != 0) | |
787 | kfree(addr, size); | |
788 | ||
789 | assert(size_needed > 0); | |
790 | size = size_needed; | |
791 | ||
792 | addr = kalloc(size); | |
793 | if (addr == 0) | |
91447636 | 794 | return (KERN_RESOURCE_SHORTAGE); |
1c79356b A |
795 | } |
796 | ||
2d21ac55 | 797 | /* OK, have memory and the list locked */ |
1c79356b | 798 | |
91447636 | 799 | actual = 0; |
1c79356b | 800 | switch (type) { |
91447636 | 801 | |
2d21ac55 A |
802 | case THING_TASK: { |
803 | task_t task, *task_list = (task_t *)addr; | |
804 | ||
805 | for (task = (task_t)queue_first(&tasks); | |
806 | !queue_end(&tasks, (queue_entry_t)task); | |
807 | task = (task_t)queue_next(&task->tasks)) { | |
808 | #if defined(SECURE_KERNEL) | |
809 | if (task != kernel_task) { | |
810 | #endif | |
811 | task_reference_internal(task); | |
812 | task_list[actual++] = task; | |
813 | #if defined(SECURE_KERNEL) | |
814 | } | |
815 | #endif | |
1c79356b | 816 | } |
91447636 | 817 | |
1c79356b | 818 | break; |
91447636 A |
819 | } |
820 | ||
2d21ac55 A |
821 | case THING_THREAD: { |
822 | thread_t thread, *thread_list = (thread_t *)addr; | |
91447636 | 823 | |
2d21ac55 A |
824 | for (thread = (thread_t)queue_first(&threads); |
825 | !queue_end(&threads, (queue_entry_t)thread); | |
826 | thread = (thread_t)queue_next(&thread->threads)) { | |
91447636 | 827 | thread_reference_internal(thread); |
2d21ac55 | 828 | thread_list[actual++] = thread; |
1c79356b | 829 | } |
91447636 | 830 | |
1c79356b | 831 | break; |
91447636 | 832 | } |
2d21ac55 | 833 | |
1c79356b | 834 | } |
9bccf70c | 835 | |
b0d623f7 | 836 | lck_mtx_unlock(&tasks_threads_lock); |
1c79356b | 837 | |
91447636 A |
838 | if (actual < maxthings) |
839 | size_needed = actual * sizeof (mach_port_t); | |
9bccf70c | 840 | |
1c79356b A |
841 | if (actual == 0) { |
842 | /* no things, so return null pointer and deallocate memory */ | |
2d21ac55 | 843 | *thing_list = NULL; |
1c79356b A |
844 | *count = 0; |
845 | ||
846 | if (size != 0) | |
847 | kfree(addr, size); | |
91447636 A |
848 | } |
849 | else { | |
1c79356b A |
850 | /* if we allocated too much, must copy */ |
851 | ||
852 | if (size_needed < size) { | |
91447636 | 853 | void *newaddr; |
1c79356b A |
854 | |
855 | newaddr = kalloc(size_needed); | |
856 | if (newaddr == 0) { | |
857 | switch (type) { | |
91447636 | 858 | |
2d21ac55 A |
859 | case THING_TASK: { |
860 | task_t *task_list = (task_t *)addr; | |
1c79356b A |
861 | |
862 | for (i = 0; i < actual; i++) | |
2d21ac55 | 863 | task_deallocate(task_list[i]); |
1c79356b | 864 | break; |
91447636 | 865 | } |
1c79356b | 866 | |
2d21ac55 A |
867 | case THING_THREAD: { |
868 | thread_t *thread_list = (thread_t *)addr; | |
1c79356b A |
869 | |
870 | for (i = 0; i < actual; i++) | |
2d21ac55 | 871 | thread_deallocate(thread_list[i]); |
1c79356b | 872 | break; |
1c79356b | 873 | } |
2d21ac55 | 874 | |
91447636 A |
875 | } |
876 | ||
1c79356b | 877 | kfree(addr, size); |
91447636 | 878 | return (KERN_RESOURCE_SHORTAGE); |
1c79356b A |
879 | } |
880 | ||
91447636 | 881 | bcopy((void *) addr, (void *) newaddr, size_needed); |
1c79356b A |
882 | kfree(addr, size); |
883 | addr = newaddr; | |
884 | } | |
885 | ||
91447636 | 886 | *thing_list = (mach_port_t *)addr; |
1c79356b A |
887 | *count = actual; |
888 | ||
889 | /* do the conversion that Mig should handle */ | |
890 | ||
891 | switch (type) { | |
91447636 | 892 | |
2d21ac55 A |
893 | case THING_TASK: { |
894 | task_t *task_list = (task_t *)addr; | |
1c79356b A |
895 | |
896 | for (i = 0; i < actual; i++) | |
2d21ac55 | 897 | (*thing_list)[i] = convert_task_to_port(task_list[i]); |
1c79356b | 898 | break; |
91447636 | 899 | } |
1c79356b | 900 | |
2d21ac55 A |
901 | case THING_THREAD: { |
902 | thread_t *thread_list = (thread_t *)addr; | |
1c79356b A |
903 | |
904 | for (i = 0; i < actual; i++) | |
2d21ac55 | 905 | (*thing_list)[i] = convert_thread_to_port(thread_list[i]); |
1c79356b | 906 | break; |
91447636 | 907 | } |
2d21ac55 | 908 | |
1c79356b A |
909 | } |
910 | } | |
911 | ||
91447636 | 912 | return (KERN_SUCCESS); |
1c79356b A |
913 | } |
914 | ||
915 | ||
916 | /* | |
917 | * processor_set_tasks: | |
918 | * | |
919 | * List all tasks in the processor set. | |
920 | */ | |
921 | kern_return_t | |
922 | processor_set_tasks( | |
923 | processor_set_t pset, | |
924 | task_array_t *task_list, | |
925 | mach_msg_type_number_t *count) | |
926 | { | |
927 | return(processor_set_things(pset, (mach_port_t **)task_list, count, THING_TASK)); | |
928 | } | |
929 | ||
930 | /* | |
931 | * processor_set_threads: | |
932 | * | |
933 | * List all threads in the processor set. | |
934 | */ | |
2d21ac55 A |
935 | #if defined(SECURE_KERNEL) |
936 | kern_return_t | |
937 | processor_set_threads( | |
938 | __unused processor_set_t pset, | |
939 | __unused thread_array_t *thread_list, | |
940 | __unused mach_msg_type_number_t *count) | |
941 | { | |
942 | return KERN_FAILURE; | |
943 | } | |
593a1d5f A |
944 | #elif defined(CONFIG_EMBEDDED) |
945 | kern_return_t | |
946 | processor_set_threads( | |
947 | __unused processor_set_t pset, | |
948 | __unused thread_array_t *thread_list, | |
949 | __unused mach_msg_type_number_t *count) | |
950 | { | |
951 | return KERN_NOT_SUPPORTED; | |
952 | } | |
2d21ac55 | 953 | #else |
1c79356b A |
954 | kern_return_t |
955 | processor_set_threads( | |
956 | processor_set_t pset, | |
957 | thread_array_t *thread_list, | |
958 | mach_msg_type_number_t *count) | |
959 | { | |
960 | return(processor_set_things(pset, (mach_port_t **)thread_list, count, THING_THREAD)); | |
961 | } | |
2d21ac55 | 962 | #endif |
1c79356b A |
963 | |
964 | /* | |
965 | * processor_set_policy_control | |
966 | * | |
967 | * Controls the scheduling attributes governing the processor set. | |
968 | * Allows control of enabled policies, and per-policy base and limit | |
969 | * priorities. | |
970 | */ | |
971 | kern_return_t | |
972 | processor_set_policy_control( | |
91447636 A |
973 | __unused processor_set_t pset, |
974 | __unused int flavor, | |
975 | __unused processor_set_info_t policy_info, | |
976 | __unused mach_msg_type_number_t count, | |
977 | __unused boolean_t change) | |
1c79356b A |
978 | { |
979 | return (KERN_INVALID_ARGUMENT); | |
980 | } | |
2d21ac55 A |
981 | |
982 | #undef pset_deallocate | |
983 | void pset_deallocate(processor_set_t pset); | |
984 | void | |
985 | pset_deallocate( | |
986 | __unused processor_set_t pset) | |
987 | { | |
988 | return; | |
989 | } | |
990 | ||
991 | #undef pset_reference | |
992 | void pset_reference(processor_set_t pset); | |
993 | void | |
994 | pset_reference( | |
995 | __unused processor_set_t pset) | |
996 | { | |
997 | return; | |
998 | } |