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