00001 /* 00002 (c) copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands. 00003 See the copyright notice in the ACK home directory, in the file "Copyright". 00004 */ 00005 00006 /* 00007 Module: SYSTEM 00008 Author: Ceriel J.H. Jacobs 00009 Version: $Header$ 00010 */ 00011 00012 /* 00013 An implementation of the Modula-2 NEWPROCESS and TRANSFER facilities 00014 using the topsize, topsave, and topload facilities. 00015 For each coroutine, a proc structure is built. For the main routine, 00016 a static space is declared to save its stack. For the other coroutines, 00017 the user specifies this space. 00018 */ 00019 00020 #include <m2_traps.h> 00021 00022 #define MAXMAIN 2048 00023 00024 struct proc { 00025 unsigned size; /* size of saved stackframe(s) */ 00026 int (*proc)(); /* address of coroutine procedure */ 00027 char *brk; /* stack break of this coroutine */ 00028 }; 00029 00030 extern unsigned topsize(); 00031 00032 static struct proc mainproc[MAXMAIN/sizeof(struct proc) + 1]; 00033 00034 static struct proc *curproc = 0;/* current coroutine */ 00035 extern char *MainLB; /* stack break of main routine */ 00036 00037 _SYSTEM__NEWPROCESS(p, a, n, p1) 00038 int (*p)(); /* coroutine procedure */ 00039 struct proc *a; /* pointer to area for saved stack-frame */ 00040 unsigned n; /* size of this area */ 00041 struct proc **p1; /* where to leave coroutine descriptor, 00042 in this implementation the address of 00043 the area for saved stack-frame(s) */ 00044 { 00045 /* This procedure creates a new coroutine, but does not 00046 transfer control to it. The routine "topsize" will compute the 00047 stack break, which will be the local base of this routine. 00048 Notice that we can do this because we do not need the stack 00049 above this point for this coroutine. In Modula-2, coroutines 00050 must be level 0 procedures without parameters. 00051 */ 00052 char *brk = 0; 00053 unsigned sz = topsize(&brk); 00054 00055 if (sz + sizeof(struct proc) > n) { 00056 /* not enough space */ 00057 TRP(M2_TOOLARGE); 00058 } 00059 a->size = n; 00060 a->proc = p; 00061 a->brk = brk; 00062 *p1 = a; 00063 if (topsave(brk, a+1)) 00064 /* stack frame saved; now just return */ 00065 ; 00066 else { 00067 /* We get here through the first transfer to the coroutine 00068 created above. 00069 This also means that curproc is now set to this coroutine. 00070 We cannot trust the parameters anymore. 00071 Just call the coroutine procedure. 00072 */ 00073 (*(curproc->proc))(); 00074 _cleanup(); 00075 _exit(0); 00076 } 00077 } 00078 00079 _SYSTEM__TRANSFER(a, b) 00080 struct proc **a, **b; 00081 { 00082 /* transfer from one coroutine to another, saving the current 00083 descriptor in the space indicated by "a", and transfering to 00084 the coroutine in descriptor "b". 00085 */ 00086 unsigned size; 00087 00088 if (! curproc) { 00089 /* the current coroutine is the main process; 00090 initialize a coroutine descriptor for it ... 00091 */ 00092 mainproc[0].brk = MainLB; 00093 mainproc[0].size = sizeof(mainproc); 00094 curproc = &mainproc[0]; 00095 } 00096 *a = curproc; /* save current descriptor in "a" */ 00097 if (*b == curproc) { 00098 /* transfer to itself is a no-op */ 00099 return; 00100 } 00101 size = topsize(&(curproc->brk)); 00102 if (size + sizeof(struct proc) > curproc->size) { 00103 TRP(M2_TOOLARGE); 00104 } 00105 if (topsave(curproc->brk, curproc+1)) { 00106 /* stack top saved. Now restore context of target 00107 coroutine 00108 */ 00109 curproc = *b; 00110 topload(curproc+1); 00111 /* we never get here ... */ 00112 } 00113 /* but we do get here, when a transfer is done to the coroutine in "a". 00114 */ 00115 }
1.5.8