1989-02-13 18:41:17 +00:00
|
|
|
/*
|
|
|
|
(c) copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
|
|
|
See the copyright notice in the ACK home directory, in the file "Copyright".
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
Module: SYSTEM
|
|
|
|
Author: Ceriel J.H. Jacobs
|
1994-06-24 14:02:31 +00:00
|
|
|
Version: $Id$
|
1989-02-13 18:41:17 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2018-06-25 20:22:37 +00:00
|
|
|
An implementation of the Modula-2 NEWPROCESS and TRANSFER facilities
|
|
|
|
using the topsize, topsave, and topload facilities.
|
|
|
|
For each coroutine, a proc structure is built. For the main routine,
|
|
|
|
a static space is declared to save its stack. For the other coroutines,
|
|
|
|
the user specifies this space.
|
1989-02-13 18:41:17 +00:00
|
|
|
*/
|
|
|
|
|
2018-06-25 20:22:37 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
#include "libm2.h"
|
1989-02-13 18:41:17 +00:00
|
|
|
#include <m2_traps.h>
|
|
|
|
|
2018-06-25 20:22:37 +00:00
|
|
|
#define MAXMAIN 2048
|
1989-02-13 18:41:17 +00:00
|
|
|
|
2018-06-25 20:22:37 +00:00
|
|
|
static struct proc mainproc[MAXMAIN / sizeof(struct proc) + 1];
|
1989-02-13 18:41:17 +00:00
|
|
|
|
2018-06-25 20:22:37 +00:00
|
|
|
static struct proc* curproc = 0; /* current coroutine */
|
|
|
|
extern char* MainLB; /* stack break of main routine */
|
1989-03-10 14:03:34 +00:00
|
|
|
|
2018-06-25 20:22:37 +00:00
|
|
|
void _SYSTEM__NEWPROCESS(
|
|
|
|
int (*p)(void) /* coroutine procedure */,
|
|
|
|
struct proc* a /* pointer to area for saved stack-frame */,
|
|
|
|
unsigned int n /* size of this area */,
|
|
|
|
struct proc** p1 /* where to leave coroutine descriptor,
|
|
|
|
in this implementation the address of
|
|
|
|
the area for saved stack-frame(s) */
|
|
|
|
)
|
1989-02-13 18:41:17 +00:00
|
|
|
{
|
|
|
|
/* This procedure creates a new coroutine, but does not
|
2018-06-25 20:22:37 +00:00
|
|
|
transfer control to it. The routine "topsize" will compute the
|
|
|
|
stack break, which will be the local base of this routine.
|
|
|
|
Notice that we can do this because we do not need the stack
|
|
|
|
above this point for this coroutine. In Modula-2, coroutines
|
|
|
|
must be level 0 procedures without parameters.
|
1989-02-13 18:41:17 +00:00
|
|
|
*/
|
2018-06-25 20:22:37 +00:00
|
|
|
char* brk = 0;
|
1989-03-10 14:03:34 +00:00
|
|
|
unsigned sz = topsize(&brk);
|
1989-02-13 18:41:17 +00:00
|
|
|
|
2018-06-25 20:22:37 +00:00
|
|
|
if (sz + sizeof(struct proc) > n)
|
|
|
|
{
|
1989-02-13 18:41:17 +00:00
|
|
|
/* not enough space */
|
|
|
|
TRP(M2_TOOLARGE);
|
|
|
|
}
|
|
|
|
a->size = n;
|
|
|
|
a->proc = p;
|
|
|
|
a->brk = brk;
|
|
|
|
*p1 = a;
|
2018-06-25 20:22:37 +00:00
|
|
|
if (topsave(brk, a + 1))
|
1989-02-13 18:41:17 +00:00
|
|
|
/* stack frame saved; now just return */
|
|
|
|
;
|
2018-06-25 20:22:37 +00:00
|
|
|
else
|
|
|
|
{
|
1989-02-13 18:41:17 +00:00
|
|
|
/* We get here through the first transfer to the coroutine
|
|
|
|
created above.
|
|
|
|
This also means that curproc is now set to this coroutine.
|
|
|
|
We cannot trust the parameters anymore.
|
|
|
|
Just call the coroutine procedure.
|
|
|
|
*/
|
|
|
|
(*(curproc->proc))();
|
1991-03-15 09:24:03 +00:00
|
|
|
_cleanup();
|
1989-02-13 18:41:17 +00:00
|
|
|
_exit(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-25 20:22:37 +00:00
|
|
|
void _SYSTEM__TRANSFER(struct proc** a, struct proc** b)
|
1989-02-13 18:41:17 +00:00
|
|
|
{
|
|
|
|
/* transfer from one coroutine to another, saving the current
|
2018-06-25 20:22:37 +00:00
|
|
|
descriptor in the space indicated by "a", and transfering to
|
|
|
|
the coroutine in descriptor "b".
|
1989-02-13 18:41:17 +00:00
|
|
|
*/
|
1989-03-10 14:03:34 +00:00
|
|
|
unsigned size;
|
1989-02-13 18:41:17 +00:00
|
|
|
|
2018-06-25 20:22:37 +00:00
|
|
|
if (!curproc)
|
|
|
|
{
|
1989-02-13 18:41:17 +00:00
|
|
|
/* the current coroutine is the main process;
|
|
|
|
initialize a coroutine descriptor for it ...
|
|
|
|
*/
|
|
|
|
mainproc[0].brk = MainLB;
|
|
|
|
mainproc[0].size = sizeof(mainproc);
|
|
|
|
curproc = &mainproc[0];
|
|
|
|
}
|
2018-06-25 20:22:37 +00:00
|
|
|
*a = curproc; /* save current descriptor in "a" */
|
|
|
|
if (*b == curproc)
|
|
|
|
{
|
1989-02-13 18:41:17 +00:00
|
|
|
/* transfer to itself is a no-op */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
size = topsize(&(curproc->brk));
|
2018-06-25 20:22:37 +00:00
|
|
|
if (size + sizeof(struct proc) > curproc->size)
|
|
|
|
{
|
1989-02-13 18:41:17 +00:00
|
|
|
TRP(M2_TOOLARGE);
|
|
|
|
}
|
2018-06-25 20:22:37 +00:00
|
|
|
if (topsave(curproc->brk, curproc + 1))
|
|
|
|
{
|
1989-02-13 18:41:17 +00:00
|
|
|
/* stack top saved. Now restore context of target
|
|
|
|
coroutine
|
|
|
|
*/
|
|
|
|
curproc = *b;
|
2018-06-25 20:22:37 +00:00
|
|
|
topload(curproc + 1);
|
1989-02-13 18:41:17 +00:00
|
|
|
/* we never get here ... */
|
|
|
|
}
|
|
|
|
/* but we do get here, when a transfer is done to the coroutine in "a".
|
|
|
|
*/
|
|
|
|
}
|