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