]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/bsd_kern.c
xnu-344.49.tar.gz
[apple/xnu.git] / osfmk / kern / bsd_kern.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
43866e37 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
43866e37
A
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
43866e37
A
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
1c79356b
A
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25#include <mach/mach_types.h>
26#include <kern/queue.h>
27#include <kern/ast.h>
28#include <kern/thread.h>
29#include <kern/thread_act.h>
30#include <kern/task.h>
31#include <kern/spl.h>
32#include <kern/lock.h>
33#include <vm/vm_map.h>
34#include <vm/pmap.h>
35#include <ipc/ipc_port.h>
36#include <ipc/ipc_object.h>
37
38#undef thread_should_halt
39#undef ipc_port_release
1c79356b
A
40
41decl_simple_lock_data(extern,reaper_lock)
42extern queue_head_t reaper_queue;
43
44/* BSD KERN COMPONENT INTERFACE */
45
9bccf70c 46task_t bsd_init_task = TASK_NULL;
1c79356b
A
47char init_task_failure_data[1024];
48
49thread_act_t get_firstthread(task_t);
50vm_map_t get_task_map(task_t);
51ipc_space_t get_task_ipcspace(task_t);
52boolean_t is_kerneltask(task_t);
53boolean_t is_thread_idle(thread_t);
9bccf70c 54boolean_t is_thread_running(thread_act_t);
1c79356b
A
55thread_shuttle_t getshuttle_thread( thread_act_t);
56thread_act_t getact_thread( thread_shuttle_t);
57vm_offset_t get_map_min( vm_map_t);
58vm_offset_t get_map_max( vm_map_t);
59int get_task_userstop(task_t);
60int get_thread_userstop(thread_act_t);
1c79356b
A
61boolean_t thread_should_abort(thread_shuttle_t);
62boolean_t current_thread_aborted(void);
63void task_act_iterate_wth_args(task_t, void(*)(thread_act_t, void *), void *);
64void ipc_port_release(ipc_port_t);
1c79356b 65boolean_t is_thread_active(thread_t);
1c79356b
A
66kern_return_t get_thread_waitresult(thread_t);
67vm_size_t get_vmmap_size(vm_map_t);
68int get_vmmap_entries(vm_map_t);
69int get_task_numacts(task_t);
70thread_act_t get_firstthread(task_t task);
71kern_return_t get_signalact(task_t , thread_act_t *, thread_t *, int);
9bccf70c 72void astbsd_on(void);
1c79356b 73
1c79356b
A
74/*
75 *
76 */
77void *get_bsdtask_info(task_t t)
78{
79 return(t->bsd_info);
80}
81
82/*
83 *
84 */
85void set_bsdtask_info(task_t t,void * v)
86{
87 t->bsd_info=v;
88}
89
90/*
91 *
92 */
93void *get_bsdthread_info(thread_act_t th)
94{
95 return(th->uthread);
96}
97
98/*
99 * XXX: wait for BSD to fix signal code
100 * Until then, we cannot block here. We know the task
101 * can't go away, so we make sure it is still active after
102 * retrieving the first thread for extra safety.
103 */
104thread_act_t get_firstthread(task_t task)
105{
106 thread_act_t thr_act;
107
108 thr_act = (thread_act_t)queue_first(&task->thr_acts);
109 if (thr_act == (thread_act_t)&task->thr_acts)
110 thr_act = THR_ACT_NULL;
111 if (!task->active)
112 return(THR_ACT_NULL);
113 return(thr_act);
114}
115
116kern_return_t get_signalact(task_t task,thread_act_t * thact, thread_t * thshut, int setast)
117{
118
119 thread_act_t inc;
120 thread_act_t ninc;
121 thread_act_t thr_act;
122 thread_t th;
123
124 task_lock(task);
125 if (!task->active) {
126 task_unlock(task);
127 return(KERN_FAILURE);
128 }
129
130 thr_act = THR_ACT_NULL;
131 for (inc = (thread_act_t)queue_first(&task->thr_acts);
132 inc != (thread_act_t)&task->thr_acts;
133 inc = ninc) {
134 th = act_lock_thread(inc);
9bccf70c
A
135 if ((inc->active) &&
136 ((th->state & (TH_ABORT|TH_ABORT_SAFELY)) != TH_ABORT)) {
1c79356b
A
137 thr_act = inc;
138 break;
139 }
140 act_unlock_thread(inc);
141 ninc = (thread_act_t)queue_next(&inc->thr_acts);
142 }
143out:
144 if (thact)
145 *thact = thr_act;
146
147 if (thshut)
148 *thshut = thr_act? thr_act->thread: THREAD_NULL ;
149 if (thr_act) {
9bccf70c
A
150 if (setast)
151 act_set_astbsd(thr_act);
152
1c79356b
A
153 act_unlock_thread(thr_act);
154 }
155 task_unlock(task);
156
157 if (thr_act)
158 return(KERN_SUCCESS);
159 else
160 return(KERN_FAILURE);
161}
162
0b4e3aa0 163
9bccf70c 164kern_return_t check_actforsig(task_t task, thread_act_t thact, thread_t * thshut, int setast)
0b4e3aa0
A
165{
166
167 thread_act_t inc;
168 thread_act_t ninc;
169 thread_act_t thr_act;
170 thread_t th;
171 int found=0;
172
173 task_lock(task);
174 if (!task->active) {
175 task_unlock(task);
176 return(KERN_FAILURE);
177 }
178
179 thr_act = THR_ACT_NULL;
180 for (inc = (thread_act_t)queue_first(&task->thr_acts);
181 inc != (thread_act_t)&task->thr_acts;
182 inc = ninc) {
183
184 if (inc != thact) {
185 ninc = (thread_act_t)queue_next(&inc->thr_acts);
186 continue;
187 }
188 th = act_lock_thread(inc);
9bccf70c
A
189 if ((inc->active) &&
190 ((th->state & (TH_ABORT|TH_ABORT_SAFELY)) != TH_ABORT)) {
0b4e3aa0
A
191 found = 1;
192 thr_act = inc;
193 break;
194 }
195 act_unlock_thread(inc);
196 /* ninc = (thread_act_t)queue_next(&inc->thr_acts); */
197 break;
198 }
199out:
200 if (found) {
201 if (thshut)
202 *thshut = thr_act? thr_act->thread: THREAD_NULL ;
9bccf70c
A
203 if (setast)
204 act_set_astbsd(thr_act);
205
0b4e3aa0
A
206 act_unlock_thread(thr_act);
207 }
208 task_unlock(task);
209
210 if (found)
211 return(KERN_SUCCESS);
212 else
213 return(KERN_FAILURE);
214}
215
1c79356b
A
216/*
217 *
218 */
219vm_map_t get_task_map(task_t t)
220{
221 return(t->map);
222}
223
224/*
225 *
226 */
227ipc_space_t get_task_ipcspace(task_t t)
228{
229 return(t->itk_space);
230}
231
232int get_task_numacts(task_t t)
233{
234 return(t->thr_act_count);
235}
236
237/*
238 * Reset the current task's map by taking a reference
239 * on the new map. The old map reference is returned.
240 */
241vm_map_t
242swap_task_map(task_t task,vm_map_t map)
243{
244 vm_map_t old_map;
245
246 vm_map_reference(map);
247 task_lock(task);
248 old_map = task->map;
249 task->map = map;
250 task_unlock(task);
251 return old_map;
252}
253
254/*
255 * Reset the current act map.
256 * The caller donates us a reference to the new map
257 * and we donote our reference to the old map to him.
258 */
259vm_map_t
260swap_act_map(thread_act_t thr_act,vm_map_t map)
261{
262 vm_map_t old_map;
263
264 act_lock(thr_act);
265 old_map = thr_act->map;
266 thr_act->map = map;
267 act_unlock(thr_act);
268 return old_map;
269}
270
271/*
272 *
273 */
274pmap_t get_task_pmap(task_t t)
275{
276 return(t->map->pmap);
277}
278
279/*
280 *
281 */
282pmap_t get_map_pmap(vm_map_t map)
283{
284 return(map->pmap);
285}
286/*
287 *
288 */
289task_t get_threadtask(thread_act_t th)
290{
291 return(th->task);
292}
293
294
295/*
296 *
297 */
298boolean_t is_thread_idle(thread_t th)
299{
300 return((th->state & TH_IDLE) == TH_IDLE);
301}
302
303/*
304 *
305 */
9bccf70c 306boolean_t is_thread_running(thread_act_t thact)
1c79356b 307{
9bccf70c 308 thread_t th = thact->thread;
1c79356b
A
309 return((th->state & TH_RUN) == TH_RUN);
310}
311
312/*
313 *
314 */
315thread_shuttle_t
316getshuttle_thread(
317 thread_act_t th)
318{
319#ifdef DEBUG
320 assert(th->thread);
321#endif
322 return(th->thread);
323}
324
325/*
326 *
327 */
328thread_act_t
329getact_thread(
330 thread_shuttle_t th)
331{
332#ifdef DEBUG
333 assert(th->top_act);
334#endif
335 return(th->top_act);
336}
337
338/*
339 *
340 */
341vm_offset_t
342get_map_min(
343 vm_map_t map)
344{
345 return(vm_map_min(map));
346}
347
348/*
349 *
350 */
351vm_offset_t
352get_map_max(
353 vm_map_t map)
354{
355 return(vm_map_max(map));
356}
357vm_size_t
358get_vmmap_size(
359 vm_map_t map)
360{
361 return(map->size);
362}
363
364int
365get_vmsubmap_entries(
366 vm_map_t map,
367 vm_object_offset_t start,
368 vm_object_offset_t end)
369{
370 int total_entries = 0;
371 vm_map_entry_t entry;
372
373 vm_map_lock(map);
374 entry = vm_map_first_entry(map);
375 while((entry != vm_map_to_entry(map)) && (entry->vme_start < start)) {
376 entry = entry->vme_next;
377 }
378
379 while((entry != vm_map_to_entry(map)) && (entry->vme_start < end)) {
380 if(entry->is_sub_map) {
381 total_entries +=
382 get_vmsubmap_entries(entry->object.sub_map,
383 entry->offset,
384 entry->offset +
385 (entry->vme_end - entry->vme_start));
386 } else {
387 total_entries += 1;
388 }
389 entry = entry->vme_next;
390 }
391 vm_map_unlock(map);
392 return(total_entries);
393}
394
395int
396get_vmmap_entries(
397 vm_map_t map)
398{
399 int total_entries = 0;
400 vm_map_entry_t entry;
401
402 vm_map_lock(map);
403 entry = vm_map_first_entry(map);
404
405 while(entry != vm_map_to_entry(map)) {
406 if(entry->is_sub_map) {
407 total_entries +=
408 get_vmsubmap_entries(entry->object.sub_map,
409 entry->offset,
410 entry->offset +
411 (entry->vme_end - entry->vme_start));
412 } else {
413 total_entries += 1;
414 }
415 entry = entry->vme_next;
416 }
417 vm_map_unlock(map);
418 return(total_entries);
419}
420
421/*
422 *
423 */
424/*
425 *
426 */
427int
428get_task_userstop(
429 task_t task)
430{
431 return(task->user_stop_count);
432}
433
434/*
435 *
436 */
437int
438get_thread_userstop(
439 thread_act_t th)
440{
441 return(th->user_stop_count);
442}
443
1c79356b
A
444/*
445 *
446 */
447boolean_t
448thread_should_abort(
449 thread_shuttle_t th)
450{
9bccf70c
A
451 return(!th->top_act || !th->top_act->active ||
452 (th->state & (TH_ABORT|TH_ABORT_SAFELY)) == TH_ABORT);
1c79356b
A
453}
454
455/*
9bccf70c
A
456 * This routine is like thread_should_abort() above. It checks to
457 * see if the current thread is aborted. But unlike above, it also
458 * checks to see if thread is safely aborted. If so, it returns
459 * that fact, and clears the condition (safe aborts only should
460 * have a single effect, and a poll of the abort status
461 * qualifies.
1c79356b
A
462 */
463boolean_t
464current_thread_aborted (
465 void)
466{
467 thread_t th = current_thread();
9bccf70c
A
468 spl_t s;
469
470 if (!th->top_act ||
471 ((th->state & (TH_ABORT|TH_ABORT_SAFELY)) == TH_ABORT &&
472 th->interrupt_level != THREAD_UNINT))
473 return (TRUE);
474 if (th->state & TH_ABORT_SAFELY) {
475 s = splsched();
476 thread_lock(th);
477 if (th->state & TH_ABORT_SAFELY)
478 th->state &= ~(TH_ABORT|TH_ABORT_SAFELY);
479 thread_unlock(th);
480 splx(s);
481 }
482 return FALSE;
1c79356b
A
483}
484
485/*
486 *
487 */
488void
489task_act_iterate_wth_args(
490 task_t task,
491 void (*func_callback)(thread_act_t, void *),
492 void *func_arg)
493{
494 thread_act_t inc, ninc;
495
496 task_lock(task);
497 for (inc = (thread_act_t)queue_first(&task->thr_acts);
498 inc != (thread_act_t)&task->thr_acts;
499 inc = ninc) {
500 ninc = (thread_act_t)queue_next(&inc->thr_acts);
501 (void) (*func_callback)(inc, func_arg);
502 }
503 task_unlock(task);
504}
505
506void
507ipc_port_release(
508 ipc_port_t port)
509{
510 ipc_object_release(&(port)->ip_object);
511}
512
1c79356b
A
513boolean_t
514is_thread_active(
515 thread_shuttle_t th)
516{
517 return(th->active);
518}
519
1c79356b
A
520kern_return_t
521get_thread_waitresult(
522 thread_shuttle_t th)
523{
524 return(th->wait_result);
525}
526
9bccf70c
A
527void
528astbsd_on(void)
529{
530 boolean_t reenable;
1c79356b 531
9bccf70c
A
532 reenable = ml_set_interrupts_enabled(FALSE);
533 ast_on_fast(AST_BSD);
534 (void)ml_set_interrupts_enabled(reenable);
535}