]> git.saurik.com Git - apple/xnu.git/blob - osfmk/chud/chud_thread.c
1f67149b663a2b532a845386577ecef45d2fb6e5
[apple/xnu.git] / osfmk / chud / chud_thread.c
1 /*
2 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <mach/mach_types.h>
30 #include <mach/task.h>
31 #include <mach/thread_act.h>
32
33 #include <kern/kern_types.h>
34 #include <kern/processor.h>
35 #include <kern/thread.h>
36 #include <kern/kalloc.h>
37
38 #include <chud/chud_xnu.h>
39 #include <chud/chud_xnu_private.h>
40
41 #include <machine/machine_routines.h>
42
43 // include the correct file to find real_ncpus
44 #if defined(__i386__) || defined(__x86_64__)
45 # include <i386/mp.h>
46 #endif // i386 or x86_64
47
48 #if defined(__ppc__) || defined(__ppc64__)
49 # include <ppc/cpu_internal.h>
50 #endif // ppc or ppc64
51
52 #pragma mark **** thread binding ****
53
54 __private_extern__ kern_return_t
55 chudxnu_bind_thread(thread_t thread, int cpu)
56 {
57 processor_t proc = NULL;
58
59 if(cpu >= real_ncpus) // sanity check
60 return KERN_FAILURE;
61
62 proc = cpu_to_processor(cpu);
63
64 if(proc && !(proc->state == PROCESSOR_OFF_LINE) &&
65 !(proc->state == PROCESSOR_SHUTDOWN)) {
66 /* disallow bind to shutdown processor */
67 thread_bind(thread, proc);
68 if(thread==current_thread()) {
69 (void)thread_block(THREAD_CONTINUE_NULL);
70 }
71 return KERN_SUCCESS;
72 }
73 return KERN_FAILURE;
74 }
75
76 __private_extern__ kern_return_t
77 chudxnu_unbind_thread(thread_t thread)
78 {
79 thread_bind(thread, PROCESSOR_NULL);
80 return KERN_SUCCESS;
81 }
82
83 #pragma mark **** task and thread info ****
84
85 __private_extern__
86 boolean_t chudxnu_is_64bit_task(task_t task)
87 {
88 return (task_has_64BitAddr(task));
89 }
90
91 #define THING_TASK 0
92 #define THING_THREAD 1
93
94 // an exact copy of processor_set_things() except no mig conversion at the end!
95 static kern_return_t
96 chudxnu_private_processor_set_things(
97 processor_set_t pset,
98 mach_port_t **thing_list,
99 mach_msg_type_number_t *count,
100 int type)
101 {
102 unsigned int actual; /* this many things */
103 unsigned int maxthings;
104 unsigned int i;
105
106 vm_size_t size, size_needed;
107 void *addr;
108
109 if (pset == PROCESSOR_SET_NULL)
110 return (KERN_INVALID_ARGUMENT);
111
112 size = 0; addr = 0;
113
114 for (;;) {
115 pset_lock(pset);
116 if (!pset->active) {
117 pset_unlock(pset);
118
119 return (KERN_FAILURE);
120 }
121
122 if (type == THING_TASK)
123 maxthings = pset->task_count;
124 else
125 maxthings = pset->thread_count;
126
127 /* do we have the memory we need? */
128
129 size_needed = maxthings * sizeof (mach_port_t);
130 if (size_needed <= size)
131 break;
132
133 /* unlock the pset and allocate more memory */
134 pset_unlock(pset);
135
136 if (size != 0)
137 kfree(addr, size);
138
139 assert(size_needed > 0);
140 size = size_needed;
141
142 addr = kalloc(size);
143 if (addr == 0)
144 return (KERN_RESOURCE_SHORTAGE);
145 }
146
147 /* OK, have memory and the processor_set is locked & active */
148
149 actual = 0;
150 switch (type) {
151
152 case THING_TASK:
153 {
154 task_t task, *tasks = (task_t *)addr;
155
156 for (task = (task_t)queue_first(&pset->tasks);
157 !queue_end(&pset->tasks, (queue_entry_t)task);
158 task = (task_t)queue_next(&task->pset_tasks)) {
159 task_reference_internal(task);
160 tasks[actual++] = task;
161 }
162
163 break;
164 }
165
166 case THING_THREAD:
167 {
168 thread_t thread, *threads = (thread_t *)addr;
169
170 for (i = 0, thread = (thread_t)queue_first(&pset->threads);
171 !queue_end(&pset->threads, (queue_entry_t)thread);
172 thread = (thread_t)queue_next(&thread->pset_threads)) {
173 thread_reference_internal(thread);
174 threads[actual++] = thread;
175 }
176
177 break;
178 }
179 }
180
181 pset_unlock(pset);
182
183 if (actual < maxthings)
184 size_needed = actual * sizeof (mach_port_t);
185
186 if (actual == 0) {
187 /* no things, so return null pointer and deallocate memory */
188 *thing_list = 0;
189 *count = 0;
190
191 if (size != 0)
192 kfree(addr, size);
193 }
194 else {
195 /* if we allocated too much, must copy */
196
197 if (size_needed < size) {
198 void *newaddr;
199
200 newaddr = kalloc(size_needed);
201 if (newaddr == 0) {
202 switch (type) {
203
204 case THING_TASK:
205 {
206 task_t *tasks = (task_t *)addr;
207
208 for (i = 0; i < actual; i++)
209 task_deallocate(tasks[i]);
210 break;
211 }
212
213 case THING_THREAD:
214 {
215 thread_t *threads = (thread_t *)addr;
216
217 for (i = 0; i < actual; i++)
218 thread_deallocate(threads[i]);
219 break;
220 }
221 }
222
223 kfree(addr, size);
224 return (KERN_RESOURCE_SHORTAGE);
225 }
226
227 bcopy((void *) addr, (void *) newaddr, size_needed);
228 kfree(addr, size);
229 addr = newaddr;
230 }
231
232 *thing_list = (mach_port_t *)addr;
233 *count = actual;
234 }
235
236 return (KERN_SUCCESS);
237 }
238
239 // an exact copy of task_threads() except no mig conversion at the end!
240 static kern_return_t
241 chudxnu_private_task_threads(
242 task_t task,
243 thread_act_array_t *threads_out,
244 mach_msg_type_number_t *count)
245 {
246 mach_msg_type_number_t actual;
247 thread_t *threads;
248 thread_t thread;
249 vm_size_t size, size_needed;
250 void *addr;
251 unsigned int i, j;
252
253 if (task == TASK_NULL)
254 return (KERN_INVALID_ARGUMENT);
255
256 size = 0; addr = 0;
257
258 for (;;) {
259 task_lock(task);
260 if (!task->active) {
261 task_unlock(task);
262
263 if (size != 0)
264 kfree(addr, size);
265
266 return (KERN_FAILURE);
267 }
268
269 actual = task->thread_count;
270
271 /* do we have the memory we need? */
272 size_needed = actual * sizeof (mach_port_t);
273 if (size_needed <= size)
274 break;
275
276 /* unlock the task and allocate more memory */
277 task_unlock(task);
278
279 if (size != 0)
280 kfree(addr, size);
281
282 assert(size_needed > 0);
283 size = size_needed;
284
285 addr = kalloc(size);
286 if (addr == 0)
287 return (KERN_RESOURCE_SHORTAGE);
288 }
289
290 /* OK, have memory and the task is locked & active */
291 threads = (thread_t *)addr;
292
293 i = j = 0;
294
295 for (thread = (thread_t)queue_first(&task->threads); i < actual;
296 ++i, thread = (thread_t)queue_next(&thread->task_threads)) {
297 thread_reference_internal(thread);
298 threads[j++] = thread;
299 }
300
301 assert(queue_end(&task->threads, (queue_entry_t)thread));
302
303 actual = j;
304 size_needed = actual * sizeof (mach_port_t);
305
306 /* can unlock task now that we've got the thread refs */
307 task_unlock(task);
308
309 if (actual == 0) {
310 /* no threads, so return null pointer and deallocate memory */
311
312 *threads_out = 0;
313 *count = 0;
314
315 if (size != 0)
316 kfree(addr, size);
317 }
318 else {
319 /* if we allocated too much, must copy */
320
321 if (size_needed < size) {
322 void *newaddr;
323
324 newaddr = kalloc(size_needed);
325 if (newaddr == 0) {
326 for (i = 0; i < actual; ++i)
327 thread_deallocate(threads[i]);
328 kfree(addr, size);
329 return (KERN_RESOURCE_SHORTAGE);
330 }
331
332 bcopy(addr, newaddr, size_needed);
333 kfree(addr, size);
334 threads = (thread_t *)newaddr;
335 }
336
337 *threads_out = threads;
338 *count = actual;
339 }
340
341 return (KERN_SUCCESS);
342 }
343
344
345 __private_extern__ kern_return_t
346 chudxnu_all_tasks(
347 task_array_t *task_list,
348 mach_msg_type_number_t *count)
349 {
350 return chudxnu_private_processor_set_things(&default_pset, (mach_port_t **)task_list, count, THING_TASK);
351 }
352
353 __private_extern__ kern_return_t
354 chudxnu_free_task_list(
355 task_array_t *task_list,
356 mach_msg_type_number_t *count)
357 {
358 vm_size_t size = (*count)*sizeof(mach_port_t);
359 void *addr = *task_list;
360
361 if(addr) {
362 int i, maxCount = *count;
363 for(i=0; i<maxCount; i++) {
364 task_deallocate((*task_list)[i]);
365 }
366 kfree(addr, size);
367 *task_list = NULL;
368 *count = 0;
369 return KERN_SUCCESS;
370 } else {
371 return KERN_FAILURE;
372 }
373 }
374
375 __private_extern__ kern_return_t
376 chudxnu_all_threads(
377 thread_array_t *thread_list,
378 mach_msg_type_number_t *count)
379 {
380 return chudxnu_private_processor_set_things(&default_pset, (mach_port_t **)thread_list, count, THING_THREAD);
381 }
382
383 __private_extern__ kern_return_t
384 chudxnu_task_threads(
385 task_t task,
386 thread_array_t *thread_list,
387 mach_msg_type_number_t *count)
388 {
389 return chudxnu_private_task_threads(task, thread_list, count);
390 }
391
392 __private_extern__ kern_return_t
393 chudxnu_free_thread_list(
394 thread_array_t *thread_list,
395 mach_msg_type_number_t *count)
396 {
397 vm_size_t size = (*count)*sizeof(mach_port_t);
398 void *addr = *thread_list;
399
400 if(addr) {
401 int i, maxCount = *count;
402 for(i=0; i<maxCount; i++) {
403 thread_deallocate((*thread_list)[i]);
404 }
405 kfree(addr, size);
406 *thread_list = NULL;
407 *count = 0;
408 return KERN_SUCCESS;
409 } else {
410 return KERN_FAILURE;
411 }
412 }
413
414 __private_extern__ task_t
415 chudxnu_current_task(void)
416 {
417 return current_task();
418 }
419
420 __private_extern__ thread_t
421 chudxnu_current_thread(void)
422 {
423 return current_thread();
424 }
425
426 __private_extern__ task_t
427 chudxnu_task_for_thread(thread_t thread)
428 {
429 return get_threadtask(thread);
430 }
431
432 __private_extern__ kern_return_t
433 chudxnu_thread_info(
434 thread_t thread,
435 thread_flavor_t flavor,
436 thread_info_t thread_info_out,
437 mach_msg_type_number_t *thread_info_count)
438 {
439 return thread_info(thread, flavor, thread_info_out, thread_info_count);
440 }
441
442 __private_extern__ kern_return_t
443 chudxnu_thread_last_context_switch(thread_t thread, uint64_t *timestamp)
444 {
445 *timestamp = thread->last_switch;
446 return KERN_SUCCESS;
447 }
448