/* signaller.c
L. Stewart August 24, 1982 12:05 PM
L. Stewart November 8, 1982 3:25 PM, osstatics
*/
#include <Signal.h>
#include <Env.h>
#include <Ec.h>
extern MyFrame();
extern CallSwat();
extern CallersFrame();
extern ReturnLoc();
extern Call0();
extern Apply();
extern Ugt();
extern ByteBlt();
struct enab {
int ensignal;
int enproc;
int enframe;
int enenframe;
int enid;
int encontinue;
struct Seal *enseal;
};
#define lenenab 14
struct sigvec {
int svused;
int svmaxEnabled;
struct enab sven[1];
};
#define lensigvec 4
#define sealseal 0132576
extern int getsv;
extern int sigid;
extern int signame;
SigInit(svec, sveclen, gvproc)
struct sigvec *svec;
int sveclen;
int gvproc;
{
sigid = 0;
signame = 037777;
getsv = gvproc;
svec->svused = 0;
svec->svmaxEnabled = (sveclen-lensigvec)/lenenab;
};
int Enable(s, p, sl)
int s, p;
struct Seal *sl;
{
return(EnableWithFrame(s, p, sl, MyFrame()));
};
int EnableWithFrame(s, p, sl, f)
int s; /* signal */
int p; /* proc to call */
struct Seal *sl;
int f;
{
struct sigvec *sv;
struct enab *en;
sv = Call0(getsv);
if (sv->svused == sv->svmaxEnabled) {
if (purgesv() >= sv->svmaxEnabled) CallSwat(ecSignal+1);
};
en = &sv->sven[sv->svused];
sv->svused += 1;
en->ensignal = s;
en->enproc = p;
en->enenframe = f;
en->enframe = CallersFrame(f);
en->enseal = sl;
en->encontinue = ReturnLoc(f);
sigid += 1;
en->enid = sigid;
sl->slauth = sealseal;
sl->slid = sigid;
return(0);
};
Disable(sl)
struct Seal *sl;
{
sl->slauth = 0;
};
Signal(s, c)
int s; /* Signal */
int c; /* unspecified */
{
struct enab *en;
struct sigvec *sv;
int enindex;
int enabres;
int ent;
int result;
int argv[3];
sv = Call0(getsv);
enindex = purgesv();
for (;;) {
enabres = true;
en = finden(s, &enindex);
if (en==0) CallSwat(ecSignal+2);
argv[0] = s;
argv[1] = c;
argv[2] = (int) en->enseal;
result = Apply(argv, en->enproc, 3);
switch (result) {
case REJECT: continue; /* look for next catch phrase */
case RESUME: return;
case RETRY: enabres = false;
case CONTINUE:
unwind(enindex, enabres);
break;
default: CallSwat(ecSignal+3);
};
};
};
int Code()
{
signame += 1;
return(signame);
};
static int purgesv()
{
int f, prevf, invalid;
int enf, dest, i;
struct sigvec *sv;
struct enab *en;
struct Seal *sl;
sv = Call0(getsv);
f = CallersFrame(MyFrame());
prevf = 0;
invalid = false;
for (i = (sv->svused) - 1; i >= 0; i -= 1) {
en = &sv->sven[i];
sl = en->enseal;
if ((sl->slauth != sealseal) || (sl->slid != en->enid)) {
en->enid = 0;
invalid = true;
continue;
};
enf = en->enframe;
while (Ugt(enf, f)) f = CallersFrame(f);
if (Ugt(prevf, enf) || Ugt(f, enf)) {
en->enid = 0;
invalid = true;
};
else prevf = f;
};
dest = 0;
if (invalid) {
for (i=0; i < sv->svused; i+= 1) {
en = &sv->sven[i];
if (en->enid == 0) continue; /* invalid */
if (dest != i) {
ByteBlt(&sv->sven[dest], &sv->sven[i], lenenab);
};
dest += 1;
};
sv->svused = dest;
};
return (sv->svused);
};
static struct enab *finden(s, lvindex)
int s, *lvindex;
{
struct sigvec *sv;
struct enab *en;
int i;
sv = Call0(getsv);
for (i = (*lvindex) - 1; i >= 0; i -= 1) {
en = &sv->sven[i];
if ((en->ensignal == s) || (en->ensignal == ANY)) {
*lvindex = i;
return (en);
};
};
*lvindex = (-1);
return (0);
};
static unwind(toenindex, result)
int toenindex, result;
{
struct sigvec *sv;
struct enab *toen, *en;
int id, index, toframe, toenframe, prevframe, nextframe;
int argv[3];
sv = Call0(getsv);
toen = &sv->sven[toenindex];
id = toen->enid;
index = purgesv();
/* purgesv should not invalidate toen */
if ((index<=toenindex) || (toen->enid != id)) CallSwat(ecSignal+4);
toframe = toen->enframe;
toenframe = toen->enenframe;
prevframe = MyFrame();
en = finden(UNWIND, &index);
for (;;) {
nextframe = CallersFrame(prevframe);
while ((index>toenindex) && (en->enframe == nextframe)) {
argv[0] = UNWIND;
argv[1] = 0;
argv[2] = (int) en->enseal;
Apply(argv, en->enproc, 3);
en = finden(UNWIND, &index);
};
if (nextframe==toframe) break;
prevframe = nextframe;
};
returnto(toenframe, toframe, toen->encontinue, result);
};