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