]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
91447636 | 2 | * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. |
1c79356b | 3 | * |
8f6c56a5 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
1c79356b | 5 | * |
8f6c56a5 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. | |
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 | |
8ad349bb | 24 | * limitations under the License. |
8f6c56a5 A |
25 | * |
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_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> | |
1c79356b A |
61 | #include <kern/mach_param.h> |
62 | #include <kern/zalloc.h> | |
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> | |
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> | |
0b4e3aa0 | 76 | #include <kern/processor.h> |
91447636 | 77 | #include <kern/timer.h> |
1c79356b A |
78 | #include <mach_prof.h> |
79 | #include <mach/rpc.h> | |
80 | ||
91447636 A |
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); | |
1c79356b A |
85 | |
86 | /* | |
87 | * Internal routine to terminate a thread. | |
9bccf70c | 88 | * Sometimes called with task already locked. |
1c79356b A |
89 | */ |
90 | kern_return_t | |
91 | thread_terminate_internal( | |
91447636 | 92 | thread_t thread) |
1c79356b | 93 | { |
91447636 | 94 | kern_return_t result = KERN_SUCCESS; |
1c79356b | 95 | |
91447636 | 96 | thread_mtx_lock(thread); |
1c79356b | 97 | |
91447636 A |
98 | if (thread->active) { |
99 | thread->active = FALSE; | |
1c79356b | 100 | |
91447636 | 101 | act_abort(thread); |
e7c99d92 | 102 | |
91447636 A |
103 | if (thread->started) |
104 | clear_wait(thread, THREAD_INTERRUPTED); | |
105 | else { | |
106 | clear_wait(thread, THREAD_AWAKENED); | |
107 | thread->started = TRUE; | |
108 | } | |
1c79356b | 109 | } |
91447636 A |
110 | else |
111 | result = KERN_TERMINATED; | |
1c79356b | 112 | |
91447636 A |
113 | thread_mtx_unlock(thread); |
114 | ||
115 | if (thread != current_thread() && result == KERN_SUCCESS) | |
116 | thread_wait(thread); | |
9bccf70c A |
117 | |
118 | return (result); | |
1c79356b A |
119 | } |
120 | ||
121 | /* | |
9bccf70c | 122 | * Terminate a thread. |
1c79356b A |
123 | */ |
124 | kern_return_t | |
125 | thread_terminate( | |
91447636 | 126 | thread_t thread) |
1c79356b | 127 | { |
9bccf70c | 128 | kern_return_t result; |
1c79356b | 129 | |
91447636 | 130 | if (thread == THREAD_NULL) |
9bccf70c | 131 | return (KERN_INVALID_ARGUMENT); |
1c79356b | 132 | |
91447636 A |
133 | if ( thread->task == kernel_task && |
134 | thread != current_thread() ) | |
9bccf70c | 135 | return (KERN_FAILURE); |
1c79356b | 136 | |
91447636 | 137 | result = thread_terminate_internal(thread); |
1c79356b A |
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 | */ | |
91447636 | 145 | if (thread->task == kernel_task) { |
55e303ae | 146 | ml_set_interrupts_enabled(FALSE); |
55e303ae | 147 | ast_taken(AST_APC, TRUE); |
9bccf70c A |
148 | panic("thread_terminate"); |
149 | } | |
1c79356b | 150 | |
9bccf70c | 151 | return (result); |
1c79356b A |
152 | } |
153 | ||
154 | /* | |
9bccf70c A |
155 | * Suspend execution of the specified thread. |
156 | * This is a recursive-style suspension of the thread, a count of | |
157 | * suspends is maintained. | |
1c79356b | 158 | * |
91447636 | 159 | * Called with thread mutex held. |
1c79356b A |
160 | */ |
161 | void | |
162 | thread_hold( | |
91447636 | 163 | register thread_t thread) |
1c79356b | 164 | { |
91447636 A |
165 | if (thread->suspend_count++ == 0) { |
166 | install_special_handler(thread); | |
167 | if (thread->started) | |
168 | thread_wakeup_one(&thread->suspend_count); | |
1c79356b A |
169 | } |
170 | } | |
171 | ||
172 | /* | |
91447636 | 173 | * Decrement internal suspension count, setting thread |
1c79356b A |
174 | * runnable when count falls to zero. |
175 | * | |
91447636 | 176 | * Called with thread mutex held. |
1c79356b A |
177 | */ |
178 | void | |
179 | thread_release( | |
91447636 | 180 | register thread_t thread) |
1c79356b | 181 | { |
91447636 A |
182 | if ( thread->suspend_count > 0 && |
183 | --thread->suspend_count == 0 ) { | |
184 | if (thread->started) | |
185 | thread_wakeup_one(&thread->suspend_count); | |
186 | else { | |
9bccf70c | 187 | clear_wait(thread, THREAD_AWAKENED); |
91447636 | 188 | thread->started = TRUE; |
9bccf70c | 189 | } |
9bccf70c | 190 | } |
1c79356b A |
191 | } |
192 | ||
193 | kern_return_t | |
194 | thread_suspend( | |
91447636 | 195 | register thread_t thread) |
1c79356b | 196 | { |
91447636 A |
197 | thread_t self = current_thread(); |
198 | kern_return_t result = KERN_SUCCESS; | |
1c79356b | 199 | |
91447636 | 200 | if (thread == THREAD_NULL || thread->task == kernel_task) |
9bccf70c A |
201 | return (KERN_INVALID_ARGUMENT); |
202 | ||
91447636 | 203 | thread_mtx_lock(thread); |
9bccf70c | 204 | |
91447636 A |
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); | |
1c79356b A |
211 | } |
212 | } | |
9bccf70c | 213 | else |
91447636 A |
214 | result = KERN_TERMINATED; |
215 | ||
216 | thread_mtx_unlock(thread); | |
217 | ||
218 | if (thread != self && result == KERN_SUCCESS) | |
219 | thread_wait(thread); | |
9bccf70c | 220 | |
91447636 | 221 | return (result); |
1c79356b A |
222 | } |
223 | ||
224 | kern_return_t | |
225 | thread_resume( | |
91447636 | 226 | register thread_t thread) |
1c79356b | 227 | { |
91447636 | 228 | kern_return_t result = KERN_SUCCESS; |
1c79356b | 229 | |
91447636 | 230 | if (thread == THREAD_NULL || thread->task == kernel_task) |
9bccf70c | 231 | return (KERN_INVALID_ARGUMENT); |
1c79356b | 232 | |
91447636 | 233 | thread_mtx_lock(thread); |
9bccf70c | 234 | |
91447636 A |
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 { | |
9bccf70c | 242 | clear_wait(thread, THREAD_AWAKENED); |
91447636 | 243 | thread->started = TRUE; |
9bccf70c | 244 | } |
1c79356b A |
245 | } |
246 | } | |
247 | else | |
9bccf70c | 248 | result = KERN_FAILURE; |
1c79356b A |
249 | } |
250 | else | |
9bccf70c A |
251 | result = KERN_TERMINATED; |
252 | ||
91447636 | 253 | thread_mtx_unlock(thread); |
9bccf70c A |
254 | |
255 | return (result); | |
1c79356b A |
256 | } |
257 | ||
1c79356b A |
258 | /* |
259 | * thread_depress_abort: | |
260 | * | |
261 | * Prematurely abort priority depression if there is one. | |
262 | */ | |
263 | kern_return_t | |
264 | thread_depress_abort( | |
91447636 | 265 | register thread_t thread) |
1c79356b | 266 | { |
91447636 | 267 | kern_return_t result; |
1c79356b | 268 | |
91447636 | 269 | if (thread == THREAD_NULL) |
1c79356b A |
270 | return (KERN_INVALID_ARGUMENT); |
271 | ||
91447636 | 272 | thread_mtx_lock(thread); |
1c79356b | 273 | |
91447636 A |
274 | if (thread->active) |
275 | result = thread_depress_abort_internal(thread); | |
276 | else | |
277 | result = KERN_TERMINATED; | |
1c79356b | 278 | |
91447636 | 279 | thread_mtx_unlock(thread); |
1c79356b A |
280 | |
281 | return (result); | |
282 | } | |
283 | ||
284 | ||
285 | /* | |
9bccf70c | 286 | * Indicate that the activation should run its |
91447636 | 287 | * special handler to detect a condition. |
9bccf70c | 288 | * |
91447636 | 289 | * Called with thread mutex held. |
1c79356b | 290 | */ |
91447636 | 291 | void |
9bccf70c | 292 | act_abort( |
91447636 | 293 | thread_t thread) |
1c79356b | 294 | { |
9bccf70c | 295 | spl_t s = splsched(); |
1c79356b | 296 | |
9bccf70c | 297 | thread_lock(thread); |
91447636 | 298 | |
9bccf70c A |
299 | if (!(thread->state & TH_ABORT)) { |
300 | thread->state |= TH_ABORT; | |
91447636 | 301 | install_special_handler_locked(thread); |
1c79356b | 302 | } |
91447636 A |
303 | else |
304 | thread->state &= ~TH_ABORT_SAFELY; | |
305 | ||
9bccf70c A |
306 | thread_unlock(thread); |
307 | splx(s); | |
1c79356b A |
308 | } |
309 | ||
310 | kern_return_t | |
311 | thread_abort( | |
91447636 | 312 | register thread_t thread) |
1c79356b | 313 | { |
91447636 | 314 | kern_return_t result = KERN_SUCCESS; |
1c79356b | 315 | |
91447636 | 316 | if (thread == THREAD_NULL) |
1c79356b | 317 | return (KERN_INVALID_ARGUMENT); |
9bccf70c | 318 | |
91447636 | 319 | thread_mtx_lock(thread); |
9bccf70c | 320 | |
91447636 A |
321 | if (thread->active) { |
322 | act_abort(thread); | |
323 | clear_wait(thread, THREAD_INTERRUPTED); | |
1c79356b | 324 | } |
91447636 A |
325 | else |
326 | result = KERN_TERMINATED; | |
1c79356b | 327 | |
91447636 | 328 | thread_mtx_unlock(thread); |
9bccf70c A |
329 | |
330 | return (result); | |
1c79356b A |
331 | } |
332 | ||
333 | kern_return_t | |
334 | thread_abort_safely( | |
91447636 | 335 | thread_t thread) |
1c79356b | 336 | { |
91447636 | 337 | kern_return_t result = KERN_SUCCESS; |
1c79356b | 338 | |
91447636 | 339 | if (thread == THREAD_NULL) |
9bccf70c | 340 | return (KERN_INVALID_ARGUMENT); |
1c79356b | 341 | |
91447636 | 342 | thread_mtx_lock(thread); |
9bccf70c | 343 | |
91447636 A |
344 | if (thread->active) { |
345 | spl_t s = splsched(); | |
9bccf70c | 346 | |
91447636 A |
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 | } | |
9bccf70c | 354 | } |
91447636 A |
355 | thread_unlock(thread); |
356 | splx(s); | |
1c79356b | 357 | } |
91447636 A |
358 | else |
359 | result = KERN_TERMINATED; | |
9bccf70c | 360 | |
91447636 | 361 | thread_mtx_unlock(thread); |
9bccf70c | 362 | |
91447636 | 363 | return (result); |
1c79356b A |
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> | |
1c79356b A |
370 | |
371 | kern_return_t | |
372 | thread_info( | |
91447636 | 373 | thread_t thread, |
1c79356b A |
374 | thread_flavor_t flavor, |
375 | thread_info_t thread_info_out, | |
376 | mach_msg_type_number_t *thread_info_count) | |
377 | { | |
1c79356b A |
378 | kern_return_t result; |
379 | ||
91447636 | 380 | if (thread == THREAD_NULL) |
1c79356b A |
381 | return (KERN_INVALID_ARGUMENT); |
382 | ||
91447636 | 383 | thread_mtx_lock(thread); |
1c79356b | 384 | |
91447636 A |
385 | if (thread->active) |
386 | result = thread_info_internal( | |
387 | thread, flavor, thread_info_out, thread_info_count); | |
388 | else | |
389 | result = KERN_TERMINATED; | |
1c79356b | 390 | |
91447636 | 391 | thread_mtx_unlock(thread); |
1c79356b A |
392 | |
393 | return (result); | |
394 | } | |
395 | ||
1c79356b | 396 | kern_return_t |
91447636 A |
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*/ | |
1c79356b | 402 | { |
91447636 | 403 | kern_return_t result = KERN_SUCCESS; |
1c79356b | 404 | |
91447636 A |
405 | if (thread == THREAD_NULL) |
406 | return (KERN_INVALID_ARGUMENT); | |
1c79356b | 407 | |
91447636 | 408 | thread_mtx_lock(thread); |
1c79356b | 409 | |
91447636 A |
410 | if (thread->active) { |
411 | if (thread != current_thread()) { | |
412 | thread_hold(thread); | |
1c79356b | 413 | |
91447636 | 414 | thread_mtx_unlock(thread); |
1c79356b | 415 | |
91447636 A |
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 | } | |
1c79356b | 426 | |
91447636 A |
427 | thread_release(thread); |
428 | } | |
429 | else | |
430 | result = machine_thread_get_state( | |
431 | thread, flavor, state, state_count); | |
1c79356b | 432 | } |
91447636 A |
433 | else |
434 | result = KERN_TERMINATED; | |
1c79356b | 435 | |
91447636 | 436 | thread_mtx_unlock(thread); |
1c79356b | 437 | |
91447636 | 438 | return (result); |
1c79356b A |
439 | } |
440 | ||
441 | /* | |
91447636 A |
442 | * Change thread's machine-dependent state. Called with nothing |
443 | * locked. Returns same way. | |
1c79356b A |
444 | */ |
445 | kern_return_t | |
91447636 A |
446 | thread_set_state( |
447 | register thread_t thread, | |
9bccf70c | 448 | int flavor, |
91447636 A |
449 | thread_state_t state, |
450 | mach_msg_type_number_t state_count) | |
1c79356b | 451 | { |
9bccf70c | 452 | kern_return_t result = KERN_SUCCESS; |
1c79356b | 453 | |
91447636 | 454 | if (thread == THREAD_NULL) |
1c79356b A |
455 | return (KERN_INVALID_ARGUMENT); |
456 | ||
91447636 | 457 | thread_mtx_lock(thread); |
9bccf70c | 458 | |
91447636 A |
459 | if (thread->active) { |
460 | if (thread != current_thread()) { | |
461 | thread_hold(thread); | |
1c79356b | 462 | |
91447636 | 463 | thread_mtx_unlock(thread); |
9bccf70c | 464 | |
91447636 A |
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 | } | |
9bccf70c | 475 | |
91447636 | 476 | thread_release(thread); |
9bccf70c | 477 | } |
91447636 A |
478 | else |
479 | result = machine_thread_set_state( | |
480 | thread, flavor, state, state_count); | |
1c79356b | 481 | } |
91447636 A |
482 | else |
483 | result = KERN_TERMINATED; | |
1c79356b | 484 | |
91447636 | 485 | thread_mtx_unlock(thread); |
9bccf70c A |
486 | |
487 | return (result); | |
1c79356b | 488 | } |
91447636 A |
489 | |
490 | ||
1c79356b | 491 | /* |
91447636 A |
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. | |
1c79356b A |
497 | */ |
498 | kern_return_t | |
91447636 A |
499 | thread_state_initialize( |
500 | register thread_t thread) | |
1c79356b | 501 | { |
9bccf70c | 502 | kern_return_t result = KERN_SUCCESS; |
1c79356b | 503 | |
91447636 | 504 | if (thread == THREAD_NULL) |
1c79356b | 505 | return (KERN_INVALID_ARGUMENT); |
1c79356b | 506 | |
91447636 | 507 | thread_mtx_lock(thread); |
9bccf70c | 508 | |
91447636 A |
509 | if (thread->active) { |
510 | if (thread != current_thread()) { | |
511 | thread_hold(thread); | |
9bccf70c | 512 | |
91447636 | 513 | thread_mtx_unlock(thread); |
9bccf70c | 514 | |
91447636 A |
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 | } | |
9bccf70c | 524 | |
91447636 | 525 | thread_release(thread); |
9bccf70c | 526 | } |
91447636 A |
527 | else |
528 | result = machine_thread_state_initialize( thread ); | |
1c79356b | 529 | } |
91447636 A |
530 | else |
531 | result = KERN_TERMINATED; | |
9bccf70c | 532 | |
91447636 | 533 | thread_mtx_unlock(thread); |
9bccf70c A |
534 | |
535 | return (result); | |
1c79356b A |
536 | } |
537 | ||
1c79356b A |
538 | |
539 | kern_return_t | |
540 | thread_dup( | |
91447636 | 541 | register thread_t target) |
1c79356b | 542 | { |
91447636 | 543 | thread_t self = current_thread(); |
9bccf70c | 544 | kern_return_t result = KERN_SUCCESS; |
1c79356b | 545 | |
91447636 | 546 | if (target == THREAD_NULL || target == self) |
1c79356b A |
547 | return (KERN_INVALID_ARGUMENT); |
548 | ||
91447636 | 549 | thread_mtx_lock(target); |
9bccf70c | 550 | |
91447636 A |
551 | if (target->active) { |
552 | thread_hold(target); | |
9bccf70c | 553 | |
91447636 | 554 | thread_mtx_unlock(target); |
9bccf70c | 555 | |
91447636 A |
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); | |
9bccf70c | 563 | result = KERN_ABORTED; |
9bccf70c A |
564 | } |
565 | ||
91447636 | 566 | thread_release(target); |
1c79356b | 567 | } |
91447636 A |
568 | else |
569 | result = KERN_TERMINATED; | |
9bccf70c | 570 | |
91447636 | 571 | thread_mtx_unlock(target); |
9bccf70c A |
572 | |
573 | return (result); | |
1c79356b A |
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( | |
91447636 | 585 | register thread_t thread, |
9bccf70c A |
586 | int flavor, |
587 | thread_state_t tstate, | |
1c79356b A |
588 | mach_msg_type_number_t count) |
589 | { | |
9bccf70c | 590 | |
91447636 | 591 | return (thread_set_state(thread, flavor, tstate, count)); |
1c79356b A |
592 | } |
593 | ||
594 | /* | |
595 | * thread_getstatus: | |
596 | * | |
597 | * Get the status of the specified thread. | |
598 | */ | |
599 | kern_return_t | |
600 | thread_getstatus( | |
91447636 | 601 | register thread_t thread, |
9bccf70c A |
602 | int flavor, |
603 | thread_state_t tstate, | |
1c79356b A |
604 | mach_msg_type_number_t *count) |
605 | { | |
91447636 | 606 | return (thread_get_state(thread, flavor, tstate, count)); |
1c79356b A |
607 | } |
608 | ||
609 | /* | |
91447636 | 610 | * install_special_handler: |
1c79356b | 611 | * |
1c79356b A |
612 | * Install the special returnhandler that handles suspension and |
613 | * termination, if it hasn't been installed already. | |
614 | * | |
91447636 | 615 | * Called with the thread mutex held. |
1c79356b A |
616 | */ |
617 | void | |
618 | install_special_handler( | |
91447636 | 619 | thread_t thread) |
1c79356b | 620 | { |
91447636 | 621 | spl_t s = splsched(); |
1c79356b | 622 | |
e7c99d92 | 623 | thread_lock(thread); |
91447636 | 624 | install_special_handler_locked(thread); |
e7c99d92 | 625 | thread_unlock(thread); |
91447636 | 626 | splx(s); |
1c79356b A |
627 | } |
628 | ||
629 | /* | |
91447636 A |
630 | * install_special_handler_locked: |
631 | * | |
1c79356b A |
632 | * Do the work of installing the special_handler. |
633 | * | |
91447636 | 634 | * Called with the thread mutex and scheduling lock held. |
1c79356b A |
635 | */ |
636 | void | |
637 | install_special_handler_locked( | |
91447636 | 638 | thread_t thread) |
1c79356b A |
639 | { |
640 | ReturnHandler **rh; | |
1c79356b A |
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. */ | |
91447636 | 644 | for (rh = &thread->handlers; *rh; rh = &(*rh)->next) |
9bccf70c | 645 | continue; |
1c79356b | 646 | |
91447636 A |
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); | |
9bccf70c A |
662 | else { |
663 | processor_t processor = thread->last_processor; | |
664 | ||
55e303ae A |
665 | if ( processor != PROCESSOR_NULL && |
666 | processor->state == PROCESSOR_RUNNING && | |
667 | processor->active_thread == thread ) | |
9bccf70c A |
668 | cause_ast_check(processor); |
669 | } | |
670 | } | |
1c79356b | 671 | |
1c79356b A |
672 | /* |
673 | * Activation control support routines internal to this file: | |
674 | */ | |
675 | ||
9bccf70c A |
676 | void |
677 | act_execute_returnhandlers(void) | |
1c79356b | 678 | { |
91447636 | 679 | thread_t thread = current_thread(); |
1c79356b | 680 | |
91447636 | 681 | thread_ast_clear(thread, AST_APC); |
1c79356b | 682 | spllo(); |
1c79356b | 683 | |
9bccf70c A |
684 | for (;;) { |
685 | ReturnHandler *rh; | |
91447636 A |
686 | |
687 | thread_mtx_lock(thread); | |
9bccf70c | 688 | |
1c79356b A |
689 | (void)splsched(); |
690 | thread_lock(thread); | |
91447636 A |
691 | |
692 | rh = thread->handlers; | |
693 | if (rh != NULL) { | |
694 | thread->handlers = rh->next; | |
695 | ||
1c79356b | 696 | thread_unlock(thread); |
9bccf70c | 697 | spllo(); |
1c79356b | 698 | |
91447636 A |
699 | thread_mtx_unlock(thread); |
700 | ||
701 | /* Execute it */ | |
702 | (*rh->handler)(rh, thread); | |
703 | } | |
704 | else | |
705 | break; | |
1c79356b | 706 | } |
91447636 A |
707 | |
708 | thread_unlock(thread); | |
709 | spllo(); | |
710 | ||
711 | thread_mtx_unlock(thread); | |
1c79356b A |
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 | { | |
91447636 A |
726 | thread_t thread = current_thread(); |
727 | ||
728 | thread_mtx_lock(thread); | |
1c79356b | 729 | |
91447636 A |
730 | if (thread->suspend_count > 0) |
731 | install_special_handler(thread); | |
1c79356b | 732 | else { |
9bccf70c A |
733 | spl_t s = splsched(); |
734 | ||
1c79356b | 735 | thread_lock(thread); |
9bccf70c A |
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; | |
1c79356b A |
742 | } |
743 | thread_unlock(thread); | |
744 | splx(s); | |
745 | } | |
9bccf70c | 746 | |
91447636 A |
747 | thread_mtx_unlock(thread); |
748 | ||
1c79356b | 749 | thread_exception_return(); |
9bccf70c | 750 | /*NOTREACHED*/ |
1c79356b A |
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( | |
91447636 A |
759 | __unused ReturnHandler *rh, |
760 | thread_t thread) | |
1c79356b | 761 | { |
91447636 | 762 | spl_t s; |
1c79356b | 763 | |
91447636 | 764 | thread_mtx_lock(thread); |
1c79356b A |
765 | |
766 | s = splsched(); | |
1c79356b | 767 | thread_lock(thread); |
9bccf70c | 768 | thread->state &= ~(TH_ABORT|TH_ABORT_SAFELY); /* clear any aborts */ |
1c79356b A |
769 | thread_unlock(thread); |
770 | splx(s); | |
771 | ||
1c79356b A |
772 | /* |
773 | * If we're suspended, go to sleep and wait for someone to wake us up. | |
774 | */ | |
91447636 A |
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 | } | |
9bccf70c | 783 | |
91447636 | 784 | thread_mtx_unlock(thread); |
9bccf70c | 785 | |
91447636 A |
786 | special_handler_continue(); |
787 | /*NOTREACHED*/ | |
9bccf70c | 788 | } |
1c79356b | 789 | } |
91447636 A |
790 | else { |
791 | thread_mtx_unlock(thread); | |
1c79356b | 792 | |
91447636 A |
793 | thread_terminate_self(); |
794 | /*NOTREACHED*/ | |
795 | } | |
1c79356b | 796 | |
91447636 | 797 | thread_mtx_unlock(thread); |
1c79356b A |
798 | } |
799 | ||
800 | kern_return_t | |
91447636 A |
801 | act_set_state( |
802 | thread_t thread, | |
803 | int flavor, | |
804 | thread_state_t state, | |
805 | mach_msg_type_number_t count) | |
1c79356b | 806 | { |
91447636 A |
807 | if (thread == current_thread()) |
808 | return (KERN_INVALID_ARGUMENT); | |
1c79356b | 809 | |
91447636 | 810 | return (thread_set_state(thread, flavor, state, count)); |
1c79356b A |
811 | |
812 | } | |
813 | ||
814 | kern_return_t | |
91447636 A |
815 | act_get_state( |
816 | thread_t thread, | |
817 | int flavor, | |
818 | thread_state_t state, | |
819 | mach_msg_type_number_t *count) | |
1c79356b | 820 | { |
91447636 A |
821 | if (thread == current_thread()) |
822 | return (KERN_INVALID_ARGUMENT); | |
1c79356b | 823 | |
91447636 | 824 | return (thread_get_state(thread, flavor, state, count)); |
1c79356b A |
825 | } |
826 | ||
1c79356b | 827 | void |
9bccf70c | 828 | act_set_astbsd( |
91447636 | 829 | thread_t thread) |
1c79356b | 830 | { |
91447636 | 831 | spl_t s = splsched(); |
0b4e3aa0 | 832 | |
91447636 A |
833 | if (thread == current_thread()) { |
834 | thread_ast_set(thread, AST_BSD); | |
835 | ast_propagate(thread->ast); | |
1c79356b | 836 | } |
9bccf70c | 837 | else { |
9bccf70c | 838 | processor_t processor; |
0b4e3aa0 | 839 | |
9bccf70c | 840 | thread_lock(thread); |
91447636 | 841 | thread_ast_set(thread, AST_BSD); |
9bccf70c | 842 | processor = thread->last_processor; |
55e303ae A |
843 | if ( processor != PROCESSOR_NULL && |
844 | processor->state == PROCESSOR_RUNNING && | |
845 | processor->active_thread == thread ) | |
9bccf70c A |
846 | cause_ast_check(processor); |
847 | thread_unlock(thread); | |
0b4e3aa0 A |
848 | } |
849 | ||
9bccf70c | 850 | splx(s); |
1c79356b A |
851 | } |
852 | ||
853 | void | |
9bccf70c | 854 | act_set_apc( |
91447636 | 855 | thread_t thread) |
1c79356b | 856 | { |
91447636 | 857 | spl_t s = splsched(); |
9bccf70c | 858 | |
91447636 A |
859 | if (thread == current_thread()) { |
860 | thread_ast_set(thread, AST_APC); | |
861 | ast_propagate(thread->ast); | |
9bccf70c A |
862 | } |
863 | else { | |
9bccf70c A |
864 | processor_t processor; |
865 | ||
866 | thread_lock(thread); | |
91447636 | 867 | thread_ast_set(thread, AST_APC); |
9bccf70c | 868 | processor = thread->last_processor; |
55e303ae A |
869 | if ( processor != PROCESSOR_NULL && |
870 | processor->state == PROCESSOR_RUNNING && | |
871 | processor->active_thread == thread ) | |
9bccf70c A |
872 | cause_ast_check(processor); |
873 | thread_unlock(thread); | |
874 | } | |
875 | ||
876 | splx(s); | |
1c79356b | 877 | } |