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