channel.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /* $Header$ */
  2. /* channel.c - basic channel handling routines */
  3. #include <errno.h>
  4. #include <signal.h>
  5. #define __CHANNEL__
  6. #ifdef __USG
  7. #include <termio.h>
  8. #else
  9. #include <sgtty.h>
  10. #endif
  11. #include "ocm_chan.h"
  12. static void disaster();
  13. void c_init(c, z) register chan *c; register unsigned z;
  14. /* Initialise an array of interprocess channels declared as: CHAN c[z]. */
  15. {
  16. do {
  17. c->type=C_T_CHAN;
  18. (c++)->c.synch=C_S_FREE;
  19. } while (--z!=0);
  20. }
  21. void chan_in(v, c) long *v; register chan *c;
  22. /* Reads a value from channel c and returns it through v. */
  23. {
  24. switch(c->type) {
  25. case C_T_FILE:
  26. if ((c->f.flgs&C_F_READAHEAD)!=0) {
  27. *v=(c->f.preread&0377);
  28. c->f.flgs&= ~C_F_READAHEAD;
  29. } else {
  30. register FILE *fp= unix_file[c->f.index];
  31. *v= feof(fp) ? C_F_EOF : getc(fp);
  32. }
  33. break;
  34. case C_T_CHAN:
  35. deadlock=0; /* Wait for value to arrive */
  36. while (c->c.synch!=C_S_ANY) resumenext();
  37. *v=c->c.val;
  38. c->c.synch=C_S_ACK; /* Acknowledge receipt */
  39. break;
  40. default:
  41. disaster();
  42. }
  43. }
  44. void chan_out(v, c) long v; register chan *c;
  45. /* Send value v through channel c. */
  46. {
  47. switch(c->type) {
  48. case C_T_FILE: {
  49. register FILE *fp= unix_file[c->f.index];
  50. #ifdef __USG
  51. struct termio tty;
  52. #else
  53. struct sgttyb tty;
  54. #endif
  55. if ((v& ~0xff)==0) /* Plain character */
  56. putc( (int) v, fp);
  57. else
  58. if (v==C_F_TEXT) {
  59. #ifdef __USG
  60. ioctl(fileno(fp), TCGETA, &tty);
  61. tty.c_oflag |= (ONLCR);
  62. tty.c_iflag |= (ICRNL);
  63. tty.c_cc[VMIN] = 1;
  64. tty.c_cc[VTIME] = 0;
  65. tty.c_lflag |= (ECHO|ICANON);
  66. ioctl(fileno(fp), TCSETA, &tty);
  67. #else
  68. ioctl(fileno(fp), TIOCGETP, &tty);
  69. tty.sg_flags&= ~CBREAK;
  70. tty.sg_flags|= ECHO|CRMOD;
  71. ioctl(fileno(fp), TIOCSETN, &tty);
  72. #endif
  73. } else
  74. if (v==C_F_RAW) {
  75. #ifdef __USG
  76. ioctl(fileno(fp), TCGETA, &tty);
  77. tty.c_oflag &= ~(ONLCR);
  78. tty.c_iflag &= ~(ICRNL);
  79. tty.c_cc[VMIN] = 1;
  80. tty.c_cc[VTIME] = 0;
  81. tty.c_lflag &= ~(ECHO|ICANON);
  82. ioctl(fileno(fp), TCSETA, &tty);
  83. #else
  84. ioctl(fileno(fp), TIOCGETP ,&tty);
  85. tty.sg_flags|= CBREAK;
  86. tty.sg_flags&= ~(ECHO|CRMOD);
  87. ioctl(fileno(fp), TIOCSETN, &tty);
  88. #endif
  89. }
  90. } break;
  91. case C_T_CHAN:
  92. deadlock=0; /* Wait until channel is free */
  93. while (c->c.synch!=C_S_FREE) resumenext();
  94. c->c.val=v;
  95. c->c.synch=C_S_ANY; /* Channel has data */
  96. deadlock=0; /* Wait for acknowledgement */
  97. while (c->c.synch!=C_S_ACK) resumenext();
  98. c->c.synch=C_S_FREE; /* Back to normal */
  99. break;
  100. default:
  101. disaster();
  102. }
  103. }
  104. static int timeout();
  105. int chan_any(c) register chan *c;
  106. {
  107. switch (c->type) {
  108. case C_T_FILE:
  109. if ((c->f.flgs&C_F_READAHEAD)!=0)
  110. return 1;
  111. else {
  112. register FILE *fp= unix_file[c->f.index];
  113. if (feof(fp))
  114. return 1;
  115. else {
  116. extern int errno;
  117. register ch;
  118. deadlock=0;
  119. /* No deadlock while waiting for key */
  120. signal(SIGALRM, timeout);
  121. alarm(1);
  122. errno=0;
  123. ch=getc(fp);
  124. signal(SIGALRM, SIG_IGN);
  125. alarm(0);
  126. if (errno==EINTR)
  127. return 0;
  128. else {
  129. if (!feof(fp)) {
  130. c->f.flgs|=C_F_READAHEAD;
  131. c->f.preread=ch;
  132. }
  133. return 1;
  134. }
  135. }
  136. }
  137. case C_T_CHAN:
  138. return c->c.synch==C_S_ANY;
  139. default:
  140. disaster();
  141. }
  142. }
  143. /* The ch=getc(fp) in the above function calls read(2) to do its task, but if
  144. * there's no input on the file (pipe or terminal) then the read will block.
  145. * To stop this read from blocking, we use the fact that if the read is
  146. * interrupted by a signal that is caught by the program, then the read returns
  147. * error EINTR after the signal is processed. Thus we use a one second alarm
  148. * to interrupt the read with a trap to timeout(). But since the alarm signal
  149. * may occur *before* the read is called, it is continuously restarted in
  150. * timeout() to prevent it from getting lost.
  151. */
  152. static int timeout(sig)
  153. {
  154. signal(SIGALRM, timeout);
  155. alarm(1);
  156. }
  157. static void disaster()
  158. {
  159. write(2, "Fatal error: Channel variable corrupted\n", 40);
  160. abort();
  161. }