channel.c 3.9 KB

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