]>
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 | 334 | { |
316670eb A |
335 | processor_cpu_load_info_t cpu_load_info; |
336 | timer_data_t idle_temp; | |
337 | timer_t idle_state; | |
91447636 | 338 | |
6d2010ae | 339 | if (*count < PROCESSOR_CPU_LOAD_INFO_COUNT) |
91447636 | 340 | return (KERN_FAILURE); |
1c79356b | 341 | |
6d2010ae | 342 | cpu_load_info = (processor_cpu_load_info_t) info; |
316670eb A |
343 | if (precise_user_kernel_time) { |
344 | cpu_load_info->cpu_ticks[CPU_STATE_USER] = | |
b0d623f7 | 345 | (uint32_t)(timer_grab(&PROCESSOR_DATA(processor, user_state)) / hz_tick_interval); |
316670eb | 346 | cpu_load_info->cpu_ticks[CPU_STATE_SYSTEM] = |
b0d623f7 | 347 | (uint32_t)(timer_grab(&PROCESSOR_DATA(processor, system_state)) / hz_tick_interval); |
316670eb A |
348 | } else { |
349 | uint64_t tval = timer_grab(&PROCESSOR_DATA(processor, user_state)) + | |
350 | timer_grab(&PROCESSOR_DATA(processor, system_state)); | |
351 | ||
352 | cpu_load_info->cpu_ticks[CPU_STATE_USER] = (uint32_t)(tval / hz_tick_interval); | |
353 | cpu_load_info->cpu_ticks[CPU_STATE_SYSTEM] = 0; | |
354 | } | |
6d2010ae A |
355 | |
356 | idle_state = &PROCESSOR_DATA(processor, idle_state); | |
357 | idle_temp = *idle_state; | |
358 | ||
359 | if (PROCESSOR_DATA(processor, current_state) != idle_state || | |
316670eb | 360 | timer_grab(&idle_temp) != timer_grab(idle_state)) { |
6d2010ae | 361 | cpu_load_info->cpu_ticks[CPU_STATE_IDLE] = |
b0d623f7 | 362 | (uint32_t)(timer_grab(&PROCESSOR_DATA(processor, idle_state)) / hz_tick_interval); |
316670eb | 363 | } else { |
6d2010ae A |
364 | timer_advance(&idle_temp, mach_absolute_time() - idle_temp.tstamp); |
365 | ||
366 | cpu_load_info->cpu_ticks[CPU_STATE_IDLE] = | |
367 | (uint32_t)(timer_grab(&idle_temp) / hz_tick_interval); | |
368 | } | |
316670eb | 369 | |
2d21ac55 | 370 | cpu_load_info->cpu_ticks[CPU_STATE_NICE] = 0; |
1c79356b A |
371 | |
372 | *count = PROCESSOR_CPU_LOAD_INFO_COUNT; | |
373 | *host = &realhost; | |
91447636 A |
374 | |
375 | return (KERN_SUCCESS); | |
376 | } | |
377 | ||
1c79356b | 378 | default: |
b0d623f7 | 379 | result = cpu_info(flavor, cpu_id, info, count); |
91447636 A |
380 | if (result == KERN_SUCCESS) |
381 | *host = &realhost; | |
382 | ||
383 | return (result); | |
1c79356b A |
384 | } |
385 | } | |
386 | ||
387 | kern_return_t | |
388 | processor_start( | |
2d21ac55 | 389 | processor_t processor) |
1c79356b | 390 | { |
2d21ac55 A |
391 | processor_set_t pset; |
392 | thread_t thread; | |
393 | kern_return_t result; | |
394 | spl_t s; | |
1c79356b | 395 | |
2d21ac55 | 396 | if (processor == PROCESSOR_NULL || processor->processor_set == PROCESSOR_SET_NULL) |
91447636 | 397 | return (KERN_INVALID_ARGUMENT); |
1c79356b | 398 | |
0b4e3aa0 | 399 | if (processor == master_processor) { |
55e303ae A |
400 | processor_t prev; |
401 | ||
2d21ac55 | 402 | prev = thread_bind(processor); |
9bccf70c | 403 | thread_block(THREAD_CONTINUE_NULL); |
0b4e3aa0 | 404 | |
b0d623f7 | 405 | result = cpu_start(processor->cpu_id); |
55e303ae | 406 | |
2d21ac55 | 407 | thread_bind(prev); |
55e303ae A |
408 | |
409 | return (result); | |
0b4e3aa0 | 410 | } |
1c79356b A |
411 | |
412 | s = splsched(); | |
2d21ac55 A |
413 | pset = processor->processor_set; |
414 | pset_lock(pset); | |
55e303ae | 415 | if (processor->state != PROCESSOR_OFF_LINE) { |
2d21ac55 | 416 | pset_unlock(pset); |
1c79356b | 417 | splx(s); |
55e303ae A |
418 | |
419 | return (KERN_FAILURE); | |
1c79356b | 420 | } |
55e303ae | 421 | |
1c79356b | 422 | processor->state = PROCESSOR_START; |
2d21ac55 | 423 | pset_unlock(pset); |
1c79356b A |
424 | splx(s); |
425 | ||
91447636 A |
426 | /* |
427 | * Create the idle processor thread. | |
428 | */ | |
429 | if (processor->idle_thread == THREAD_NULL) { | |
430 | result = idle_thread_create(processor); | |
431 | if (result != KERN_SUCCESS) { | |
432 | s = splsched(); | |
2d21ac55 | 433 | pset_lock(pset); |
91447636 | 434 | processor->state = PROCESSOR_OFF_LINE; |
2d21ac55 | 435 | pset_unlock(pset); |
91447636 A |
436 | splx(s); |
437 | ||
438 | return (result); | |
439 | } | |
440 | } | |
441 | ||
442 | /* | |
443 | * If there is no active thread, the processor | |
444 | * has never been started. Create a dedicated | |
445 | * start up thread. | |
446 | */ | |
447 | if ( processor->active_thread == THREAD_NULL && | |
448 | processor->next_thread == THREAD_NULL ) { | |
449 | result = kernel_thread_create((thread_continue_t)processor_start_thread, NULL, MAXPRI_KERNEL, &thread); | |
450 | if (result != KERN_SUCCESS) { | |
451 | s = splsched(); | |
2d21ac55 | 452 | pset_lock(pset); |
91447636 | 453 | processor->state = PROCESSOR_OFF_LINE; |
2d21ac55 | 454 | pset_unlock(pset); |
91447636 A |
455 | splx(s); |
456 | ||
457 | return (result); | |
458 | } | |
1c79356b A |
459 | |
460 | s = splsched(); | |
461 | thread_lock(thread); | |
55e303ae | 462 | thread->bound_processor = processor; |
1c79356b | 463 | processor->next_thread = thread; |
55e303ae | 464 | thread->state = TH_RUN; |
1c79356b A |
465 | thread_unlock(thread); |
466 | splx(s); | |
91447636 A |
467 | |
468 | thread_deallocate(thread); | |
1c79356b A |
469 | } |
470 | ||
55e303ae A |
471 | if (processor->processor_self == IP_NULL) |
472 | ipc_processor_init(processor); | |
1c79356b | 473 | |
b0d623f7 | 474 | result = cpu_start(processor->cpu_id); |
55e303ae | 475 | if (result != KERN_SUCCESS) { |
1c79356b | 476 | s = splsched(); |
2d21ac55 | 477 | pset_lock(pset); |
1c79356b | 478 | processor->state = PROCESSOR_OFF_LINE; |
2d21ac55 | 479 | pset_unlock(pset); |
1c79356b | 480 | splx(s); |
55e303ae A |
481 | |
482 | return (result); | |
1c79356b A |
483 | } |
484 | ||
55e303ae A |
485 | ipc_processor_enable(processor); |
486 | ||
487 | return (KERN_SUCCESS); | |
1c79356b A |
488 | } |
489 | ||
490 | kern_return_t | |
491 | processor_exit( | |
492 | processor_t processor) | |
493 | { | |
494 | if (processor == PROCESSOR_NULL) | |
495 | return(KERN_INVALID_ARGUMENT); | |
496 | ||
497 | return(processor_shutdown(processor)); | |
498 | } | |
499 | ||
500 | kern_return_t | |
501 | processor_control( | |
502 | processor_t processor, | |
503 | processor_info_t info, | |
504 | mach_msg_type_number_t count) | |
505 | { | |
506 | if (processor == PROCESSOR_NULL) | |
507 | return(KERN_INVALID_ARGUMENT); | |
508 | ||
b0d623f7 | 509 | return(cpu_control(processor->cpu_id, info, count)); |
1c79356b | 510 | } |
1c79356b A |
511 | |
512 | kern_return_t | |
513 | processor_set_create( | |
91447636 A |
514 | __unused host_t host, |
515 | __unused processor_set_t *new_set, | |
516 | __unused processor_set_t *new_name) | |
1c79356b | 517 | { |
1c79356b A |
518 | return(KERN_FAILURE); |
519 | } | |
520 | ||
521 | kern_return_t | |
522 | processor_set_destroy( | |
91447636 | 523 | __unused processor_set_t pset) |
1c79356b | 524 | { |
1c79356b A |
525 | return(KERN_FAILURE); |
526 | } | |
527 | ||
528 | kern_return_t | |
529 | processor_get_assignment( | |
530 | processor_t processor, | |
531 | processor_set_t *pset) | |
532 | { | |
2d21ac55 | 533 | int state; |
1c79356b | 534 | |
316670eb A |
535 | if (processor == PROCESSOR_NULL) |
536 | return(KERN_INVALID_ARGUMENT); | |
537 | ||
1c79356b A |
538 | state = processor->state; |
539 | if (state == PROCESSOR_SHUTDOWN || state == PROCESSOR_OFF_LINE) | |
540 | return(KERN_FAILURE); | |
541 | ||
2d21ac55 A |
542 | *pset = &pset0; |
543 | ||
1c79356b A |
544 | return(KERN_SUCCESS); |
545 | } | |
546 | ||
547 | kern_return_t | |
548 | processor_set_info( | |
549 | processor_set_t pset, | |
550 | int flavor, | |
551 | host_t *host, | |
552 | processor_set_info_t info, | |
553 | mach_msg_type_number_t *count) | |
554 | { | |
555 | if (pset == PROCESSOR_SET_NULL) | |
556 | return(KERN_INVALID_ARGUMENT); | |
557 | ||
558 | if (flavor == PROCESSOR_SET_BASIC_INFO) { | |
559 | register processor_set_basic_info_t basic_info; | |
560 | ||
561 | if (*count < PROCESSOR_SET_BASIC_INFO_COUNT) | |
562 | return(KERN_FAILURE); | |
563 | ||
564 | basic_info = (processor_set_basic_info_t) info; | |
2d21ac55 | 565 | basic_info->processor_count = processor_avail_count; |
0b4e3aa0 | 566 | basic_info->default_policy = POLICY_TIMESHARE; |
1c79356b A |
567 | |
568 | *count = PROCESSOR_SET_BASIC_INFO_COUNT; | |
569 | *host = &realhost; | |
570 | return(KERN_SUCCESS); | |
571 | } | |
572 | else if (flavor == PROCESSOR_SET_TIMESHARE_DEFAULT) { | |
573 | register policy_timeshare_base_t ts_base; | |
574 | ||
575 | if (*count < POLICY_TIMESHARE_BASE_COUNT) | |
576 | return(KERN_FAILURE); | |
577 | ||
578 | ts_base = (policy_timeshare_base_t) info; | |
0b4e3aa0 | 579 | ts_base->base_priority = BASEPRI_DEFAULT; |
1c79356b A |
580 | |
581 | *count = POLICY_TIMESHARE_BASE_COUNT; | |
582 | *host = &realhost; | |
583 | return(KERN_SUCCESS); | |
584 | } | |
585 | else if (flavor == PROCESSOR_SET_FIFO_DEFAULT) { | |
586 | register policy_fifo_base_t fifo_base; | |
587 | ||
588 | if (*count < POLICY_FIFO_BASE_COUNT) | |
589 | return(KERN_FAILURE); | |
590 | ||
591 | fifo_base = (policy_fifo_base_t) info; | |
0b4e3aa0 | 592 | fifo_base->base_priority = BASEPRI_DEFAULT; |
1c79356b A |
593 | |
594 | *count = POLICY_FIFO_BASE_COUNT; | |
595 | *host = &realhost; | |
596 | return(KERN_SUCCESS); | |
597 | } | |
598 | else if (flavor == PROCESSOR_SET_RR_DEFAULT) { | |
599 | register policy_rr_base_t rr_base; | |
600 | ||
601 | if (*count < POLICY_RR_BASE_COUNT) | |
602 | return(KERN_FAILURE); | |
603 | ||
604 | rr_base = (policy_rr_base_t) info; | |
0b4e3aa0 A |
605 | rr_base->base_priority = BASEPRI_DEFAULT; |
606 | rr_base->quantum = 1; | |
1c79356b A |
607 | |
608 | *count = POLICY_RR_BASE_COUNT; | |
609 | *host = &realhost; | |
610 | return(KERN_SUCCESS); | |
611 | } | |
612 | else if (flavor == PROCESSOR_SET_TIMESHARE_LIMITS) { | |
613 | register policy_timeshare_limit_t ts_limit; | |
614 | ||
615 | if (*count < POLICY_TIMESHARE_LIMIT_COUNT) | |
616 | return(KERN_FAILURE); | |
617 | ||
618 | ts_limit = (policy_timeshare_limit_t) info; | |
91447636 | 619 | ts_limit->max_priority = MAXPRI_KERNEL; |
1c79356b A |
620 | |
621 | *count = POLICY_TIMESHARE_LIMIT_COUNT; | |
622 | *host = &realhost; | |
623 | return(KERN_SUCCESS); | |
624 | } | |
625 | else if (flavor == PROCESSOR_SET_FIFO_LIMITS) { | |
626 | register policy_fifo_limit_t fifo_limit; | |
627 | ||
628 | if (*count < POLICY_FIFO_LIMIT_COUNT) | |
629 | return(KERN_FAILURE); | |
630 | ||
631 | fifo_limit = (policy_fifo_limit_t) info; | |
91447636 | 632 | fifo_limit->max_priority = MAXPRI_KERNEL; |
1c79356b A |
633 | |
634 | *count = POLICY_FIFO_LIMIT_COUNT; | |
635 | *host = &realhost; | |
636 | return(KERN_SUCCESS); | |
637 | } | |
638 | else if (flavor == PROCESSOR_SET_RR_LIMITS) { | |
639 | register policy_rr_limit_t rr_limit; | |
640 | ||
641 | if (*count < POLICY_RR_LIMIT_COUNT) | |
642 | return(KERN_FAILURE); | |
643 | ||
644 | rr_limit = (policy_rr_limit_t) info; | |
91447636 | 645 | rr_limit->max_priority = MAXPRI_KERNEL; |
1c79356b A |
646 | |
647 | *count = POLICY_RR_LIMIT_COUNT; | |
648 | *host = &realhost; | |
649 | return(KERN_SUCCESS); | |
650 | } | |
651 | else if (flavor == PROCESSOR_SET_ENABLED_POLICIES) { | |
652 | register int *enabled; | |
653 | ||
654 | if (*count < (sizeof(*enabled)/sizeof(int))) | |
655 | return(KERN_FAILURE); | |
656 | ||
657 | enabled = (int *) info; | |
0b4e3aa0 | 658 | *enabled = POLICY_TIMESHARE | POLICY_RR | POLICY_FIFO; |
1c79356b A |
659 | |
660 | *count = sizeof(*enabled)/sizeof(int); | |
661 | *host = &realhost; | |
662 | return(KERN_SUCCESS); | |
663 | } | |
664 | ||
665 | ||
666 | *host = HOST_NULL; | |
667 | return(KERN_INVALID_ARGUMENT); | |
668 | } | |
669 | ||
670 | /* | |
671 | * processor_set_statistics | |
672 | * | |
673 | * Returns scheduling statistics for a processor set. | |
674 | */ | |
675 | kern_return_t | |
676 | processor_set_statistics( | |
677 | processor_set_t pset, | |
678 | int flavor, | |
679 | processor_set_info_t info, | |
680 | mach_msg_type_number_t *count) | |
681 | { | |
2d21ac55 A |
682 | if (pset == PROCESSOR_SET_NULL || pset != &pset0) |
683 | return (KERN_INVALID_PROCESSOR_SET); | |
684 | ||
685 | if (flavor == PROCESSOR_SET_LOAD_INFO) { | |
686 | register processor_set_load_info_t load_info; | |
1c79356b | 687 | |
2d21ac55 A |
688 | if (*count < PROCESSOR_SET_LOAD_INFO_COUNT) |
689 | return(KERN_FAILURE); | |
1c79356b | 690 | |
2d21ac55 | 691 | load_info = (processor_set_load_info_t) info; |
1c79356b | 692 | |
2d21ac55 A |
693 | load_info->mach_factor = sched_mach_factor; |
694 | load_info->load_average = sched_load_average; | |
1c79356b | 695 | |
2d21ac55 A |
696 | load_info->task_count = tasks_count; |
697 | load_info->thread_count = threads_count; | |
1c79356b | 698 | |
2d21ac55 A |
699 | *count = PROCESSOR_SET_LOAD_INFO_COUNT; |
700 | return(KERN_SUCCESS); | |
701 | } | |
1c79356b | 702 | |
2d21ac55 | 703 | return(KERN_INVALID_ARGUMENT); |
1c79356b A |
704 | } |
705 | ||
706 | /* | |
707 | * processor_set_max_priority: | |
708 | * | |
709 | * Specify max priority permitted on processor set. This affects | |
710 | * newly created and assigned threads. Optionally change existing | |
711 | * ones. | |
712 | */ | |
713 | kern_return_t | |
714 | processor_set_max_priority( | |
91447636 A |
715 | __unused processor_set_t pset, |
716 | __unused int max_priority, | |
717 | __unused boolean_t change_threads) | |
1c79356b A |
718 | { |
719 | return (KERN_INVALID_ARGUMENT); | |
720 | } | |
721 | ||
722 | /* | |
723 | * processor_set_policy_enable: | |
724 | * | |
725 | * Allow indicated policy on processor set. | |
726 | */ | |
727 | ||
728 | kern_return_t | |
729 | processor_set_policy_enable( | |
91447636 A |
730 | __unused processor_set_t pset, |
731 | __unused int policy) | |
1c79356b A |
732 | { |
733 | return (KERN_INVALID_ARGUMENT); | |
734 | } | |
735 | ||
736 | /* | |
737 | * processor_set_policy_disable: | |
738 | * | |
739 | * Forbid indicated policy on processor set. Time sharing cannot | |
740 | * be forbidden. | |
741 | */ | |
742 | kern_return_t | |
743 | processor_set_policy_disable( | |
91447636 A |
744 | __unused processor_set_t pset, |
745 | __unused int policy, | |
746 | __unused boolean_t change_threads) | |
1c79356b A |
747 | { |
748 | return (KERN_INVALID_ARGUMENT); | |
749 | } | |
750 | ||
751 | #define THING_TASK 0 | |
752 | #define THING_THREAD 1 | |
753 | ||
754 | /* | |
755 | * processor_set_things: | |
756 | * | |
757 | * Common internals for processor_set_{threads,tasks} | |
758 | */ | |
759 | kern_return_t | |
760 | processor_set_things( | |
91447636 A |
761 | processor_set_t pset, |
762 | mach_port_t **thing_list, | |
1c79356b | 763 | mach_msg_type_number_t *count, |
91447636 | 764 | int type) |
1c79356b A |
765 | { |
766 | unsigned int actual; /* this many things */ | |
91447636 A |
767 | unsigned int maxthings; |
768 | unsigned int i; | |
1c79356b A |
769 | |
770 | vm_size_t size, size_needed; | |
91447636 | 771 | void *addr; |
1c79356b | 772 | |
2d21ac55 | 773 | if (pset == PROCESSOR_SET_NULL || pset != &pset0) |
91447636 | 774 | return (KERN_INVALID_ARGUMENT); |
1c79356b | 775 | |
2d21ac55 A |
776 | size = 0; |
777 | addr = NULL; | |
1c79356b A |
778 | |
779 | for (;;) { | |
b0d623f7 | 780 | lck_mtx_lock(&tasks_threads_lock); |
1c79356b A |
781 | |
782 | if (type == THING_TASK) | |
2d21ac55 | 783 | maxthings = tasks_count; |
1c79356b | 784 | else |
2d21ac55 | 785 | maxthings = threads_count; |
1c79356b A |
786 | |
787 | /* do we have the memory we need? */ | |
788 | ||
91447636 | 789 | size_needed = maxthings * sizeof (mach_port_t); |
1c79356b A |
790 | if (size_needed <= size) |
791 | break; | |
792 | ||
2d21ac55 | 793 | /* unlock and allocate more memory */ |
b0d623f7 | 794 | lck_mtx_unlock(&tasks_threads_lock); |
1c79356b A |
795 | |
796 | if (size != 0) | |
797 | kfree(addr, size); | |
798 | ||
799 | assert(size_needed > 0); | |
800 | size = size_needed; | |
801 | ||
802 | addr = kalloc(size); | |
803 | if (addr == 0) | |
91447636 | 804 | return (KERN_RESOURCE_SHORTAGE); |
1c79356b A |
805 | } |
806 | ||
2d21ac55 | 807 | /* OK, have memory and the list locked */ |
1c79356b | 808 | |
91447636 | 809 | actual = 0; |
1c79356b | 810 | switch (type) { |
91447636 | 811 | |
2d21ac55 A |
812 | case THING_TASK: { |
813 | task_t task, *task_list = (task_t *)addr; | |
814 | ||
815 | for (task = (task_t)queue_first(&tasks); | |
816 | !queue_end(&tasks, (queue_entry_t)task); | |
817 | task = (task_t)queue_next(&task->tasks)) { | |
818 | #if defined(SECURE_KERNEL) | |
819 | if (task != kernel_task) { | |
820 | #endif | |
821 | task_reference_internal(task); | |
822 | task_list[actual++] = task; | |
823 | #if defined(SECURE_KERNEL) | |
824 | } | |
825 | #endif | |
1c79356b | 826 | } |
91447636 | 827 | |
1c79356b | 828 | break; |
91447636 A |
829 | } |
830 | ||
2d21ac55 A |
831 | case THING_THREAD: { |
832 | thread_t thread, *thread_list = (thread_t *)addr; | |
91447636 | 833 | |
2d21ac55 A |
834 | for (thread = (thread_t)queue_first(&threads); |
835 | !queue_end(&threads, (queue_entry_t)thread); | |
836 | thread = (thread_t)queue_next(&thread->threads)) { | |
91447636 | 837 | thread_reference_internal(thread); |
2d21ac55 | 838 | thread_list[actual++] = thread; |
1c79356b | 839 | } |
91447636 | 840 | |
1c79356b | 841 | break; |
91447636 | 842 | } |
2d21ac55 | 843 | |
1c79356b | 844 | } |
9bccf70c | 845 | |
b0d623f7 | 846 | lck_mtx_unlock(&tasks_threads_lock); |
1c79356b | 847 | |
91447636 A |
848 | if (actual < maxthings) |
849 | size_needed = actual * sizeof (mach_port_t); | |
9bccf70c | 850 | |
1c79356b A |
851 | if (actual == 0) { |
852 | /* no things, so return null pointer and deallocate memory */ | |
2d21ac55 | 853 | *thing_list = NULL; |
1c79356b A |
854 | *count = 0; |
855 | ||
856 | if (size != 0) | |
857 | kfree(addr, size); | |
91447636 A |
858 | } |
859 | else { | |
1c79356b A |
860 | /* if we allocated too much, must copy */ |
861 | ||
862 | if (size_needed < size) { | |
91447636 | 863 | void *newaddr; |
1c79356b A |
864 | |
865 | newaddr = kalloc(size_needed); | |
866 | if (newaddr == 0) { | |
867 | switch (type) { | |
91447636 | 868 | |
2d21ac55 A |
869 | case THING_TASK: { |
870 | task_t *task_list = (task_t *)addr; | |
1c79356b A |
871 | |
872 | for (i = 0; i < actual; i++) | |
2d21ac55 | 873 | task_deallocate(task_list[i]); |
1c79356b | 874 | break; |
91447636 | 875 | } |
1c79356b | 876 | |
2d21ac55 A |
877 | case THING_THREAD: { |
878 | thread_t *thread_list = (thread_t *)addr; | |
1c79356b A |
879 | |
880 | for (i = 0; i < actual; i++) | |
2d21ac55 | 881 | thread_deallocate(thread_list[i]); |
1c79356b | 882 | break; |
1c79356b | 883 | } |
2d21ac55 | 884 | |
91447636 A |
885 | } |
886 | ||
1c79356b | 887 | kfree(addr, size); |
91447636 | 888 | return (KERN_RESOURCE_SHORTAGE); |
1c79356b A |
889 | } |
890 | ||
91447636 | 891 | bcopy((void *) addr, (void *) newaddr, size_needed); |
1c79356b A |
892 | kfree(addr, size); |
893 | addr = newaddr; | |
894 | } | |
895 | ||
91447636 | 896 | *thing_list = (mach_port_t *)addr; |
1c79356b A |
897 | *count = actual; |
898 | ||
899 | /* do the conversion that Mig should handle */ | |
900 | ||
901 | switch (type) { | |
91447636 | 902 | |
2d21ac55 A |
903 | case THING_TASK: { |
904 | task_t *task_list = (task_t *)addr; | |
1c79356b A |
905 | |
906 | for (i = 0; i < actual; i++) | |
2d21ac55 | 907 | (*thing_list)[i] = convert_task_to_port(task_list[i]); |
1c79356b | 908 | break; |
91447636 | 909 | } |
1c79356b | 910 | |
2d21ac55 A |
911 | case THING_THREAD: { |
912 | thread_t *thread_list = (thread_t *)addr; | |
1c79356b A |
913 | |
914 | for (i = 0; i < actual; i++) | |
2d21ac55 | 915 | (*thing_list)[i] = convert_thread_to_port(thread_list[i]); |
1c79356b | 916 | break; |
91447636 | 917 | } |
2d21ac55 | 918 | |
1c79356b A |
919 | } |
920 | } | |
921 | ||
91447636 | 922 | return (KERN_SUCCESS); |
1c79356b A |
923 | } |
924 | ||
925 | ||
926 | /* | |
927 | * processor_set_tasks: | |
928 | * | |
929 | * List all tasks in the processor set. | |
930 | */ | |
931 | kern_return_t | |
932 | processor_set_tasks( | |
933 | processor_set_t pset, | |
934 | task_array_t *task_list, | |
935 | mach_msg_type_number_t *count) | |
936 | { | |
937 | return(processor_set_things(pset, (mach_port_t **)task_list, count, THING_TASK)); | |
938 | } | |
939 | ||
940 | /* | |
941 | * processor_set_threads: | |
942 | * | |
943 | * List all threads in the processor set. | |
944 | */ | |
2d21ac55 A |
945 | #if defined(SECURE_KERNEL) |
946 | kern_return_t | |
947 | processor_set_threads( | |
948 | __unused processor_set_t pset, | |
949 | __unused thread_array_t *thread_list, | |
950 | __unused mach_msg_type_number_t *count) | |
951 | { | |
952 | return KERN_FAILURE; | |
953 | } | |
593a1d5f A |
954 | #elif defined(CONFIG_EMBEDDED) |
955 | kern_return_t | |
956 | processor_set_threads( | |
957 | __unused processor_set_t pset, | |
958 | __unused thread_array_t *thread_list, | |
959 | __unused mach_msg_type_number_t *count) | |
960 | { | |
961 | return KERN_NOT_SUPPORTED; | |
962 | } | |
2d21ac55 | 963 | #else |
1c79356b A |
964 | kern_return_t |
965 | processor_set_threads( | |
966 | processor_set_t pset, | |
967 | thread_array_t *thread_list, | |
968 | mach_msg_type_number_t *count) | |
969 | { | |
970 | return(processor_set_things(pset, (mach_port_t **)thread_list, count, THING_THREAD)); | |
971 | } | |
2d21ac55 | 972 | #endif |
1c79356b A |
973 | |
974 | /* | |
975 | * processor_set_policy_control | |
976 | * | |
977 | * Controls the scheduling attributes governing the processor set. | |
978 | * Allows control of enabled policies, and per-policy base and limit | |
979 | * priorities. | |
980 | */ | |
981 | kern_return_t | |
982 | processor_set_policy_control( | |
91447636 A |
983 | __unused processor_set_t pset, |
984 | __unused int flavor, | |
985 | __unused processor_set_info_t policy_info, | |
986 | __unused mach_msg_type_number_t count, | |
987 | __unused boolean_t change) | |
1c79356b A |
988 | { |
989 | return (KERN_INVALID_ARGUMENT); | |
990 | } | |
2d21ac55 A |
991 | |
992 | #undef pset_deallocate | |
993 | void pset_deallocate(processor_set_t pset); | |
994 | void | |
995 | pset_deallocate( | |
996 | __unused processor_set_t pset) | |
997 | { | |
998 | return; | |
999 | } | |
1000 | ||
1001 | #undef pset_reference | |
1002 | void pset_reference(processor_set_t pset); | |
1003 | void | |
1004 | pset_reference( | |
1005 | __unused processor_set_t pset) | |
1006 | { | |
1007 | return; | |
1008 | } |