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