2 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <mach/mach_types.h>
30 #include <mach/task.h>
31 #include <mach/thread_act.h>
33 #include <kern/kern_types.h>
34 #include <kern/processor.h>
35 #include <kern/thread.h>
36 #include <kern/kalloc.h>
38 #include <chud/chud_xnu.h>
39 #include <chud/chud_xnu_private.h>
41 #include <machine/machine_routines.h>
43 // include the correct file to find real_ncpus
44 #if defined(__i386__) || defined(__x86_64__)
46 #endif // i386 or x86_64
48 #if defined(__ppc__) || defined(__ppc64__)
49 # include <ppc/cpu_internal.h>
50 #endif // ppc or ppc64
52 #pragma mark **** thread binding ****
54 __private_extern__ kern_return_t
55 chudxnu_bind_thread(thread_t thread
, int cpu
)
57 processor_t proc
= NULL
;
59 if(cpu
>= real_ncpus
) // sanity check
62 proc
= cpu_to_processor(cpu
);
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
);
76 __private_extern__ kern_return_t
77 chudxnu_unbind_thread(thread_t thread
)
79 thread_bind(thread
, PROCESSOR_NULL
);
83 #pragma mark **** task and thread info ****
86 boolean_t
chudxnu_is_64bit_task(task_t task
)
88 return (task_has_64BitAddr(task
));
92 #define THING_THREAD 1
94 // an exact copy of processor_set_things() except no mig conversion at the end!
96 chudxnu_private_processor_set_things(
98 mach_port_t
**thing_list
,
99 mach_msg_type_number_t
*count
,
102 unsigned int actual
; /* this many things */
103 unsigned int maxthings
;
106 vm_size_t size
, size_needed
;
109 if (pset
== PROCESSOR_SET_NULL
)
110 return (KERN_INVALID_ARGUMENT
);
119 return (KERN_FAILURE
);
122 if (type
== THING_TASK
)
123 maxthings
= pset
->task_count
;
125 maxthings
= pset
->thread_count
;
127 /* do we have the memory we need? */
129 size_needed
= maxthings
* sizeof (mach_port_t
);
130 if (size_needed
<= size
)
133 /* unlock the pset and allocate more memory */
139 assert(size_needed
> 0);
144 return (KERN_RESOURCE_SHORTAGE
);
147 /* OK, have memory and the processor_set is locked & active */
154 task_t task
, *tasks
= (task_t
*)addr
;
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
;
168 thread_t thread
, *threads
= (thread_t
*)addr
;
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
;
183 if (actual
< maxthings
)
184 size_needed
= actual
* sizeof (mach_port_t
);
187 /* no things, so return null pointer and deallocate memory */
195 /* if we allocated too much, must copy */
197 if (size_needed
< size
) {
200 newaddr
= kalloc(size_needed
);
206 task_t
*tasks
= (task_t
*)addr
;
208 for (i
= 0; i
< actual
; i
++)
209 task_deallocate(tasks
[i
]);
215 thread_t
*threads
= (thread_t
*)addr
;
217 for (i
= 0; i
< actual
; i
++)
218 thread_deallocate(threads
[i
]);
224 return (KERN_RESOURCE_SHORTAGE
);
227 bcopy((void *) addr
, (void *) newaddr
, size_needed
);
232 *thing_list
= (mach_port_t
*)addr
;
236 return (KERN_SUCCESS
);
239 // an exact copy of task_threads() except no mig conversion at the end!
241 chudxnu_private_task_threads(
243 thread_act_array_t
*threads_out
,
244 mach_msg_type_number_t
*count
)
246 mach_msg_type_number_t actual
;
249 vm_size_t size
, size_needed
;
253 if (task
== TASK_NULL
)
254 return (KERN_INVALID_ARGUMENT
);
266 return (KERN_FAILURE
);
269 actual
= task
->thread_count
;
271 /* do we have the memory we need? */
272 size_needed
= actual
* sizeof (mach_port_t
);
273 if (size_needed
<= size
)
276 /* unlock the task and allocate more memory */
282 assert(size_needed
> 0);
287 return (KERN_RESOURCE_SHORTAGE
);
290 /* OK, have memory and the task is locked & active */
291 threads
= (thread_t
*)addr
;
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
;
301 assert(queue_end(&task
->threads
, (queue_entry_t
)thread
));
304 size_needed
= actual
* sizeof (mach_port_t
);
306 /* can unlock task now that we've got the thread refs */
310 /* no threads, so return null pointer and deallocate memory */
319 /* if we allocated too much, must copy */
321 if (size_needed
< size
) {
324 newaddr
= kalloc(size_needed
);
326 for (i
= 0; i
< actual
; ++i
)
327 thread_deallocate(threads
[i
]);
329 return (KERN_RESOURCE_SHORTAGE
);
332 bcopy(addr
, newaddr
, size_needed
);
334 threads
= (thread_t
*)newaddr
;
337 *threads_out
= threads
;
341 return (KERN_SUCCESS
);
345 __private_extern__ kern_return_t
347 task_array_t
*task_list
,
348 mach_msg_type_number_t
*count
)
350 return chudxnu_private_processor_set_things(&default_pset
, (mach_port_t
**)task_list
, count
, THING_TASK
);
353 __private_extern__ kern_return_t
354 chudxnu_free_task_list(
355 task_array_t
*task_list
,
356 mach_msg_type_number_t
*count
)
358 vm_size_t size
= (*count
)*sizeof(mach_port_t
);
359 void *addr
= *task_list
;
362 int i
, maxCount
= *count
;
363 for(i
=0; i
<maxCount
; i
++) {
364 task_deallocate((*task_list
)[i
]);
375 __private_extern__ kern_return_t
377 thread_array_t
*thread_list
,
378 mach_msg_type_number_t
*count
)
380 return chudxnu_private_processor_set_things(&default_pset
, (mach_port_t
**)thread_list
, count
, THING_THREAD
);
383 __private_extern__ kern_return_t
384 chudxnu_task_threads(
386 thread_array_t
*thread_list
,
387 mach_msg_type_number_t
*count
)
389 return chudxnu_private_task_threads(task
, thread_list
, count
);
392 __private_extern__ kern_return_t
393 chudxnu_free_thread_list(
394 thread_array_t
*thread_list
,
395 mach_msg_type_number_t
*count
)
397 vm_size_t size
= (*count
)*sizeof(mach_port_t
);
398 void *addr
= *thread_list
;
401 int i
, maxCount
= *count
;
402 for(i
=0; i
<maxCount
; i
++) {
403 thread_deallocate((*thread_list
)[i
]);
414 __private_extern__ task_t
415 chudxnu_current_task(void)
417 return current_task();
420 __private_extern__ thread_t
421 chudxnu_current_thread(void)
423 return current_thread();
426 __private_extern__ task_t
427 chudxnu_task_for_thread(thread_t thread
)
429 return get_threadtask(thread
);
432 __private_extern__ kern_return_t
435 thread_flavor_t flavor
,
436 thread_info_t thread_info_out
,
437 mach_msg_type_number_t
*thread_info_count
)
439 return thread_info(thread
, flavor
, thread_info_out
, thread_info_count
);
442 __private_extern__ kern_return_t
443 chudxnu_thread_last_context_switch(thread_t thread
, uint64_t *timestamp
)
445 *timestamp
= thread
->last_switch
;