File: | obj-scan-build/../kern/processor.c |
Location: | line 927, column 4 |
Description: | Array access (from variable 'threads') results in a null pointer dereference |
1 | /* | |||
2 | * Mach Operating System | |||
3 | * Copyright (c) 1993-1988 Carnegie Mellon University | |||
4 | * All Rights Reserved. | |||
5 | * | |||
6 | * Permission to use, copy, modify and distribute this software and its | |||
7 | * documentation is hereby granted, provided that both the copyright | |||
8 | * notice and this permission notice appear in all copies of the | |||
9 | * software, derivative works or modified versions, and any portions | |||
10 | * thereof, and that both notices appear in supporting documentation. | |||
11 | * | |||
12 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" | |||
13 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR | |||
14 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. | |||
15 | * | |||
16 | * Carnegie Mellon requests users of this software to return to | |||
17 | * | |||
18 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU | |||
19 | * School of Computer Science | |||
20 | * Carnegie Mellon University | |||
21 | * Pittsburgh PA 15213-3890 | |||
22 | * | |||
23 | * any improvements or extensions that they make and grant Carnegie Mellon | |||
24 | * the rights to redistribute these changes. | |||
25 | */ | |||
26 | /* | |||
27 | * processor.c: processor and processor_set manipulation routines. | |||
28 | */ | |||
29 | ||||
30 | #include <string.h> | |||
31 | ||||
32 | #include <mach/boolean.h> | |||
33 | #include <mach/policy.h> | |||
34 | #include <mach/processor_info.h> | |||
35 | #include <mach/vm_param.h> | |||
36 | #include <kern/cpu_number.h> | |||
37 | #include <kern/debug.h> | |||
38 | #include <kern/kalloc.h> | |||
39 | #include <kern/lock.h> | |||
40 | #include <kern/host.h> | |||
41 | #include <kern/ipc_tt.h> | |||
42 | #include <kern/processor.h> | |||
43 | #include <kern/sched.h> | |||
44 | #include <kern/task.h> | |||
45 | #include <kern/thread.h> | |||
46 | #include <kern/ipc_host.h> | |||
47 | #include <ipc/ipc_port.h> | |||
48 | ||||
49 | #if MACH_HOST0 | |||
50 | #include <kern/slab.h> | |||
51 | struct kmem_cache pset_cache; | |||
52 | #endif /* MACH_HOST */ | |||
53 | ||||
54 | ||||
55 | /* | |||
56 | * Exported variables. | |||
57 | */ | |||
58 | struct processor_set default_pset; | |||
59 | struct processor processor_array[NCPUS1]; | |||
60 | ||||
61 | queue_head_t all_psets; | |||
62 | int all_psets_count; | |||
63 | decl_simple_lock_data(, all_psets_lock); | |||
64 | ||||
65 | processor_t master_processor; | |||
66 | processor_t processor_ptr[NCPUS1]; | |||
67 | ||||
68 | /* | |||
69 | * Forward declarations. | |||
70 | */ | |||
71 | void quantum_set(processor_set_t); | |||
72 | void pset_init(processor_set_t); | |||
73 | void processor_init(processor_t, int); | |||
74 | ||||
75 | /* | |||
76 | * Bootstrap the processor/pset system so the scheduler can run. | |||
77 | */ | |||
78 | void pset_sys_bootstrap(void) | |||
79 | { | |||
80 | register int i; | |||
81 | ||||
82 | pset_init(&default_pset); | |||
83 | default_pset.empty = FALSE((boolean_t) 0); | |||
84 | for (i = 0; i < NCPUS1; i++) { | |||
85 | /* | |||
86 | * Initialize processor data structures. | |||
87 | * Note that cpu_to_processor(i) is processor_ptr[i]. | |||
88 | */ | |||
89 | processor_ptr[i] = &processor_array[i]; | |||
90 | processor_init(processor_ptr[i], i); | |||
91 | } | |||
92 | master_processor = cpu_to_processor(master_cpu)(processor_ptr[master_cpu]); | |||
93 | queue_init(&all_psets)((&all_psets)->next = (&all_psets)->prev = & all_psets); | |||
94 | simple_lock_init(&all_psets_lock); | |||
95 | queue_enter(&all_psets, &default_pset, processor_set_t, all_psets){ register queue_entry_t prev; prev = (&all_psets)->prev ; if ((&all_psets) == prev) { (&all_psets)->next = (queue_entry_t) (&default_pset); } else { ((processor_set_t )prev)->all_psets.next = (queue_entry_t)(&default_pset ); } (&default_pset)->all_psets.prev = prev; (&default_pset )->all_psets.next = &all_psets; (&all_psets)->prev = (queue_entry_t) &default_pset; }; | |||
96 | all_psets_count = 1; | |||
97 | default_pset.active = TRUE((boolean_t) 1); | |||
98 | default_pset.empty = FALSE((boolean_t) 0); | |||
99 | ||||
100 | /* | |||
101 | * Note: the default_pset has a max_priority of BASEPRI_USER. | |||
102 | * Internal kernel threads override this in kernel_thread. | |||
103 | */ | |||
104 | } | |||
105 | ||||
106 | #if MACH_HOST0 | |||
107 | /* | |||
108 | * Rest of pset system initializations. | |||
109 | */ | |||
110 | void pset_sys_init(void) | |||
111 | { | |||
112 | register int i; | |||
113 | register processor_t processor; | |||
114 | ||||
115 | /* | |||
116 | * Allocate the cache for processor sets. | |||
117 | */ | |||
118 | kmem_cache_init(&pset_cache, "processor_set", | |||
119 | sizeof(struct processor_set), 0, NULL((void *) 0), NULL((void *) 0), NULL((void *) 0), 0); | |||
120 | ||||
121 | /* | |||
122 | * Give each processor a control port. | |||
123 | * The master processor already has one. | |||
124 | */ | |||
125 | for (i = 0; i < NCPUS1; i++) { | |||
126 | processor = cpu_to_processor(i)(processor_ptr[i]); | |||
127 | if (processor != master_processor && | |||
128 | machine_slot[i].is_cpu) | |||
129 | { | |||
130 | ipc_processor_init(processor); | |||
131 | } | |||
132 | } | |||
133 | } | |||
134 | #endif /* MACH_HOST */ | |||
135 | ||||
136 | /* | |||
137 | * Initialize the given processor_set structure. | |||
138 | */ | |||
139 | ||||
140 | void pset_init( | |||
141 | register processor_set_t pset) | |||
142 | { | |||
143 | int i; | |||
144 | ||||
145 | simple_lock_init(&pset->runq.lock); | |||
146 | pset->runq.low = 0; | |||
147 | pset->runq.count = 0; | |||
148 | for (i = 0; i < NRQS50; i++) { | |||
149 | queue_init(&(pset->runq.runq[i]))((&(pset->runq.runq[i]))->next = (&(pset->runq .runq[i]))->prev = &(pset->runq.runq[i])); | |||
150 | } | |||
151 | queue_init(&pset->idle_queue)((&pset->idle_queue)->next = (&pset->idle_queue )->prev = &pset->idle_queue); | |||
152 | pset->idle_count = 0; | |||
153 | simple_lock_init(&pset->idle_lock); | |||
154 | queue_init(&pset->processors)((&pset->processors)->next = (&pset->processors )->prev = &pset->processors); | |||
155 | pset->processor_count = 0; | |||
156 | pset->empty = TRUE((boolean_t) 1); | |||
157 | queue_init(&pset->tasks)((&pset->tasks)->next = (&pset->tasks)->prev = &pset->tasks); | |||
158 | pset->task_count = 0; | |||
159 | queue_init(&pset->threads)((&pset->threads)->next = (&pset->threads)-> prev = &pset->threads); | |||
160 | pset->thread_count = 0; | |||
161 | pset->ref_count = 1; | |||
162 | simple_lock_init(&pset->ref_lock); | |||
163 | queue_init(&pset->all_psets)((&pset->all_psets)->next = (&pset->all_psets )->prev = &pset->all_psets); | |||
164 | pset->active = FALSE((boolean_t) 0); | |||
165 | simple_lock_init(&pset->lock); | |||
166 | pset->pset_self = IP_NULL((ipc_port_t) ((ipc_object_t) 0)); | |||
167 | pset->pset_name_self = IP_NULL((ipc_port_t) ((ipc_object_t) 0)); | |||
168 | pset->max_priority = BASEPRI_USER25; | |||
169 | #if MACH_FIXPRI1 | |||
170 | pset->policies = POLICY_TIMESHARE1; | |||
171 | #endif /* MACH_FIXPRI */ | |||
172 | pset->set_quantum = min_quantum; | |||
173 | #if NCPUS1 > 1 | |||
174 | pset->quantum_adj_index = 0; | |||
175 | simple_lock_init(&pset->quantum_adj_lock); | |||
176 | ||||
177 | for (i = 0; i <= NCPUS1; i++) { | |||
178 | pset->machine_quantum[i] = min_quantum; | |||
179 | } | |||
180 | #endif /* NCPUS > 1 */ | |||
181 | pset->mach_factor = 0; | |||
182 | pset->load_average = 0; | |||
183 | pset->sched_load = SCHED_SCALE128; /* i.e. 1 */ | |||
184 | } | |||
185 | ||||
186 | /* | |||
187 | * Initialize the given processor structure for the processor in | |||
188 | * the slot specified by slot_num. | |||
189 | */ | |||
190 | ||||
191 | void processor_init( | |||
192 | register processor_t pr, | |||
193 | int slot_num) | |||
194 | { | |||
195 | int i; | |||
196 | ||||
197 | simple_lock_init(&pr->runq.lock); | |||
198 | pr->runq.low = 0; | |||
199 | pr->runq.count = 0; | |||
200 | for (i = 0; i < NRQS50; i++) { | |||
201 | queue_init(&(pr->runq.runq[i]))((&(pr->runq.runq[i]))->next = (&(pr->runq.runq [i]))->prev = &(pr->runq.runq[i])); | |||
202 | } | |||
203 | queue_init(&pr->processor_queue)((&pr->processor_queue)->next = (&pr->processor_queue )->prev = &pr->processor_queue); | |||
204 | pr->state = PROCESSOR_OFF_LINE0; | |||
205 | pr->next_thread = THREAD_NULL((thread_t) 0); | |||
206 | pr->idle_thread = THREAD_NULL((thread_t) 0); | |||
207 | pr->quantum = 0; | |||
208 | pr->first_quantum = FALSE((boolean_t) 0); | |||
209 | pr->last_quantum = 0; | |||
210 | pr->processor_set = PROCESSOR_SET_NULL((processor_set_t) 0); | |||
211 | pr->processor_set_next = PROCESSOR_SET_NULL((processor_set_t) 0); | |||
212 | queue_init(&pr->processors)((&pr->processors)->next = (&pr->processors) ->prev = &pr->processors); | |||
213 | simple_lock_init(&pr->lock); | |||
214 | pr->processor_self = IP_NULL((ipc_port_t) ((ipc_object_t) 0)); | |||
215 | pr->slot_num = slot_num; | |||
216 | } | |||
217 | ||||
218 | /* | |||
219 | * pset_remove_processor() removes a processor from a processor_set. | |||
220 | * It can only be called on the current processor. Caller must | |||
221 | * hold lock on current processor and processor set. | |||
222 | */ | |||
223 | ||||
224 | void pset_remove_processor( | |||
225 | processor_set_t pset, | |||
226 | processor_t processor) | |||
227 | { | |||
228 | if (pset != processor->processor_set) | |||
229 | panic("pset_remove_processor: wrong pset"); | |||
230 | ||||
231 | queue_remove(&pset->processors, processor, processor_t, processors){ register queue_entry_t next, prev; next = (processor)->processors .next; prev = (processor)->processors.prev; if ((&pset ->processors) == next) (&pset->processors)->prev = prev; else ((processor_t)next)->processors.prev = prev; if ((&pset->processors) == prev) (&pset->processors )->next = next; else ((processor_t)prev)->processors.next = next; }; | |||
232 | processor->processor_set = PROCESSOR_SET_NULL((processor_set_t) 0); | |||
233 | pset->processor_count--; | |||
234 | quantum_set(pset); | |||
235 | } | |||
236 | ||||
237 | /* | |||
238 | * pset_add_processor() adds a processor to a processor_set. | |||
239 | * It can only be called on the current processor. Caller must | |||
240 | * hold lock on curent processor and on pset. No reference counting on | |||
241 | * processors. Processor reference to pset is implicit. | |||
242 | */ | |||
243 | ||||
244 | void pset_add_processor( | |||
245 | processor_set_t pset, | |||
246 | processor_t processor) | |||
247 | { | |||
248 | queue_enter(&pset->processors, processor, processor_t, processors){ register queue_entry_t prev; prev = (&pset->processors )->prev; if ((&pset->processors) == prev) { (&pset ->processors)->next = (queue_entry_t) (processor); } else { ((processor_t)prev)->processors.next = (queue_entry_t)( processor); } (processor)->processors.prev = prev; (processor )->processors.next = &pset->processors; (&pset-> processors)->prev = (queue_entry_t) processor; }; | |||
249 | processor->processor_set = pset; | |||
250 | pset->processor_count++; | |||
251 | quantum_set(pset); | |||
252 | } | |||
253 | ||||
254 | /* | |||
255 | * pset_remove_task() removes a task from a processor_set. | |||
256 | * Caller must hold locks on pset and task. Pset reference count | |||
257 | * is not decremented; caller must explicitly pset_deallocate. | |||
258 | */ | |||
259 | ||||
260 | void pset_remove_task( | |||
261 | processor_set_t pset, | |||
262 | task_t task) | |||
263 | { | |||
264 | if (pset != task->processor_set) | |||
265 | return; | |||
266 | ||||
267 | queue_remove(&pset->tasks, task, task_t, pset_tasks){ register queue_entry_t next, prev; next = (task)->pset_tasks .next; prev = (task)->pset_tasks.prev; if ((&pset-> tasks) == next) (&pset->tasks)->prev = prev; else ( (task_t)next)->pset_tasks.prev = prev; if ((&pset-> tasks) == prev) (&pset->tasks)->next = next; else ( (task_t)prev)->pset_tasks.next = next; }; | |||
268 | task->processor_set = PROCESSOR_SET_NULL((processor_set_t) 0); | |||
269 | pset->task_count--; | |||
270 | } | |||
271 | ||||
272 | /* | |||
273 | * pset_add_task() adds a task to a processor_set. | |||
274 | * Caller must hold locks on pset and task. Pset references to | |||
275 | * tasks are implicit. | |||
276 | */ | |||
277 | ||||
278 | void pset_add_task( | |||
279 | processor_set_t pset, | |||
280 | task_t task) | |||
281 | { | |||
282 | queue_enter(&pset->tasks, task, task_t, pset_tasks){ register queue_entry_t prev; prev = (&pset->tasks)-> prev; if ((&pset->tasks) == prev) { (&pset->tasks )->next = (queue_entry_t) (task); } else { ((task_t)prev)-> pset_tasks.next = (queue_entry_t)(task); } (task)->pset_tasks .prev = prev; (task)->pset_tasks.next = &pset->tasks ; (&pset->tasks)->prev = (queue_entry_t) task; }; | |||
283 | task->processor_set = pset; | |||
284 | pset->task_count++; | |||
285 | } | |||
286 | ||||
287 | /* | |||
288 | * pset_remove_thread() removes a thread from a processor_set. | |||
289 | * Caller must hold locks on pset and thread. Pset reference count | |||
290 | * is not decremented; caller must explicitly pset_deallocate. | |||
291 | */ | |||
292 | ||||
293 | void pset_remove_thread( | |||
294 | processor_set_t pset, | |||
295 | thread_t thread) | |||
296 | { | |||
297 | queue_remove(&pset->threads, thread, thread_t, pset_threads){ register queue_entry_t next, prev; next = (thread)->pset_threads .next; prev = (thread)->pset_threads.prev; if ((&pset-> threads) == next) (&pset->threads)->prev = prev; else ((thread_t)next)->pset_threads.prev = prev; if ((&pset ->threads) == prev) (&pset->threads)->next = next ; else ((thread_t)prev)->pset_threads.next = next; }; | |||
298 | thread->processor_set = PROCESSOR_SET_NULL((processor_set_t) 0); | |||
299 | pset->thread_count--; | |||
300 | } | |||
301 | ||||
302 | /* | |||
303 | * pset_add_thread() adds a thread to a processor_set. | |||
304 | * Caller must hold locks on pset and thread. Pset references to | |||
305 | * threads are implicit. | |||
306 | */ | |||
307 | ||||
308 | void pset_add_thread( | |||
309 | processor_set_t pset, | |||
310 | thread_t thread) | |||
311 | { | |||
312 | queue_enter(&pset->threads, thread, thread_t, pset_threads){ register queue_entry_t prev; prev = (&pset->threads) ->prev; if ((&pset->threads) == prev) { (&pset-> threads)->next = (queue_entry_t) (thread); } else { ((thread_t )prev)->pset_threads.next = (queue_entry_t)(thread); } (thread )->pset_threads.prev = prev; (thread)->pset_threads.next = &pset->threads; (&pset->threads)->prev = ( queue_entry_t) thread; }; | |||
313 | thread->processor_set = pset; | |||
314 | pset->thread_count++; | |||
315 | } | |||
316 | ||||
317 | /* | |||
318 | * thread_change_psets() changes the pset of a thread. Caller must | |||
319 | * hold locks on both psets and thread. The old pset must be | |||
320 | * explicitly pset_deallocat()'ed by caller. | |||
321 | */ | |||
322 | ||||
323 | void thread_change_psets( | |||
324 | thread_t thread, | |||
325 | processor_set_t old_pset, | |||
326 | processor_set_t new_pset) | |||
327 | { | |||
328 | queue_remove(&old_pset->threads, thread, thread_t, pset_threads){ register queue_entry_t next, prev; next = (thread)->pset_threads .next; prev = (thread)->pset_threads.prev; if ((&old_pset ->threads) == next) (&old_pset->threads)->prev = prev; else ((thread_t)next)->pset_threads.prev = prev; if ((&old_pset->threads) == prev) (&old_pset->threads )->next = next; else ((thread_t)prev)->pset_threads.next = next; }; | |||
329 | old_pset->thread_count--; | |||
330 | queue_enter(&new_pset->threads, thread, thread_t, pset_threads){ register queue_entry_t prev; prev = (&new_pset->threads )->prev; if ((&new_pset->threads) == prev) { (& new_pset->threads)->next = (queue_entry_t) (thread); } else { ((thread_t)prev)->pset_threads.next = (queue_entry_t)(thread ); } (thread)->pset_threads.prev = prev; (thread)->pset_threads .next = &new_pset->threads; (&new_pset->threads )->prev = (queue_entry_t) thread; }; | |||
331 | thread->processor_set = new_pset; | |||
332 | new_pset->thread_count++; | |||
333 | } | |||
334 | ||||
335 | /* | |||
336 | * pset_deallocate: | |||
337 | * | |||
338 | * Remove one reference to the processor set. Destroy processor_set | |||
339 | * if this was the last reference. | |||
340 | */ | |||
341 | void pset_deallocate( | |||
342 | processor_set_t pset) | |||
343 | { | |||
344 | if (pset == PROCESSOR_SET_NULL((processor_set_t) 0)) | |||
345 | return; | |||
346 | ||||
347 | pset_ref_lock(pset); | |||
348 | if (--pset->ref_count > 0) { | |||
349 | pset_ref_unlock(pset); | |||
350 | return; | |||
351 | } | |||
352 | #if !MACH_HOST0 | |||
353 | panic("pset_deallocate: default_pset destroyed"); | |||
354 | #endif /* !MACH_HOST */ | |||
355 | ||||
356 | #if MACH_HOST0 | |||
357 | /* | |||
358 | * Reference count is zero, however the all_psets list | |||
359 | * holds an implicit reference and may make new ones. | |||
360 | * Its lock also dominates the pset lock. To check for this, | |||
361 | * temporarily restore one reference, and then lock the | |||
362 | * other structures in the right order. | |||
363 | */ | |||
364 | pset->ref_count = 1; | |||
365 | pset_ref_unlock(pset); | |||
366 | ||||
367 | simple_lock(&all_psets_lock); | |||
368 | pset_ref_lock(pset); | |||
369 | if (--pset->ref_count > 0) { | |||
370 | /* | |||
371 | * Made an extra reference. | |||
372 | */ | |||
373 | pset_ref_unlock(pset); | |||
374 | simple_unlock(&all_psets_lock); | |||
375 | return; | |||
376 | } | |||
377 | ||||
378 | /* | |||
379 | * Ok to destroy pset. Make a few paranoia checks. | |||
380 | */ | |||
381 | ||||
382 | if ((pset == &default_pset) || (pset->thread_count > 0) || | |||
383 | (pset->task_count > 0) || pset->processor_count > 0) { | |||
384 | panic("pset_deallocate: destroy default or active pset"); | |||
385 | } | |||
386 | /* | |||
387 | * Remove from all_psets queue. | |||
388 | */ | |||
389 | queue_remove(&all_psets, pset, processor_set_t, all_psets){ register queue_entry_t next, prev; next = (pset)->all_psets .next; prev = (pset)->all_psets.prev; if ((&all_psets) == next) (&all_psets)->prev = prev; else ((processor_set_t )next)->all_psets.prev = prev; if ((&all_psets) == prev ) (&all_psets)->next = next; else ((processor_set_t)prev )->all_psets.next = next; }; | |||
390 | all_psets_count--; | |||
391 | ||||
392 | pset_ref_unlock(pset); | |||
393 | simple_unlock(&all_psets_lock); | |||
394 | ||||
395 | /* | |||
396 | * That's it, free data structure. | |||
397 | */ | |||
398 | kmem_cache_free(&pset_cache, (vm_offset_t)pset); | |||
399 | #endif /* MACH_HOST */ | |||
400 | } | |||
401 | ||||
402 | /* | |||
403 | * pset_reference: | |||
404 | * | |||
405 | * Add one reference to the processor set. | |||
406 | */ | |||
407 | void pset_reference( | |||
408 | processor_set_t pset) | |||
409 | { | |||
410 | pset_ref_lock(pset); | |||
411 | pset->ref_count++; | |||
412 | pset_ref_unlock(pset); | |||
413 | } | |||
414 | ||||
415 | kern_return_t | |||
416 | processor_info( | |||
417 | register processor_t processor, | |||
418 | int flavor, | |||
419 | host_t *host, | |||
420 | processor_info_t info, | |||
421 | natural_t *count) | |||
422 | { | |||
423 | register int slot_num, state; | |||
424 | register processor_basic_info_t basic_info; | |||
425 | ||||
426 | if (processor == PROCESSOR_NULL((processor_t) 0)) | |||
427 | return KERN_INVALID_ARGUMENT4; | |||
428 | ||||
429 | if (flavor != PROCESSOR_BASIC_INFO1 || | |||
430 | *count < PROCESSOR_BASIC_INFO_COUNT(sizeof(processor_basic_info_data_t)/sizeof(integer_t))) | |||
431 | return KERN_FAILURE5; | |||
432 | ||||
433 | basic_info = (processor_basic_info_t) info; | |||
434 | ||||
435 | slot_num = processor->slot_num; | |||
436 | basic_info->cpu_type = machine_slot[slot_num].cpu_type; | |||
437 | basic_info->cpu_subtype = machine_slot[slot_num].cpu_subtype; | |||
438 | state = processor->state; | |||
439 | if (state == PROCESSOR_SHUTDOWN5 || state == PROCESSOR_OFF_LINE0) | |||
440 | basic_info->running = FALSE((boolean_t) 0); | |||
441 | else | |||
442 | basic_info->running = TRUE((boolean_t) 1); | |||
443 | basic_info->slot_num = slot_num; | |||
444 | if (processor == master_processor) | |||
445 | basic_info->is_master = TRUE((boolean_t) 1); | |||
446 | else | |||
447 | basic_info->is_master = FALSE((boolean_t) 0); | |||
448 | ||||
449 | *count = PROCESSOR_BASIC_INFO_COUNT(sizeof(processor_basic_info_data_t)/sizeof(integer_t)); | |||
450 | *host = &realhost; | |||
451 | return KERN_SUCCESS0; | |||
452 | } | |||
453 | ||||
454 | kern_return_t processor_start( | |||
455 | processor_t processor) | |||
456 | { | |||
457 | if (processor == PROCESSOR_NULL((processor_t) 0)) | |||
458 | return KERN_INVALID_ARGUMENT4; | |||
459 | #if NCPUS1 > 1 | |||
460 | return cpu_start(processor->slot_num); | |||
461 | #else /* NCPUS > 1 */ | |||
462 | return KERN_FAILURE5; | |||
463 | #endif /* NCPUS > 1 */ | |||
464 | } | |||
465 | ||||
466 | kern_return_t processor_exit( | |||
467 | processor_t processor) | |||
468 | { | |||
469 | if (processor == PROCESSOR_NULL((processor_t) 0)) | |||
470 | return KERN_INVALID_ARGUMENT4; | |||
471 | ||||
472 | #if NCPUS1 > 1 | |||
473 | return processor_shutdown(processor); | |||
474 | #else /* NCPUS > 1 */ | |||
475 | return KERN_FAILURE5; | |||
476 | #endif /* NCPUS > 1 */ | |||
477 | } | |||
478 | ||||
479 | kern_return_t | |||
480 | processor_control( | |||
481 | processor_t processor, | |||
482 | processor_info_t info, | |||
483 | natural_t count) | |||
484 | { | |||
485 | if (processor == PROCESSOR_NULL((processor_t) 0)) | |||
486 | return KERN_INVALID_ARGUMENT4; | |||
487 | ||||
488 | #if NCPUS1 > 1 | |||
489 | return cpu_control(processor->slot_num, (int *)info, count); | |||
490 | #else /* NCPUS > 1 */ | |||
491 | return KERN_FAILURE5; | |||
492 | #endif /* NCPUS > 1 */ | |||
493 | } | |||
494 | ||||
495 | /* | |||
496 | * Precalculate the appropriate system quanta based on load. The | |||
497 | * index into machine_quantum is the number of threads on the | |||
498 | * processor set queue. It is limited to the number of processors in | |||
499 | * the set. | |||
500 | */ | |||
501 | ||||
502 | void quantum_set( | |||
503 | processor_set_t pset) | |||
504 | { | |||
505 | #if NCPUS1 > 1 | |||
506 | register int i,ncpus; | |||
507 | ||||
508 | ncpus = pset->processor_count; | |||
509 | ||||
510 | for ( i=1 ; i <= ncpus ; i++) { | |||
511 | pset->machine_quantum[i] = | |||
512 | ((min_quantum * ncpus) + (i/2)) / i ; | |||
513 | } | |||
514 | pset->machine_quantum[0] = 2 * pset->machine_quantum[1]; | |||
515 | ||||
516 | i = ((pset->runq.count > pset->processor_count) ? | |||
517 | pset->processor_count : pset->runq.count); | |||
518 | pset->set_quantum = pset->machine_quantum[i]; | |||
519 | #else /* NCPUS > 1 */ | |||
520 | default_pset.set_quantum = min_quantum; | |||
521 | #endif /* NCPUS > 1 */ | |||
522 | } | |||
523 | ||||
524 | #if MACH_HOST0 | |||
525 | /* | |||
526 | * processor_set_create: | |||
527 | * | |||
528 | * Create and return a new processor set. | |||
529 | */ | |||
530 | ||||
531 | kern_return_t | |||
532 | processor_set_create( | |||
533 | host_t host, | |||
534 | processor_set_t *new_set, | |||
535 | processor_set_t *new_name) | |||
536 | { | |||
537 | processor_set_t pset; | |||
538 | ||||
539 | if (host == HOST_NULL((host_t)0)) | |||
540 | return KERN_INVALID_ARGUMENT4; | |||
541 | ||||
542 | pset = (processor_set_t) kmem_cache_alloc(&pset_cache); | |||
543 | pset_init(pset); | |||
544 | pset_reference(pset); /* for new_set out argument */ | |||
545 | pset_reference(pset); /* for new_name out argument */ | |||
546 | ipc_pset_init(pset); | |||
547 | pset->active = TRUE((boolean_t) 1); | |||
548 | ||||
549 | simple_lock(&all_psets_lock); | |||
550 | queue_enter(&all_psets, pset, processor_set_t, all_psets){ register queue_entry_t prev; prev = (&all_psets)->prev ; if ((&all_psets) == prev) { (&all_psets)->next = (queue_entry_t) (pset); } else { ((processor_set_t)prev)-> all_psets.next = (queue_entry_t)(pset); } (pset)->all_psets .prev = prev; (pset)->all_psets.next = &all_psets; (& all_psets)->prev = (queue_entry_t) pset; }; | |||
551 | all_psets_count++; | |||
552 | simple_unlock(&all_psets_lock); | |||
553 | ||||
554 | ipc_pset_enable(pset); | |||
555 | ||||
556 | *new_set = pset; | |||
557 | *new_name = pset; | |||
558 | return KERN_SUCCESS0; | |||
559 | } | |||
560 | ||||
561 | /* | |||
562 | * processor_set_destroy: | |||
563 | * | |||
564 | * destroy a processor set. Any tasks, threads or processors | |||
565 | * currently assigned to it are reassigned to the default pset. | |||
566 | */ | |||
567 | kern_return_t processor_set_destroy( | |||
568 | processor_set_t pset) | |||
569 | { | |||
570 | register queue_entry_t elem; | |||
571 | register queue_head_t *list; | |||
572 | ||||
573 | if (pset == PROCESSOR_SET_NULL((processor_set_t) 0) || pset == &default_pset) | |||
574 | return KERN_INVALID_ARGUMENT4; | |||
575 | ||||
576 | /* | |||
577 | * Handle multiple termination race. First one through sets | |||
578 | * active to FALSE and disables ipc access. | |||
579 | */ | |||
580 | pset_lock(pset); | |||
581 | if (!(pset->active)) { | |||
582 | pset_unlock(pset); | |||
583 | return KERN_FAILURE5; | |||
584 | } | |||
585 | ||||
586 | pset->active = FALSE((boolean_t) 0); | |||
587 | ipc_pset_disable(pset); | |||
588 | ||||
589 | ||||
590 | /* | |||
591 | * Now reassign everything in this set to the default set. | |||
592 | */ | |||
593 | ||||
594 | if (pset->task_count > 0) { | |||
595 | list = &pset->tasks; | |||
596 | while (!queue_empty(list)(((list)) == (((list)->next)))) { | |||
597 | elem = queue_first(list)((list)->next); | |||
598 | task_reference((task_t) elem); | |||
599 | pset_unlock(pset); | |||
600 | task_assign((task_t) elem, &default_pset, FALSE((boolean_t) 0)); | |||
601 | task_deallocate((task_t) elem); | |||
602 | pset_lock(pset); | |||
603 | } | |||
604 | } | |||
605 | ||||
606 | if (pset->thread_count > 0) { | |||
607 | list = &pset->threads; | |||
608 | while (!queue_empty(list)(((list)) == (((list)->next)))) { | |||
609 | elem = queue_first(list)((list)->next); | |||
610 | thread_reference((thread_t) elem); | |||
611 | pset_unlock(pset); | |||
612 | thread_assign((thread_t) elem, &default_pset); | |||
613 | thread_deallocate((thread_t) elem); | |||
614 | pset_lock(pset); | |||
615 | } | |||
616 | } | |||
617 | ||||
618 | if (pset->processor_count > 0) { | |||
619 | list = &pset->processors; | |||
620 | while(!queue_empty(list)(((list)) == (((list)->next)))) { | |||
621 | elem = queue_first(list)((list)->next); | |||
622 | pset_unlock(pset); | |||
623 | processor_assign((processor_t) elem, &default_pset, TRUE((boolean_t) 1)); | |||
624 | pset_lock(pset); | |||
625 | } | |||
626 | } | |||
627 | ||||
628 | pset_unlock(pset); | |||
629 | ||||
630 | /* | |||
631 | * Destroy ipc state. | |||
632 | */ | |||
633 | ipc_pset_terminate(pset); | |||
634 | ||||
635 | /* | |||
636 | * Deallocate pset's reference to itself. | |||
637 | */ | |||
638 | pset_deallocate(pset); | |||
639 | return KERN_SUCCESS0; | |||
640 | } | |||
641 | ||||
642 | #else /* MACH_HOST */ | |||
643 | ||||
644 | kern_return_t | |||
645 | processor_set_create( | |||
646 | host_t host, | |||
647 | processor_set_t *new_set, | |||
648 | processor_set_t *new_name) | |||
649 | { | |||
650 | return KERN_FAILURE5; | |||
651 | } | |||
652 | ||||
653 | kern_return_t processor_set_destroy( | |||
654 | processor_set_t pset) | |||
655 | { | |||
656 | return KERN_FAILURE5; | |||
657 | } | |||
658 | ||||
659 | #endif /* MACH_HOST */ | |||
660 | ||||
661 | kern_return_t | |||
662 | processor_get_assignment( | |||
663 | processor_t processor, | |||
664 | processor_set_t *pset) | |||
665 | { | |||
666 | int state; | |||
667 | ||||
668 | state = processor->state; | |||
669 | if (state == PROCESSOR_SHUTDOWN5 || state == PROCESSOR_OFF_LINE0) | |||
670 | return KERN_FAILURE5; | |||
671 | ||||
672 | *pset = processor->processor_set; | |||
673 | pset_reference(*pset); | |||
674 | return KERN_SUCCESS0; | |||
675 | } | |||
676 | ||||
677 | kern_return_t | |||
678 | processor_set_info( | |||
679 | processor_set_t pset, | |||
680 | int flavor, | |||
681 | host_t *host, | |||
682 | processor_set_info_t info, | |||
683 | natural_t *count) | |||
684 | { | |||
685 | if (pset == PROCESSOR_SET_NULL((processor_set_t) 0)) | |||
686 | return KERN_INVALID_ARGUMENT4; | |||
687 | ||||
688 | if (flavor == PROCESSOR_SET_BASIC_INFO1) { | |||
689 | register processor_set_basic_info_t basic_info; | |||
690 | ||||
691 | if (*count < PROCESSOR_SET_BASIC_INFO_COUNT(sizeof(processor_set_basic_info_data_t)/sizeof(integer_t))) | |||
692 | return KERN_FAILURE5; | |||
693 | ||||
694 | basic_info = (processor_set_basic_info_t) info; | |||
695 | ||||
696 | pset_lock(pset); | |||
697 | basic_info->processor_count = pset->processor_count; | |||
698 | basic_info->task_count = pset->task_count; | |||
699 | basic_info->thread_count = pset->thread_count; | |||
700 | basic_info->mach_factor = pset->mach_factor; | |||
701 | basic_info->load_average = pset->load_average; | |||
702 | pset_unlock(pset); | |||
703 | ||||
704 | *count = PROCESSOR_SET_BASIC_INFO_COUNT(sizeof(processor_set_basic_info_data_t)/sizeof(integer_t)); | |||
705 | *host = &realhost; | |||
706 | return KERN_SUCCESS0; | |||
707 | } | |||
708 | else if (flavor == PROCESSOR_SET_SCHED_INFO2) { | |||
709 | register processor_set_sched_info_t sched_info; | |||
710 | ||||
711 | if (*count < PROCESSOR_SET_SCHED_INFO_COUNT(sizeof(processor_set_sched_info_data_t)/sizeof(integer_t))) | |||
712 | return KERN_FAILURE5; | |||
713 | ||||
714 | sched_info = (processor_set_sched_info_t) info; | |||
715 | ||||
716 | pset_lock(pset); | |||
717 | #if MACH_FIXPRI1 | |||
718 | sched_info->policies = pset->policies; | |||
719 | #else /* MACH_FIXPRI */ | |||
720 | sched_info->policies = POLICY_TIMESHARE1; | |||
721 | #endif /* MACH_FIXPRI */ | |||
722 | sched_info->max_priority = pset->max_priority; | |||
723 | pset_unlock(pset); | |||
724 | ||||
725 | *count = PROCESSOR_SET_SCHED_INFO_COUNT(sizeof(processor_set_sched_info_data_t)/sizeof(integer_t)); | |||
726 | *host = &realhost; | |||
727 | return KERN_SUCCESS0; | |||
728 | } | |||
729 | ||||
730 | *host = HOST_NULL((host_t)0); | |||
731 | return KERN_INVALID_ARGUMENT4; | |||
732 | } | |||
733 | ||||
734 | /* | |||
735 | * processor_set_max_priority: | |||
736 | * | |||
737 | * Specify max priority permitted on processor set. This affects | |||
738 | * newly created and assigned threads. Optionally change existing | |||
739 | * ones. | |||
740 | */ | |||
741 | kern_return_t | |||
742 | processor_set_max_priority( | |||
743 | processor_set_t pset, | |||
744 | int max_priority, | |||
745 | boolean_t change_threads) | |||
746 | { | |||
747 | if (pset == PROCESSOR_SET_NULL((processor_set_t) 0) || invalid_pri(max_priority)(((max_priority) < 0) || ((max_priority) >= 50))) | |||
748 | return KERN_INVALID_ARGUMENT4; | |||
749 | ||||
750 | pset_lock(pset); | |||
751 | pset->max_priority = max_priority; | |||
752 | ||||
753 | if (change_threads) { | |||
754 | register queue_head_t *list; | |||
755 | register thread_t thread; | |||
756 | ||||
757 | list = &pset->threads; | |||
758 | queue_iterate(list, thread, thread_t, pset_threads)for ((thread) = (thread_t) ((list)->next); !(((list)) == ( (queue_entry_t)(thread))); (thread) = (thread_t) ((&(thread )->pset_threads)->next)) { | |||
759 | if (thread->max_priority < max_priority) | |||
760 | thread_max_priority(thread, pset, max_priority); | |||
761 | } | |||
762 | } | |||
763 | ||||
764 | pset_unlock(pset); | |||
765 | ||||
766 | return KERN_SUCCESS0; | |||
767 | } | |||
768 | ||||
769 | /* | |||
770 | * processor_set_policy_enable: | |||
771 | * | |||
772 | * Allow indicated policy on processor set. | |||
773 | */ | |||
774 | ||||
775 | kern_return_t | |||
776 | processor_set_policy_enable( | |||
777 | processor_set_t pset, | |||
778 | int policy) | |||
779 | { | |||
780 | if ((pset == PROCESSOR_SET_NULL((processor_set_t) 0)) || invalid_policy(policy)(((policy) <= 0) || ((policy) > 2))) | |||
781 | return KERN_INVALID_ARGUMENT4; | |||
782 | ||||
783 | #if MACH_FIXPRI1 | |||
784 | pset_lock(pset); | |||
785 | pset->policies |= policy; | |||
786 | pset_unlock(pset); | |||
787 | ||||
788 | return KERN_SUCCESS0; | |||
789 | #else /* MACH_FIXPRI */ | |||
790 | if (policy == POLICY_TIMESHARE1) | |||
791 | return KERN_SUCCESS0; | |||
792 | else | |||
793 | return KERN_FAILURE5; | |||
794 | #endif /* MACH_FIXPRI */ | |||
795 | } | |||
796 | ||||
797 | /* | |||
798 | * processor_set_policy_disable: | |||
799 | * | |||
800 | * Forbid indicated policy on processor set. Time sharing cannot | |||
801 | * be forbidden. | |||
802 | */ | |||
803 | ||||
804 | kern_return_t | |||
805 | processor_set_policy_disable( | |||
806 | processor_set_t pset, | |||
807 | int policy, | |||
808 | boolean_t change_threads) | |||
809 | { | |||
810 | if ((pset == PROCESSOR_SET_NULL((processor_set_t) 0)) || policy == POLICY_TIMESHARE1 || | |||
811 | invalid_policy(policy)(((policy) <= 0) || ((policy) > 2))) | |||
812 | return KERN_INVALID_ARGUMENT4; | |||
813 | ||||
814 | #if MACH_FIXPRI1 | |||
815 | pset_lock(pset); | |||
816 | ||||
817 | /* | |||
818 | * Check if policy enabled. Disable if so, then handle | |||
819 | * change_threads. | |||
820 | */ | |||
821 | if (pset->policies & policy) { | |||
822 | pset->policies &= ~policy; | |||
823 | ||||
824 | if (change_threads) { | |||
825 | register queue_head_t *list; | |||
826 | register thread_t thread; | |||
827 | ||||
828 | list = &pset->threads; | |||
829 | queue_iterate(list, thread, thread_t, pset_threads)for ((thread) = (thread_t) ((list)->next); !(((list)) == ( (queue_entry_t)(thread))); (thread) = (thread_t) ((&(thread )->pset_threads)->next)) { | |||
830 | if (thread->policy == policy) | |||
831 | thread_policy(thread, POLICY_TIMESHARE1, 0); | |||
832 | } | |||
833 | } | |||
834 | } | |||
835 | pset_unlock(pset); | |||
836 | #endif /* MACH_FIXPRI */ | |||
837 | ||||
838 | return KERN_SUCCESS0; | |||
839 | } | |||
840 | ||||
841 | #define THING_TASK0 0 | |||
842 | #define THING_THREAD1 1 | |||
843 | ||||
844 | /* | |||
845 | * processor_set_things: | |||
846 | * | |||
847 | * Common internals for processor_set_{threads,tasks} | |||
848 | */ | |||
849 | kern_return_t | |||
850 | processor_set_things( | |||
851 | processor_set_t pset, | |||
852 | mach_port_t **thing_list, | |||
853 | natural_t *count, | |||
854 | int type) | |||
855 | { | |||
856 | unsigned int actual; /* this many things */ | |||
857 | int i; | |||
858 | ||||
859 | vm_size_t size, size_needed; | |||
860 | vm_offset_t addr; | |||
861 | ||||
862 | if (pset == PROCESSOR_SET_NULL((processor_set_t) 0)) | |||
863 | return KERN_INVALID_ARGUMENT4; | |||
864 | ||||
865 | size = 0; addr = 0; | |||
866 | ||||
867 | for (;;) { | |||
868 | pset_lock(pset); | |||
869 | if (!pset->active) { | |||
870 | pset_unlock(pset); | |||
871 | return KERN_FAILURE5; | |||
872 | } | |||
873 | ||||
874 | if (type == THING_TASK0) | |||
875 | actual = pset->task_count; | |||
876 | else | |||
877 | actual = pset->thread_count; | |||
878 | ||||
879 | /* do we have the memory we need? */ | |||
880 | ||||
881 | size_needed = actual * sizeof(mach_port_t); | |||
882 | if (size_needed <= size) | |||
883 | break; | |||
884 | ||||
885 | /* unlock the pset and allocate more memory */ | |||
886 | pset_unlock(pset); | |||
887 | ||||
888 | if (size != 0) | |||
889 | kfree(addr, size); | |||
890 | ||||
891 | assert(size_needed > 0)({ if (!(size_needed > 0)) Assert("size_needed > 0", "../kern/processor.c" , 891); }); | |||
892 | size = size_needed; | |||
893 | ||||
894 | addr = kalloc(size); | |||
895 | if (addr == 0) | |||
896 | return KERN_RESOURCE_SHORTAGE6; | |||
897 | } | |||
898 | ||||
899 | /* OK, have memory and the processor_set is locked & active */ | |||
900 | ||||
901 | switch (type) { | |||
902 | case THING_TASK0: { | |||
903 | task_t *tasks = (task_t *) addr; | |||
904 | task_t task; | |||
905 | ||||
906 | for (i = 0, task = (task_t) queue_first(&pset->tasks)((&pset->tasks)->next); | |||
907 | i < actual; | |||
908 | i++, task = (task_t) queue_next(&task->pset_tasks)((&task->pset_tasks)->next)) { | |||
909 | /* take ref for convert_task_to_port */ | |||
910 | task_reference(task); | |||
911 | tasks[i] = task; | |||
912 | } | |||
913 | assert(queue_end(&pset->tasks, (queue_entry_t) task))({ if (!(((&pset->tasks) == ((queue_entry_t) task)))) Assert ("queue_end(&pset->tasks, (queue_entry_t) task)", "../kern/processor.c" , 913); }); | |||
914 | break; | |||
915 | } | |||
916 | ||||
917 | case THING_THREAD1: { | |||
918 | thread_t *threads = (thread_t *) addr; | |||
919 | thread_t thread; | |||
920 | ||||
921 | for (i = 0, thread = (thread_t) queue_first(&pset->threads)((&pset->threads)->next); | |||
922 | i < actual; | |||
923 | i++, | |||
924 | thread = (thread_t) queue_next(&thread->pset_threads)((&thread->pset_threads)->next)) { | |||
925 | /* take ref for convert_thread_to_port */ | |||
926 | thread_reference(thread); | |||
927 | threads[i] = thread; | |||
| ||||
928 | } | |||
929 | assert(queue_end(&pset->threads, (queue_entry_t) thread))({ if (!(((&pset->threads) == ((queue_entry_t) thread) ))) Assert("queue_end(&pset->threads, (queue_entry_t) thread)" , "../kern/processor.c", 929); }); | |||
930 | break; | |||
931 | } | |||
932 | } | |||
933 | ||||
934 | /* can unlock processor set now that we have the task/thread refs */ | |||
935 | pset_unlock(pset); | |||
936 | ||||
937 | if (actual == 0) { | |||
938 | /* no things, so return null pointer and deallocate memory */ | |||
939 | *thing_list = 0; | |||
940 | *count = 0; | |||
941 | ||||
942 | if (size != 0) | |||
943 | kfree(addr, size); | |||
944 | } else { | |||
945 | /* if we allocated too much, must copy */ | |||
946 | ||||
947 | if (size_needed < size) { | |||
948 | vm_offset_t newaddr; | |||
949 | ||||
950 | newaddr = kalloc(size_needed); | |||
951 | if (newaddr == 0) { | |||
952 | switch (type) { | |||
953 | case THING_TASK0: { | |||
954 | task_t *tasks = (task_t *) addr; | |||
955 | ||||
956 | for (i = 0; i < actual; i++) | |||
957 | task_deallocate(tasks[i]); | |||
958 | break; | |||
959 | } | |||
960 | ||||
961 | case THING_THREAD1: { | |||
962 | thread_t *threads = (thread_t *) addr; | |||
963 | ||||
964 | for (i = 0; i < actual; i++) | |||
965 | thread_deallocate(threads[i]); | |||
966 | break; | |||
967 | } | |||
968 | } | |||
969 | kfree(addr, size); | |||
970 | return KERN_RESOURCE_SHORTAGE6; | |||
971 | } | |||
972 | ||||
973 | memcpy((void *) newaddr, (void *) addr, size_needed); | |||
974 | kfree(addr, size); | |||
975 | addr = newaddr; | |||
976 | } | |||
977 | ||||
978 | *thing_list = (mach_port_t *) addr; | |||
979 | *count = actual; | |||
980 | ||||
981 | /* do the conversion that Mig should handle */ | |||
982 | ||||
983 | switch (type) { | |||
984 | case THING_TASK0: { | |||
985 | task_t *tasks = (task_t *) addr; | |||
986 | ||||
987 | for (i = 0; i < actual; i++) | |||
988 | ((mach_port_t *) tasks)[i] = | |||
989 | (mach_port_t)convert_task_to_port(tasks[i]); | |||
990 | break; | |||
991 | } | |||
992 | ||||
993 | case THING_THREAD1: { | |||
994 | thread_t *threads = (thread_t *) addr; | |||
995 | ||||
996 | for (i = 0; i < actual; i++) | |||
997 | ((mach_port_t *) threads)[i] = | |||
998 | (mach_port_t)convert_thread_to_port(threads[i]); | |||
999 | break; | |||
1000 | } | |||
1001 | } | |||
1002 | } | |||
1003 | ||||
1004 | return KERN_SUCCESS0; | |||
1005 | } | |||
1006 | ||||
1007 | ||||
1008 | /* | |||
1009 | * processor_set_tasks: | |||
1010 | * | |||
1011 | * List all tasks in the processor set. | |||
1012 | */ | |||
1013 | kern_return_t | |||
1014 | processor_set_tasks( | |||
1015 | processor_set_t pset, | |||
1016 | task_array_t *task_list, | |||
1017 | natural_t *count) | |||
1018 | { | |||
1019 | return processor_set_things(pset, task_list, count, THING_TASK0); | |||
1020 | } | |||
1021 | ||||
1022 | /* | |||
1023 | * processor_set_threads: | |||
1024 | * | |||
1025 | * List all threads in the processor set. | |||
1026 | */ | |||
1027 | kern_return_t | |||
1028 | processor_set_threads( | |||
1029 | processor_set_t pset, | |||
1030 | thread_array_t *thread_list, | |||
1031 | natural_t *count) | |||
1032 | { | |||
1033 | return processor_set_things(pset, thread_list, count, THING_THREAD1); | |||
| ||||
1034 | } |