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