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