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