ack/lang/occam/lib/channel.c

153 lines
3.2 KiB
C
Raw Normal View History

1987-02-24 18:36:02 +00:00
/* channel.c - basic channel handling routines */
#include <errno.h>
#include <signal.h>
#include <sgtty.h>
1987-02-25 16:41:09 +00:00
#include "ocm_chan.h"
1987-02-24 18:36:02 +00:00
static void disaster();
void c_init(c, z) register chan *c; register unsigned z;
/* Initialise an array of interprocess channels declared as: CHAN c[z]. */
{
do {
c->type=C_T_CHAN;
(c++)->c.synch=C_S_FREE;
} while (--z!=0);
}
void chan_in(v, c) long *v; register chan *c;
/* Reads a value from channel c and returns it through v. */
{
switch(c->type) {
case C_T_FILE:
if ((c->f.flgs&C_F_READAHEAD)!=0) {
*v=(c->f.preread&0377);
c->f.flgs&= ~C_F_READAHEAD;
} else {
register FILE *fp= unix_file[c->f.index];
*v= feof(fp) ? C_F_EOF : getc(fp);
}
break;
case C_T_CHAN:
deadlock=0; /* Wait for value to arrive */
while (c->c.synch!=C_S_ANY) resumenext();
*v=c->c.val;
c->c.synch=C_S_ACK; /* Acknowledge receipt */
break;
default:
disaster();
}
}
void chan_out(v, c) long v; register chan *c;
/* Send value v through channel c. */
{
switch(c->type) {
case C_T_FILE: {
register FILE *fp= unix_file[c->f.index];
struct sgttyb tty;
if ((v& ~0xff)==0) /* Plain character */
putc( (int) v, fp);
else
if (v==C_F_TEXT) {
1987-02-25 16:41:09 +00:00
gtty(fileno(fp), &tty);
1987-02-24 18:36:02 +00:00
tty.sg_flags&= ~CBREAK;
tty.sg_flags|= ECHO|CRMOD;
1987-02-25 16:41:09 +00:00
stty(fileno(fp), &tty);
1987-02-24 18:36:02 +00:00
} else
if (v==C_F_RAW) {
1987-02-25 16:41:09 +00:00
gtty(fileno(fp), &tty);
1987-02-24 18:36:02 +00:00
tty.sg_flags|= CBREAK;
tty.sg_flags&= ~(ECHO|CRMOD);
1987-02-25 16:41:09 +00:00
stty(fileno(fp), &tty);
1987-02-24 18:36:02 +00:00
}
} break;
case C_T_CHAN:
deadlock=0; /* Wait until channel is free */
while (c->c.synch!=C_S_FREE) resumenext();
c->c.val=v;
c->c.synch=C_S_ANY; /* Channel has data */
deadlock=0; /* Wait for acknowledgement */
while (c->c.synch!=C_S_ACK) resumenext();
c->c.synch=C_S_FREE; /* Back to normal */
break;
default:
disaster();
}
}
static int timeout();
int chan_any(c) register chan *c;
{
switch (c->type) {
case C_T_FILE:
if ((c->f.flgs&C_F_READAHEAD)!=0)
return 1;
else {
register FILE *fp= unix_file[c->f.index];
if (feof(fp))
return 1;
else {
extern int errno;
register ch;
deadlock=0;
/* No deadlock while waiting for key */
signal(SIGALRM, timeout);
alarm(1);
errno=0;
ch=getc(fp);
signal(SIGALRM, SIG_IGN);
alarm(0);
if (errno==EINTR)
return 0;
else {
if (!feof(fp)) {
c->f.flgs|=C_F_READAHEAD;
c->f.preread=ch;
}
return 1;
}
}
}
case C_T_CHAN:
return c->c.synch==C_S_ANY;
default:
disaster();
}
}
/* The ch=getc(fp) in the above function calls read(2) to do its task, but if
* there's no input on the file (pipe or terminal) then the read will block.
* To stop this read from blocking, we use the fact that if the read is
* interrupted by a signal that is caught by the program, then the read returns
* error EINTR after the signal is processed. Thus we use a one second alarm
* to interrupt the read with a trap to timeout(). But since the alarm signal
* may occur *before* the read is called, it is continuously restarted in
* timeout() to prevent it from getting lost.
*/
static int timeout(sig)
{
signal(SIGALRM, timeout);
alarm(1);
}
static void disaster()
{
write(2, "Fatal error: Channel variable corrupted\n", 40);
abort();
}