fd-io.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /* Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. *
  3. * Authors: Richard Kelsey, Jonathan Rees, Mike Sperber, Marcus Crestani
  4. */
  5. /* NB: sysdep.h must come first in order for LFS to be enabled
  6. properly */
  7. #include "sysdep.h"
  8. #include <unistd.h>
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <sys/types.h>
  12. #include <sys/stat.h>
  13. #include <fcntl.h>
  14. #include <sys/time.h>
  15. #include <errno.h> /* for errno, (POSIX?/ANSI) */
  16. #include <string.h> /* FD_ZERO sometimes needs this */
  17. #include <locale.h> /* ISO C99 */
  18. #ifdef HAVE_POLL_H
  19. #include <poll.h>
  20. #endif
  21. #include "c-mods.h"
  22. #include "scheme48vm.h"
  23. #include "event.h"
  24. #include "fd-io.h"
  25. #include "unix.h"
  26. /* Non-blocking I/O on file descriptors.
  27. There appear to be two ways to get non-blocking input and output. One
  28. is to open files with the O_NONBLOCK flag (and to use fcntl() to do the
  29. same to stdin and stdout), the other is to call select() on each file
  30. descriptor before doing the I/O operation. O_NONBLOCK has the problem
  31. of being a property of the file descriptor, and its use with stdin and
  32. stdout can lead to horrible results.
  33. We use a mixture of both. For input files we call select() before doing
  34. a read(), because read() will return immediately if there are any bytes
  35. available at all, and using O_NONBLOCK on stdin is a very bad idea.
  36. Output files are opened using O_NONBLOCK and stdout is left alone.
  37. */
  38. int
  39. ps_open_fd(char *filename, psbool is_input, long *status)
  40. {
  41. #define FILE_NAME_SIZE 1024
  42. #define PERMISSION 0666 /* read and write for everyone */
  43. char filename_temp[FILE_NAME_SIZE];
  44. char *expanded;
  45. extern char *s48_expand_file_name(char *, char *, int);
  46. int flags;
  47. mode_t mode;
  48. expanded = s48_expand_file_name(filename, filename_temp, FILE_NAME_SIZE);
  49. if (expanded == NULL)
  50. return -1;
  51. if (is_input) {
  52. flags = O_RDONLY;
  53. mode = 0; }
  54. else {
  55. flags = O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK;
  56. mode = PERMISSION; }
  57. /* keep trying if interrupted */
  58. while(1) {
  59. int fd = open(expanded, flags, mode);
  60. if (fd != -1) {
  61. *status = NO_ERRORS;
  62. return fd; }
  63. else if (errno != EINTR) {
  64. *status = errno;
  65. return -1; }
  66. }
  67. }
  68. int
  69. ps_close_fd(long fd_as_long)
  70. {
  71. int fd = (int)fd_as_long;
  72. /* keep retrying if interrupted */
  73. while(1) {
  74. int status = close(fd);
  75. if (status != -1) {
  76. s48_remove_fd(fd);
  77. return NO_ERRORS; }
  78. else if (errno != EINTR)
  79. return errno;
  80. }
  81. }
  82. psbool ps_check_fd(long fd_as_long, psbool is_read, long *status)
  83. {
  84. int fd = (int)fd_as_long;
  85. int ready;
  86. #if defined HAVE_GLIB
  87. struct pollfd pollfds[1];
  88. pollfds[0].fd = fd;
  89. pollfds[0].events = is_read? POLLIN : POLLOUT;
  90. *status = NO_ERRORS;
  91. while(1) {
  92. ready = poll(pollfds, 1, 0);
  93. #elif defined HAVE_POLL
  94. struct pollfd pollfds[1];
  95. pollfds[0].fd = fd;
  96. pollfds[0].events = is_read? POLLIN : POLLOUT;
  97. *status = NO_ERRORS;
  98. while(1) {
  99. ready = poll(pollfds, 1, 0);
  100. #elif defined HAVE_SELECT
  101. struct timeval timeout;
  102. fd_set fds;
  103. FD_ZERO(&fds);
  104. FD_SET(fd, &fds);
  105. timerclear(&timeout);
  106. *status = NO_ERRORS;
  107. while(1) {
  108. ready = select(fd + 1,
  109. is_read ? &fds : NULL,
  110. is_read ? NULL : &fds,
  111. &fds,
  112. &timeout);
  113. #endif /* HAVE_SELECT */
  114. if (ready == 0)
  115. return PSFALSE;
  116. /* Mike has witnessed it return 2 on Mac OS X. */
  117. else if (ready >= 1)
  118. return PSTRUE;
  119. else if (errno != EINTR) {
  120. *status = errno;
  121. return PSFALSE; } }
  122. }
  123. long
  124. ps_read_fd(long fd_as_long, char *buffer, long max, psbool waitp,
  125. psbool *eofp, psbool *pending, long *status)
  126. {
  127. int got, ready;
  128. void *buf = (void *)buffer;
  129. int fd = (int)fd_as_long;
  130. #if defined HAVE_GLIB
  131. struct pollfd pollfds[1];
  132. pollfds[0].fd = fd;
  133. pollfds[0].events = POLLIN;
  134. /* for the normal return */
  135. *eofp = PSFALSE;
  136. *pending = PSFALSE;
  137. *status = NO_ERRORS;
  138. while(1) {
  139. ready = poll(pollfds, 1, 0);
  140. #elif defined HAVE_POLL
  141. struct pollfd pollfds[1];
  142. pollfds[0].fd = fd;
  143. pollfds[0].events = POLLIN;
  144. /* for the normal return */
  145. *eofp = PSFALSE;
  146. *pending = PSFALSE;
  147. *status = NO_ERRORS;
  148. while(1) {
  149. ready = poll(pollfds, 1, 0);
  150. #elif HAVE_SELECT
  151. struct timeval timeout;
  152. fd_set readfds;
  153. FD_ZERO(&readfds);
  154. FD_SET(fd, &readfds);
  155. timerclear(&timeout);
  156. /* for the normal return */
  157. *eofp = PSFALSE;
  158. *pending = PSFALSE;
  159. *status = NO_ERRORS;
  160. while(1) {
  161. ready = select(fd + 1, &readfds, NULL, &readfds, &timeout);
  162. #endif /* HAVE_SELECT */
  163. if (ready == 0) {
  164. if (!waitp)
  165. return 0;
  166. else if (s48_add_pending_fd(fd, PSTRUE)) {
  167. *pending = PSTRUE;
  168. return 0; }
  169. else {
  170. *status = ENOMEM; /* as close as POSIX gets */
  171. return 0; }}
  172. else if (ready == -1) {
  173. if (errno != EINTR) {
  174. *status = errno;
  175. return 0; } }
  176. else { /* characters waiting */
  177. got = read(fd, buf, max);
  178. if (got > 0) { /* all is well */
  179. return got; }
  180. else if (got == 0) { /* end of file */
  181. *eofp = PSTRUE;
  182. return 0; }
  183. else if (errno == EINTR) { /* HCC */
  184. return 0; }
  185. else if (errno == EAGAIN) { /* HCC */
  186. if (!waitp)
  187. return 0;
  188. else if (s48_add_pending_fd(fd, PSTRUE)) {
  189. *pending = PSTRUE;
  190. return 0; }
  191. else {
  192. *status = ENOMEM; /* as close as POSIX gets */
  193. return 0; } }
  194. else {
  195. *status = errno;
  196. return 0; } } }
  197. }
  198. long
  199. ps_write_fd(long fd_as_long, char *buffer, long max, psbool *pending, long *status)
  200. {
  201. int sent;
  202. int fd = (int)fd_as_long;
  203. void *buf = (void *)buffer;
  204. *pending = PSFALSE;
  205. *status = NO_ERRORS;
  206. sent = write(fd, buf, max);
  207. if (sent > 0)
  208. {}
  209. else if (errno == EINTR || errno == EAGAIN) { /* HCC */
  210. if (s48_add_pending_fd(fd, PSFALSE))
  211. *pending = PSTRUE;
  212. else
  213. *status = ENOMEM; /* as close as POSIX gets */
  214. sent = 0; }
  215. else {
  216. *status = errno;
  217. sent = 0; }
  218. return sent;
  219. }
  220. long
  221. ps_io_buffer_size(void)
  222. {
  223. return 4096;
  224. }
  225. psbool
  226. ps_io_crlf_p(void)
  227. {
  228. return PSFALSE;
  229. }
  230. char *
  231. ps_console_encoding(long fd_as_long)
  232. {
  233. static char *encoding_STDIN = NULL;
  234. static char *encoding_STDOUT = NULL;
  235. static char *encoding_STDERR = NULL;
  236. static char setlocale_called = PSFALSE;
  237. char *codeset;
  238. char** encoding_p;
  239. if (fd_as_long == STDIN_FD())
  240. encoding_p = &encoding_STDIN;
  241. else if (fd_as_long == STDOUT_FD())
  242. encoding_p = &encoding_STDOUT;
  243. else if (fd_as_long == STDERR_FD())
  244. encoding_p = &encoding_STDERR;
  245. /* Mike has no clue what the rationale for needing this is. */
  246. if (!setlocale_called)
  247. {
  248. setlocale(LC_CTYPE, "");
  249. setlocale_called = PSTRUE;
  250. }
  251. if (*encoding_p == NULL)
  252. {
  253. codeset = nl_langinfo(CODESET); /* this ain't reentrant */
  254. *encoding_p = malloc(strlen(codeset) + 1);
  255. if (*encoding_p == NULL)
  256. return NULL;
  257. strcpy(*encoding_p, codeset);
  258. }
  259. return *encoding_p;
  260. }
  261. long
  262. ps_abort_fd_op(long fd_as_long)
  263. {
  264. int fd = (int)fd_as_long;
  265. if (!s48_remove_fd(fd))
  266. fprintf(stderr, "Error: ps_abort_fd_op, no pending operation on fd %d\n",
  267. fd);
  268. return 0; /* because we do not actually do any I/O in parallel the
  269. status is always zero: no characters transfered. */
  270. }
  271. /*
  272. * This checks that fd's destined for output channels are marked
  273. * as nonblocking. Stdout and stderr are a special case because
  274. * we do not want to screw up the shell, if we were invoked from
  275. * one.
  276. */
  277. s48_ref_t
  278. s48_add_channel_2(s48_call_t call, s48_ref_t mode, s48_ref_t id, long fd)
  279. {
  280. if (s48_eq_p_2(call, mode, s48_channel_status_output_2(call))
  281. && fd != 1
  282. && fd != 2) {
  283. int flags;
  284. RETRY_OR_RAISE_NEG(flags, fcntl(fd, F_GETFL));
  285. if ((flags & O_NONBLOCK) == 0)
  286. fprintf(stderr,
  287. "Warning: output channel file descriptor %d is not non-blocking\n",
  288. (int) fd); }
  289. return s48_make_local_ref(call, s48_really_add_channel(s48_deref(mode), s48_deref(id), fd));
  290. }
  291. s48_ref_t
  292. s48_set_channel_os_index_2(s48_call_t call, s48_ref_t channel, long fd)
  293. {
  294. /* back to the VM */
  295. return s48_make_local_ref(call, s48_set_channel_os_index(s48_deref(channel), fd));
  296. }