123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- /* $Id$ */
- /* channel.c - basic channel handling routines */
- #include <errno.h>
- #ifndef __BSD4_2
- #include <signal.h>
- #endif
- #include <sgtty.h>
- #include "ocm_chan.h"
- 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) {
- gtty(fileno(fp), &tty);
- tty.sg_flags&= ~CBREAK;
- tty.sg_flags|= ECHO|CRMOD;
- stty(fileno(fp), &tty);
- } else
- if (v==C_F_RAW) {
- gtty(fileno(fp),&tty);
- tty.sg_flags|= CBREAK;
- tty.sg_flags&= ~(ECHO|CRMOD);
- stty(fileno(fp), &tty);
- }
- } 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();
- }
- }
- #ifndef __BSD4_2
- static void timeout();
- #endif
- int chan_any(c) register chan *c;
- {
- #ifdef __BSD4_2
- #include <fcntl.h>
- int flags;
- #endif
- 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 */
- /* 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
- signal(SIGALRM, timeout);
- alarm(1);
- errno=0;
- ch=getc(fp);
- signal(SIGALRM, SIG_IGN);
- alarm(0);
- if (errno==EINTR) {
- clearerr(fp);
- return 0;
- }
- #endif
- 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();
- }
- }
- #ifndef __BSD4_2
- /* 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 void timeout(sig)
- {
- signal(SIGALRM, timeout);
- alarm(1);
- }
- #endif
- static void disaster()
- {
- write(2, "Fatal error: Channel variable corrupted\n", 40);
- abort();
- }
|