]>
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. | |
3e170ce0 | 89 | * Always called with the thread mutex locked. |
2d21ac55 | 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( | |
3e170ce0 | 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 | |
3e170ce0 | 406 | if (thread->active || thread->inspection) |
91447636 A |
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 | } |
3e170ce0 A |
454 | else if (thread->inspection) |
455 | { | |
456 | result = machine_thread_get_state( | |
457 | thread, flavor, state, state_count); | |
458 | } | |
91447636 A |
459 | else |
460 | result = KERN_TERMINATED; | |
1c79356b | 461 | |
91447636 | 462 | thread_mtx_unlock(thread); |
1c79356b | 463 | |
91447636 | 464 | return (result); |
1c79356b A |
465 | } |
466 | ||
467 | /* | |
91447636 A |
468 | * Change thread's machine-dependent state. Called with nothing |
469 | * locked. Returns same way. | |
1c79356b | 470 | */ |
6d2010ae A |
471 | static kern_return_t |
472 | thread_set_state_internal( | |
91447636 | 473 | register thread_t thread, |
9bccf70c | 474 | int flavor, |
91447636 | 475 | thread_state_t state, |
6d2010ae A |
476 | mach_msg_type_number_t state_count, |
477 | boolean_t from_user) | |
1c79356b | 478 | { |
9bccf70c | 479 | kern_return_t result = KERN_SUCCESS; |
1c79356b | 480 | |
91447636 | 481 | if (thread == THREAD_NULL) |
1c79356b A |
482 | return (KERN_INVALID_ARGUMENT); |
483 | ||
91447636 | 484 | thread_mtx_lock(thread); |
9bccf70c | 485 | |
91447636 A |
486 | if (thread->active) { |
487 | if (thread != current_thread()) { | |
488 | thread_hold(thread); | |
1c79356b | 489 | |
91447636 | 490 | thread_mtx_unlock(thread); |
9bccf70c | 491 | |
fe8ab488 | 492 | if (thread_stop(thread, TRUE)) { |
91447636 A |
493 | thread_mtx_lock(thread); |
494 | result = machine_thread_set_state( | |
495 | thread, flavor, state, state_count); | |
496 | thread_unstop(thread); | |
497 | } | |
498 | else { | |
499 | thread_mtx_lock(thread); | |
500 | result = KERN_ABORTED; | |
501 | } | |
9bccf70c | 502 | |
91447636 | 503 | thread_release(thread); |
9bccf70c | 504 | } |
91447636 A |
505 | else |
506 | result = machine_thread_set_state( | |
507 | thread, flavor, state, state_count); | |
1c79356b | 508 | } |
91447636 A |
509 | else |
510 | result = KERN_TERMINATED; | |
1c79356b | 511 | |
6d2010ae A |
512 | if ((result == KERN_SUCCESS) && from_user) |
513 | extmod_statistics_incr_thread_set_state(thread); | |
514 | ||
91447636 | 515 | thread_mtx_unlock(thread); |
9bccf70c A |
516 | |
517 | return (result); | |
1c79356b | 518 | } |
6d2010ae A |
519 | |
520 | /* No prototype, since thread_act_server.h has the _from_user version if KERNEL_SERVER */ | |
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 | kern_return_t | |
529 | thread_set_state( | |
530 | register thread_t thread, | |
531 | int flavor, | |
532 | thread_state_t state, | |
533 | mach_msg_type_number_t state_count) | |
534 | { | |
535 | return thread_set_state_internal(thread, flavor, state, state_count, FALSE); | |
536 | } | |
91447636 | 537 | |
6d2010ae A |
538 | kern_return_t |
539 | thread_set_state_from_user( | |
540 | register thread_t thread, | |
541 | int flavor, | |
542 | thread_state_t state, | |
543 | mach_msg_type_number_t state_count) | |
544 | { | |
545 | return thread_set_state_internal(thread, flavor, state, state_count, TRUE); | |
546 | } | |
91447636 | 547 | |
1c79356b | 548 | /* |
91447636 A |
549 | * Kernel-internal "thread" interfaces used outside this file: |
550 | */ | |
551 | ||
552 | /* Initialize (or re-initialize) a thread state. Called from execve | |
553 | * with nothing locked, returns same way. | |
1c79356b A |
554 | */ |
555 | kern_return_t | |
91447636 A |
556 | thread_state_initialize( |
557 | register thread_t thread) | |
1c79356b | 558 | { |
9bccf70c | 559 | kern_return_t result = KERN_SUCCESS; |
1c79356b | 560 | |
91447636 | 561 | if (thread == THREAD_NULL) |
1c79356b | 562 | return (KERN_INVALID_ARGUMENT); |
1c79356b | 563 | |
91447636 | 564 | thread_mtx_lock(thread); |
9bccf70c | 565 | |
91447636 A |
566 | if (thread->active) { |
567 | if (thread != current_thread()) { | |
568 | thread_hold(thread); | |
9bccf70c | 569 | |
91447636 | 570 | thread_mtx_unlock(thread); |
9bccf70c | 571 | |
39236c6e | 572 | if (thread_stop(thread, TRUE)) { |
91447636 A |
573 | thread_mtx_lock(thread); |
574 | result = machine_thread_state_initialize( thread ); | |
575 | thread_unstop(thread); | |
576 | } | |
577 | else { | |
578 | thread_mtx_lock(thread); | |
579 | result = KERN_ABORTED; | |
580 | } | |
9bccf70c | 581 | |
91447636 | 582 | thread_release(thread); |
9bccf70c | 583 | } |
91447636 | 584 | else |
316670eb | 585 | result = machine_thread_state_initialize( thread ); |
1c79356b | 586 | } |
91447636 A |
587 | else |
588 | result = KERN_TERMINATED; | |
9bccf70c | 589 | |
91447636 | 590 | thread_mtx_unlock(thread); |
9bccf70c A |
591 | |
592 | return (result); | |
1c79356b A |
593 | } |
594 | ||
1c79356b A |
595 | |
596 | kern_return_t | |
597 | thread_dup( | |
91447636 | 598 | register thread_t target) |
1c79356b | 599 | { |
91447636 | 600 | thread_t self = current_thread(); |
9bccf70c | 601 | kern_return_t result = KERN_SUCCESS; |
1c79356b | 602 | |
91447636 | 603 | if (target == THREAD_NULL || target == self) |
1c79356b A |
604 | return (KERN_INVALID_ARGUMENT); |
605 | ||
91447636 | 606 | thread_mtx_lock(target); |
9bccf70c | 607 | |
91447636 A |
608 | if (target->active) { |
609 | thread_hold(target); | |
9bccf70c | 610 | |
91447636 | 611 | thread_mtx_unlock(target); |
9bccf70c | 612 | |
39236c6e | 613 | if (thread_stop(target, TRUE)) { |
91447636 A |
614 | thread_mtx_lock(target); |
615 | result = machine_thread_dup(self, target); | |
2d21ac55 A |
616 | if (self->affinity_set != AFFINITY_SET_NULL) |
617 | thread_affinity_dup(self, target); | |
91447636 A |
618 | thread_unstop(target); |
619 | } | |
620 | else { | |
621 | thread_mtx_lock(target); | |
9bccf70c | 622 | result = KERN_ABORTED; |
9bccf70c A |
623 | } |
624 | ||
91447636 | 625 | thread_release(target); |
1c79356b | 626 | } |
91447636 A |
627 | else |
628 | result = KERN_TERMINATED; | |
9bccf70c | 629 | |
91447636 | 630 | thread_mtx_unlock(target); |
9bccf70c A |
631 | |
632 | return (result); | |
1c79356b A |
633 | } |
634 | ||
635 | ||
636 | /* | |
637 | * thread_setstatus: | |
638 | * | |
639 | * Set the status of the specified thread. | |
640 | * Called with (and returns with) no locks held. | |
641 | */ | |
642 | kern_return_t | |
643 | thread_setstatus( | |
91447636 | 644 | register thread_t thread, |
9bccf70c A |
645 | int flavor, |
646 | thread_state_t tstate, | |
1c79356b A |
647 | mach_msg_type_number_t count) |
648 | { | |
9bccf70c | 649 | |
91447636 | 650 | return (thread_set_state(thread, flavor, tstate, count)); |
1c79356b A |
651 | } |
652 | ||
653 | /* | |
654 | * thread_getstatus: | |
655 | * | |
656 | * Get the status of the specified thread. | |
657 | */ | |
658 | kern_return_t | |
659 | thread_getstatus( | |
91447636 | 660 | register thread_t thread, |
9bccf70c A |
661 | int flavor, |
662 | thread_state_t tstate, | |
1c79356b A |
663 | mach_msg_type_number_t *count) |
664 | { | |
91447636 | 665 | return (thread_get_state(thread, flavor, tstate, count)); |
1c79356b A |
666 | } |
667 | ||
fe8ab488 A |
668 | /* |
669 | * Change thread's machine-dependent userspace TSD base. | |
670 | * Called with nothing locked. Returns same way. | |
671 | */ | |
672 | kern_return_t | |
673 | thread_set_tsd_base( | |
674 | thread_t thread, | |
675 | mach_vm_offset_t tsd_base) | |
676 | { | |
677 | kern_return_t result = KERN_SUCCESS; | |
678 | ||
679 | if (thread == THREAD_NULL) | |
680 | return (KERN_INVALID_ARGUMENT); | |
681 | ||
682 | thread_mtx_lock(thread); | |
683 | ||
684 | if (thread->active) { | |
685 | if (thread != current_thread()) { | |
686 | thread_hold(thread); | |
687 | ||
688 | thread_mtx_unlock(thread); | |
689 | ||
690 | if (thread_stop(thread, TRUE)) { | |
691 | thread_mtx_lock(thread); | |
692 | result = machine_thread_set_tsd_base(thread, tsd_base); | |
693 | thread_unstop(thread); | |
694 | } | |
695 | else { | |
696 | thread_mtx_lock(thread); | |
697 | result = KERN_ABORTED; | |
698 | } | |
699 | ||
700 | thread_release(thread); | |
701 | } | |
702 | else | |
703 | result = machine_thread_set_tsd_base(thread, tsd_base); | |
704 | } | |
705 | else | |
706 | result = KERN_TERMINATED; | |
707 | ||
708 | thread_mtx_unlock(thread); | |
709 | ||
710 | return (result); | |
711 | } | |
712 | ||
1c79356b | 713 | /* |
91447636 | 714 | * install_special_handler: |
1c79356b | 715 | * |
1c79356b A |
716 | * Install the special returnhandler that handles suspension and |
717 | * termination, if it hasn't been installed already. | |
718 | * | |
91447636 | 719 | * Called with the thread mutex held. |
1c79356b A |
720 | */ |
721 | void | |
722 | install_special_handler( | |
91447636 | 723 | thread_t thread) |
1c79356b | 724 | { |
91447636 | 725 | spl_t s = splsched(); |
1c79356b | 726 | |
e7c99d92 | 727 | thread_lock(thread); |
91447636 | 728 | install_special_handler_locked(thread); |
e7c99d92 | 729 | thread_unlock(thread); |
91447636 | 730 | splx(s); |
1c79356b A |
731 | } |
732 | ||
733 | /* | |
91447636 A |
734 | * install_special_handler_locked: |
735 | * | |
1c79356b A |
736 | * Do the work of installing the special_handler. |
737 | * | |
91447636 | 738 | * Called with the thread mutex and scheduling lock held. |
1c79356b A |
739 | */ |
740 | void | |
741 | install_special_handler_locked( | |
91447636 | 742 | thread_t thread) |
1c79356b | 743 | { |
3e170ce0 | 744 | |
91447636 A |
745 | /* |
746 | * Temporarily undepress, so target has | |
747 | * a chance to do locking required to | |
748 | * block itself in special_handler(). | |
749 | */ | |
6d2010ae | 750 | if (thread->sched_flags & TH_SFLAG_DEPRESSED_MASK) |
3e170ce0 | 751 | thread_recompute_sched_pri(thread, TRUE); |
91447636 A |
752 | |
753 | thread_ast_set(thread, AST_APC); | |
754 | ||
755 | if (thread == current_thread()) | |
756 | ast_propagate(thread->ast); | |
9bccf70c A |
757 | else { |
758 | processor_t processor = thread->last_processor; | |
759 | ||
55e303ae A |
760 | if ( processor != PROCESSOR_NULL && |
761 | processor->state == PROCESSOR_RUNNING && | |
762 | processor->active_thread == thread ) | |
9bccf70c A |
763 | cause_ast_check(processor); |
764 | } | |
765 | } | |
1c79356b | 766 | |
1c79356b A |
767 | /* |
768 | * Activation control support routines internal to this file: | |
3e170ce0 | 769 | * |
1c79356b A |
770 | */ |
771 | ||
1c79356b A |
772 | /* |
773 | * special_handler_continue | |
774 | * | |
775 | * Continuation routine for the special handler blocks. It checks | |
776 | * to see whether there has been any new suspensions. If so, it | |
777 | * installs the special handler again. Otherwise, it checks to see | |
778 | * if the current depression needs to be re-instated (it may have | |
779 | * been temporarily removed in order to get to this point in a hurry). | |
780 | */ | |
781 | void | |
782 | special_handler_continue(void) | |
783 | { | |
91447636 A |
784 | thread_t thread = current_thread(); |
785 | ||
786 | thread_mtx_lock(thread); | |
1c79356b | 787 | |
91447636 A |
788 | if (thread->suspend_count > 0) |
789 | install_special_handler(thread); | |
1c79356b | 790 | else { |
9bccf70c A |
791 | spl_t s = splsched(); |
792 | ||
1c79356b | 793 | thread_lock(thread); |
6d2010ae | 794 | if (thread->sched_flags & TH_SFLAG_DEPRESSED_MASK) { |
9bccf70c A |
795 | processor_t myprocessor = thread->last_processor; |
796 | ||
797 | thread->sched_pri = DEPRESSPRI; | |
798 | myprocessor->current_pri = thread->sched_pri; | |
1c79356b A |
799 | } |
800 | thread_unlock(thread); | |
801 | splx(s); | |
802 | } | |
9bccf70c | 803 | |
91447636 A |
804 | thread_mtx_unlock(thread); |
805 | ||
1c79356b | 806 | thread_exception_return(); |
9bccf70c | 807 | /*NOTREACHED*/ |
1c79356b A |
808 | } |
809 | ||
810 | /* | |
811 | * special_handler - handles suspension, termination. Called | |
812 | * with nothing locked. Returns (if it returns) the same way. | |
813 | */ | |
814 | void | |
815 | special_handler( | |
91447636 | 816 | thread_t thread) |
1c79356b | 817 | { |
91447636 | 818 | spl_t s; |
1c79356b | 819 | |
91447636 | 820 | thread_mtx_lock(thread); |
1c79356b A |
821 | |
822 | s = splsched(); | |
1c79356b | 823 | thread_lock(thread); |
6d2010ae | 824 | thread->sched_flags &= ~TH_SFLAG_ABORTED_MASK; |
1c79356b A |
825 | thread_unlock(thread); |
826 | splx(s); | |
827 | ||
1c79356b A |
828 | /* |
829 | * If we're suspended, go to sleep and wait for someone to wake us up. | |
830 | */ | |
91447636 A |
831 | if (thread->active) { |
832 | if (thread->suspend_count > 0) { | |
3e170ce0 | 833 | assert_wait(&thread->suspend_count, THREAD_ABORTSAFE); |
91447636 | 834 | thread_mtx_unlock(thread); |
3e170ce0 | 835 | thread_block((thread_continue_t)special_handler_continue); |
91447636 | 836 | /*NOTREACHED*/ |
9bccf70c | 837 | } |
1c79356b | 838 | } |
91447636 A |
839 | else { |
840 | thread_mtx_unlock(thread); | |
1c79356b | 841 | |
91447636 A |
842 | thread_terminate_self(); |
843 | /*NOTREACHED*/ | |
844 | } | |
1c79356b | 845 | |
91447636 | 846 | thread_mtx_unlock(thread); |
1c79356b A |
847 | } |
848 | ||
6d2010ae A |
849 | /* Prototype, see justification above */ |
850 | kern_return_t | |
851 | act_set_state( | |
852 | thread_t thread, | |
853 | int flavor, | |
854 | thread_state_t state, | |
855 | mach_msg_type_number_t count); | |
856 | ||
1c79356b | 857 | kern_return_t |
91447636 A |
858 | act_set_state( |
859 | thread_t thread, | |
860 | int flavor, | |
861 | thread_state_t state, | |
862 | mach_msg_type_number_t count) | |
1c79356b | 863 | { |
91447636 A |
864 | if (thread == current_thread()) |
865 | return (KERN_INVALID_ARGUMENT); | |
1c79356b | 866 | |
91447636 | 867 | return (thread_set_state(thread, flavor, state, count)); |
1c79356b A |
868 | |
869 | } | |
870 | ||
6d2010ae A |
871 | kern_return_t |
872 | act_set_state_from_user( | |
873 | thread_t thread, | |
874 | int flavor, | |
875 | thread_state_t state, | |
876 | mach_msg_type_number_t count) | |
877 | { | |
878 | if (thread == current_thread()) | |
879 | return (KERN_INVALID_ARGUMENT); | |
880 | ||
881 | return (thread_set_state_from_user(thread, flavor, state, count)); | |
882 | ||
883 | } | |
884 | ||
1c79356b | 885 | kern_return_t |
91447636 A |
886 | act_get_state( |
887 | thread_t thread, | |
888 | int flavor, | |
889 | thread_state_t state, | |
890 | mach_msg_type_number_t *count) | |
1c79356b | 891 | { |
91447636 A |
892 | if (thread == current_thread()) |
893 | return (KERN_INVALID_ARGUMENT); | |
1c79356b | 894 | |
91447636 | 895 | return (thread_get_state(thread, flavor, state, count)); |
1c79356b A |
896 | } |
897 | ||
316670eb A |
898 | static void |
899 | act_set_ast( | |
3e170ce0 | 900 | thread_t thread, |
316670eb | 901 | ast_t ast) |
1c79356b | 902 | { |
3e170ce0 A |
903 | spl_t s = splsched(); |
904 | ||
91447636 | 905 | if (thread == current_thread()) { |
316670eb | 906 | thread_ast_set(thread, ast); |
91447636 | 907 | ast_propagate(thread->ast); |
3e170ce0 A |
908 | } else { |
909 | processor_t processor; | |
0b4e3aa0 | 910 | |
9bccf70c | 911 | thread_lock(thread); |
316670eb | 912 | thread_ast_set(thread, ast); |
9bccf70c | 913 | processor = thread->last_processor; |
316670eb A |
914 | if ( processor != PROCESSOR_NULL && |
915 | processor->state == PROCESSOR_RUNNING && | |
3e170ce0 | 916 | processor->active_thread == thread ) |
9bccf70c A |
917 | cause_ast_check(processor); |
918 | thread_unlock(thread); | |
0b4e3aa0 | 919 | } |
3e170ce0 | 920 | |
9bccf70c | 921 | splx(s); |
1c79356b A |
922 | } |
923 | ||
316670eb A |
924 | void |
925 | act_set_astbsd( | |
926 | thread_t thread) | |
927 | { | |
928 | act_set_ast( thread, AST_BSD ); | |
929 | } | |
930 | ||
316670eb A |
931 | void |
932 | act_set_kperf( | |
933 | thread_t thread) | |
934 | { | |
935 | /* safety check */ | |
936 | if (thread != current_thread()) | |
937 | if( !ml_get_interrupts_enabled() ) | |
938 | panic("unsafe act_set_kperf operation"); | |
939 | ||
940 | act_set_ast( thread, AST_KPERF ); | |
941 | } | |
942 | ||
943 | #if CONFIG_MACF | |
944 | void | |
945 | act_set_astmacf( | |
946 | thread_t thread) | |
947 | { | |
948 | act_set_ast( thread, AST_MACF); | |
1c79356b | 949 | } |
316670eb | 950 | #endif |
3e170ce0 A |
951 | |
952 | void | |
953 | set_astledger(thread_t thread) | |
954 | { | |
955 | act_set_ast(thread, AST_LEDGER); | |
956 | } | |
957 | ||
958 |