|
|
1.1 root 1: /*
2: * Copyright (c) 1993,1994 The University of Utah and
3: * the Computer Systems Laboratory (CSL). All rights reserved.
4: *
5: * Permission to use, copy, modify and distribute this software and its
6: * documentation is hereby granted, provided that both the copyright
7: * notice and this permission notice appear in all copies of the
8: * software, derivative works or modified versions, and any portions
9: * thereof, and that both notices appear in supporting documentation.
10: *
11: * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
12: * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
13: * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
14: *
15: * CSL requests users of this software to return to [email protected] any
16: * improvements that they make and grant CSL redistribution rights.
17: *
18: * Author: Bryan Ford, University of Utah CSL
19: */
20: /*
21: * File: act.c
22: *
23: * Activation management routines
24: *
25: */
26:
27: #ifdef MIGRATING_THREADS
28:
1.1.1.3 root 29: #include <string.h>
30:
1.1 root 31: #include <mach/kern_return.h>
32: #include <mach/alert.h>
1.1.1.3 root 33: #include <kern/slab.h>
1.1 root 34: #include <kern/thread.h>
35: #include <kern/task.h>
1.1.1.3 root 36: #include <kern/debug.h>
1.1 root 37: #include <kern/act.h>
38: #include <kern/current.h>
39: #include "ipc_target.h"
40:
41: static void special_handler(ReturnHandler *rh, struct Act *act);
42:
43: #ifdef ACT_STATIC_KLUDGE
44: #undef ACT_STATIC_KLUDGE
45: #define ACT_STATIC_KLUDGE 300
46: #endif
47:
48: #ifndef ACT_STATIC_KLUDGE
1.1.1.3 root 49: static struct kmem_cache act_cache;
1.1 root 50: #else
51: static Act *act_freelist;
52: static Act free_acts[ACT_STATIC_KLUDGE];
53: #endif
54:
55: /* This is a rather special activation
56: which resides at the top and bottom of every thread.
57: When the last "real" activation on a thread is destroyed,
58: the null_act on the bottom gets invoked, destroying the thread.
59: At the top, the null_act acts as an "invalid" cached activation,
60: which will always fail the cached-activation test on RPC paths.
61:
62: As you might expect, most of its members have no particular value.
63: alerts is zero. */
64: Act null_act;
65:
66: void
1.1.1.4 root 67: global_act_init(void)
1.1 root 68: {
69: #ifndef ACT_STATIC_KLUDGE
1.1.1.3 root 70: kmem_cache_init(&act_cache, "Act", sizeof(struct Act), 0,
1.1.1.5 ! root 71: NULL, 0);
1.1 root 72: #else
73: int i;
74:
75: printf("activations: [%x-%x]\n", &free_acts[0], &free_acts[ACT_STATIC_KLUDGE]);
76: act_freelist = &free_acts[0];
77: free_acts[0].ipt_next = 0;
78: for (i = 1; i < ACT_STATIC_KLUDGE; i++) {
79: free_acts[i].ipt_next = act_freelist;
80: act_freelist = &free_acts[i];
81: }
82: /* XXX simple_lock_init(&act_freelist->lock); */
83: #endif
84:
85: #if 0
86: simple_lock_init(&null_act.lock);
87: refcount_init(&null_act.ref_count, 1);
88: #endif
89:
90: act_machine_init();
91: }
92:
93: /* Create a new activation in a specific task.
94: Locking: Task */
95: kern_return_t act_create(task_t task, vm_offset_t user_stack,
96: vm_offset_t user_rbuf, vm_size_t user_rbuf_size,
97: struct Act **new_act)
98: {
99: Act *act;
100:
101: #ifndef ACT_STATIC_KLUDGE
1.1.1.3 root 102: act = (Act*)kmem_cache_alloc(&act_cache);
1.1 root 103: if (act == 0)
104: return(KERN_RESOURCE_SHORTAGE);
105: #else
106: /* XXX ipt_lock(act_freelist); */
107: act = act_freelist;
108: if (act == 0) panic("out of activations");
109: act_freelist = act->ipt_next;
110: /* XXX ipt_unlock(act_freelist); */
111: act->ipt_next = 0;
112: #endif
1.1.1.3 root 113: memset(act, 0, sizeof(*act)); /*XXX shouldn't be needed */
1.1 root 114:
115: #ifdef DEBUG
116: act->lower = act->higher = 0;
117: #endif
118:
119: /* Start with one reference for being active, another for the caller */
120: simple_lock_init(&act->lock);
121: refcount_init(&act->ref_count, 2);
122:
123: /* Latch onto the task. */
124: act->task = task;
125: task_reference(task);
126:
127: /* Other simple setup */
128: act->ipt = 0;
129: act->thread = 0;
130: act->suspend_count = 0;
131: act->active = 1;
132: act->handlers = 0;
133:
134: /* The special_handler will always be last on the returnhandlers list. */
135: act->special_handler.next = 0;
136: act->special_handler.handler = special_handler;
137:
138: ipc_act_init(task, act);
139: act_machine_create(task, act, user_stack, user_rbuf, user_rbuf_size);
140:
141: task_lock(task);
142:
143: /* Chain the act onto the task's list */
144: act->task_links.next = task->acts.next;
145: act->task_links.prev = &task->acts;
146: task->acts.next->prev = &act->task_links;
147: task->acts.next = &act->task_links;
148: task->act_count++;
149:
150: task_unlock(task);
151:
152: *new_act = act;
153: return KERN_SUCCESS;
154: }
155:
156: /* This is called when an act's ref_count drops to zero.
157: This can only happen when thread is zero (not in use),
158: ipt is zero (not attached to any ipt),
159: and active is false (terminated). */
160: static void act_free(Act *inc)
161: {
162: act_machine_destroy(inc);
163: ipc_act_destroy(inc);
164:
165: /* Drop the task reference. */
166: task_deallocate(inc->task);
167:
1.1.1.3 root 168: /* Put the act back on the act cache */
1.1 root 169: #ifndef ACT_STATIC_KLUDGE
1.1.1.3 root 170: kmem_cache_free(&act_cache, (vm_offset_t)inc);
1.1 root 171: #else
172: /* XXX ipt_lock(act_freelist); */
173: inc->ipt_next = act_freelist;
174: act_freelist = inc;
175: /* XXX ipt_unlock(act_freelist); */
176: #endif
177: }
178:
179: void act_deallocate(Act *inc)
180: {
181: refcount_drop(&inc->ref_count, act_free(inc));
182: }
183:
184: /* Attach an act to the top of a thread ("push the stack").
185: The thread must be either the current one or a brand-new one.
186: Assumes the act is active but not in use.
187: Assumes that if it is attached to an ipt (i.e. the ipt pointer is nonzero),
188: the act has already been taken off the ipt's list.
189:
190: Already locked: cur_thread, act */
191: void act_attach(Act *act, thread_t thread, unsigned init_alert_mask)
192: {
193: Act *lower;
194:
195: act->thread = thread;
196:
197: /* The thread holds a reference to the activation while using it. */
198: refcount_take(&act->ref_count);
199:
200: /* XXX detach any cached activations from above the target */
201:
202: /* Chain the act onto the thread's act stack. */
203: lower = thread->top_act;
204: act->lower = lower;
205: lower->higher = act;
206: thread->top_act = act;
207:
208: act->alert_mask = init_alert_mask;
209: act->alerts = lower->alerts & init_alert_mask;
210: }
211:
212: /* Remove the current act from the top of the current thread ("pop the stack").
213: Return it to the ipt it lives on, if any.
214: Locking: Thread > Act(not on ipt) > ipc_target */
215: void act_detach(Act *cur_act)
216: {
217: thread_t cur_thread = cur_act->thread;
218:
219: thread_lock(cur_thread);
220: act_lock(cur_act);
221:
222: /* Unlink the act from the thread's act stack */
223: cur_thread->top_act = cur_act->lower;
224: cur_act->thread = 0;
225: #ifdef DEBUG
226: cur_act->lower = cur_act->higher = 0;
227: #endif
228:
229: thread_unlock(cur_thread);
230:
231: /* Return it to the ipt's list */
232: if (cur_act->ipt)
233: {
234: ipt_lock(cur_act->ipt);
235: cur_act->ipt_next = cur_act->ipt->ipt_acts;
236: cur_act->ipt->ipt_acts = cur_act;
237: ipt_unlock(cur_act->ipt);
238: #if 0
239: printf(" return to ipt %x\n", cur_act->ipt);
240: #endif
241: }
242:
243: act_unlock(cur_act);
244:
245: /* Drop the act reference taken for being in use. */
246: refcount_drop(&cur_act->ref_count, act_free(cur_act));
247: }
248:
249:
250:
251: /*** Activation control support routines ***/
252:
253: /* This is called by system-dependent code
254: when it detects that act->handlers is non-null
255: while returning into user mode.
256: Activations linked onto an ipt always have null act->handlers,
257: so RPC entry paths need not check it.
258:
259: Locking: Act */
1.1.1.4 root 260: void act_execute_returnhandlers(void)
1.1 root 261: {
262: Act *act = current_act();
263:
264: #if 0
265: printf("execute_returnhandlers\n");
266: #endif
267: while (1) {
268: ReturnHandler *rh;
269:
270: /* Grab the next returnhandler */
271: act_lock(act);
272: rh = act->handlers;
273: if (!rh) {
274: act_unlock(act);
275: return;
276: }
277: act->handlers = rh->next;
278: act_unlock(act);
279:
280: /* Execute it */
281: (*rh->handler)(rh, act);
282: }
283: }
284:
285: /* Try to nudge an act into executing its returnhandler chain.
286: Ensures that the activation will execute its returnhandlers
287: before it next executes any of its user-level code.
288: Also ensures that it is safe to break the thread's activation chain
289: immediately above this activation,
290: by rolling out of any outstanding two-way-optimized RPC.
291:
292: The target activation is not necessarily active
293: or even in use by a thread.
294: If it isn't, this routine does nothing.
295:
296: Already locked: Act */
297: static void act_nudge(struct Act *act)
298: {
299: /* If it's suspended, wake it up. */
300: thread_wakeup(&act->suspend_count);
301:
302: /* Do a machine-dependent low-level nudge.
303: If we're on a multiprocessor,
304: this may mean sending an interprocessor interrupt.
305: In any case, it means rolling out of two-way-optimized RPC paths. */
306: act_machine_nudge(act);
307: }
308:
309: /* Install the special returnhandler that handles suspension and termination,
310: if it hasn't been installed already.
311:
312: Already locked: Act */
313: static void install_special_handler(struct Act *act)
314: {
315: ReturnHandler **rh;
316:
317: /* The work handler must always be the last ReturnHandler on the list,
318: because it can do tricky things like detach the act. */
319: for (rh = &act->handlers; *rh; rh = &(*rh)->next);
320: if (rh != &act->special_handler.next) {
321: *rh = &act->special_handler;
322: }
323:
324: /* Nudge the target activation,
325: to ensure that it will see the returnhandler we're adding. */
326: act_nudge(act);
327: }
328:
329: /* Locking: Act */
330: static void special_handler(ReturnHandler *rh, struct Act *cur_act)
331: {
332: retry:
333:
334: act_lock(cur_act);
335:
336: /* If someone has killed this invocation,
337: invoke the return path with a terminated exception. */
338: if (!cur_act->active) {
339: act_unlock(cur_act);
340: act_machine_return(KERN_TERMINATED);
341: /* XXX should just set the activation's reentry_routine
342: and then return from special_handler().
343: The magic reentry_routine should just pop its own activation
344: and chain to the reentry_routine of the _lower_ activation.
345: If that lower activation is the null_act,
346: the thread will then be terminated. */
347: }
348:
349: /* If we're suspended, go to sleep and wait for someone to wake us up. */
350: if (cur_act->suspend_count) {
351: act_unlock(cur_act);
352: /* XXX mp unsafe */
353: thread_wait((int)&cur_act->suspend_count, FALSE);
354:
355: act_lock(cur_act);
356:
357: /* If we're still (or again) suspended,
358: go to sleep again after executing any new returnhandlers that may have appeared. */
359: if (cur_act->suspend_count)
360: install_special_handler(cur_act);
361: }
362:
363: act_unlock(cur_act);
364: }
365:
366: #if 0 /************************ OLD SEMI-OBSOLETE CODE *********************/
367: static __dead void act_throughcall_return(Act *act)
368: {
369: /* Done - destroy the act and return */
370: act_detach(act);
371: act_terminate(act);
372: act_deallocate(act);
373:
374: /* XXX */
375: thread_terminate_self();
376: }
377:
378: __dead void act_throughcall(task_t task, void (*infunc)())
379: {
380: thread_t thread = current_thread();
381: Act *act;
382: ReturnHandler rh;
383: int rc;
384:
385: rc = act_create(task, 0, 0, 0, &act);
386: if (rc) return rc;
387:
388: act->return_routine = act_throughcall_return;
389:
390: thread_lock(thread);
391: act_lock(act);
392:
393: act_attach(thread, act, 0);
394:
395: rh.handler = infunc;
396: rh.next = act->handlers;
397: act->handlers = &rh;
398:
399: act_unlock(act);
400: thread_unlock(thread);
401:
402: /* Call through the act into the returnhandler list */
403: act_machine_throughcall(act);
404: }
405:
406:
407: /* Grab an act from the specified pool, to pass to act_upcall.
408: Returns with the act locked, since it's in an inconsistent state
409: (not on its ipt but not on a thread either).
410: Returns null if no acts are available on the ipt.
411:
412: Locking: ipc_target > Act(on ipt) */
413: Act *act_grab(struct ipc_target *ipt)
414: {
415: Act *act;
416:
417: ipt_lock(ipt);
418:
419: retry:
420:
421: /* Pull an act off the ipt's list. */
422: act = ipt->acts;
423: if (!act)
424: goto none_avail;
425: ipt->acts = act->ipt_next;
426:
427: act_lock(act);
428:
429: /* If it's been terminated, drop it and get another one. */
430: if (!act->active) {
431: #if 0
432: printf("dropping terminated act %08x\n", act);
433: #endif
434: /* XXX ipt_deallocate(ipt); */
435: act->ipt = 0;
436: act_unlock(act);
437: act_deallocate(act);
438: goto retry;
439: }
440:
441: none_avail:
442: ipt_unlock(ipt);
443:
444: return act;
445: }
446:
447: /* Try to make an upcall with an act on the specified ipt.
448: If the ipt is empty, returns KERN_RESOURCE_SHORTAGE. XXX???
449:
450: Locking: ipc_target > Act > Thread */
451: kern_return_t act_upcall(struct Act *act, unsigned init_alert_mask,
452: vm_offset_t user_entrypoint, vm_offset_t user_data)
453: {
454: thread_t cur_thread = current_thread();
455: int rc;
456:
457: /* XXX locking */
458:
459: act_attach(cur_thread, act, init_alert_mask);
460:
461: /* Make the upcall into the destination task */
462: rc = act_machine_upcall(act, user_entrypoint, user_data);
463:
464: /* Done - detach the act and return */
465: act_detach(act);
466:
467: return rc;
468: }
469: #endif /************************ END OF OLD SEMI-OBSOLETE CODE *********************/
470:
471:
472:
473:
474: /*** Act service routines ***/
475:
476: /* Lock this act and its current thread.
477: We can only find the thread from the act
478: and the thread must be locked before the act,
479: requiring a little icky juggling.
480:
481: If the thread is not currently on any thread,
482: returns with only the act locked.
483:
484: Note that this routine is not called on any performance-critical path.
485: It is only for explicit act operations
486: which don't happen often.
487:
488: Locking: Thread > Act */
489: static thread_t act_lock_thread(Act *act)
490: {
491: thread_t thread;
492:
493: retry:
494:
495: /* Find the thread */
496: act_lock(act);
497: thread = act->thread;
498: if (thread == 0)
499: {
500: act_unlock(act);
501: return 0;
502: }
503: thread_reference(thread);
504: act_unlock(act);
505:
506: /* Lock the thread and re-lock the act,
507: and make sure the thread didn't change. */
508: thread_lock(thread);
509: act_lock(act);
510: if (act->thread != thread)
511: {
512: act_unlock(act);
513: thread_unlock(thread);
514: thread_deallocate(thread);
515: goto retry;
516: }
517:
518: thread_deallocate(thread);
519:
520: return thread;
521: }
522:
523: /* Already locked: act->task
524: Locking: Task > Act */
525: kern_return_t act_terminate_task_locked(struct Act *act)
526: {
527: act_lock(act);
528:
529: if (act->active)
530: {
531: /* Unlink the act from the task's act list,
532: so it doesn't appear in calls to task_acts and such.
533: The act still keeps its ref on the task, however,
534: until it loses all its own references and is freed. */
535: act->task_links.next->prev = act->task_links.prev;
536: act->task_links.prev->next = act->task_links.next;
537: act->task->act_count--;
538:
539: /* Remove it from any ipc_target. XXX is this right? */
540: act_set_target(act, 0);
541:
542: /* This will allow no more control operations on this act. */
543: act->active = 0;
544:
545: /* When the special_handler gets executed,
546: it will see the terminated condition and exit immediately. */
547: install_special_handler(act);
548:
549: /* Drop the act reference taken for being active.
550: (There is still at least one reference left: the one we were passed.) */
551: act_deallocate(act);
552: }
553:
554: act_unlock(act);
555:
556: return KERN_SUCCESS;
557: }
558:
559: /* Locking: Task > Act */
560: kern_return_t act_terminate(struct Act *act)
561: {
562: task_t task = act->task;
563: kern_return_t rc;
564:
565: /* act->task never changes,
566: so we can read it before locking the act. */
567: task_lock(act->task);
568:
569: rc = act_terminate_task_locked(act);
570:
571: task_unlock(act->task);
572:
573: return rc;
574: }
575:
576: /* If this Act is on a Thread and is not the topmost,
577: yank it and everything below it off of the thread's stack
578: and put it all on a new thread forked from the original one.
579: May fail due to resource shortage, but can always be retried.
580:
581: Locking: Thread > Act */
582: kern_return_t act_yank(Act *act)
583: {
584: thread_t thread = act_lock_thread(act);
585:
586: #if 0
587: printf("act_yank inc %08x thread %08x\n", act, thread);
588: #endif
589: if (thread)
590: {
591: if (thread->top_act != act)
592: {
593: printf("detaching act %08x from thread %08x\n", act, thread);
594:
595: /* Nudge the activation into a clean point for detachment. */
596: act_nudge(act);
597:
598: /* Now detach the activation
599: and give the orphan its own flow of control. */
600: /*XXX*/
601: }
602:
603: thread_unlock(thread);
604: }
605: act_unlock(act);
606:
607: /* Ask the thread to return as quickly as possible,
608: because its results are now useless. */
609: act_abort(act);
610:
611: return KERN_SUCCESS;
612: }
613:
614: /* Assign an activation to a specific ipc_target.
615: Fails if the activation is already assigned to another pool.
616: If ipt == 0, we remove the from its ipt.
617:
618: Locking: Act(not on ipt) > ipc_target > Act(on ipt) */
619: kern_return_t act_set_target(Act *act, struct ipc_target *ipt)
620: {
621: act_lock(act);
622:
623: if (ipt == 0)
624: {
625: Act **lact;
626:
627: ipt = act->ipt;
628: if (ipt == 0)
629: return;
630:
631: /* XXX This is a violation of the locking order. */
632: ipt_lock(ipt);
633: for (lact = &ipt->ipt_acts; *lact; lact = &((*lact)->ipt_next))
634: if (act == *lact)
635: {
636: *lact = act->ipt_next;
637: break;
638: }
639: ipt_unlock(ipt);
640:
641: act->ipt = 0;
642: /* XXX ipt_deallocate(ipt); */
643: act_deallocate(act);
644: return;
645: }
646: if (act->ipt != ipt)
647: {
648: if (act->ipt != 0)
649: {
650: act_unlock(act);
651: return KERN_FAILURE; /*XXX*/
652: }
653: act->ipt = ipt;
654: ipt->ipt_type |= IPT_TYPE_MIGRATE_RPC;
655:
656: /* They get references to each other. */
657: act_reference(act);
658: ipt_reference(ipt);
659:
660: /* If it is available,
661: add it to the ipt's available-activation list. */
662: if ((act->thread == 0) && (act->suspend_count == 0))
663: {
664: ipt_lock(ipt);
665: act->ipt_next = ipt->ipt_acts;
666: act->ipt->ipt_acts = act;
667: ipt_unlock(ipt);
668: }
669: }
670: act_unlock(act);
671:
672: return KERN_SUCCESS;
673: }
674:
675: /* Register an alert from this activation.
676: Each set bit is propagated upward from (but not including) this activation,
677: until the top of the chain is reached or the bit is masked.
678:
679: Locking: Thread > Act */
680: kern_return_t act_alert(struct Act *act, unsigned alerts)
681: {
682: thread_t thread = act_lock_thread(act);
683:
684: #if 0
685: printf("act_alert %08x: %08x\n", act, alerts);
686: #endif
687: if (thread)
688: {
689: struct Act *act_up = act;
690: while ((alerts) && (act_up != thread->top_act))
691: {
692: act_up = act_up->higher;
693: alerts &= act_up->alert_mask;
694: act_up->alerts |= alerts;
695: }
696:
697: /* XXX If we reach the top, and it is blocked in glue code, do something. */
698:
699: thread_unlock(thread);
700: }
701: act_unlock(act);
702:
703: return KERN_SUCCESS;
704: }
705:
706: /* Locking: Thread > Act */
707: kern_return_t act_abort(struct Act *act)
708: {
709: return act_alert(act, ALERT_ABORT_STRONG);
710: }
711:
712: /* Locking: Thread > Act */
713: kern_return_t act_abort_safely(struct Act *act)
714: {
715: return act_alert(act, ALERT_ABORT_SAFE);
716: }
717:
718: /* Locking: Thread > Act */
719: kern_return_t act_alert_mask(struct Act *act, unsigned alert_mask)
720: {
721: panic("act_alert_mask\n");
722: return KERN_SUCCESS;
723: }
724:
725: /* Locking: Thread > Act */
726: kern_return_t act_suspend(struct Act *act)
727: {
728: thread_t thread = act_lock_thread(act);
729: kern_return_t rc = KERN_SUCCESS;
730:
731: #if 0
732: printf("act_suspend %08x\n", act);
733: #endif
734: if (act->active)
735: {
736: if (act->suspend_count++ == 0)
737: {
738: /* XXX remove from ipt */
739: install_special_handler(act);
740: act_nudge(act);
741: }
742: }
743: else
744: rc = KERN_TERMINATED;
745:
746: if (thread)
747: thread_unlock(thread);
748: act_unlock(act);
749:
750: return rc;
751: }
752:
753: /* Locking: Act */
754: kern_return_t act_resume(struct Act *act)
755: {
756: #if 0
757: printf("act_resume %08x from %d\n", act, act->suspend_count);
758: #endif
759:
760: act_lock(act);
761: if (!act->active)
762: {
763: act_unlock(act);
764: return KERN_TERMINATED;
765: }
766:
767: if (act->suspend_count > 0) {
768: if (--act->suspend_count == 0) {
769: thread_wakeup(&act->suspend_count);
770: /* XXX return to ipt */
771: }
772: }
773:
774: act_unlock(act);
775:
776: return KERN_SUCCESS;
777: }
778:
779: typedef struct GetSetState {
780: struct ReturnHandler rh;
781: int flavor;
782: void *state;
783: int *pcount;
784: int result;
785: } GetSetState;
786:
787: /* Locking: Thread */
788: kern_return_t get_set_state(struct Act *act, int flavor, void *state, int *pcount,
789: void (*handler)(ReturnHandler *rh, struct Act *act))
790: {
791: GetSetState gss;
792:
793: /* Initialize a small parameter structure */
794: gss.rh.handler = handler;
795: gss.flavor = flavor;
796: gss.state = state;
797: gss.pcount = pcount;
798:
799: /* Add it to the act's return handler list */
800: act_lock(act);
801: gss.rh.next = act->handlers;
802: act->handlers = &gss.rh;
803:
804: act_nudge(act);
805:
806: act_unlock(act);
807: /* XXX mp unsafe */
808: thread_wait((int)&gss, 0); /* XXX could be interruptible */
809:
810: return gss.result;
811: }
812:
813: static void get_state_handler(ReturnHandler *rh, struct Act *act)
814: {
815: GetSetState *gss = (GetSetState*)rh;
816:
817: gss->result = act_machine_get_state(act, gss->flavor, gss->state, gss->pcount);
818: thread_wakeup((int)gss);
819: }
820:
821: /* Locking: Thread */
822: kern_return_t act_get_state(struct Act *act, int flavor, natural_t *state, natural_t *pcount)
823: {
824: return get_set_state(act, flavor, state, pcount, get_state_handler);
825: }
826:
827: static void set_state_handler(ReturnHandler *rh, struct Act *act)
828: {
829: GetSetState *gss = (GetSetState*)rh;
830:
831: gss->result = act_machine_set_state(act, gss->flavor, gss->state, *gss->pcount);
832: thread_wakeup((int)gss);
833: }
834:
835: /* Locking: Thread */
836: kern_return_t act_set_state(struct Act *act, int flavor, natural_t *state, natural_t count)
837: {
838: return get_set_state(act, flavor, state, &count, set_state_handler);
839: }
840:
841:
842:
843: /*** backward compatibility hacks ***/
844:
845: #include <mach/thread_info.h>
846: #include <mach/thread_special_ports.h>
847: #include <ipc/ipc_port.h>
848:
849: kern_return_t act_thread_info(Act *act, int flavor,
850: thread_info_t thread_info_out, unsigned *thread_info_count)
851: {
852: return thread_info(act->thread, flavor, thread_info_out, thread_info_count);
853: }
854:
855: kern_return_t
856: act_thread_assign(Act *act, processor_set_t new_pset)
857: {
858: return thread_assign(act->thread, new_pset);
859: }
860:
861: kern_return_t
862: act_thread_assign_default(Act *act)
863: {
864: return thread_assign_default(act->thread);
865: }
866:
867: kern_return_t
868: act_thread_get_assignment(Act *act, processor_set_t *pset)
869: {
870: return thread_get_assignment(act->thread, pset);
871: }
872:
873: kern_return_t
874: act_thread_priority(Act *act, int priority, boolean_t set_max)
875: {
876: return thread_priority(act->thread, priority, set_max);
877: }
878:
879: kern_return_t
880: act_thread_max_priority(Act *act, processor_set_t *pset, int max_priority)
881: {
882: return thread_max_priority(act->thread, pset, max_priority);
883: }
884:
885: kern_return_t
886: act_thread_policy(Act *act, int policy, int data)
887: {
888: return thread_policy(act->thread, policy, data);
889: }
890:
891: kern_return_t
892: act_thread_wire(struct host *host, Act *act, boolean_t wired)
893: {
894: return thread_wire(host, act->thread, wired);
895: }
896:
897: kern_return_t
898: act_thread_depress_abort(Act *act)
899: {
900: return thread_depress_abort(act->thread);
901: }
902:
903: /*
904: * Routine: act_get_special_port [kernel call]
905: * Purpose:
906: * Clones a send right for one of the thread's
907: * special ports.
908: * Conditions:
909: * Nothing locked.
910: * Returns:
911: * KERN_SUCCESS Extracted a send right.
912: * KERN_INVALID_ARGUMENT The thread is null.
913: * KERN_FAILURE The thread is dead.
914: * KERN_INVALID_ARGUMENT Invalid special port.
915: */
916:
917: kern_return_t
918: act_get_special_port(Act *act, int which, ipc_port_t *portp)
919: {
920: ipc_port_t *whichp;
921: ipc_port_t port;
922:
923: #if 0
924: printf("act_get_special_port\n");
925: #endif
926: if (act == 0)
927: return KERN_INVALID_ARGUMENT;
928:
929: switch (which) {
930: case THREAD_KERNEL_PORT:
931: whichp = &act->self_port;
932: break;
933:
934: case THREAD_EXCEPTION_PORT:
935: whichp = &act->exception_port;
936: break;
937:
938: default:
939: return KERN_INVALID_ARGUMENT;
940: }
941:
942: thread_lock(act->thread);
943:
944: if (act->self_port == IP_NULL) {
945: thread_unlock(act->thread);
946: return KERN_FAILURE;
947: }
948:
949: port = ipc_port_copy_send(*whichp);
950: thread_unlock(act->thread);
951:
952: *portp = port;
953: return KERN_SUCCESS;
954: }
955:
956: /*
957: * Routine: act_set_special_port [kernel call]
958: * Purpose:
959: * Changes one of the thread's special ports,
960: * setting it to the supplied send right.
961: * Conditions:
962: * Nothing locked. If successful, consumes
963: * the supplied send right.
964: * Returns:
965: * KERN_SUCCESS Changed the special port.
966: * KERN_INVALID_ARGUMENT The thread is null.
967: * KERN_FAILURE The thread is dead.
968: * KERN_INVALID_ARGUMENT Invalid special port.
969: */
970:
971: kern_return_t
972: act_set_special_port(Act *act, int which, ipc_port_t port)
973: {
974: ipc_port_t *whichp;
975: ipc_port_t old;
976:
977: #if 0
978: printf("act_set_special_port\n");
979: #endif
980: if (act == 0)
981: return KERN_INVALID_ARGUMENT;
982:
983: switch (which) {
984: case THREAD_KERNEL_PORT:
985: whichp = &act->self_port;
986: break;
987:
988: case THREAD_EXCEPTION_PORT:
989: whichp = &act->exception_port;
990: break;
991:
992: default:
993: return KERN_INVALID_ARGUMENT;
994: }
995:
996: thread_lock(act->thread);
997: if (act->self_port == IP_NULL) {
998: thread_unlock(act->thread);
999: return KERN_FAILURE;
1000: }
1001:
1002: old = *whichp;
1003: *whichp = port;
1004: thread_unlock(act->thread);
1005:
1006: if (IP_VALID(old))
1007: ipc_port_release_send(old);
1008: return KERN_SUCCESS;
1009: }
1010:
1011: /*
1012: * XXX lame, non-blocking ways to get/set state.
1013: * Return thread's machine-dependent state.
1014: */
1015: kern_return_t
1.1.1.4 root 1016: act_get_state_immediate(
1017: Act *act,
1018: int flavor,
1019: void *old_state, /* pointer to OUT array */
1020: unsigned int *old_state_count) /*IN/OUT*/
1.1 root 1021: {
1022: kern_return_t ret;
1023:
1024: act_lock(act);
1025: /* not the top activation, return current state */
1026: if (act->thread && act->thread->top_act != act) {
1027: ret = act_machine_get_state(act, flavor,
1028: old_state, old_state_count);
1029: act_unlock(act);
1030: return ret;
1031: }
1032: act_unlock(act);
1033:
1034: /* not sure this makes sense */
1035: return act_get_state(act, flavor, old_state, old_state_count);
1036: }
1037:
1038: /*
1039: * Change thread's machine-dependent state.
1040: */
1041: kern_return_t
1.1.1.4 root 1042: act_set_state_immediate(
1043: Act *act,
1044: int flavor,
1045: void *new_state,
1046: unsigned int new_state_count)
1.1 root 1047: {
1048: kern_return_t ret;
1049:
1050: act_lock(act);
1051: /* not the top activation, set it now */
1052: if (act->thread && act->thread->top_act != act) {
1053: ret = act_machine_set_state(act, flavor,
1054: new_state, new_state_count);
1055: act_unlock(act);
1056: return ret;
1057: }
1058: act_unlock(act);
1059:
1060: /* not sure this makes sense */
1061: return act_set_state(act, flavor, new_state, new_state_count);
1062: }
1063:
1.1.1.4 root 1064: void act_count(void)
1.1 root 1065: {
1066: int i;
1067: Act *act;
1068: static int amin = ACT_STATIC_KLUDGE;
1069:
1070: i = 0;
1071: for (act = act_freelist; act; act = act->ipt_next)
1072: i++;
1073: if (i < amin)
1074: amin = i;
1075: printf("%d of %d activations in use, %d max\n",
1076: ACT_STATIC_KLUDGE-i, ACT_STATIC_KLUDGE, ACT_STATIC_KLUDGE-amin);
1077: }
1078:
1.1.1.4 root 1079: void dump_act(act)
1.1 root 1080: Act *act;
1081: {
1082: act_count();
1083: kact_count();
1084: while (act) {
1085: printf("%08.8x: thread=%x, task=%x, hi=%x, lo=%x, ref=%x\n",
1086: act, act->thread, act->task,
1087: act->higher, act->lower, act->ref_count);
1088: printf("\talerts=%x, mask=%x, susp=%x, active=%x\n",
1089: act->alerts, act->alert_mask,
1090: act->suspend_count, act->active);
1091: machine_dump_act(&act->mact);
1092: if (act == act->lower)
1093: break;
1094: act = act->lower;
1095: }
1096: }
1097:
1098: #ifdef ACTWATCH
1099: Act *
1.1.1.4 root 1100: get_next_act(int sp)
1.1 root 1101: {
1102: static int i;
1103: Act *act;
1104:
1105: while (1) {
1106: if (i == ACT_STATIC_KLUDGE) {
1107: i = 0;
1108: return 0;
1109: }
1110: act = &free_acts[i];
1111: i++;
1112: if (act->mact.space == sp)
1113: return act;
1114: }
1115: }
1.1.1.4 root 1116: #endif /* ACTWATCH */
1.1 root 1117:
1118: #endif /* MIGRATING_THREADS */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.