fd-io.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. /* Copyright (c) 1993-2005 by Richard Kelsey and Jonathan Rees.
  2. See file COPYING. */
  3. #include <unistd.h>
  4. #include <stdio.h>
  5. #include <sys/types.h>
  6. #include <sys/stat.h>
  7. #include <fcntl.h>
  8. #include <sys/time.h>
  9. #include <errno.h> /* for errno, (POSIX?/ANSI) */
  10. #include <string.h> /* FD_ZERO sometimes needs this */
  11. #include "sysdep.h"
  12. #include "c-mods.h"
  13. #include "scheme48vm.h"
  14. #include "event.h"
  15. #include "unix.h"
  16. /* Non-blocking I/O on file descriptors.
  17. There appear to be two ways to get non-blocking input and output. One
  18. is to open files with the O_NONBLOCK flag (and to use fcntl() to do the
  19. same to stdin and stdout), the other is to call select() on each file
  20. descriptor before doing the I/O operation. O_NONBLOCK has the problem
  21. of being a property of the file descriptor, and its use with stdin and
  22. stdout can lead to horrible results.
  23. We use a mixture of both. For input files we call select() before doing
  24. a read(), because read() will return immediately if there are any bytes
  25. available at all, and using O_NONBLOCK on stdin is a very bad idea.
  26. Output files are opened using O_NONBLOCK and stdout is left alone.
  27. */
  28. int
  29. ps_open_fd(char *filename, psbool is_input, long *status)
  30. {
  31. #define FILE_NAME_SIZE 1024
  32. #define PERMISSION 0666 /* read and write for everyone */
  33. char filename_temp[FILE_NAME_SIZE];
  34. char *expanded;
  35. extern char *s48_expand_file_name(char *, char *, int);
  36. int flags;
  37. mode_t mode;
  38. expanded = s48_expand_file_name(filename, filename_temp, FILE_NAME_SIZE);
  39. if (expanded == NULL)
  40. return -1;
  41. if (is_input) {
  42. flags = O_RDONLY;
  43. mode = 0; }
  44. else {
  45. flags = O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK;
  46. mode = PERMISSION; }
  47. /* keep trying if interrupted */
  48. while(1) {
  49. int fd = open(expanded, flags, mode);
  50. if (fd != -1) {
  51. *status = NO_ERRORS;
  52. return fd; }
  53. else if (errno != EINTR) {
  54. *status = errno;
  55. return -1; }
  56. }
  57. }
  58. int
  59. ps_close_fd(long fd_as_long)
  60. {
  61. int fd = (int)fd_as_long;
  62. /* keep retrying if interrupted */
  63. while(1) {
  64. int status = close(fd);
  65. if (status != -1) {
  66. s48_remove_fd(fd);
  67. return NO_ERRORS; }
  68. else if (errno != EINTR)
  69. return errno;
  70. }
  71. }
  72. psbool ps_check_fd(long fd_as_long, psbool is_read, long *status)
  73. {
  74. int fd = (int)fd_as_long;
  75. int ready;
  76. struct timeval timeout;
  77. fd_set fds;
  78. FD_ZERO(&fds);
  79. FD_SET(fd, &fds);
  80. timerclear(&timeout);
  81. *status = NO_ERRORS;
  82. while(1) {
  83. ready = select(fd + 1,
  84. is_read ? &fds : NULL,
  85. is_read ? NULL : &fds,
  86. &fds,
  87. &timeout);
  88. if (ready == 0)
  89. return PSFALSE;
  90. else if (ready == 1)
  91. return PSTRUE;
  92. else if (errno != EINTR) {
  93. *status = errno;
  94. return PSFALSE; } }
  95. }
  96. long
  97. ps_read_fd(long fd_as_long, char *buffer, long max, psbool waitp,
  98. psbool *eofp, psbool *pending, long *status)
  99. {
  100. int got, ready;
  101. void *buf = (void *)buffer;
  102. int fd = (int)fd_as_long;
  103. struct timeval timeout;
  104. fd_set readfds;
  105. FD_ZERO(&readfds);
  106. FD_SET(fd, &readfds);
  107. timerclear(&timeout);
  108. /* for the normal return */
  109. *eofp = PSFALSE;
  110. *pending = PSFALSE;
  111. *status = NO_ERRORS;
  112. while(1) {
  113. ready = select(fd + 1, &readfds, NULL, &readfds, &timeout);
  114. if (ready == 0) {
  115. if (!waitp)
  116. return 0;
  117. else if (s48_add_pending_fd(fd, PSTRUE)) {
  118. *pending = PSTRUE;
  119. return 0; }
  120. else {
  121. *status = ENOMEM; /* as close as POSIX gets */
  122. return 0; }}
  123. else if (ready == -1) {
  124. if (errno != EINTR) {
  125. *status = errno;
  126. return 0; } }
  127. else { /* characters waiting */
  128. got = read(fd, buf, max);
  129. if (got > 0) { /* all is well */
  130. return got; }
  131. else if (got == 0) { /* end of file */
  132. *eofp = PSTRUE;
  133. return 0; }
  134. else if (errno == EINTR) { /* HCC */
  135. return 0; }
  136. else if (errno == EAGAIN) { /* HCC */
  137. if (!waitp)
  138. return 0;
  139. else if (s48_add_pending_fd(fd, PSTRUE)) {
  140. *pending = PSTRUE;
  141. return 0; }
  142. else {
  143. *status = ENOMEM; /* as close as POSIX gets */
  144. return 0; } }
  145. else {
  146. *status = errno;
  147. return 0; } } }
  148. }
  149. long
  150. ps_write_fd(long fd_as_long, char *buffer, long max, psbool *pending, long *status)
  151. {
  152. int sent;
  153. int fd = (int)fd_as_long;
  154. void *buf = (void *)buffer;
  155. *pending = PSFALSE;
  156. *status = NO_ERRORS;
  157. sent = write(fd, buf, max);
  158. if (sent > 0)
  159. {}
  160. else if (errno == EINTR || errno == EAGAIN) { /* HCC */
  161. if (s48_add_pending_fd(fd, PSFALSE))
  162. *pending = PSTRUE;
  163. else
  164. *status = ENOMEM; /* as close as POSIX gets */
  165. sent = 0; }
  166. else {
  167. *status = errno;
  168. sent = 0; }
  169. return sent;
  170. }
  171. long
  172. ps_abort_fd_op(long fd_as_long)
  173. {
  174. int fd = (int)fd_as_long;
  175. if (!s48_remove_fd(fd))
  176. fprintf(stderr, "Error: ps_abort_fd_op, no pending operation on fd %d\n",
  177. fd);
  178. return 0; /* because we do not actually do any I/O in parallel the
  179. status is always zero: no characters transfered. */
  180. }
  181. /*
  182. * This checks that fd's destined for output channels are marked
  183. * as nonblocking. Stdout and stderr are a special case because
  184. * we do not want to screw up the shell, if we were invoked from
  185. * one.
  186. */
  187. s48_value
  188. s48_add_channel(s48_value mode, s48_value id, long fd)
  189. {
  190. if (mode == S48_CHANNEL_STATUS_OUTPUT
  191. && fd != 1
  192. && fd != 2) {
  193. int flags;
  194. RETRY_OR_RAISE_NEG(flags, fcntl(fd, F_GETFL));
  195. if ((flags & O_NONBLOCK) == 0)
  196. fprintf(stderr,
  197. "Warning: output channel file descriptor %d is not non-blocking\n",
  198. fd); }
  199. return s48_really_add_channel(mode, id, fd);
  200. }