|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * @OSF_FREE_COPYRIGHT@
24: */
25: /*
26: * Copyright (c) 1993 The University of Utah and
27: * the Center for Software Science (CSS). All rights reserved.
28: *
29: * Permission to use, copy, modify and distribute this software and its
30: * documentation is hereby granted, provided that both the copyright
31: * notice and this permission notice appear in all copies of the
32: * software, derivative works or modified versions, and any portions
33: * thereof, and that both notices appear in supporting documentation.
34: *
35: * THE UNIVERSITY OF UTAH AND CSS ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
36: * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSS DISCLAIM ANY LIABILITY OF
37: * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
38: *
39: * CSS requests users of this software to return to [email protected] any
40: * improvements that they make and grant CSS redistribution rights.
41: *
42: * Author: Bryan Ford, University of Utah CSS
43: *
44: * Thread_Activation management routines
45: */
46:
47: #include <cpus.h>
48: #include <task_swapper.h>
49: #include <mach/kern_return.h>
50: #include <mach/alert.h>
51: #include <kern/etap_macros.h>
52: #include <kern/mach_param.h>
53: #include <kern/zalloc.h>
54: #include <kern/thread.h>
55: #include <kern/thread_swap.h>
56: #include <kern/task.h>
57: #include <kern/task_swap.h>
58: #include <kern/thread_act.h>
59: #include <kern/thread_pool.h>
60: #include <kern/sched_prim.h>
61: #include <kern/misc_protos.h>
62: #include <kern/assert.h>
63: #include <kern/exception.h>
64: #include <kern/ipc_mig.h>
65: #include <kern/ipc_tt.h>
66: #include <kern/profile.h>
67: #include <kern/machine.h>
68: #include <kern/spl.h>
69: #include <kern/syscall_subr.h>
70: #include <kern/sync_lock.h>
71: #include <kern/sf.h>
72: #include <kern/mk_sp.h> /*** ??? fix so this can be removed ***/
73: #include <mach_prof.h>
74: #include <mach/rpc.h>
75:
76: /*
77: * Debugging printf control
78: */
79: #if MACH_ASSERT
80: unsigned int watchacts = 0 /* WA_ALL */
81: ; /* Do-it-yourself & patchable */
82: #endif
83:
84: /*
85: * Track the number of times we need to swapin a thread to deallocate it.
86: */
87: int act_free_swapin = 0;
88: extern boolean_t thread_swap_unwire_stack;
89:
90: #if THREAD_SWAP_UNWIRE_USER_STACK
91: extern boolean_t thread_swap_unwire_user_stack;
92: #else /* THREAD_SWAP_UNWIRE_USER_STACK */
93: #define thread_swap_unwire_user_stack FALSE
94: #endif /* THREAD_SWAP_UNWIRE_USER_STACK */
95:
96: /*
97: * Forward declarations for functions local to this file.
98: */
99: kern_return_t act_abort( thread_act_t, int);
100: void special_handler(ReturnHandler *, thread_act_t);
101: void nudge(thread_act_t);
102: kern_return_t act_set_state_locked(thread_act_t, int,
103: thread_state_t,
104: mach_msg_type_number_t);
105: kern_return_t act_get_state_locked(thread_act_t, int,
106: thread_state_t,
107: mach_msg_type_number_t *);
108: void act_set_apc(thread_act_t);
109: void act_clr_apc(thread_act_t);
110: void act_user_to_kernel(thread_act_t);
111: void act_ulock_release_all(thread_act_t thr_act);
112:
113: kern_return_t terminate_empty_act(thread_act_t);
114: void install_special_handler_locked(thread_act_t);
115:
116: static zone_t thr_act_zone;
117:
118: /*
119: * Thread interfaces accessed via a thread_activation:
120: */
121:
122: /*
123: * Terminate a thread. Called with nothing locked.
124: * Returns same way.
125: */
126: kern_return_t
127: thread_terminate(
128: register thread_act_t thr_act)
129: {
130: thread_t thread;
131: task_t task;
132: struct ipc_port *iplock;
133: kern_return_t ret = KERN_INVALID_ARGUMENT;
134: #if NCPUS > 1
135: boolean_t held;
136: #endif /* NCPUS > 1 */
137:
138: if (thr_act == THR_ACT_NULL)
139: return(ret);
140:
141: if (((thr_act->task == kernel_task) || (thr_act->kernel_loaded == TRUE))
142: && (current_act() != thr_act)) {
143: return(KERN_FAILURE);
144: }
145:
146: #if THREAD_SWAPPER
147: thread_swap_disable(thr_act);
148: #endif /* THREAD_SWAPPER */
149:
150: /*
151: * Lock task containing target thread before (really)
152: * getting thread locks.
153: */
154: act_lock(thr_act);
155: task = thr_act->task;
156: act_unlock(thr_act);
157: task_lock(task);
158:
159: thread = act_lock_thread(thr_act);
160: if (!thr_act->active) {
161: act_unlock_thread(thr_act);
162: task_unlock(task);
163: return(KERN_TERMINATED);
164: }
165:
166: /*
167: * Break IPC control over the thread.
168: */
169: ipc_thr_act_disable_act_locked(thr_act);
170:
171: #if NCPUS > 1
172: /*
173: * Make sure this thread enters the kernel
174: */
175: if (thread != THREAD_NULL && thread != current_thread()) {
176: thread_hold(thr_act);
177: act_unlock_thread(thr_act);
178: #if 1 /* Grenoble */
179: if (!thread_stop_wait(thread)) {
180: ret = KERN_ABORTED;
181: (void)act_lock_thread(thr_act);
182: thread_release(thr_act);
183: act_unlock_thread(thr_act);
184: task_unlock(task);
185: return (ret);
186: }
187: #else
188: thread_stop_wait(thread);
189: #endif
190: held = TRUE;
191: (void)act_lock_thread(thr_act);
192: } else {
193: held = FALSE;
194: }
195: #endif /* NCPUS > 1 */
196:
197: #if 0 /* Grenoble */
198: /*
199: * Lock task containing target.
200: * Use mutex_try to respect lock ordering.
201: */
202:
203: task = thr_act->task;
204: if (!mutex_try(&task->lock)) {
205: act_unlock_thread(thr_act);
206: task_lock(task);
207: thread = act_lock_thread(thr_act);
208: }
209:
210:
211: if (!thr_act->active) {
212: act_unlock_thread(thr_act);
213: task_unlock(task);
214: ret = KERN_TERMINATED;
215: goto out;
216: }
217:
218: /*
219: * Break IPC control over the thread.
220: */
221: ipc_thr_act_disable_act_locked(thr_act);
222:
223: #endif
224: /*
225: * Check for terminating an empty thread_act -- detach it from
226: * its task, then deallocate its remaining refs here.
227: */
228: if (thr_act->thread == THREAD_NULL) {
229: iplock = thr_act->pool_port; /* remember for unlock call */
230: ret = terminate_empty_act( thr_act );
231:
232: /*
233: * Release locks individually. (`act_unlock_thread()'
234: * will not work since `pool_port' field has changed.)
235: */
236: ip_unlock(iplock);
237: act_unlock(thr_act);
238: }
239: else {
240: assert(thr_act->active);
241: act_disable_task_locked(thr_act);
242: ret = act_abort(thr_act,FALSE);
243: act_unlock_thread(thr_act);
244: }
245:
246: task_unlock(task);
247:
248: if (((thr_act->task == kernel_task) || (thr_act->kernel_loaded == TRUE))
249: && (current_act() == thr_act)) {
250: ast_taken(FALSE, AST_APC, 0);
251: panic("thread_terminate(): returning from ast_taken() for %x kernel activation\n", thr_act);
252: }
253:
254: #if 0 /* Grenoble */
255: out:
256: #endif
257:
258: #if NCPUS > 1
259: if (held) {
260: thread_unstop(thread);
261: (void)act_lock_thread(thr_act);
262: thread_release(thr_act);
263: act_unlock_thread(thr_act);
264: }
265: #endif /* NCPUS > 1 */
266: return(ret);
267: }
268:
269: /*
270: * Called with empty thread activation and its pool port locked.
271: * Activation is currently "active."
272: * Task containing activation is also locked.
273: * Returns the same way.
274: */
275: kern_return_t
276: terminate_empty_act( thread_act_t thr_act ) {
277: /*
278: * remove the activation from the pool port
279: * (this prevents it from being used)
280: */
281: if (thr_act->pool_port) {
282: act_locked_act_set_thread_pool(thr_act, IP_NULL);
283: }
284:
285: /*
286: * disassociate the thread from the task
287: */
288: assert(thr_act->active);
289: act_disable_task_locked( thr_act );
290:
291: return KERN_SUCCESS;
292: }
293:
294: /*
295: * thread_hold:
296: *
297: * Suspend execution of the specified thread.
298: * This is a recursive-style suspension of the thread, a count of
299: * suspends is maintained.
300: *
301: * Called with thr_act locked "appropriately" for synchrony with
302: * RPC (see act_lock_thread()). Returns same way.
303: */
304: void
305: thread_hold(
306: register thread_act_t thr_act)
307: {
308: if (thr_act->suspend_count++ == 0) {
309: install_special_handler(thr_act);
310: nudge(thr_act);
311: }
312: }
313:
314: /*
315: * Decrement internal suspension count for thr_act, setting thread
316: * runnable when count falls to zero.
317: *
318: * Called with thr_act locked "appropriately" for synchrony
319: * with RPC (see act_lock_thread()).
320: */
321: void
322: thread_release(
323: register thread_act_t thr_act)
324: {
325: if( thr_act->suspend_count &&
326: (--thr_act->suspend_count == 0) )
327: nudge( thr_act );
328: }
329:
330: kern_return_t
331: thread_suspend(
332: register thread_act_t thr_act)
333: {
334: thread_t thread;
335:
336: if (thr_act == THR_ACT_NULL) {
337: return(KERN_INVALID_ARGUMENT);
338: }
339: thread = act_lock_thread(thr_act);
340: if (!thr_act->active) {
341: act_unlock_thread(thr_act);
342: return(KERN_TERMINATED);
343: }
344: if (thr_act->user_stop_count++ == 0 &&
345: thr_act->suspend_count++ == 0 ) {
346: install_special_handler(thr_act);
347: if (thread &&
348: thr_act == thread->top_act && thread != current_thread()) {
349: nudge(thr_act);
350: act_unlock_thread(thr_act);
351: (void)thread_wait(thread);
352: }
353: else {
354: /*
355: * No need to wait for target thread
356: */
357: act_unlock_thread(thr_act);
358: }
359: }
360: else {
361: /*
362: * Thread is already suspended
363: */
364: act_unlock_thread(thr_act);
365: }
366: return(KERN_SUCCESS);
367: }
368:
369: kern_return_t
370: thread_resume(
371: register thread_act_t thr_act)
372: {
373: register kern_return_t ret;
374: spl_t s;
375: thread_t thread;
376:
377: if (thr_act == THR_ACT_NULL)
378: return(KERN_INVALID_ARGUMENT);
379: thread = act_lock_thread(thr_act);
380: ret = KERN_SUCCESS;
381:
382: if (thr_act->active) {
383: if (thr_act->user_stop_count > 0) {
384: if( --thr_act->user_stop_count == 0 ) {
385: --thr_act->suspend_count;
386: nudge( thr_act );
387: }
388: }
389: else
390: ret = KERN_FAILURE;
391: }
392: else
393: ret = KERN_TERMINATED;
394: act_unlock_thread( thr_act );
395: return ret;
396: }
397:
398: /*
399: * This routine walks toward the head of an RPC chain starting at
400: * a specified thread activation. An alert bit is set and a special
401: * handler is installed for each thread it encounters.
402: *
403: * The target thread act and thread shuttle are already locked.
404: */
405: kern_return_t
406: post_alert(
407: register thread_act_t thr_act,
408: unsigned alert_bits )
409: {
410: thread_act_t next;
411: thread_t thread;
412:
413: /*
414: * Chase the chain, setting alert bits and installing
415: * special handlers for each thread act.
416: */
417: /*** Not yet SMP safe ***/
418: /*** Worse, where's the activation locking as the chain is walked? ***/
419: for (next = thr_act; next != THR_ACT_NULL; next = next->higher) {
420: next->alerts |= alert_bits;
421: install_special_handler_locked(next);
422: }
423:
424: return(KERN_SUCCESS);
425: }
426:
427: /*
428: * thread_depress_abort:
429: *
430: * Prematurely abort priority depression if there is one.
431: */
432: kern_return_t
433: thread_depress_abort(
434: register thread_act_t thr_act)
435: {
436: register thread_t thread;
437: kern_return_t result;
438: sched_policy_t *policy;
439: spl_t s;
440:
441: if (thr_act == THR_ACT_NULL)
442: return (KERN_INVALID_ARGUMENT);
443:
444: thread = act_lock_thread(thr_act);
445: /* if activation is terminating, this operation is not meaningful */
446: if (!thr_act->active) {
447: act_unlock_thread(thr_act);
448:
449: return (KERN_TERMINATED);
450: }
451:
452: if (thread == THREAD_NULL) {
453: act_unlock_thread(thr_act);
454:
455: return (KERN_INVALID_ARGUMENT);
456: }
457:
458: s = splsched();
459: thread_lock(thread);
460: policy = &sched_policy[thread->policy];
461: thread_unlock(thread);
462: splx(s);
463:
464: result = policy->sp_ops.sp_thread_depress_abort(policy, thread);
465:
466: act_unlock_thread(thr_act);
467:
468: return (result);
469: }
470:
471:
472: /*
473: * Already locked: all RPC-related locks for thr_act (see
474: * act_lock_thread()).
475: */
476: kern_return_t
477: act_abort( thread_act_t thr_act, int chain_break )
478: {
479: spl_t spl;
480: thread_t thread;
481: struct ipc_port *iplock = thr_act->pool_port;
482: thread_act_t orphan;
483: kern_return_t kr;
484: etap_data_t probe_data;
485:
486: /*
487: * mark the activation for abort,
488: * update the suspend count,
489: * always install the special handler
490: */
491: install_special_handler(thr_act);
492:
493: ETAP_DATA_LOAD(probe_data[0], thr_act);
494: ETAP_DATA_LOAD(probe_data[1], thr_act->thread);
495: ETAP_PROBE_DATA(ETAP_P_ACT_ABORT,
496: 0,
497: current_thread(),
498: &probe_data,
499: ETAP_DATA_ENTRY*2);
500:
501: spl = splsched();
502: thread_lock( thr_act->thread );
503:
504: /*
505: * If the target thread activation is not the head...
506: */
507: if ( thr_act->thread->top_act != thr_act ) {
508: #ifdef AGRESSIVE_ABORT
509: /* release state buffer for target's outstanding invocation */
510: if (unwind_invoke_state(thr_act) != KERN_SUCCESS) {
511: panic("unwind_invoke_state failure");
512: }
513:
514: /* release state buffer for target's incoming invocation */
515: if (thr_act->lower != THR_ACT_NULL) {
516: if (unwind_invoke_state(thr_act->lower)
517: != KERN_SUCCESS) {
518: panic("unwind_invoke_state failure");
519: }
520: }
521:
522: /* unlink target thread activation from shuttle chain */
523: if ( thr_act->lower == THR_ACT_NULL ) {
524: /*
525: * This is the root thread activation of the chain.
526: * Unlink the root thread act from the bottom of
527: * the chain.
528: */
529: thr_act->higher->lower = THR_ACT_NULL;
530: } else {
531: /*
532: * This thread act is in the middle of the chain.
533: * Unlink the thread act from the middle of the chain.
534: */
535: thr_act->higher->lower = thr_act->lower;
536: thr_act->lower->higher = thr_act->higher;
537:
538: /* set the terminated bit for RPC return processing */
539: thr_act->lower->alerts |= SERVER_TERMINATED;
540: }
541:
542: orphan = thr_act->higher;
543:
544: /* remove the activation from its thread pool */
545: /* (note: this is okay for "rooted threads," too) */
546: act_locked_act_set_thread_pool(thr_act, IP_NULL);
547:
548: /* (just to be thorough) release the IP lock */
549: if (iplock != IP_NULL) ip_unlock(iplock);
550:
551: /* release one more reference for a rooted thread */
552: if (iplock == IP_NULL) act_locked_act_deallocate(thr_act);
553:
554: /* Presumably, the only reference to this activation is
555: * now held by the caller of this routine. */
556: assert(thr_act->ref_count == 1);
557: #else /*AGRESSIVE_ABORT*/
558: /* If there is a lower activation in the RPC chain... */
559: if (thr_act->lower != THR_ACT_NULL) {
560: /* ...indicate the server activation was terminated */
561: thr_act->lower->alerts |= SERVER_TERMINATED;
562: }
563: /* Mark (and process) any orphaned activations */
564: orphan = thr_act->higher;
565: #endif /*AGRESSIVE_ABORT*/
566:
567: /* indicate client of orphaned chain has been terminated */
568: orphan->alerts |= CLIENT_TERMINATED;
569:
570: /*
571: * Set up posting of alert to headward portion of
572: * the RPC chain.
573: */
574: /*** fix me -- orphan act is not locked ***/
575: post_alert(orphan, ORPHANED);
576:
577: /*
578: * Get attention of head of RPC chain.
579: */
580: thread_unlock(thr_act->thread);
581: nudge(thr_act->thread->top_act);
582: splx(spl);
583: return (KERN_SUCCESS);
584: }
585:
586: /*
587: * If the target thread is the end of the chain, the thread
588: * has to be marked for abort and rip it out of any wait.
589: */
590: if (thr_act->thread->top_act == thr_act) {
591: thr_act->thread->state |= TH_ABORT;
592: thread_unlock(thr_act->thread);
593: install_special_handler(thr_act);
594: nudge( thr_act );
595:
596: /*
597: * if it's waiting, clear it.
598: */
599: if( thr_act->thread->state & TH_WAIT ){
600: clear_wait(thr_act->thread, THREAD_INTERRUPTED, TRUE);
601: splx(spl);
602: return KERN_SUCCESS;
603: }
604: }
605: else {
606: thread_unlock(thr_act->thread);
607: }
608: splx(spl);
609: return KERN_SUCCESS;
610: }
611:
612: kern_return_t
613: thread_abort(
614: register thread_act_t thr_act)
615: {
616: int ret;
617: thread_t thread;
618:
619: if (thr_act == THR_ACT_NULL || thr_act == current_act())
620: return (KERN_INVALID_ARGUMENT);
621: /*
622: * Lock the target thread and the current thread now,
623: * in case thread_halt() ends up being called below.
624: */
625: thread = act_lock_thread(thr_act);
626: if (!thr_act->active) {
627: act_unlock_thread(thr_act);
628: return(KERN_TERMINATED);
629: }
630:
631: if( thread == THREAD_NULL ) {
632: act_unlock_thread(thr_act);
633: return KERN_NO_THREAD;
634: }
635:
636: ret = act_abort( thr_act, FALSE );
637: act_unlock_thread( thr_act );
638: return ret;
639: }
640:
641: kern_return_t
642: thread_abort_safely(
643: register thread_act_t thr_act)
644: {
645: boolean_t r;
646: thread_t cur_thr = current_thread();
647: thread_t thread, othread;
648: thread_act_t cur_thr_act = current_act();
649: spl_t spl;
650:
651: if (thr_act == THR_ACT_NULL || thr_act == current_act())
652: return(KERN_INVALID_ARGUMENT);
653:
654: othread = act_lock_thread(thr_act);
655: if (othread == THREAD_NULL) {
656: act_unlock_thread(thr_act);
657: return(KERN_INVALID_ARGUMENT);
658: }
659: if (!thr_act->active) {
660: act_unlock_thread(thr_act);
661: return(KERN_TERMINATED);
662: }
663: if (othread->top_act != thr_act) {
664: act_unlock_thread(thr_act);
665: return(KERN_FAILURE);
666: }
667:
668: /*
669: * This is the head of the chain. Stop it and check to see if
670: * it's in a condition which can be interrupted and restarted and,
671: * if so, clear the wait.
672: */
673: thread_hold(thr_act);
674: act_unlock_thread(thr_act);
675: r = thread_stop_wait(othread);
676: if ((thread = act_lock_thread(thr_act)) != othread || !r) {
677: thread_release(thr_act);
678: act_unlock_thread(thr_act);
679: if (r) {
680: thread_unstop(othread);
681: return (KERN_FAILURE);
682: }
683: else
684: return(KERN_ABORTED);
685: }
686:
687: assert(thread == thr_act->thread);
688:
689: spl = splsched();
690: thread_lock(thread);
691:
692: if( (thread->state&(TH_RUN|TH_UNINT|TH_WAIT)) == TH_WAIT ){
693: if ( thread->at_safe_point ) {
694: /*
695: * It's an interruptible wait, clear it, then
696: * let the thread go and return successfully.
697: */
698: thread_unlock(thread);
699: splx(spl);
700: clear_wait(thread, THREAD_INTERRUPTED, TRUE);
701: thread_unstop(thread);
702: thread_release(thr_act);
703: act_unlock_thread(thr_act);
704: return KERN_SUCCESS;
705: }
706: }
707: /*
708: * if not stopped at a safepoint, just let it go and return failure.
709: */
710: thread_unlock(thread);
711: splx(spl);
712: thread_unstop(thread);
713: thread_release(thr_act);
714: act_unlock_thread(thr_act);
715: return KERN_FAILURE;
716: }
717:
718: /*** backward compatibility hacks ***/
719: #include <mach/thread_info.h>
720: #include <mach/thread_special_ports.h>
721: #include <ipc/ipc_port.h>
722: #include <mach/thread_act_server.h>
723:
724: kern_return_t
725: thread_info(
726: thread_act_t thr_act,
727: thread_flavor_t flavor,
728: thread_info_t thread_info_out,
729: mach_msg_type_number_t *thread_info_count)
730: {
731: register thread_t thread;
732: kern_return_t result;
733:
734: if (thr_act == THR_ACT_NULL)
735: return (KERN_INVALID_ARGUMENT);
736:
737: thread = act_lock_thread(thr_act);
738: if (!thr_act->active) {
739: act_unlock_thread(thr_act);
740:
741: return (KERN_TERMINATED);
742: }
743:
744: if (thread == THREAD_NULL) {
745: act_unlock_thread(thr_act);
746:
747: return (KERN_NO_THREAD);
748: }
749:
750: result = thread_info_shuttle(thr_act, flavor,
751: thread_info_out, thread_info_count);
752:
753: act_unlock_thread(thr_act);
754:
755: return (result);
756: }
757:
758: /*
759: * Routine: thread_get_special_port [kernel call]
760: * Purpose:
761: * Clones a send right for one of the thread's
762: * special ports.
763: * Conditions:
764: * Nothing locked.
765: * Returns:
766: * KERN_SUCCESS Extracted a send right.
767: * KERN_INVALID_ARGUMENT The thread is null.
768: * KERN_FAILURE The thread is dead.
769: * KERN_INVALID_ARGUMENT Invalid special port.
770: */
771:
772: kern_return_t
773: thread_get_special_port(
774: thread_act_t thr_act,
775: int which,
776: ipc_port_t *portp)
777: {
778: ipc_port_t *whichp;
779: ipc_port_t port;
780: thread_t thread;
781:
782: #if MACH_ASSERT
783: if (watchacts & WA_PORT)
784: printf("thread_get_special_port(thr_act=%x, which=%x port@%x=%x\n",
785: thr_act, which, portp, (portp ? *portp : 0));
786: #endif /* MACH_ASSERT */
787:
788: if (!thr_act)
789: return KERN_INVALID_ARGUMENT;
790: thread = act_lock_thread(thr_act);
791: switch (which) {
792: case THREAD_KERNEL_PORT:
793: whichp = &thr_act->ith_sself;
794: break;
795:
796: default:
797: act_unlock_thread(thr_act);
798: return KERN_INVALID_ARGUMENT;
799: }
800:
801: if (!thr_act->active) {
802: act_unlock_thread(thr_act);
803: return KERN_FAILURE;
804: }
805:
806: port = ipc_port_copy_send(*whichp);
807: act_unlock_thread(thr_act);
808:
809: *portp = port;
810: return KERN_SUCCESS;
811: }
812:
813: /*
814: * Routine: thread_set_special_port [kernel call]
815: * Purpose:
816: * Changes one of the thread's special ports,
817: * setting it to the supplied send right.
818: * Conditions:
819: * Nothing locked. If successful, consumes
820: * the supplied send right.
821: * Returns:
822: * KERN_SUCCESS Changed the special port.
823: * KERN_INVALID_ARGUMENT The thread is null.
824: * KERN_FAILURE The thread is dead.
825: * KERN_INVALID_ARGUMENT Invalid special port.
826: */
827:
828: kern_return_t
829: thread_set_special_port(
830: thread_act_t thr_act,
831: int which,
832: ipc_port_t port)
833: {
834: ipc_port_t *whichp;
835: ipc_port_t old;
836: thread_t thread;
837:
838: #if MACH_ASSERT
839: if (watchacts & WA_PORT)
840: printf("thread_set_special_port(thr_act=%x,which=%x,port=%x\n",
841: thr_act, which, port);
842: #endif /* MACH_ASSERT */
843:
844: if (thr_act == 0)
845: return KERN_INVALID_ARGUMENT;
846:
847: thread = act_lock_thread(thr_act);
848: switch (which) {
849: case THREAD_KERNEL_PORT:
850: whichp = &thr_act->ith_self;
851: break;
852:
853: default:
854: act_unlock_thread(thr_act);
855: return KERN_INVALID_ARGUMENT;
856: }
857:
858: if (!thr_act->active) {
859: act_unlock_thread(thr_act);
860: return KERN_FAILURE;
861: }
862:
863: old = *whichp;
864: *whichp = port;
865: act_unlock_thread(thr_act);
866:
867: if (IP_VALID(old))
868: ipc_port_release_send(old);
869: return KERN_SUCCESS;
870: }
871:
872: /*
873: * thread state should always be accessible by locking the thread
874: * and copying it. The activation messes things up so for right
875: * now if it's not the top of the chain, use a special handler to
876: * get the information when the shuttle returns to the activation.
877: */
878: kern_return_t
879: thread_get_state(
880: register thread_act_t thr_act,
881: int flavor,
882: thread_state_t state, /* pointer to OUT array */
883: mach_msg_type_number_t *state_count) /*IN/OUT*/
884: {
885: kern_return_t ret;
886: thread_t thread, nthread;
887:
888: #if 0 /* Grenoble - why?? */
889: if (thr_act == THR_ACT_NULL || thr_act == current_act())
890: #else
891: if (thr_act == THR_ACT_NULL)
892: #endif
893: return (KERN_INVALID_ARGUMENT);
894:
895: thread = act_lock_thread(thr_act);
896: if (!thr_act->active) {
897: act_unlock_thread(thr_act);
898: return(KERN_TERMINATED);
899: }
900:
901: thread_hold(thr_act);
902: while (1) {
903: if (!thread || thr_act != thread->top_act)
904: break;
905: act_unlock_thread(thr_act);
906: (void)thread_stop_wait(thread);
907: nthread = act_lock_thread(thr_act);
908: if (nthread == thread)
909: break;
910: thread_unstop(thread);
911: thread = nthread;
912: }
913: ret = act_machine_get_state(thr_act, flavor,
914: state, state_count);
915: if (thread && thr_act == thread->top_act)
916: thread_unstop(thread);
917: thread_release(thr_act);
918: act_unlock_thread(thr_act);
919:
920: return(ret);
921: }
922:
923: /*
924: * Change thread's machine-dependent state. Called with nothing
925: * locked. Returns same way.
926: */
927: kern_return_t
928: thread_set_state(
929: register thread_act_t thr_act,
930: int flavor,
931: thread_state_t state,
932: mach_msg_type_number_t state_count)
933: {
934: kern_return_t ret;
935: thread_t thread, nthread;
936:
937: #if 0 /* Grenoble - why?? */
938: if (thr_act == THR_ACT_NULL || thr_act == current_act())
939: #else
940: if (thr_act == THR_ACT_NULL)
941: #endif
942: return (KERN_INVALID_ARGUMENT);
943: /*
944: * We have no kernel activations, so Utah's MO fails for signals etc.
945: *
946: * If we're blocked in the kernel, use non-blocking method, else
947: * pass locked thr_act+thread in to "normal" act_[gs]et_state().
948: */
949:
950: thread = act_lock_thread(thr_act);
951: if (!thr_act->active) {
952: act_unlock_thread(thr_act);
953: return(KERN_TERMINATED);
954: }
955:
956: thread_hold(thr_act);
957: while (1) {
958: if (!thread || thr_act != thread->top_act)
959: break;
960: act_unlock_thread(thr_act);
961: (void)thread_stop_wait(thread);
962: nthread = act_lock_thread(thr_act);
963: if (nthread == thread)
964: break;
965: thread_unstop(thread);
966: thread = nthread;
967: }
968: ret = act_machine_set_state(thr_act, flavor,
969: state, state_count);
970: if (thread && thr_act == thread->top_act)
971: thread_unstop(thread);
972: thread_release(thr_act);
973: act_unlock_thread(thr_act);
974:
975: return(ret);
976: }
977:
978: /*
979: * Kernel-internal "thread" interfaces used outside this file:
980: */
981:
982: kern_return_t
983: thread_dup(
984: thread_act_t source_thr_act,
985: thread_act_t target_thr_act)
986: {
987: kern_return_t ret;
988: thread_t thread, nthread;
989:
990: if (target_thr_act == THR_ACT_NULL || target_thr_act == current_act())
991: return (KERN_INVALID_ARGUMENT);
992:
993: thread = act_lock_thread(target_thr_act);
994: if (!target_thr_act->active) {
995: act_unlock_thread(target_thr_act);
996: return(KERN_TERMINATED);
997: }
998:
999: thread_hold(target_thr_act);
1000: while (1) {
1001: if (!thread || target_thr_act != thread->top_act)
1002: break;
1003: act_unlock_thread(target_thr_act);
1004: (void)thread_stop_wait(thread);
1005: nthread = act_lock_thread(target_thr_act);
1006: if (nthread == thread)
1007: break;
1008: thread_unstop(thread);
1009: thread = nthread;
1010: }
1011: ret = act_thread_dup(source_thr_act, target_thr_act);
1012: if (thread && target_thr_act == thread->top_act)
1013: thread_unstop(thread);
1014: thread_release(target_thr_act);
1015: act_unlock_thread(target_thr_act);
1016:
1017: return(ret);
1018: }
1019:
1020:
1021: /*
1022: * thread_setstatus:
1023: *
1024: * Set the status of the specified thread.
1025: * Called with (and returns with) no locks held.
1026: */
1027: kern_return_t
1028: thread_setstatus(
1029: thread_act_t thr_act,
1030: int flavor,
1031: thread_state_t tstate,
1032: mach_msg_type_number_t count)
1033: {
1034: kern_return_t kr;
1035: thread_t thread;
1036:
1037: thread = act_lock_thread(thr_act);
1038: assert(thread);
1039: assert(thread->top_act == thr_act);
1040: kr = act_machine_set_state(thr_act, flavor, tstate, count);
1041: act_unlock_thread(thr_act);
1042: return(kr);
1043: }
1044:
1045: /*
1046: * thread_getstatus:
1047: *
1048: * Get the status of the specified thread.
1049: */
1050: kern_return_t
1051: thread_getstatus(
1052: thread_act_t thr_act,
1053: int flavor,
1054: thread_state_t tstate,
1055: mach_msg_type_number_t *count)
1056: {
1057: kern_return_t kr;
1058: thread_t thread;
1059:
1060: thread = act_lock_thread(thr_act);
1061: assert(thread);
1062: assert(thread->top_act == thr_act);
1063: kr = act_machine_get_state(thr_act, flavor, tstate, count);
1064: act_unlock_thread(thr_act);
1065: return(kr);
1066: }
1067:
1068: /*
1069: * Kernel-internal thread_activation interfaces used outside this file:
1070: */
1071:
1072: /*
1073: * act_init() - Initialize activation handling code
1074: */
1075: void
1076: act_init()
1077: {
1078: thr_act_zone = zinit(
1079: sizeof(struct thread_activation),
1080: ACT_MAX * sizeof(struct thread_activation), /* XXX */
1081: ACT_CHUNK * sizeof(struct thread_activation),
1082: "activations");
1083: act_machine_init();
1084: }
1085:
1086:
1087: /*
1088: * act_create - Create a new activation in a specific task.
1089: */
1090: kern_return_t
1091: act_create(task_t task,
1092: thread_act_params_t params,
1093: thread_act_t *new_act)
1094: {
1095: thread_act_t thr_act;
1096: int rc;
1097: vm_map_t map;
1098:
1099: thr_act = (thread_act_t)zalloc(thr_act_zone);
1100: if (thr_act == 0)
1101: return(KERN_RESOURCE_SHORTAGE);
1102:
1103: #if MACH_ASSERT
1104: if (watchacts & WA_ACT_LNK)
1105: printf("act_create(task=%x,stk=%x,thr_act@%x=%x)\n",
1106: task, params ? params->stack : 0, new_act, thr_act);
1107: #endif /* MACH_ASSERT */
1108:
1109: /* Start by zeroing everything; then init non-zero items only */
1110: bzero((char *)thr_act, sizeof(*thr_act));
1111:
1112: /* Start with one reference for being active, another for the caller */
1113: act_lock_init(thr_act);
1114: thr_act->ref_count = 2;
1115:
1116: /* Latch onto the task. */
1117: thr_act->task = task;
1118: task_reference(task);
1119: thr_act->active = 1;
1120:
1121: /* Initialize sigbufp for High-Watermark buffer allocation */
1122: thr_act->r_sigbufp = (routine_descriptor_t) &thr_act->r_sigbuf;
1123: thr_act->r_sigbuf_size = sizeof(thr_act->r_sigbuf);
1124:
1125: /* Initialize thread stack */
1126: if (params)
1127: {
1128: thr_act->user_stack = params->stack;
1129: thr_act->user_stack_size = params->stack_size;
1130: thr_act->user_entry = params->entry_func;
1131: }
1132: else
1133: {
1134: thr_act->user_stack = 0;
1135: thr_act->user_stack_size = 0;
1136: thr_act->user_entry = 0;
1137: }
1138:
1139: #if THREAD_SWAPPER
1140: thr_act->swap_state = TH_SW_IN;
1141: #if MACH_ASSERT
1142: thr_act->kernel_stack_swapped_in = TRUE;
1143: #if THREAD_SWAP_UNWIRE_USER_STACK
1144: thr_act->user_stack_swapped_in = TRUE;
1145: #endif /* THREAD_SWAP_UNWIRE_USER_STACK */
1146: #endif /* MACH_ASSERT */
1147: #endif /* THREAD_SWAPPER */
1148:
1149: /* special_handler will always be last on the returnhandlers list. */
1150: thr_act->special_handler.next = 0;
1151: thr_act->special_handler.handler = special_handler;
1152:
1153: #if MACH_PROF
1154: thr_act->act_profiled = FALSE;
1155: thr_act->act_profiled_own = FALSE;
1156: thr_act->profil_buffer = NULLPROFDATA;
1157: #endif
1158:
1159: /* Initialize the held_ulocks queue as empty */
1160: queue_init(&thr_act->held_ulocks);
1161:
1162: /* Inherit the profiling status of the parent task */
1163: act_prof_init(thr_act, task);
1164:
1165: ipc_thr_act_init(task, thr_act);
1166: act_machine_create(task, thr_act);
1167:
1168: /*
1169: * If thr_act created in kernel-loaded task, alter its saved
1170: * state to so indicate
1171: */
1172: if (task->kernel_loaded) {
1173: act_user_to_kernel(thr_act);
1174: /*
1175: * If a user_stack was given, assume this is not a "base"
1176: * activation -- assert that it's fully kernel-loaded
1177: * already.
1178: */
1179: if (thr_act->user_stack != 0) {
1180: thr_act->kernel_loading = FALSE;
1181: thr_act->kernel_loaded = TRUE;
1182: }
1183: }
1184:
1185: task_lock(task);
1186:
1187: /* Chain the thr_act onto the task's list */
1188: mutex_lock(&task->act_list_lock);
1189: queue_enter(&task->thr_acts, thr_act, thread_act_t, thr_acts);
1190: task->thr_act_count++;
1191: /* no need to check for transition from 0 -> 1 here */
1192: task->res_act_count++;
1193: mutex_unlock(&task->act_list_lock);
1194:
1195: task_unlock(task);
1196:
1197: /* Cache the task's map and take a reference to it */
1198: thr_act->map = task->map;
1199:
1200: /* Inline vm_map_reference cause we don't want to increment res_count */
1201: map = task->map;
1202: mutex_lock(&map->s_lock);
1203: #if TASK_SWAPPER
1204: assert(map->res_count > 0);
1205: assert(map->ref_count >= map->res_count);
1206: #endif /* TASK_SWAPPER */
1207: map->ref_count++;
1208: mutex_unlock(&map->s_lock);
1209:
1210: *new_act = thr_act;
1211: return KERN_SUCCESS;
1212: }
1213:
1214: /*
1215: * act_free - called when an thr_act's ref_count drops to zero.
1216: *
1217: * This can only happen when thread is zero (not in use),
1218: * thread_pool is zero (not attached to any thread_pool),
1219: * and active is false (terminated). Called with act locked,
1220: * so that its shuttle pointer can be zeroed atomically.
1221: */
1222: #if MACH_ASSERT
1223: int dangerous_bzero = 1; /* paranoia & safety */
1224: #endif
1225:
1226: void
1227: act_free(thread_act_t thr_act)
1228: {
1229: thread_t thr;
1230: vm_map_t map;
1231: unsigned int ref;
1232:
1233: #if MACH_ASSERT
1234: if (watchacts & WA_EXIT)
1235: printf("act_free(%x(%d)) thr=%x tsk=%x(%d) pport=%x%sactive\n",
1236: thr_act, thr_act->ref_count, thr_act->thread,
1237: thr_act->task,
1238: thr_act->task ? thr_act->task->ref_count : 0,
1239: thr_act->pool_port,
1240: thr_act->active ? " " : " !");
1241: #endif /* MACH_ASSERT */
1242:
1243: /* Drop final ref to shuttle (not really ours, but we're
1244: * allowed to handle it). */
1245: if (thr = thr_act->thread) {
1246: thr_act->thread = 0;
1247: act_unlock(thr_act);
1248: thread_deallocate(thr);
1249: }
1250: else
1251: act_unlock(thr_act);
1252:
1253: #if THREAD_SWAPPER
1254: thread_swap_disable(thr_act);
1255: assert(thr_act->kernel_stack_swapped_in);
1256: #endif /* THREAD_SWAPPER */
1257:
1258: assert(!thr_act->active);
1259: assert(!thr_act->pool_port);
1260:
1261: act_machine_destroy(thr_act);
1262: ipc_thr_act_disable(thr_act);
1263: ipc_thr_act_terminate(thr_act);
1264:
1265: act_prof_deallocate(thr_act);
1266:
1267: /*
1268: * Drop the cached map reference.
1269: * Inline version of vm_map_deallocate() because we
1270: * don't want to decrement the map's residence count here.
1271: */
1272: map = thr_act->map;
1273: mutex_lock(&map->s_lock);
1274: #if TASK_SWAPPER
1275: assert(map->res_count >= 0);
1276: assert(map->ref_count > map->res_count);
1277: #endif /* TASK_SWAPPER */
1278: ref = --map->ref_count;
1279: mutex_unlock(&map->s_lock);
1280:
1281: /*
1282: * The task must still have a reference on the map. Also, if
1283: * the reference count drops to two (one remaining act and the
1284: * task itself), then someone may be waiting in task_halt_wait.
1285: * Wake them up, if needed.
1286: */
1287: if (ref == 0)
1288: panic("thread_deallocate: released last reference on map");
1289: else if (ref == 2)
1290: thread_wakeup(&map->ref_count);
1291:
1292: /* Drop the task reference. */
1293: task_deallocate(thr_act->task);
1294:
1295: #if MACH_ASSERT
1296: if (dangerous_bzero) /* dangerous if we're still using it! */
1297: bzero((char *)thr_act, sizeof(*thr_act));
1298: #endif /* MACH_ASSERT */
1299: /* Put the thr_act back on the thr_act zone */
1300: zfree(thr_act_zone, (vm_offset_t)thr_act);
1301: }
1302:
1303:
1304: /*
1305: * act_attach - Attach an thr_act to the top of a thread ("push the stack").
1306: *
1307: * The thread_shuttle must be either the current one or a brand-new one.
1308: * Assumes the thr_act is active but not in use, also, that if it is
1309: * attached to an thread_pool (i.e. the thread_pool pointer is nonzero),
1310: * the thr_act has already been taken off the thread_pool's list.
1311: *
1312: * Already locked: thr_act plus "appropriate" thread-related locks
1313: * (see act_lock_thread()).
1314: */
1315: void
1316: act_attach(
1317: thread_act_t thr_act,
1318: thread_t thread,
1319: unsigned init_alert_mask)
1320: {
1321: thread_act_t lower;
1322:
1323: #if MACH_ASSERT
1324: assert(thread == current_thread() || thread->top_act == THR_ACT_NULL);
1325: if (watchacts & WA_ACT_LNK)
1326: printf("act_attach(thr_act %x(%d) thread %x(%d) mask %d)\n",
1327: thr_act, thr_act->ref_count, thread, thread->ref_count,
1328: init_alert_mask);
1329: #endif /* MACH_ASSERT */
1330:
1331: /*
1332: * Chain the thr_act onto the thread's thr_act stack.
1333: * Set mask and auto-propagate alerts from below.
1334: */
1335: thr_act->thread = thread;
1336: thr_act->higher = THR_ACT_NULL; /*safety*/
1337: thr_act->alerts = 0;
1338: thr_act->alert_mask = init_alert_mask;
1339: lower = thr_act->lower = thread->top_act;
1340:
1341: if (lower != THR_ACT_NULL) {
1342: lower->higher = thr_act;
1343: thr_act->alerts = (lower->alerts & init_alert_mask);
1344: }
1345:
1346: thread->top_act = thr_act;
1347: }
1348:
1349: /*
1350: * act_detach
1351: *
1352: * Remove the current thr_act from the top of the current thread, i.e.
1353: * "pop the stack". Assumes already locked: thr_act plus "appropriate"
1354: * thread-related locks (see act_lock_thread).
1355: */
1356: void
1357: act_detach(
1358: thread_act_t cur_act)
1359: {
1360: thread_t cur_thread = cur_act->thread;
1361:
1362: #if MACH_ASSERT
1363: if (watchacts & (WA_EXIT|WA_ACT_LNK))
1364: printf("act_detach: thr_act %x(%d), thrd %x(%d) task=%x(%d)\n",
1365: cur_act, cur_act->ref_count,
1366: cur_thread, cur_thread->ref_count,
1367: cur_act->task,
1368: cur_act->task ? cur_act->task->ref_count : 0);
1369: #endif /* MACH_ASSERT */
1370:
1371: /* Unlink the thr_act from the thread's thr_act stack */
1372: cur_thread->top_act = cur_act->lower;
1373: cur_act->thread = 0;
1374:
1375: thread_pool_put_act(cur_act);
1376:
1377: #if MACH_ASSERT
1378: cur_act->lower = cur_act->higher = THR_ACT_NULL;
1379: if (cur_thread->top_act)
1380: cur_thread->top_act->higher = THR_ACT_NULL;
1381: #endif /* MACH_ASSERT */
1382:
1383: return;
1384: }
1385:
1386:
1387: /*
1388: * Synchronize a thread operation with RPC. Called with nothing
1389: * locked. Returns with thr_act locked, plus one of four
1390: * combinations of other locks held:
1391: * none - for new activation not yet associated with thread_pool
1392: * or shuttle
1393: * rpc_lock(thr_act->thread) only - for base activation (one
1394: * without pool_port)
1395: * ip_lock(thr_act->pool_port) only - for empty activation (one
1396: * with no associated shuttle)
1397: * both locks - for "active" activation (has shuttle, lives
1398: * on thread_pool)
1399: * If thr_act has an associated shuttle, this function returns
1400: * its address. Otherwise it returns zero.
1401: */
1402: thread_t
1403: act_lock_thread(
1404: thread_act_t thr_act)
1405: {
1406: ipc_port_t pport;
1407:
1408: /*
1409: * Allow the shuttle cloning code (q.v., when it
1410: * exists :-}) to obtain ip_lock()'s while holding
1411: * an rpc_lock().
1412: */
1413: while (1) {
1414: act_lock(thr_act);
1415: pport = thr_act->pool_port;
1416: if (!pport || ip_lock_try(pport)) {
1417: if (!thr_act->thread)
1418: break;
1419: if (rpc_lock_try(thr_act->thread))
1420: break;
1421: if (pport)
1422: ip_unlock(pport);
1423: }
1424: act_unlock(thr_act);
1425: mutex_pause();
1426: }
1427: return (thr_act->thread);
1428: }
1429:
1430: /*
1431: * Unsynchronize with RPC (i.e., undo an act_lock_thread() call).
1432: * Called with thr_act locked, plus thread locks held that are
1433: * "correct" for thr_act's state. Returns with nothing locked.
1434: */
1435: void
1436: act_unlock_thread(thread_act_t thr_act)
1437: {
1438: if (thr_act->thread)
1439: rpc_unlock(thr_act->thread);
1440: if (thr_act->pool_port)
1441: ip_unlock(thr_act->pool_port);
1442: act_unlock(thr_act);
1443: }
1444:
1445: /*
1446: * Synchronize with RPC given a pointer to a shuttle (instead of an
1447: * activation). Called with nothing locked; returns with all
1448: * "appropriate" thread-related locks held (see act_lock_thread()).
1449: */
1450: thread_act_t
1451: thread_lock_act(
1452: thread_t thread)
1453: {
1454: thread_act_t thr_act;
1455:
1456: while (1) {
1457: rpc_lock(thread);
1458: thr_act = thread->top_act;
1459: if (!thr_act)
1460: break;
1461: if (!act_lock_try(thr_act)) {
1462: rpc_unlock(thread);
1463: mutex_pause();
1464: continue;
1465: }
1466: if (thr_act->pool_port &&
1467: !ip_lock_try(thr_act->pool_port)) {
1468: rpc_unlock(thread);
1469: act_unlock(thr_act);
1470: mutex_pause();
1471: continue;
1472: }
1473: break;
1474: }
1475: return (thr_act);
1476: }
1477:
1478: /*
1479: * Unsynchronize with RPC starting from a pointer to a shuttle.
1480: * Called with RPC-related locks held that are appropriate to
1481: * shuttle's state; any activation is also locked.
1482: */
1483: void
1484: thread_unlock_act(
1485: thread_t thread)
1486: {
1487: thread_act_t thr_act;
1488:
1489: if (thr_act = thread->top_act) {
1490: if (thr_act->pool_port)
1491: ip_unlock(thr_act->pool_port);
1492: act_unlock(thr_act);
1493: }
1494: rpc_unlock(thread);
1495: }
1496:
1497: /*
1498: * switch_act
1499: *
1500: * If a new activation is given, switch to it. If not,
1501: * switch to the lower activation (pop). Returns the old
1502: * activation. This is for RPC support.
1503: */
1504: thread_act_t
1505: switch_act(
1506: thread_act_t act)
1507: {
1508: thread_t thread;
1509: thread_act_t old, new;
1510: unsigned cpu;
1511: spl_t spl;
1512:
1513:
1514: disable_preemption();
1515:
1516: cpu = cpu_number();
1517: thread = current_thread();
1518:
1519: /*
1520: * Find the old and new activation for switch.
1521: */
1522: old = thread->top_act;
1523:
1524: if (act) {
1525: new = act;
1526: new->thread = thread;
1527: }
1528: else {
1529: new = old->lower;
1530: }
1531:
1532: assert(new != THR_ACT_NULL);
1533: #if THREAD_SWAPPER
1534: assert(new->swap_state != TH_SW_OUT &&
1535: new->swap_state != TH_SW_COMING_IN);
1536: #endif /* THREAD_SWAPPER */
1537:
1538: assert(cpu_data[cpu].active_thread == thread);
1539: active_kloaded[cpu] = (new->kernel_loaded) ? new : 0;
1540:
1541: /* This is where all the work happens */
1542: machine_switch_act(thread, old, new, cpu);
1543:
1544: /*
1545: * Push or pop an activation on the chain.
1546: */
1547: if (act) {
1548: act_attach(new, thread, 0);
1549: }
1550: else {
1551: act_detach(old);
1552: }
1553:
1554: enable_preemption();
1555:
1556: return(old);
1557: }
1558:
1559: /*
1560: * install_special_handler
1561: * Install the special returnhandler that handles suspension and
1562: * termination, if it hasn't been installed already.
1563: *
1564: * Already locked: RPC-related locks for thr_act, but not
1565: * scheduling lock (thread_lock()) of the associated thread.
1566: */
1567: void
1568: install_special_handler(
1569: thread_act_t thr_act)
1570: {
1571: spl_t spl;
1572: thread_t thread = thr_act->thread;
1573:
1574: #if MACH_ASSERT
1575: if (watchacts & WA_ACT_HDLR)
1576: printf("act_%x: install_special_hdlr(%x)\n",current_act(),thr_act);
1577: #endif /* MACH_ASSERT */
1578:
1579: spl = splsched();
1580: if (thread)
1581: thread_lock(thread);
1582: install_special_handler_locked(thr_act);
1583: act_set_apc(thr_act);
1584: if (thread)
1585: thread_unlock(thread);
1586: splx(spl);
1587: }
1588:
1589: /*
1590: * install_special_handler_locked
1591: * Do the work of installing the special_handler.
1592: *
1593: * Already locked: RPC-related locks for thr_act, plus the
1594: * scheduling lock (thread_lock()) of the associated thread.
1595: */
1596: void
1597: install_special_handler_locked(
1598: thread_act_t thr_act)
1599: {
1600: ReturnHandler **rh;
1601: thread_t thread = thr_act->thread;
1602:
1603: /* The work handler must always be the last ReturnHandler on the list,
1604: because it can do tricky things like detach the thr_act. */
1605: for (rh = &thr_act->handlers; *rh; rh = &(*rh)->next)
1606: /* */ ;
1607: if (rh != &thr_act->special_handler.next) {
1608: *rh = &thr_act->special_handler;
1609: }
1610: if (thread && thr_act == thread->top_act) {
1611: /*
1612: * Temporarily undepress, so target has
1613: * a chance to do locking required to
1614: * block itself in special_handler().
1615: */
1616: /*** ??? fix me ***/
1617: assert(thread->sp_info != SP_INFO_NULL);
1618: if (((thread->policy == POLICY_TIMESHARE) ||
1619: (thread->policy == POLICY_RR) ||
1620: (thread->policy == POLICY_FIFO)) &&
1621: ((mk_sp_info_t)thread->sp_info)->depress_priority >= 0) {
1622: ((mk_sp_info_t)thread->sp_info)->priority = ((mk_sp_info_t)thread->sp_info)->depress_priority;
1623: /* Use special value -2 to indicate need
1624: * to redepress priority in special_handler
1625: * as thread blocks
1626: */
1627: ((mk_sp_info_t)thread->sp_info)->depress_priority = -2;
1628: compute_priority(thread, FALSE);
1629: }
1630: }
1631: act_set_apc(thr_act);
1632: }
1633:
1634: /*
1635: * JMM -
1636: * These two routines will be enhanced over time to call the general handler registration
1637: * mechanism used by special handlers and alerts. They are hack in for now to avoid
1638: * having to export the gory details of ASTs to the BSD code right now.
1639: */
1640: extern thread_apc_handler_t bsd_ast;
1641:
1642: kern_return_t
1643: thread_apc_set(
1644: thread_act_t thr_act,
1645: thread_apc_handler_t apc)
1646: {
1647: assert(apc == bsd_ast);
1648: thread_ast_set(thr_act, AST_BSD);
1649: if (thr_act == current_act())
1650: ast_propagate(thr_act->ast);
1651: return KERN_SUCCESS;
1652: }
1653:
1654: kern_return_t
1655: thread_apc_clear(
1656: thread_act_t thr_act,
1657: thread_apc_handler_t apc)
1658: {
1659: assert(apc == bsd_ast);
1660: thread_ast_clear(thr_act, AST_BSD);
1661: if (thr_act == current_act())
1662: ast_off(AST_BSD);
1663: return KERN_SUCCESS;
1664: }
1665:
1666: /*
1667: * act_set_thread_pool - Assign an activation to a specific thread_pool.
1668: * Fails if the activation is already assigned to another pool.
1669: * If thread_pool == 0, we remove the thr_act from its thread_pool.
1670: *
1671: * Called the port containing thread_pool already locked.
1672: * Returns the same way.
1673: */
1674: kern_return_t act_set_thread_pool(
1675: thread_act_t thr_act,
1676: ipc_port_t pool_port)
1677: {
1678: thread_pool_t thread_pool;
1679:
1680: #if MACH_ASSERT
1681: if (watchacts & WA_ACT_LNK)
1682: printf("act_set_thread_pool: %x(%d) -> %x\n",
1683: thr_act, thr_act->ref_count, thread_pool);
1684: #endif /* MACH_ASSERT */
1685:
1686: if (pool_port == 0) {
1687: thread_act_t *lact;
1688:
1689: if (thr_act->pool_port == 0)
1690: return KERN_SUCCESS;
1691: thread_pool = &thr_act->pool_port->ip_thread_pool;
1692:
1693: for (lact = &thread_pool->thr_acts; *lact;
1694: lact = &((*lact)->thread_pool_next)) {
1695: if (thr_act == *lact) {
1696: *lact = thr_act->thread_pool_next;
1697: break;
1698: }
1699: }
1700: act_lock(thr_act);
1701: thr_act->pool_port = 0;
1702: thr_act->thread_pool_next = 0;
1703: act_unlock(thr_act);
1704: act_deallocate(thr_act);
1705: return KERN_SUCCESS;
1706: }
1707: if (thr_act->pool_port != pool_port) {
1708: thread_pool = &pool_port->ip_thread_pool;
1709: if (thr_act->pool_port != 0) {
1710: #if MACH_ASSERT
1711: if (watchacts & WA_ACT_LNK)
1712: printf("act_set_thread_pool found %x!\n",
1713: thr_act->pool_port);
1714: #endif /* MACH_ASSERT */
1715: return(KERN_FAILURE);
1716: }
1717: act_lock(thr_act);
1718: thr_act->pool_port = pool_port;
1719:
1720: /* The pool gets a ref to the activation -- have
1721: * to inline operation because thr_act is already
1722: * locked.
1723: */
1724: act_locked_act_reference(thr_act);
1725:
1726: /* If it is available,
1727: * add it to the thread_pool's available-activation list.
1728: */
1729: if ((thr_act->thread == 0) && (thr_act->suspend_count == 0)) {
1730: thr_act->thread_pool_next = thread_pool->thr_acts;
1731: pool_port->ip_thread_pool.thr_acts = thr_act;
1732: if (thread_pool->waiting)
1733: thread_pool_wakeup(thread_pool);
1734: }
1735: act_unlock(thr_act);
1736: }
1737:
1738: return KERN_SUCCESS;
1739: }
1740:
1741: /*
1742: * act_locked_act_set_thread_pool- Assign activation to a specific thread_pool.
1743: * Fails if the activation is already assigned to another pool.
1744: * If thread_pool == 0, we remove the thr_act from its thread_pool.
1745: *
1746: * Called the port containing thread_pool already locked.
1747: * Also called with the thread activation locked.
1748: * Returns the same way.
1749: *
1750: * This routine is the same as `act_set_thread_pool()' except that it does
1751: * not call `act_deallocate(),' which unconditionally tries to obtain the
1752: * thread activation lock.
1753: */
1754: kern_return_t act_locked_act_set_thread_pool(
1755: thread_act_t thr_act,
1756: ipc_port_t pool_port)
1757: {
1758: thread_pool_t thread_pool;
1759:
1760: #if MACH_ASSERT
1761: if (watchacts & WA_ACT_LNK)
1762: printf("act_set_thread_pool: %x(%d) -> %x\n",
1763: thr_act, thr_act->ref_count, thread_pool);
1764: #endif /* MACH_ASSERT */
1765:
1766: if (pool_port == 0) {
1767: thread_act_t *lact;
1768:
1769: if (thr_act->pool_port == 0)
1770: return KERN_SUCCESS;
1771: thread_pool = &thr_act->pool_port->ip_thread_pool;
1772:
1773: for (lact = &thread_pool->thr_acts; *lact;
1774: lact = &((*lact)->thread_pool_next)) {
1775: if (thr_act == *lact) {
1776: *lact = thr_act->thread_pool_next;
1777: break;
1778: }
1779: }
1780:
1781: thr_act->pool_port = 0;
1782: thr_act->thread_pool_next = 0;
1783: act_locked_act_deallocate(thr_act);
1784: return KERN_SUCCESS;
1785: }
1786: if (thr_act->pool_port != pool_port) {
1787: thread_pool = &pool_port->ip_thread_pool;
1788: if (thr_act->pool_port != 0) {
1789: #if MACH_ASSERT
1790: if (watchacts & WA_ACT_LNK)
1791: printf("act_set_thread_pool found %x!\n",
1792: thr_act->pool_port);
1793: #endif /* MACH_ASSERT */
1794: return(KERN_FAILURE);
1795: }
1796: thr_act->pool_port = pool_port;
1797:
1798: /* The pool gets a ref to the activation -- have
1799: * to inline operation because thr_act is already
1800: * locked.
1801: */
1802: act_locked_act_reference(thr_act);
1803:
1804: /* If it is available,
1805: * add it to the thread_pool's available-activation list.
1806: */
1807: if ((thr_act->thread == 0) && (thr_act->suspend_count == 0)) {
1808: thr_act->thread_pool_next = thread_pool->thr_acts;
1809: pool_port->ip_thread_pool.thr_acts = thr_act;
1810: if (thread_pool->waiting)
1811: thread_pool_wakeup(thread_pool);
1812: }
1813: }
1814:
1815: return KERN_SUCCESS;
1816: }
1817:
1818: /*
1819: * Activation control support routines internal to this file:
1820: */
1821:
1822: /*
1823: * act_execute_returnhandlers() - does just what the name says
1824: *
1825: * This is called by system-dependent code when it detects that
1826: * thr_act->handlers is non-null while returning into user mode.
1827: * Activations linked onto an thread_pool always have null thr_act->handlers,
1828: * so RPC entry paths need not check it.
1829: */
1830: void act_execute_returnhandlers(
1831: void)
1832: {
1833: spl_t s;
1834: thread_t thread;
1835: thread_act_t thr_act = current_act();
1836:
1837: #if MACH_ASSERT
1838: if (watchacts & WA_ACT_HDLR)
1839: printf("execute_rtn_hdlrs: thr_act=%x\n", thr_act);
1840: #endif /* MACH_ASSERT */
1841:
1842: s = splsched();
1843: act_clr_apc(thr_act);
1844: spllo();
1845: while (1) {
1846: ReturnHandler *rh;
1847:
1848: /* Grab the next returnhandler */
1849: thread = act_lock_thread(thr_act);
1850: (void)splsched();
1851: thread_lock(thread);
1852: rh = thr_act->handlers;
1853: if (!rh) {
1854: thread_unlock(thread);
1855: splx(s);
1856: act_unlock_thread(thr_act);
1857: return;
1858: }
1859: thr_act->handlers = rh->next;
1860: thread_unlock(thread);
1861: spllo();
1862: act_unlock_thread(thr_act);
1863:
1864: #if MACH_ASSERT
1865: if (watchacts & WA_ACT_HDLR)
1866: printf( (rh == &thr_act->special_handler) ?
1867: "\tspecial_handler\n" : "\thandler=%x\n",
1868: rh->handler);
1869: #endif /* MACH_ASSERT */
1870:
1871: /* Execute it */
1872: (*rh->handler)(rh, thr_act);
1873: }
1874: }
1875:
1876: /*
1877: * special_handler - handles suspension, termination. Called
1878: * with nothing locked. Returns (if it returns) the same way.
1879: */
1880: void
1881: special_handler(
1882: ReturnHandler *rh,
1883: thread_act_t cur_act)
1884: {
1885: spl_t s;
1886: thread_t lthread;
1887: thread_t thread = act_lock_thread(cur_act);
1888: unsigned alert_bits;
1889: exception_data_type_t
1890: codes[EXCEPTION_CODE_MAX];
1891: kern_return_t kr;
1892: kern_return_t exc_kr;
1893:
1894: assert(thread != THREAD_NULL);
1895: #if MACH_ASSERT
1896: if (watchacts & WA_ACT_HDLR)
1897: printf("\t\tspecial_handler(thr_act=%x(%d))\n", cur_act,
1898: (cur_act ? cur_act->ref_count : 0));
1899: #endif /* MACH_ASSERT */
1900:
1901: s = splsched();
1902:
1903: thread_lock(thread);
1904: thread->state &= ~TH_ABORT; /* clear any aborts */
1905: thread_unlock(thread);
1906:
1907: /*
1908: * If someone has killed this invocation,
1909: * invoke the return path with a terminated exception.
1910: */
1911: if (!cur_act->active) {
1912: splx(s);
1913: act_unlock_thread(cur_act);
1914: act_machine_return(KERN_TERMINATED);
1915: }
1916:
1917: splx(s);
1918:
1919: /* strip server terminated bit */
1920: alert_bits = cur_act->alerts & (~SERVER_TERMINATED);
1921:
1922: /* clear server terminated bit */
1923: cur_act->alerts &= ~SERVER_TERMINATED;
1924:
1925: if ( alert_bits ) {
1926: /*
1927: * currently necessary to coordinate with the exception
1928: * code -fdr
1929: */
1930: act_unlock_thread(cur_act);
1931:
1932: /* upcall exception/alert port */
1933: codes[0] = alert_bits;
1934:
1935: /*
1936: * Exception makes a lot of assumptions. If there is no
1937: * exception handler or the exception reply is broken, the
1938: * thread will be terminated and exception will not return. If
1939: * we decide we don't like that behavior, we need to check
1940: * for the existence of an exception port before we call
1941: * exception.
1942: */
1943: exc_kr = alert_exception( EXC_RPC_ALERT, codes, 1 );
1944:
1945: /* clear the orphaned and time constraint indications */
1946: cur_act->alerts &= ~(ORPHANED | TIME_CONSTRAINT_UNSATISFIED);
1947:
1948: /* if this orphaned activation should be terminated... */
1949: if (exc_kr == KERN_RPC_TERMINATE_ORPHAN) {
1950: /*
1951: * ... terminate the activation
1952: *
1953: * This is done in two steps. First, the activation is
1954: * disabled (prepared for termination); second, the
1955: * `special_handler()' is executed again -- this time
1956: * to terminate the activation.
1957: * (`act_disable_task_locked()' arranges for the
1958: * additional execution of the `special_handler().')
1959: */
1960:
1961: #if THREAD_SWAPPER
1962: thread_swap_disable(cur_act);
1963: #endif /* THREAD_SWAPPER */
1964:
1965: /* acquire appropriate locks */
1966: task_lock(cur_act->task);
1967: act_lock_thread(cur_act);
1968:
1969: /* detach the activation from its task */
1970: kr = act_disable_task_locked(cur_act);
1971: assert( kr == KERN_SUCCESS );
1972:
1973: /* release locks */
1974: task_unlock(cur_act->task);
1975: }
1976: else {
1977: /* acquire activation lock again (released below) */
1978: act_lock_thread(cur_act);
1979: s = splsched();
1980: thread_lock(thread);
1981: /*** ??? fix me ***/
1982: assert(thread->sp_info != SP_INFO_NULL);
1983: if (((thread->policy == POLICY_TIMESHARE) ||
1984: (thread->policy == POLICY_RR) ||
1985: (thread->policy == POLICY_FIFO)) &&
1986: ((mk_sp_info_t)thread->sp_info)->depress_priority == -2) {
1987: /* We were temporarily undepressed by
1988: * install_special_handler; restore priority
1989: * depression.
1990: */
1991: ((mk_sp_info_t)thread->sp_info)->depress_priority = ((mk_sp_info_t)thread->sp_info)->priority;
1992: ((mk_sp_info_t)thread->sp_info)->priority = DEPRESSPRI;
1993: thread->sched_pri = DEPRESSPRI;
1994: }
1995: thread_unlock(thread);
1996: splx(s);
1997: }
1998: }
1999:
2000: /*
2001: * If we're suspended, go to sleep and wait for someone to wake us up.
2002: */
2003: if (cur_act->suspend_count) {
2004: if( cur_act->handlers == NULL ) {
2005: assert_wait((event_t)&cur_act->suspend_count,
2006: THREAD_ABORTSAFE);
2007: act_unlock_thread(cur_act);
2008: thread_block((void (*)(void))0);
2009: act_lock_thread(cur_act);
2010: }
2011:
2012: /*
2013: * If we're still (or again) suspended, go to sleep again
2014: * after executing any new handlers that may have appeared.
2015: */
2016: if (cur_act->suspend_count)
2017: install_special_handler(cur_act);
2018: else {
2019: s = splsched();
2020: thread_lock(thread);
2021: /*** ??? fix me ***/
2022: assert(thread->sp_info != SP_INFO_NULL);
2023: if (((thread->policy == POLICY_TIMESHARE) ||
2024: (thread->policy == POLICY_RR) ||
2025: (thread->policy == POLICY_FIFO)) &&
2026: ((mk_sp_info_t)thread->sp_info)->depress_priority == -2) {
2027: /* We were temporarily undepressed by
2028: * install_special_handler; restore priority
2029: * depression.
2030: */
2031: ((mk_sp_info_t)thread->sp_info)->depress_priority = ((mk_sp_info_t)thread->sp_info)->priority;
2032: ((mk_sp_info_t)thread->sp_info)->priority = DEPRESSPRI;
2033: thread->sched_pri = DEPRESSPRI;
2034: }
2035: thread_unlock(thread);
2036: splx(s);
2037: }
2038: }
2039:
2040: act_unlock_thread(cur_act);
2041: }
2042:
2043: /*
2044: * Try to nudge a thr_act into executing its returnhandler chain.
2045: * Ensures that the activation will execute its returnhandlers
2046: * before it next executes any of its user-level code.
2047: *
2048: * Called with thr_act's act_lock() and "appropriate" thread-related
2049: * locks held. (See act_lock_thread().) Returns same way.
2050: */
2051: void
2052: nudge(thread_act_t thr_act)
2053: {
2054: #if MACH_ASSERT
2055: if (watchacts & WA_ACT_HDLR)
2056: printf("\tact_%x: nudge(%x)\n", current_act(), thr_act);
2057: #endif /* MACH_ASSERT */
2058:
2059: /*
2060: * Don't need to do anything at all if this thr_act isn't the topmost.
2061: */
2062: if (thr_act->thread && thr_act->thread->top_act == thr_act) {
2063: /*
2064: * If it's suspended, wake it up.
2065: * This should nudge it even on another CPU.
2066: */
2067: thread_wakeup((event_t)&thr_act->suspend_count);
2068: }
2069: }
2070:
2071: /*
2072: * Update activation that belongs to a task created via kernel_task_create().
2073: */
2074: void
2075: act_user_to_kernel(
2076: thread_act_t thr_act)
2077: {
2078: pcb_user_to_kernel(thr_act);
2079: thr_act->kernel_loading = TRUE;
2080: }
2081:
2082: /*
2083: * Already locked: thr_act->task, RPC-related locks for thr_act
2084: *
2085: * Detach an activation from its task, and prepare it to terminate
2086: * itself.
2087: */
2088: kern_return_t
2089: act_disable_task_locked(
2090: thread_act_t thr_act)
2091: {
2092: thread_t thread = thr_act->thread;
2093: task_t task = thr_act->task;
2094:
2095: #if MACH_ASSERT
2096: if (watchacts & WA_EXIT) {
2097: printf("act_%x: act_disable_tl(thr_act=%x(%d))%sactive task=%x(%d)",
2098: current_act(), thr_act, thr_act->ref_count,
2099: (thr_act->active ? " " : " !"),
2100: thr_act->task, thr_act->task? thr_act->task->ref_count : 0);
2101: if (thr_act->pool_port)
2102: printf(", pool_port %x", thr_act->pool_port);
2103: printf("\n");
2104: (void) dump_act(thr_act);
2105: }
2106: #endif /* MACH_ASSERT */
2107: if (thr_act->thr_acts.next) {
2108: /* Unlink the thr_act from the task's thr_act list,
2109: * so it doesn't appear in calls to task_threads and such.
2110: * The thr_act still keeps its ref on the task, however.
2111: */
2112: #ifdef NOTEVER
2113: mutex_lock(&task->act_list_lock);
2114: #if 1
2115: queue_remove(&task->thr_acts, thr_act, thread_act_t, thr_acts);
2116: #else
2117: thr_act->thr_acts.next->prev = thr_act->thr_acts.prev;
2118: thr_act->thr_acts.prev->next = thr_act->thr_acts.next;
2119: #endif /* 1 */
2120: thr_act->thr_acts.next = 0;
2121: task->thr_act_count--;
2122: #if THREAD_SWAPPER
2123: /*
2124: * Thread is supposed to be unswappable by now...
2125: */
2126: assert(thr_act->swap_state == TH_SW_UNSWAPPABLE ||
2127: !(thread_swap_unwire_stack ||
2128: thread_swap_unwire_user_stack));
2129: #endif /* THREAD_SWAPPER */
2130: task->res_act_count--;
2131: mutex_unlock(&task->act_list_lock);
2132: #endif /* NOTEVER */
2133:
2134: /* This will allow no more control ops on this thr_act. */
2135: thr_act->active = 0;
2136:
2137: /* Clean-up any ulocks that are still owned by the thread
2138: * activation (acquired but not released or handed-off).
2139: */
2140: act_ulock_release_all(thr_act);
2141:
2142: /* If not an empty activation, install special handler */
2143: if (thr_act->thread != THREAD_NULL) {
2144:
2145: /* When the special_handler gets executed,
2146: * it will see the terminated condition and exit
2147: * immediately.
2148: */
2149: install_special_handler(thr_act);
2150: }
2151:
2152: /* If the target happens to be suspended,
2153: * give it a nudge so it can exit.
2154: */
2155: if (thr_act->suspend_count)
2156: nudge(thr_act);
2157: /* Drop the thr_act reference taken for being active.
2158: * (There is still at least one reference left:
2159: * the one we were passed.)
2160: * Inline the deallocate because thr_act is locked.
2161: */
2162: act_locked_act_deallocate(thr_act);
2163: }
2164:
2165: return(KERN_SUCCESS);
2166: }
2167:
2168: /*
2169: * act_alert - Register an alert from this activation.
2170: *
2171: * Each set bit is propagated upward from (but not including) this activation,
2172: * until the top of the chain is reached or the bit is masked.
2173: */
2174: kern_return_t
2175: act_alert(thread_act_t thr_act, unsigned alerts)
2176: {
2177: thread_t thread = act_lock_thread(thr_act);
2178:
2179: #if MACH_ASSERT
2180: if (watchacts & WA_ACT_LNK)
2181: printf("act_alert %x: %x\n", thr_act, alerts);
2182: #endif /* MACH_ASSERT */
2183:
2184: if (thread) {
2185: thread_act_t act_up = thr_act;
2186: while ((alerts) && (act_up != thread->top_act)) {
2187: act_up = act_up->higher;
2188: alerts &= act_up->alert_mask;
2189: act_up->alerts |= alerts;
2190: }
2191: /*
2192: * XXXX If we reach the top, and it is blocked in glue
2193: * code, do something to kick it. XXXX
2194: */
2195: }
2196: act_unlock_thread(thr_act);
2197:
2198: return KERN_SUCCESS;
2199: }
2200:
2201: kern_return_t act_alert_mask(thread_act_t thr_act, unsigned alert_mask)
2202: {
2203: panic("act_alert_mask NOT YET IMPLEMENTED\n");
2204: return KERN_SUCCESS;
2205: }
2206:
2207: typedef struct GetSetState {
2208: struct ReturnHandler rh;
2209: int flavor;
2210: void *state;
2211: int *pcount;
2212: int result;
2213: } GetSetState;
2214:
2215: /* Local Forward decls */
2216: kern_return_t get_set_state(
2217: thread_act_t thr_act, int flavor,
2218: thread_state_t state, int *pcount,
2219: void (*handler)(ReturnHandler *rh, thread_act_t thr_act));
2220: void get_state_handler(ReturnHandler *rh, thread_act_t thr_act);
2221: void set_state_handler(ReturnHandler *rh, thread_act_t thr_act);
2222:
2223: /*
2224: * get_set_state(thr_act ...)
2225: *
2226: * General code to install g/set_state handler.
2227: * Called with thr_act's act_lock() and "appropriate"
2228: * thread-related locks held. (See act_lock_thread().)
2229: */
2230: kern_return_t
2231: get_set_state(thread_act_t thr_act, int flavor, thread_state_t state, int *pcount,
2232: void (*handler)(ReturnHandler *rh, thread_act_t thr_act))
2233: {
2234: GetSetState gss;
2235: spl_t s;
2236:
2237: /* Initialize a small parameter structure */
2238: gss.rh.handler = handler;
2239: gss.flavor = flavor;
2240: gss.state = state;
2241: gss.pcount = pcount;
2242: gss.result = KERN_ABORTED; /* iff wait below is interrupted */
2243:
2244: /* Add it to the thr_act's return handler list */
2245: gss.rh.next = thr_act->handlers;
2246: thr_act->handlers = &gss.rh;
2247:
2248: s = splsched();
2249: act_set_apc(thr_act);
2250: splx(s);
2251:
2252: #if MACH_ASSERT
2253: if (watchacts & WA_ACT_HDLR) {
2254: printf("act_%x: get_set_state(thr_act=%x flv=%x state=%x ptr@%x=%x)",
2255: current_act(), thr_act, flavor, state,
2256: pcount, (pcount ? *pcount : 0));
2257: printf((handler == get_state_handler ? "get_state_hdlr\n" :
2258: (handler == set_state_handler ? "set_state_hdlr\n" :
2259: "hndler=%x\n")), handler);
2260: }
2261: #endif /* MACH_ASSERT */
2262:
2263: assert(thr_act->thread); /* Callers must ensure these */
2264: assert(thr_act != current_act());
2265: for (;;) {
2266: nudge(thr_act);
2267: /*
2268: * Wait must be interruptible to avoid deadlock (e.g.) with
2269: * task_suspend() when caller and target of get_set_state()
2270: * are in same task.
2271: */
2272: assert_wait((event_t)&gss, THREAD_ABORTSAFE);
2273: act_unlock_thread(thr_act);
2274: thread_block((void (*)(void))0);
2275: if (gss.result != KERN_ABORTED)
2276: break;
2277: if (current_act()->handlers)
2278: act_execute_returnhandlers();
2279: act_lock_thread(thr_act);
2280: }
2281:
2282: #if MACH_ASSERT
2283: if (watchacts & WA_ACT_HDLR)
2284: printf("act_%x: get_set_state returns %x\n",
2285: current_act(), gss.result);
2286: #endif /* MACH_ASSERT */
2287:
2288: return gss.result;
2289: }
2290:
2291: void
2292: set_state_handler(ReturnHandler *rh, thread_act_t thr_act)
2293: {
2294: GetSetState *gss = (GetSetState*)rh;
2295:
2296: #if MACH_ASSERT
2297: if (watchacts & WA_ACT_HDLR)
2298: printf("act_%x: set_state_handler(rh=%x,thr_act=%x)\n",
2299: current_act(), rh, thr_act);
2300: #endif /* MACH_ASSERT */
2301:
2302: gss->result = act_machine_set_state(thr_act, gss->flavor,
2303: gss->state, *gss->pcount);
2304: thread_wakeup((event_t)gss);
2305: }
2306:
2307: void
2308: get_state_handler(ReturnHandler *rh, thread_act_t thr_act)
2309: {
2310: GetSetState *gss = (GetSetState*)rh;
2311:
2312: #if MACH_ASSERT
2313: if (watchacts & WA_ACT_HDLR)
2314: printf("act_%x: get_state_handler(rh=%x,thr_act=%x)\n",
2315: current_act(), rh, thr_act);
2316: #endif /* MACH_ASSERT */
2317:
2318: gss->result = act_machine_get_state(thr_act, gss->flavor,
2319: gss->state,
2320: (mach_msg_type_number_t *) gss->pcount);
2321: thread_wakeup((event_t)gss);
2322: }
2323:
2324: kern_return_t
2325: act_get_state_locked(thread_act_t thr_act, int flavor, thread_state_t state,
2326: mach_msg_type_number_t *pcount)
2327: {
2328: #if MACH_ASSERT
2329: if (watchacts & WA_ACT_HDLR)
2330: printf("act_%x: act_get_state_L(thr_act=%x,flav=%x,st=%x,pcnt@%x=%x)\n",
2331: current_act(), thr_act, flavor, state, pcount,
2332: (pcount? *pcount : 0));
2333: #endif /* MACH_ASSERT */
2334:
2335: return(get_set_state(thr_act, flavor, state, (int*)pcount, get_state_handler));
2336: }
2337:
2338: kern_return_t
2339: act_set_state_locked(thread_act_t thr_act, int flavor, thread_state_t state,
2340: mach_msg_type_number_t count)
2341: {
2342: #if MACH_ASSERT
2343: if (watchacts & WA_ACT_HDLR)
2344: printf("act_%x: act_set_state_L(thr_act=%x,flav=%x,st=%x,pcnt@%x=%x)\n",
2345: current_act(), thr_act, flavor, state, count, count);
2346: #endif /* MACH_ASSERT */
2347:
2348: return(get_set_state(thr_act, flavor, state, (int*)&count, set_state_handler));
2349: }
2350:
2351: kern_return_t
2352: act_set_state(thread_act_t thr_act, int flavor, thread_state_t state,
2353: mach_msg_type_number_t count)
2354: {
2355: if (thr_act == THR_ACT_NULL || thr_act == current_act())
2356: return(KERN_INVALID_ARGUMENT);
2357:
2358: if (act_lock_thread(thr_act) == THREAD_NULL) {
2359: act_unlock(thr_act);
2360: return(KERN_INVALID_ARGUMENT);
2361: }
2362: return(act_set_state_locked(thr_act, flavor, state, count));
2363:
2364: }
2365:
2366: kern_return_t
2367: act_get_state(thread_act_t thr_act, int flavor, thread_state_t state,
2368: mach_msg_type_number_t *pcount)
2369: {
2370: if (thr_act == THR_ACT_NULL || thr_act == current_act())
2371: return(KERN_INVALID_ARGUMENT);
2372:
2373: if (act_lock_thread(thr_act) == THREAD_NULL) {
2374: act_unlock(thr_act);
2375: return(KERN_INVALID_ARGUMENT);
2376: }
2377: return(act_get_state_locked(thr_act, flavor, state, pcount));
2378: }
2379:
2380: /*
2381: * These two should be called at splsched()
2382: * Set/clear indicator to run APC (layered on ASTs)
2383: */
2384: void
2385: act_set_apc(thread_act_t thr_act)
2386: {
2387: thread_ast_set(thr_act, AST_APC);
2388: if (thr_act == current_act()) {
2389: mp_disable_preemption();
2390: ast_propagate(thr_act->ast);
2391: mp_enable_preemption();
2392: }
2393: }
2394:
2395: void
2396: act_clr_apc(thread_act_t thr_act)
2397: {
2398: thread_ast_clear(thr_act, AST_APC);
2399: }
2400:
2401: void
2402: act_ulock_release_all(thread_act_t thr_act)
2403: {
2404: ulock_t ulock;
2405:
2406: while (!queue_empty(&thr_act->held_ulocks)) {
2407: ulock = (ulock_t) queue_first(&thr_act->held_ulocks);
2408: (void) lock_make_unstable(ulock, thr_act);
2409: (void) lock_release_internal(ulock, thr_act);
2410: }
2411: }
2412:
2413: /*
2414: * Provide routines (for export to other components) of things that
2415: * are implemented as macros insternally.
2416: */
2417: #undef current_act
2418: thread_act_t
2419: current_act(void)
2420: {
2421: return(current_act_fast());
2422: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.