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