home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mitsch75.zip / scheme-7_5_17-src.zip / scheme-7.5.17 / src / microcode / uxio.c < prev    next >
C/C++ Source or Header  |  2001-04-03  |  16KB  |  664 lines

  1. /* -*-C-*-
  2.  
  3. $Id: uxio.c,v 1.46 2001/04/03 17:51:52 cph Exp $
  4.  
  5. Copyright (c) 1990-2001 Massachusetts Institute of Technology
  6.  
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or (at
  10. your option) any later version.
  11.  
  12. This program is distributed in the hope that it will be useful, but
  13. WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15. General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  20. USA.
  21. */
  22.  
  23. #include "ux.h"
  24. #include "uxio.h"
  25. #include "uxselect.h"
  26. #include "uxproc.h"
  27.  
  28. size_t OS_channel_table_size;
  29. struct channel * channel_table;
  30.  
  31. #ifndef HAVE_POLL
  32. static SELECT_TYPE input_descriptors;
  33. #ifdef HAVE_SELECT
  34. static struct timeval zero_timeout;
  35. #endif
  36. #endif
  37.  
  38. static void
  39. DEFUN_VOID (UX_channel_close_all)
  40. {
  41.   Tchannel channel;
  42.   for (channel = 0; (channel < OS_channel_table_size); channel += 1)
  43.     if (CHANNEL_OPEN_P (channel))
  44.       OS_channel_close_noerror (channel);
  45. }
  46.  
  47. extern void EXFUN (add_reload_cleanup, (void (*) (void)));
  48.  
  49. void
  50. DEFUN_VOID (UX_initialize_channels)
  51. {
  52.   OS_channel_table_size = (UX_SC_OPEN_MAX ());
  53.   channel_table =
  54.     (UX_malloc (OS_channel_table_size * (sizeof (struct channel))));
  55.   if (channel_table == 0)
  56.     {
  57.       fprintf (stderr, "\nUnable to allocate channel table.\n");
  58.       fflush (stderr);
  59.       termination_init_error ();
  60.     }
  61.   {
  62.     Tchannel channel;
  63.     for (channel = 0; (channel < OS_channel_table_size); channel += 1)
  64.       MARK_CHANNEL_CLOSED (channel);
  65.   }
  66.   add_reload_cleanup (UX_channel_close_all);
  67. #ifndef HAVE_POLL
  68.   FD_ZERO (&input_descriptors);
  69. #ifdef HAVE_SELECT
  70.   (zero_timeout . tv_sec) = 0;
  71.   (zero_timeout . tv_usec) = 0;
  72. #endif
  73. #endif
  74. }
  75.  
  76. void
  77. DEFUN_VOID (UX_reset_channels)
  78. {
  79.   UX_free (channel_table);
  80.   channel_table = 0;
  81.   OS_channel_table_size = 0;
  82. }
  83.  
  84. Tchannel
  85. DEFUN_VOID (channel_allocate)
  86. {
  87.   Tchannel channel = 0;
  88.   while (1)
  89.     {
  90.       if (channel == OS_channel_table_size)
  91.     error_out_of_channels ();
  92.       if (CHANNEL_CLOSED_P (channel))
  93.     return (channel);
  94.       channel += 1;
  95.     }
  96. }
  97.  
  98. int
  99. DEFUN (UX_channel_descriptor, (channel), Tchannel channel)
  100. {
  101.   return (CHANNEL_DESCRIPTOR (channel));
  102. }
  103.  
  104. int
  105. DEFUN (OS_channel_open_p, (channel), Tchannel channel)
  106. {
  107.   return (CHANNEL_OPEN_P (channel));
  108. }
  109.  
  110. void
  111. DEFUN (OS_channel_close, (channel), Tchannel channel)
  112. {
  113.   if (! (CHANNEL_INTERNAL (channel)))
  114.     {
  115.       STD_VOID_SYSTEM_CALL
  116.     (syscall_close, (UX_close (CHANNEL_DESCRIPTOR (channel))));
  117.       MARK_CHANNEL_CLOSED (channel);
  118.     }
  119. }
  120.  
  121. void
  122. DEFUN (OS_channel_close_noerror, (channel), Tchannel channel)
  123. {
  124.   if (! (CHANNEL_INTERNAL (channel)))
  125.     {
  126.       UX_close (CHANNEL_DESCRIPTOR (channel));
  127.       MARK_CHANNEL_CLOSED (channel);
  128.     }
  129. }
  130.  
  131. static void
  132. DEFUN (channel_close_on_abort_1, (cp), PTR cp)
  133. {
  134.   OS_channel_close (* ((Tchannel *) cp));
  135. }
  136.  
  137. void
  138. DEFUN (OS_channel_close_on_abort, (channel), Tchannel channel)
  139. {
  140.   Tchannel * cp = (dstack_alloc (sizeof (Tchannel)));
  141.   (*cp) = (channel);
  142.   transaction_record_action (tat_abort, channel_close_on_abort_1, cp);
  143. }
  144.  
  145. enum channel_type
  146. DEFUN (OS_channel_type, (channel), Tchannel channel)
  147. {
  148.   return (CHANNEL_TYPE (channel));
  149. }
  150.  
  151. long
  152. DEFUN (OS_channel_read, (channel, buffer, nbytes),
  153.        Tchannel channel AND
  154.        PTR buffer AND
  155.        size_t nbytes)
  156. {
  157.   if (nbytes == 0)
  158.     return (0);
  159.   while (1)
  160.     {
  161.       long scr = (UX_read ((CHANNEL_DESCRIPTOR (channel)), buffer, nbytes));
  162.       if (scr < 0)
  163.     {
  164. #ifdef _ULTRIX
  165.     /* This is needed for non-POSIX-ified master pseudo-terminal
  166.        driver, which always returns EWOULDBLOCK, even to POSIX
  167.        applications. */
  168.     if (CHANNEL_TYPE (channel) == channel_type_unix_pty_master)
  169.       {
  170.         if (errno == EWOULDBLOCK)
  171.           return (-1);
  172.       }
  173.     else
  174.       {
  175.         if (errno == EAGAIN)
  176.           return (-1);
  177.       }
  178. #else
  179. #ifdef ERRNO_NONBLOCK
  180.     if (errno == ERRNO_NONBLOCK)
  181.       return (-1);
  182. #endif
  183. #endif /* not _ULTRIX */
  184.       UX_prim_check_errno (syscall_read);
  185.       continue;
  186.     }
  187.       if (scr > nbytes)
  188.     error_external_return ();
  189. #ifdef AMBIGUOUS_NONBLOCK
  190.       return ((scr > 0) ? scr : (CHANNEL_NONBLOCKING (channel)) ? (-1) : 0);
  191. #else
  192.       return (scr);
  193. #endif
  194.     }
  195. }
  196.  
  197. long
  198. DEFUN (OS_channel_write, (channel, buffer, nbytes),
  199.        Tchannel channel AND
  200.        CONST PTR buffer AND
  201.        size_t nbytes)
  202. {
  203.   if (nbytes == 0)
  204.     return (0);
  205.   while (1)
  206.     {
  207.       long scr = (UX_write ((CHANNEL_DESCRIPTOR (channel)), buffer, nbytes));
  208.       if (scr < 0)
  209.     {
  210. #ifdef ERRNO_NONBLOCK
  211.       if (errno == ERRNO_NONBLOCK)
  212.         return (-1);
  213. #endif
  214.       UX_prim_check_errno (syscall_write);
  215.       continue;
  216.     }
  217.       if (scr > nbytes)
  218.     error_external_return ();
  219.       return ((scr > 0) ? scr : (-1));
  220.     }
  221. }
  222.  
  223. size_t
  224. DEFUN (OS_channel_read_load_file, (channel, buffer, nbytes),
  225.        Tchannel channel AND PTR buffer AND size_t nbytes)
  226. {
  227.   int scr = (UX_read ((CHANNEL_DESCRIPTOR (channel)), buffer, nbytes));
  228.   return ((scr < 0) ? 0 : scr);
  229. }
  230.  
  231. size_t
  232. DEFUN (OS_channel_write_dump_file, (channel, buffer, nbytes),
  233.        Tchannel channel AND CONST PTR buffer AND size_t nbytes)
  234. {
  235.   int scr = (UX_write ((CHANNEL_DESCRIPTOR (channel)), buffer, nbytes));
  236.   return ((scr < 0) ? 0 : scr);
  237. }
  238.  
  239. #ifdef _POSIX
  240. #include <string.h>
  241. #else
  242. extern int EXFUN (strlen, (CONST char *));
  243. #endif
  244.  
  245. void
  246. DEFUN (OS_channel_write_string, (channel, string),
  247.        Tchannel channel AND
  248.        CONST char * string)
  249. {
  250.   unsigned long length = (strlen (string));
  251.   if ((OS_channel_write (channel, string, length)) != length)
  252.     error_external_return ();
  253. }
  254.  
  255. void
  256. DEFUN (OS_make_pipe, (readerp, writerp),
  257.        Tchannel * readerp AND
  258.        Tchannel * writerp)
  259. {
  260.   int pv [2];
  261.   transaction_begin ();
  262.   STD_VOID_SYSTEM_CALL (syscall_pipe, (UX_pipe (pv)));
  263.   MAKE_CHANNEL ((pv[0]), channel_type_unix_pipe, (*readerp) =);
  264.   OS_channel_close_on_abort (*readerp);
  265.   MAKE_CHANNEL ((pv[1]), channel_type_unix_pipe, (*writerp) =);
  266.   transaction_commit ();
  267. }
  268.  
  269. #ifdef FCNTL_NONBLOCK
  270.  
  271. static int
  272. DEFUN (get_flags, (fd), int fd)
  273. {
  274.   int scr;
  275.   STD_UINT_SYSTEM_CALL (syscall_fcntl_GETFL, scr, (UX_fcntl (fd, F_GETFL, 0)));
  276.   return (scr);
  277. }
  278.  
  279. static void
  280. DEFUN (set_flags, (fd, flags), int fd AND int flags)
  281. {
  282.   STD_VOID_SYSTEM_CALL (syscall_fcntl_SETFL, (UX_fcntl (fd, F_SETFL, flags)));
  283. }
  284.  
  285. int
  286. DEFUN (OS_channel_nonblocking_p, (channel), Tchannel channel)
  287. {
  288.   return (CHANNEL_NONBLOCKING (channel));
  289. }
  290.  
  291. void
  292. DEFUN (OS_channel_nonblocking, (channel), Tchannel channel)
  293. {
  294.   int fd = (CHANNEL_DESCRIPTOR (channel));
  295.   int flags = (get_flags (fd));
  296.   if ((flags & FCNTL_NONBLOCK) == 0)
  297.     set_flags (fd, (flags | FCNTL_NONBLOCK));
  298. #ifdef _ULTRIX
  299.   {
  300.     /* This is needed for non-POSIX-ified pseudo-terminal driver.  fcntl
  301.        sets driver's FIONBIO flag for FNDELAY, but not FNBLOCK.  Note that
  302.        driver will return EWOULDBLOCK, rather than EAGAIN. */
  303.     int true = 1;
  304.     ioctl(fd,FIONBIO,&true);
  305.   }
  306. #endif
  307.   (CHANNEL_NONBLOCKING (channel)) = 1;
  308. }
  309.  
  310. void
  311. DEFUN (OS_channel_blocking, (channel), Tchannel channel)
  312. {
  313.   int fd = (CHANNEL_DESCRIPTOR (channel));
  314.   int flags = (get_flags (fd));
  315.   if ((flags & FCNTL_NONBLOCK) != 0)
  316.     set_flags (fd, (flags &~ FCNTL_NONBLOCK));
  317. #ifdef _ULTRIX
  318.   {
  319.     /* This is needed for non-POSIX-ified pseudo-terminal driver.  fcntl
  320.        sets driver's FIONBIO flag for FNDELAY, but not FNBLOCK. */
  321.     int false = 0;
  322.     ioctl(fd,FIONBIO,&false);
  323.   }
  324. #endif
  325.   (CHANNEL_NONBLOCKING (channel)) = 0;
  326. }
  327.  
  328. #else /* not FCNTL_NONBLOCK */
  329.  
  330. int
  331. DEFUN (OS_channel_nonblocking_p, (channel), Tchannel channel)
  332. {
  333.   return (-1);
  334. }
  335.  
  336. void
  337. DEFUN (OS_channel_nonblocking, (channel), Tchannel channel)
  338. {
  339.   error_unimplemented_primitive ();
  340. }
  341.  
  342. void
  343. DEFUN (OS_channel_blocking, (channel), Tchannel channel)
  344. {
  345. }
  346.  
  347. #endif /* FCNTL_NONBLOCK */
  348.  
  349. #ifdef HAVE_POLL
  350.  
  351. /* poll(2) */
  352.  
  353. CONST int OS_have_select_p = 1;
  354.  
  355. unsigned int
  356. DEFUN_VOID (UX_select_registry_size)
  357. {
  358.   return ((sizeof (struct pollfd)) * OS_channel_table_size);
  359. }
  360.  
  361. unsigned int
  362. DEFUN_VOID (UX_select_registry_lub)
  363. {
  364.   return (OS_channel_table_size);
  365. }
  366.  
  367. void
  368. DEFUN (UX_select_registry_clear_all, (fds), PTR fds)
  369. {
  370.   struct pollfd * scan = fds;
  371.   struct pollfd * end = (scan + OS_channel_table_size);
  372.   for (; (scan < end); scan += 1)
  373.     {
  374.       (scan -> fd) = (-1);
  375.       (scan -> events) = 0;
  376.     }
  377. }
  378.  
  379. void
  380. DEFUN (UX_select_registry_set, (fds, fd), PTR fds AND unsigned int fd)
  381. {
  382.   struct pollfd * scan = fds;
  383.   struct pollfd * end = (scan + OS_channel_table_size);
  384.   for (; (scan < end); scan += 1)
  385.     if (((scan -> fd) == (-1)) || ((scan -> fd) == fd))
  386.       {
  387.     (scan -> fd) = fd;
  388.     (scan -> events) = POLLIN;
  389.     break;
  390.       }
  391. }
  392.  
  393. void
  394. DEFUN (UX_select_registry_clear, (fds, fd), PTR fds AND unsigned int fd)
  395. {
  396.   struct pollfd * scan = fds;
  397.   struct pollfd * end = (scan + OS_channel_table_size);
  398.   for (; (scan < end); scan += 1)
  399.     if ((scan -> fd) == fd)
  400.       {
  401.     /* Shift any subsequent entries down.  */
  402.     for (; (((scan + 1) < end) && ((scan -> fd) != (-1))); scan += 1)
  403.       (*scan) = (* (scan + 1));
  404.     (scan -> fd) = (-1);
  405.     (scan -> events) = 0;
  406.     return;
  407.       }
  408. }
  409.  
  410. int
  411. DEFUN (UX_select_registry_is_set, (fds, fd), PTR fds AND unsigned int fd)
  412. {
  413.   struct pollfd * scan = fds;
  414.   struct pollfd * end = (scan + OS_channel_table_size);
  415.   for (; (scan < end); scan += 1)
  416.     if ((scan -> fd) == fd)
  417.       return (1);
  418.   return (0);
  419. }
  420.  
  421. static unsigned int
  422. count_select_registry_entries (struct pollfd * pfds)
  423. {
  424.   struct pollfd * end = (pfds + OS_channel_table_size);
  425.   struct pollfd * scan;
  426.   for (scan = pfds; (scan < end); scan += 1)
  427.     if ((scan -> fd) == (-1))
  428.       break;
  429.   return (scan - pfds);
  430. }
  431.  
  432. enum select_input
  433. DEFUN (UX_select_registry_test, (input_fds, blockp, output_fds, output_nfds),
  434.        PTR input_fds AND
  435.        int blockp AND
  436.        unsigned int * output_fds AND
  437.        unsigned int * output_nfds)
  438. {
  439.   struct pollfd * pfds = input_fds;
  440.   unsigned int n_pfds = (count_select_registry_entries (pfds));
  441.   while (1)
  442.     {
  443.       int nfds = (poll (pfds, n_pfds, (blockp ? INFTIM : 0)));
  444.       if (nfds > 0)
  445.     {
  446.       if (output_nfds != 0)
  447.         (*output_nfds) = nfds;
  448.       if (output_fds != 0)
  449.         {
  450.           struct pollfd * scan = pfds;
  451.           struct pollfd * end = (scan + n_pfds);
  452.           while (scan < end)
  453.         {
  454.           if (((scan -> fd) != (-1)) && ((scan -> revents) != 0))
  455.             {
  456.               (*output_fds++) = (scan -> fd);
  457.               if ((--nfds) == 0)
  458.             break;
  459.             }
  460.           scan += 1;
  461.         }
  462.         }
  463.       return (select_input_argument);
  464.     }
  465.       else if (nfds == 0)
  466.     {
  467.       if (!blockp)
  468.         return (select_input_none);
  469.     }
  470.       else if (! ((errno == EINTR) || (errno == EAGAIN)))
  471.     error_system_call (errno, syscall_select);
  472.       else if (OS_process_any_status_change ())
  473.     return (select_input_process_status);
  474.       if (pending_interrupts_p ())
  475.     return (select_input_interrupt);
  476.     }
  477. }
  478.  
  479. enum select_input
  480. DEFUN (UX_select_descriptor, (fd, blockp),
  481.        unsigned int fd AND
  482.        int blockp)
  483. {
  484.   struct pollfd pfds [1];
  485.   int nfds;
  486.  
  487.   ((pfds [0]) . fd) = fd;
  488.   ((pfds [0]) . events) = POLLIN;
  489.   while (1)
  490.     {
  491.       nfds = (poll (pfds, 1, (blockp ? INFTIM : 0)));
  492.       if (nfds > 0)
  493.     return (select_input_argument);
  494.       else if (nfds == 0)
  495.     {
  496.       if (!blockp)
  497.         return (select_input_none);
  498.     }
  499.       else if (errno != EINTR)
  500.     error_system_call (errno, syscall_select);
  501.       else if (OS_process_any_status_change ())
  502.     return (select_input_process_status);
  503.       if (pending_interrupts_p ())
  504.     return (select_input_interrupt);
  505.     }  
  506. }
  507.  
  508. enum select_input
  509. DEFUN (UX_select_input, (fd, blockp), int fd AND int blockp)
  510. {
  511.   return (UX_select_descriptor (fd, blockp));
  512. }
  513.  
  514. #else /* not HAVE_POLL */
  515.  
  516. /* select(2) */
  517.  
  518. #ifdef HAVE_SELECT
  519. CONST int OS_have_select_p = 1;
  520. #else
  521. CONST int OS_have_select_p = 0;
  522. #endif
  523.  
  524. unsigned int
  525. DEFUN_VOID (UX_select_registry_size)
  526. {
  527.   return (sizeof (SELECT_TYPE));
  528. }
  529.  
  530. unsigned int
  531. DEFUN_VOID (UX_select_registry_lub)
  532. {
  533.   return (FD_SETSIZE);
  534. }
  535.  
  536. void
  537. DEFUN (UX_select_registry_clear_all, (fds), PTR fds)
  538. {
  539.   FD_ZERO ((SELECT_TYPE *) fds);
  540. }
  541.  
  542. void
  543. DEFUN (UX_select_registry_set, (fds, fd), PTR fds AND unsigned int fd)
  544. {
  545.   FD_SET (fd, ((SELECT_TYPE *) fds));
  546. }
  547.  
  548. void
  549. DEFUN (UX_select_registry_clear, (fds, fd), PTR fds AND unsigned int fd)
  550. {
  551.   FD_CLR (fd, ((SELECT_TYPE *) fds));
  552. }
  553.  
  554. int
  555. DEFUN (UX_select_registry_is_set, (fds, fd), PTR fds AND unsigned int fd)
  556. {
  557.   return (FD_ISSET (fd, ((SELECT_TYPE *) fds)));
  558. }
  559.  
  560. enum select_input
  561. DEFUN (UX_select_registry_test, (input_fds, blockp, output_fds, output_nfds),
  562.        PTR input_fds AND
  563.        int blockp AND
  564.        unsigned int * output_fds AND
  565.        unsigned int * output_nfds)
  566. {
  567. #ifdef HAVE_SELECT
  568.   while (1)
  569.     {
  570.       SELECT_TYPE readable;
  571.       int nfds;
  572.   
  573.       readable = (* ((SELECT_TYPE *) input_fds));
  574.       INTERRUPTABLE_EXTENT
  575.     (nfds,
  576.      ((OS_process_any_status_change ())
  577.       ? ((errno = EINTR), (-1))
  578.       : (UX_select (FD_SETSIZE,
  579.             (&readable),
  580.             ((SELECT_TYPE *) 0),
  581.             ((SELECT_TYPE *) 0),
  582.             (blockp
  583.              ? ((struct timeval *) 0)
  584.              : (&zero_timeout))))));
  585.       if (nfds > 0)
  586.     {
  587.       unsigned int i = 0;
  588.       if (output_nfds != 0)
  589.         (*output_nfds) = nfds;
  590.       if (output_fds != 0)
  591.         while (1)
  592.           {
  593.         if (FD_ISSET (i, (&readable)))
  594.           {
  595.             (*output_fds++) = i;
  596.             if ((--nfds) == 0)
  597.               break;
  598.           }
  599.         i += 1;
  600.           }
  601.       return (select_input_argument);
  602.     }
  603.       else if (nfds == 0)
  604.     {
  605.       if (!blockp)
  606.         return (select_input_none);
  607.     }
  608.       else if (errno != EINTR)
  609.     error_system_call (errno, syscall_select);
  610.       else if (OS_process_any_status_change ())
  611.     return (select_input_process_status);
  612.       if (pending_interrupts_p ())
  613.     return (select_input_interrupt);
  614.     }
  615. #else
  616.   error_system_call (ENOSYS, syscall_select);
  617.   return (select_input_argument);
  618. #endif
  619. }
  620.  
  621. enum select_input
  622. DEFUN (UX_select_descriptor, (fd, blockp),
  623.        unsigned int fd AND
  624.        int blockp)
  625. {
  626. #ifdef HAVE_SELECT
  627.   SELECT_TYPE readable;
  628.  
  629.   FD_ZERO (&readable);
  630.   FD_SET (fd, (&readable));
  631.   return (UX_select_registry_test ((&readable), blockp, 0, 0));
  632. #else
  633.   error_system_call (ENOSYS, syscall_select);
  634.   return (select_input_argument);
  635. #endif
  636. }
  637.  
  638. enum select_input
  639. DEFUN (UX_select_input, (fd, blockp), int fd AND int blockp)
  640. {
  641.   SELECT_TYPE readable;
  642.   unsigned int fds [FD_SETSIZE];
  643.   unsigned int nfds;
  644.  
  645.   readable = input_descriptors;
  646.   FD_SET (fd, (&readable));
  647.   {
  648.     enum select_input s =
  649.       (UX_select_registry_test ((&readable), blockp, fds, (&nfds)));
  650.     if (s != select_input_argument)
  651.       return (s);
  652.   }
  653.   {
  654.     unsigned int * scan = fds;
  655.     unsigned int * end = (scan + nfds);
  656.     while (scan < end)
  657.       if ((*scan++) == fd)
  658.     return (select_input_argument);
  659.   }
  660.   return (select_input_other);
  661. }
  662.  
  663. #endif /* not HAVE_POLL */
  664.