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