ack/lang/occam/lib/channel.c

213 lines
4.5 KiB
C
Raw Normal View History

1987-03-31 11:09:18 +00:00
/* $Header$ */
1987-02-24 18:36:02 +00:00
/* channel.c - basic channel handling routines */
#include <errno.h>
#include <signal.h>
1987-03-26 17:33:23 +00:00
#define __CHANNEL__
#ifdef __USG
#include <termio.h>
#else
1987-02-24 18:36:02 +00:00
#include <sgtty.h>
1987-03-26 17:33:23 +00:00
#endif
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];
1987-03-26 17:33:23 +00:00
#ifdef __USG
struct termio tty;
#else
1987-02-24 18:36:02 +00:00
struct sgttyb tty;
1987-03-26 17:33:23 +00:00
#endif
1987-02-24 18:36:02 +00:00
if ((v& ~0xff)==0) /* Plain character */
putc( (int) v, fp);
else
if (v==C_F_TEXT) {
1987-03-26 17:33:23 +00:00
#ifdef __USG
ioctl(fileno(fp), TCGETA, &tty);
tty.c_oflag |= (ONLCR);
tty.c_iflag |= (ICRNL);
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 0;
tty.c_lflag |= (ECHO|ICANON);
ioctl(fileno(fp), TCSETA, &tty);
#else
1988-04-15 15:03:32 +00:00
gtty(fileno(fp), &tty);
1987-02-24 18:36:02 +00:00
tty.sg_flags&= ~CBREAK;
tty.sg_flags|= ECHO|CRMOD;
1988-04-15 15:03:32 +00:00
stty(fileno(fp), &tty);
1987-03-26 17:33:23 +00:00
#endif
1987-02-24 18:36:02 +00:00
} else
if (v==C_F_RAW) {
1987-03-26 17:33:23 +00:00
#ifdef __USG
ioctl(fileno(fp), TCGETA, &tty);
tty.c_oflag &= ~(ONLCR);
tty.c_iflag &= ~(ICRNL);
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 0;
tty.c_lflag &= ~(ECHO|ICANON);
ioctl(fileno(fp), TCSETA, &tty);
#else
1988-04-21 09:21:18 +00:00
gtty(fileno(fp),&tty);
1987-02-24 18:36:02 +00:00
tty.sg_flags|= CBREAK;
tty.sg_flags&= ~(ECHO|CRMOD);
1988-04-15 15:03:32 +00:00
stty(fileno(fp), &tty);
1987-03-26 17:33:23 +00:00
#endif
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;
{
1988-02-15 18:08:46 +00:00
#ifdef __BSD4_2
1991-03-18 09:16:00 +00:00
/* Sigh ... since SunOs 4.1, fcntl.h requires sys/types.h. */
#include <sys/types.h>
1988-02-15 18:08:46 +00:00
#include <fcntl.h>
#ifndef O_NDELAY
#define O_NDELAY FNDELAY
#endif
int flags;
#endif
1987-02-24 18:36:02 +00:00
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 */
1988-02-15 18:08:46 +00:00
/* Unfortunately, the mechanism that was used
here does not work on all Unix systems.
On BSD 4.2 and newer, the "read" is
automatically restarted. Therefore, on
these systems, we try it with non-blocking
reads
*/
#ifdef __BSD4_2
flags = fcntl(fileno(fp), F_GETFL, 0);
fcntl(fileno(fp), F_SETFL, flags | O_NDELAY);
errno = 0;
ch = getc(fp);
fcntl(fileno(fp), F_SETFL, flags);
if (errno == EWOULDBLOCK) {
clearerr(fp);
return 0;
}
#else
1987-02-24 18:36:02 +00:00
signal(SIGALRM, timeout);
alarm(1);
errno=0;
ch=getc(fp);
signal(SIGALRM, SIG_IGN);
alarm(0);
1988-02-15 18:08:46 +00:00
if (errno==EINTR) {
clearerr(fp);
1987-02-24 18:36:02 +00:00
return 0;
1988-02-15 18:08:46 +00:00
}
#endif
1987-02-24 18:36:02 +00:00
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();
}