]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/thread_act.c
xnu-792.12.6.tar.gz
[apple/xnu.git] / osfmk / kern / thread_act.c
1 /*
2 * Copyright (c) 2000-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 * @OSF_FREE_COPYRIGHT@
32 */
33 /*
34 * Copyright (c) 1993 The University of Utah and
35 * the Center for Software Science (CSS). All rights reserved.
36 *
37 * Permission to use, copy, modify and distribute this software and its
38 * documentation is hereby granted, provided that both the copyright
39 * notice and this permission notice appear in all copies of the
40 * software, derivative works or modified versions, and any portions
41 * thereof, and that both notices appear in supporting documentation.
42 *
43 * THE UNIVERSITY OF UTAH AND CSS ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
44 * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSS DISCLAIM ANY LIABILITY OF
45 * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
46 *
47 * CSS requests users of this software to return to css-dist@cs.utah.edu any
48 * improvements that they make and grant CSS redistribution rights.
49 *
50 * Author: Bryan Ford, University of Utah CSS
51 *
52 * Thread management routines
53 */
54 #include <mach/mach_types.h>
55 #include <mach/kern_return.h>
56 #include <mach/alert.h>
57 #include <mach_prof.h>
58 #include <mach/rpc.h>
59 #include <mach/thread_act_server.h>
60
61 #include <kern/kern_types.h>
62 #include <kern/ast.h>
63 #include <kern/mach_param.h>
64 #include <kern/zalloc.h>
65 #include <kern/thread.h>
66 #include <kern/task.h>
67 #include <kern/sched_prim.h>
68 #include <kern/misc_protos.h>
69 #include <kern/assert.h>
70 #include <kern/exception.h>
71 #include <kern/ipc_mig.h>
72 #include <kern/ipc_tt.h>
73 #include <kern/profile.h>
74 #include <kern/machine.h>
75 #include <kern/spl.h>
76 #include <kern/syscall_subr.h>
77 #include <kern/sync_lock.h>
78 #include <kern/processor.h>
79 #include <kern/timer.h>
80 #include <mach_prof.h>
81 #include <mach/rpc.h>
82
83 void act_abort(thread_t);
84 void act_set_apc(thread_t);
85 void install_special_handler_locked(thread_t);
86 void special_handler_continue(void);
87
88 /*
89 * Internal routine to terminate a thread.
90 * Sometimes called with task already locked.
91 */
92 kern_return_t
93 thread_terminate_internal(
94 thread_t thread)
95 {
96 kern_return_t result = KERN_SUCCESS;
97
98 thread_mtx_lock(thread);
99
100 if (thread->active) {
101 thread->active = FALSE;
102
103 act_abort(thread);
104
105 if (thread->started)
106 clear_wait(thread, THREAD_INTERRUPTED);
107 else {
108 clear_wait(thread, THREAD_AWAKENED);
109 thread->started = TRUE;
110 }
111 }
112 else
113 result = KERN_TERMINATED;
114
115 thread_mtx_unlock(thread);
116
117 if (thread != current_thread() && result == KERN_SUCCESS)
118 thread_wait(thread);
119
120 return (result);
121 }
122
123 /*
124 * Terminate a thread.
125 */
126 kern_return_t
127 thread_terminate(
128 thread_t thread)
129 {
130 kern_return_t result;
131
132 if (thread == THREAD_NULL)
133 return (KERN_INVALID_ARGUMENT);
134
135 if ( thread->task == kernel_task &&
136 thread != current_thread() )
137 return (KERN_FAILURE);
138
139 result = thread_terminate_internal(thread);
140
141 /*
142 * If a kernel thread is terminating itself, force an AST here.
143 * Kernel threads don't normally pass through the AST checking
144 * code - and all threads finish their own termination in the
145 * special handler APC.
146 */
147 if (thread->task == kernel_task) {
148 ml_set_interrupts_enabled(FALSE);
149 ast_taken(AST_APC, TRUE);
150 panic("thread_terminate");
151 }
152
153 return (result);
154 }
155
156 /*
157 * Suspend execution of the specified thread.
158 * This is a recursive-style suspension of the thread, a count of
159 * suspends is maintained.
160 *
161 * Called with thread mutex held.
162 */
163 void
164 thread_hold(
165 register thread_t thread)
166 {
167 if (thread->suspend_count++ == 0) {
168 install_special_handler(thread);
169 if (thread->started)
170 thread_wakeup_one(&thread->suspend_count);
171 }
172 }
173
174 /*
175 * Decrement internal suspension count, setting thread
176 * runnable when count falls to zero.
177 *
178 * Called with thread mutex held.
179 */
180 void
181 thread_release(
182 register thread_t thread)
183 {
184 if ( thread->suspend_count > 0 &&
185 --thread->suspend_count == 0 ) {
186 if (thread->started)
187 thread_wakeup_one(&thread->suspend_count);
188 else {
189 clear_wait(thread, THREAD_AWAKENED);
190 thread->started = TRUE;
191 }
192 }
193 }
194
195 kern_return_t
196 thread_suspend(
197 register thread_t thread)
198 {
199 thread_t self = current_thread();
200 kern_return_t result = KERN_SUCCESS;
201
202 if (thread == THREAD_NULL || thread->task == kernel_task)
203 return (KERN_INVALID_ARGUMENT);
204
205 thread_mtx_lock(thread);
206
207 if (thread->active) {
208 if ( thread->user_stop_count++ == 0 &&
209 thread->suspend_count++ == 0 ) {
210 install_special_handler(thread);
211 if (thread != self)
212 thread_wakeup_one(&thread->suspend_count);
213 }
214 }
215 else
216 result = KERN_TERMINATED;
217
218 thread_mtx_unlock(thread);
219
220 if (thread != self && result == KERN_SUCCESS)
221 thread_wait(thread);
222
223 return (result);
224 }
225
226 kern_return_t
227 thread_resume(
228 register thread_t thread)
229 {
230 kern_return_t result = KERN_SUCCESS;
231
232 if (thread == THREAD_NULL || thread->task == kernel_task)
233 return (KERN_INVALID_ARGUMENT);
234
235 thread_mtx_lock(thread);
236
237 if (thread->active) {
238 if (thread->user_stop_count > 0) {
239 if ( --thread->user_stop_count == 0 &&
240 --thread->suspend_count == 0 ) {
241 if (thread->started)
242 thread_wakeup_one(&thread->suspend_count);
243 else {
244 clear_wait(thread, THREAD_AWAKENED);
245 thread->started = TRUE;
246 }
247 }
248 }
249 else
250 result = KERN_FAILURE;
251 }
252 else
253 result = KERN_TERMINATED;
254
255 thread_mtx_unlock(thread);
256
257 return (result);
258 }
259
260 /*
261 * thread_depress_abort:
262 *
263 * Prematurely abort priority depression if there is one.
264 */
265 kern_return_t
266 thread_depress_abort(
267 register thread_t thread)
268 {
269 kern_return_t result;
270
271 if (thread == THREAD_NULL)
272 return (KERN_INVALID_ARGUMENT);
273
274 thread_mtx_lock(thread);
275
276 if (thread->active)
277 result = thread_depress_abort_internal(thread);
278 else
279 result = KERN_TERMINATED;
280
281 thread_mtx_unlock(thread);
282
283 return (result);
284 }
285
286
287 /*
288 * Indicate that the activation should run its
289 * special handler to detect a condition.
290 *
291 * Called with thread mutex held.
292 */
293 void
294 act_abort(
295 thread_t thread)
296 {
297 spl_t s = splsched();
298
299 thread_lock(thread);
300
301 if (!(thread->state & TH_ABORT)) {
302 thread->state |= TH_ABORT;
303 install_special_handler_locked(thread);
304 }
305 else
306 thread->state &= ~TH_ABORT_SAFELY;
307
308 thread_unlock(thread);
309 splx(s);
310 }
311
312 kern_return_t
313 thread_abort(
314 register thread_t thread)
315 {
316 kern_return_t result = KERN_SUCCESS;
317
318 if (thread == THREAD_NULL)
319 return (KERN_INVALID_ARGUMENT);
320
321 thread_mtx_lock(thread);
322
323 if (thread->active) {
324 act_abort(thread);
325 clear_wait(thread, THREAD_INTERRUPTED);
326 }
327 else
328 result = KERN_TERMINATED;
329
330 thread_mtx_unlock(thread);
331
332 return (result);
333 }
334
335 kern_return_t
336 thread_abort_safely(
337 thread_t thread)
338 {
339 kern_return_t result = KERN_SUCCESS;
340
341 if (thread == THREAD_NULL)
342 return (KERN_INVALID_ARGUMENT);
343
344 thread_mtx_lock(thread);
345
346 if (thread->active) {
347 spl_t s = splsched();
348
349 thread_lock(thread);
350 if (!thread->at_safe_point ||
351 clear_wait_internal(thread, THREAD_INTERRUPTED) != KERN_SUCCESS) {
352 if (!(thread->state & TH_ABORT)) {
353 thread->state |= (TH_ABORT|TH_ABORT_SAFELY);
354 install_special_handler_locked(thread);
355 }
356 }
357 thread_unlock(thread);
358 splx(s);
359 }
360 else
361 result = KERN_TERMINATED;
362
363 thread_mtx_unlock(thread);
364
365 return (result);
366 }
367
368 /*** backward compatibility hacks ***/
369 #include <mach/thread_info.h>
370 #include <mach/thread_special_ports.h>
371 #include <ipc/ipc_port.h>
372
373 kern_return_t
374 thread_info(
375 thread_t thread,
376 thread_flavor_t flavor,
377 thread_info_t thread_info_out,
378 mach_msg_type_number_t *thread_info_count)
379 {
380 kern_return_t result;
381
382 if (thread == THREAD_NULL)
383 return (KERN_INVALID_ARGUMENT);
384
385 thread_mtx_lock(thread);
386
387 if (thread->active)
388 result = thread_info_internal(
389 thread, flavor, thread_info_out, thread_info_count);
390 else
391 result = KERN_TERMINATED;
392
393 thread_mtx_unlock(thread);
394
395 return (result);
396 }
397
398 kern_return_t
399 thread_get_state(
400 register thread_t thread,
401 int flavor,
402 thread_state_t state, /* pointer to OUT array */
403 mach_msg_type_number_t *state_count) /*IN/OUT*/
404 {
405 kern_return_t result = KERN_SUCCESS;
406
407 if (thread == THREAD_NULL)
408 return (KERN_INVALID_ARGUMENT);
409
410 thread_mtx_lock(thread);
411
412 if (thread->active) {
413 if (thread != current_thread()) {
414 thread_hold(thread);
415
416 thread_mtx_unlock(thread);
417
418 if (thread_stop(thread)) {
419 thread_mtx_lock(thread);
420 result = machine_thread_get_state(
421 thread, flavor, state, state_count);
422 thread_unstop(thread);
423 }
424 else {
425 thread_mtx_lock(thread);
426 result = KERN_ABORTED;
427 }
428
429 thread_release(thread);
430 }
431 else
432 result = machine_thread_get_state(
433 thread, flavor, state, state_count);
434 }
435 else
436 result = KERN_TERMINATED;
437
438 thread_mtx_unlock(thread);
439
440 return (result);
441 }
442
443 /*
444 * Change thread's machine-dependent state. Called with nothing
445 * locked. Returns same way.
446 */
447 kern_return_t
448 thread_set_state(
449 register thread_t thread,
450 int flavor,
451 thread_state_t state,
452 mach_msg_type_number_t state_count)
453 {
454 kern_return_t result = KERN_SUCCESS;
455
456 if (thread == THREAD_NULL)
457 return (KERN_INVALID_ARGUMENT);
458
459 thread_mtx_lock(thread);
460
461 if (thread->active) {
462 if (thread != current_thread()) {
463 thread_hold(thread);
464
465 thread_mtx_unlock(thread);
466
467 if (thread_stop(thread)) {
468 thread_mtx_lock(thread);
469 result = machine_thread_set_state(
470 thread, flavor, state, state_count);
471 thread_unstop(thread);
472 }
473 else {
474 thread_mtx_lock(thread);
475 result = KERN_ABORTED;
476 }
477
478 thread_release(thread);
479 }
480 else
481 result = machine_thread_set_state(
482 thread, flavor, state, state_count);
483 }
484 else
485 result = KERN_TERMINATED;
486
487 thread_mtx_unlock(thread);
488
489 return (result);
490 }
491
492
493 /*
494 * Kernel-internal "thread" interfaces used outside this file:
495 */
496
497 /* Initialize (or re-initialize) a thread state. Called from execve
498 * with nothing locked, returns same way.
499 */
500 kern_return_t
501 thread_state_initialize(
502 register thread_t thread)
503 {
504 kern_return_t result = KERN_SUCCESS;
505
506 if (thread == THREAD_NULL)
507 return (KERN_INVALID_ARGUMENT);
508
509 thread_mtx_lock(thread);
510
511 if (thread->active) {
512 if (thread != current_thread()) {
513 thread_hold(thread);
514
515 thread_mtx_unlock(thread);
516
517 if (thread_stop(thread)) {
518 thread_mtx_lock(thread);
519 result = machine_thread_state_initialize( thread );
520 thread_unstop(thread);
521 }
522 else {
523 thread_mtx_lock(thread);
524 result = KERN_ABORTED;
525 }
526
527 thread_release(thread);
528 }
529 else
530 result = machine_thread_state_initialize( thread );
531 }
532 else
533 result = KERN_TERMINATED;
534
535 thread_mtx_unlock(thread);
536
537 return (result);
538 }
539
540
541 kern_return_t
542 thread_dup(
543 register thread_t target)
544 {
545 thread_t self = current_thread();
546 kern_return_t result = KERN_SUCCESS;
547
548 if (target == THREAD_NULL || target == self)
549 return (KERN_INVALID_ARGUMENT);
550
551 thread_mtx_lock(target);
552
553 if (target->active) {
554 thread_hold(target);
555
556 thread_mtx_unlock(target);
557
558 if (thread_stop(target)) {
559 thread_mtx_lock(target);
560 result = machine_thread_dup(self, target);
561 thread_unstop(target);
562 }
563 else {
564 thread_mtx_lock(target);
565 result = KERN_ABORTED;
566 }
567
568 thread_release(target);
569 }
570 else
571 result = KERN_TERMINATED;
572
573 thread_mtx_unlock(target);
574
575 return (result);
576 }
577
578
579 /*
580 * thread_setstatus:
581 *
582 * Set the status of the specified thread.
583 * Called with (and returns with) no locks held.
584 */
585 kern_return_t
586 thread_setstatus(
587 register thread_t thread,
588 int flavor,
589 thread_state_t tstate,
590 mach_msg_type_number_t count)
591 {
592
593 return (thread_set_state(thread, flavor, tstate, count));
594 }
595
596 /*
597 * thread_getstatus:
598 *
599 * Get the status of the specified thread.
600 */
601 kern_return_t
602 thread_getstatus(
603 register thread_t thread,
604 int flavor,
605 thread_state_t tstate,
606 mach_msg_type_number_t *count)
607 {
608 return (thread_get_state(thread, flavor, tstate, count));
609 }
610
611 /*
612 * install_special_handler:
613 *
614 * Install the special returnhandler that handles suspension and
615 * termination, if it hasn't been installed already.
616 *
617 * Called with the thread mutex held.
618 */
619 void
620 install_special_handler(
621 thread_t thread)
622 {
623 spl_t s = splsched();
624
625 thread_lock(thread);
626 install_special_handler_locked(thread);
627 thread_unlock(thread);
628 splx(s);
629 }
630
631 /*
632 * install_special_handler_locked:
633 *
634 * Do the work of installing the special_handler.
635 *
636 * Called with the thread mutex and scheduling lock held.
637 */
638 void
639 install_special_handler_locked(
640 thread_t thread)
641 {
642 ReturnHandler **rh;
643
644 /* The work handler must always be the last ReturnHandler on the list,
645 because it can do tricky things like detach the thr_act. */
646 for (rh = &thread->handlers; *rh; rh = &(*rh)->next)
647 continue;
648
649 if (rh != &thread->special_handler.next)
650 *rh = &thread->special_handler;
651
652 /*
653 * Temporarily undepress, so target has
654 * a chance to do locking required to
655 * block itself in special_handler().
656 */
657 if (thread->sched_mode & TH_MODE_ISDEPRESSED)
658 compute_priority(thread, TRUE);
659
660 thread_ast_set(thread, AST_APC);
661
662 if (thread == current_thread())
663 ast_propagate(thread->ast);
664 else {
665 processor_t processor = thread->last_processor;
666
667 if ( processor != PROCESSOR_NULL &&
668 processor->state == PROCESSOR_RUNNING &&
669 processor->active_thread == thread )
670 cause_ast_check(processor);
671 }
672 }
673
674 /*
675 * Activation control support routines internal to this file:
676 */
677
678 void
679 act_execute_returnhandlers(void)
680 {
681 thread_t thread = current_thread();
682
683 thread_ast_clear(thread, AST_APC);
684 spllo();
685
686 for (;;) {
687 ReturnHandler *rh;
688
689 thread_mtx_lock(thread);
690
691 (void)splsched();
692 thread_lock(thread);
693
694 rh = thread->handlers;
695 if (rh != NULL) {
696 thread->handlers = rh->next;
697
698 thread_unlock(thread);
699 spllo();
700
701 thread_mtx_unlock(thread);
702
703 /* Execute it */
704 (*rh->handler)(rh, thread);
705 }
706 else
707 break;
708 }
709
710 thread_unlock(thread);
711 spllo();
712
713 thread_mtx_unlock(thread);
714 }
715
716 /*
717 * special_handler_continue
718 *
719 * Continuation routine for the special handler blocks. It checks
720 * to see whether there has been any new suspensions. If so, it
721 * installs the special handler again. Otherwise, it checks to see
722 * if the current depression needs to be re-instated (it may have
723 * been temporarily removed in order to get to this point in a hurry).
724 */
725 void
726 special_handler_continue(void)
727 {
728 thread_t thread = current_thread();
729
730 thread_mtx_lock(thread);
731
732 if (thread->suspend_count > 0)
733 install_special_handler(thread);
734 else {
735 spl_t s = splsched();
736
737 thread_lock(thread);
738 if (thread->sched_mode & TH_MODE_ISDEPRESSED) {
739 processor_t myprocessor = thread->last_processor;
740
741 thread->sched_pri = DEPRESSPRI;
742 myprocessor->current_pri = thread->sched_pri;
743 thread->sched_mode &= ~TH_MODE_PREEMPT;
744 }
745 thread_unlock(thread);
746 splx(s);
747 }
748
749 thread_mtx_unlock(thread);
750
751 thread_exception_return();
752 /*NOTREACHED*/
753 }
754
755 /*
756 * special_handler - handles suspension, termination. Called
757 * with nothing locked. Returns (if it returns) the same way.
758 */
759 void
760 special_handler(
761 __unused ReturnHandler *rh,
762 thread_t thread)
763 {
764 spl_t s;
765
766 thread_mtx_lock(thread);
767
768 s = splsched();
769 thread_lock(thread);
770 thread->state &= ~(TH_ABORT|TH_ABORT_SAFELY); /* clear any aborts */
771 thread_unlock(thread);
772 splx(s);
773
774 /*
775 * If we're suspended, go to sleep and wait for someone to wake us up.
776 */
777 if (thread->active) {
778 if (thread->suspend_count > 0) {
779 if (thread->handlers == NULL) {
780 assert_wait(&thread->suspend_count, THREAD_ABORTSAFE);
781 thread_mtx_unlock(thread);
782 thread_block((thread_continue_t)special_handler_continue);
783 /*NOTREACHED*/
784 }
785
786 thread_mtx_unlock(thread);
787
788 special_handler_continue();
789 /*NOTREACHED*/
790 }
791 }
792 else {
793 thread_mtx_unlock(thread);
794
795 thread_terminate_self();
796 /*NOTREACHED*/
797 }
798
799 thread_mtx_unlock(thread);
800 }
801
802 kern_return_t
803 act_set_state(
804 thread_t thread,
805 int flavor,
806 thread_state_t state,
807 mach_msg_type_number_t count)
808 {
809 if (thread == current_thread())
810 return (KERN_INVALID_ARGUMENT);
811
812 return (thread_set_state(thread, flavor, state, count));
813
814 }
815
816 kern_return_t
817 act_get_state(
818 thread_t thread,
819 int flavor,
820 thread_state_t state,
821 mach_msg_type_number_t *count)
822 {
823 if (thread == current_thread())
824 return (KERN_INVALID_ARGUMENT);
825
826 return (thread_get_state(thread, flavor, state, count));
827 }
828
829 void
830 act_set_astbsd(
831 thread_t thread)
832 {
833 spl_t s = splsched();
834
835 if (thread == current_thread()) {
836 thread_ast_set(thread, AST_BSD);
837 ast_propagate(thread->ast);
838 }
839 else {
840 processor_t processor;
841
842 thread_lock(thread);
843 thread_ast_set(thread, AST_BSD);
844 processor = thread->last_processor;
845 if ( processor != PROCESSOR_NULL &&
846 processor->state == PROCESSOR_RUNNING &&
847 processor->active_thread == thread )
848 cause_ast_check(processor);
849 thread_unlock(thread);
850 }
851
852 splx(s);
853 }
854
855 void
856 act_set_apc(
857 thread_t thread)
858 {
859 spl_t s = splsched();
860
861 if (thread == current_thread()) {
862 thread_ast_set(thread, AST_APC);
863 ast_propagate(thread->ast);
864 }
865 else {
866 processor_t processor;
867
868 thread_lock(thread);
869 thread_ast_set(thread, AST_APC);
870 processor = thread->last_processor;
871 if ( processor != PROCESSOR_NULL &&
872 processor->state == PROCESSOR_RUNNING &&
873 processor->active_thread == thread )
874 cause_ast_check(processor);
875 thread_unlock(thread);
876 }
877
878 splx(s);
879 }