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