2 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
31 #include <mach/mach_types.h>
32 #include <mach/task.h>
33 #include <mach/thread_act.h>
35 #include <kern/kern_types.h>
36 #include <kern/processor.h>
37 #include <kern/thread.h>
38 #include <kern/kalloc.h>
40 #include <chud/chud_xnu.h>
41 #include <chud/chud_xnu_private.h>
43 #include <machine/machine_routines.h>
45 // include the correct file to find real_ncpus
46 #if defined(__i386__) || defined(__x86_64__)
48 #endif // i386 or x86_64
50 #if defined(__ppc__) || defined(__ppc64__)
51 # include <ppc/cpu_internal.h>
52 #endif // ppc or ppc64
54 #pragma mark **** thread binding ****
56 __private_extern__ kern_return_t
57 chudxnu_bind_thread(thread_t thread
, int cpu
)
59 processor_t proc
= NULL
;
61 if(cpu
>= real_ncpus
) // sanity check
64 proc
= cpu_to_processor(cpu
);
66 if(proc
&& !(proc
->state
== PROCESSOR_OFF_LINE
) &&
67 !(proc
->state
== PROCESSOR_SHUTDOWN
)) {
68 /* disallow bind to shutdown processor */
69 thread_bind(thread
, proc
);
70 if(thread
==current_thread()) {
71 (void)thread_block(THREAD_CONTINUE_NULL
);
78 __private_extern__ kern_return_t
79 chudxnu_unbind_thread(thread_t thread
)
81 thread_bind(thread
, PROCESSOR_NULL
);
85 #pragma mark **** task and thread info ****
88 boolean_t
chudxnu_is_64bit_task(task_t task
)
90 return (task_has_64BitAddr(task
));
94 #define THING_THREAD 1
96 // an exact copy of processor_set_things() except no mig conversion at the end!
98 chudxnu_private_processor_set_things(
100 mach_port_t
**thing_list
,
101 mach_msg_type_number_t
*count
,
104 unsigned int actual
; /* this many things */
105 unsigned int maxthings
;
108 vm_size_t size
, size_needed
;
111 if (pset
== PROCESSOR_SET_NULL
)
112 return (KERN_INVALID_ARGUMENT
);
121 return (KERN_FAILURE
);
124 if (type
== THING_TASK
)
125 maxthings
= pset
->task_count
;
127 maxthings
= pset
->thread_count
;
129 /* do we have the memory we need? */
131 size_needed
= maxthings
* sizeof (mach_port_t
);
132 if (size_needed
<= size
)
135 /* unlock the pset and allocate more memory */
141 assert(size_needed
> 0);
146 return (KERN_RESOURCE_SHORTAGE
);
149 /* OK, have memory and the processor_set is locked & active */
156 task_t task
, *tasks
= (task_t
*)addr
;
158 for (task
= (task_t
)queue_first(&pset
->tasks
);
159 !queue_end(&pset
->tasks
, (queue_entry_t
)task
);
160 task
= (task_t
)queue_next(&task
->pset_tasks
)) {
161 task_reference_internal(task
);
162 tasks
[actual
++] = task
;
170 thread_t thread
, *threads
= (thread_t
*)addr
;
172 for (i
= 0, thread
= (thread_t
)queue_first(&pset
->threads
);
173 !queue_end(&pset
->threads
, (queue_entry_t
)thread
);
174 thread
= (thread_t
)queue_next(&thread
->pset_threads
)) {
175 thread_reference_internal(thread
);
176 threads
[actual
++] = thread
;
185 if (actual
< maxthings
)
186 size_needed
= actual
* sizeof (mach_port_t
);
189 /* no things, so return null pointer and deallocate memory */
197 /* if we allocated too much, must copy */
199 if (size_needed
< size
) {
202 newaddr
= kalloc(size_needed
);
208 task_t
*tasks
= (task_t
*)addr
;
210 for (i
= 0; i
< actual
; i
++)
211 task_deallocate(tasks
[i
]);
217 thread_t
*threads
= (thread_t
*)addr
;
219 for (i
= 0; i
< actual
; i
++)
220 thread_deallocate(threads
[i
]);
226 return (KERN_RESOURCE_SHORTAGE
);
229 bcopy((void *) addr
, (void *) newaddr
, size_needed
);
234 *thing_list
= (mach_port_t
*)addr
;
238 return (KERN_SUCCESS
);
241 // an exact copy of task_threads() except no mig conversion at the end!
243 chudxnu_private_task_threads(
245 thread_act_array_t
*threads_out
,
246 mach_msg_type_number_t
*count
)
248 mach_msg_type_number_t actual
;
251 vm_size_t size
, size_needed
;
255 if (task
== TASK_NULL
)
256 return (KERN_INVALID_ARGUMENT
);
268 return (KERN_FAILURE
);
271 actual
= task
->thread_count
;
273 /* do we have the memory we need? */
274 size_needed
= actual
* sizeof (mach_port_t
);
275 if (size_needed
<= size
)
278 /* unlock the task and allocate more memory */
284 assert(size_needed
> 0);
289 return (KERN_RESOURCE_SHORTAGE
);
292 /* OK, have memory and the task is locked & active */
293 threads
= (thread_t
*)addr
;
297 for (thread
= (thread_t
)queue_first(&task
->threads
); i
< actual
;
298 ++i
, thread
= (thread_t
)queue_next(&thread
->task_threads
)) {
299 thread_reference_internal(thread
);
300 threads
[j
++] = thread
;
303 assert(queue_end(&task
->threads
, (queue_entry_t
)thread
));
306 size_needed
= actual
* sizeof (mach_port_t
);
308 /* can unlock task now that we've got the thread refs */
312 /* no threads, so return null pointer and deallocate memory */
321 /* if we allocated too much, must copy */
323 if (size_needed
< size
) {
326 newaddr
= kalloc(size_needed
);
328 for (i
= 0; i
< actual
; ++i
)
329 thread_deallocate(threads
[i
]);
331 return (KERN_RESOURCE_SHORTAGE
);
334 bcopy(addr
, newaddr
, size_needed
);
336 threads
= (thread_t
*)newaddr
;
339 *threads_out
= threads
;
343 return (KERN_SUCCESS
);
347 __private_extern__ kern_return_t
349 task_array_t
*task_list
,
350 mach_msg_type_number_t
*count
)
352 return chudxnu_private_processor_set_things(&default_pset
, (mach_port_t
**)task_list
, count
, THING_TASK
);
355 __private_extern__ kern_return_t
356 chudxnu_free_task_list(
357 task_array_t
*task_list
,
358 mach_msg_type_number_t
*count
)
360 vm_size_t size
= (*count
)*sizeof(mach_port_t
);
361 void *addr
= *task_list
;
364 int i
, maxCount
= *count
;
365 for(i
=0; i
<maxCount
; i
++) {
366 task_deallocate((*task_list
)[i
]);
377 __private_extern__ kern_return_t
379 thread_array_t
*thread_list
,
380 mach_msg_type_number_t
*count
)
382 return chudxnu_private_processor_set_things(&default_pset
, (mach_port_t
**)thread_list
, count
, THING_THREAD
);
385 __private_extern__ kern_return_t
386 chudxnu_task_threads(
388 thread_array_t
*thread_list
,
389 mach_msg_type_number_t
*count
)
391 return chudxnu_private_task_threads(task
, thread_list
, count
);
394 __private_extern__ kern_return_t
395 chudxnu_free_thread_list(
396 thread_array_t
*thread_list
,
397 mach_msg_type_number_t
*count
)
399 vm_size_t size
= (*count
)*sizeof(mach_port_t
);
400 void *addr
= *thread_list
;
403 int i
, maxCount
= *count
;
404 for(i
=0; i
<maxCount
; i
++) {
405 thread_deallocate((*thread_list
)[i
]);
416 __private_extern__ task_t
417 chudxnu_current_task(void)
419 return current_task();
422 __private_extern__ thread_t
423 chudxnu_current_thread(void)
425 return current_thread();
428 __private_extern__ task_t
429 chudxnu_task_for_thread(thread_t thread
)
431 return get_threadtask(thread
);
434 __private_extern__ kern_return_t
437 thread_flavor_t flavor
,
438 thread_info_t thread_info_out
,
439 mach_msg_type_number_t
*thread_info_count
)
441 return thread_info(thread
, flavor
, thread_info_out
, thread_info_count
);
444 __private_extern__ kern_return_t
445 chudxnu_thread_last_context_switch(thread_t thread
, uint64_t *timestamp
)
447 *timestamp
= thread
->last_switch
;