home *** CD-ROM | disk | FTP | other *** search
/ PC Extra Super CD 1998 January / PCPLUS131.iso / DJGPP / V2 / DJLSR201.ZIP / src / libc / compat / time / select.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-23  |  7.0 KB  |  292 lines

  1. /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */
  2. /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
  3. /* An implementation of select()
  4.  
  5.    Copyright 1995 by Morten Welinder
  6.    This file maybe freely distributed and modified as long as the
  7.    copyright notice remains.
  8.  
  9.    Notes: In a single process system as Dos this really boils down to
  10.    something that can check whether a character from standard input
  11.    is ready.  However, the code is organised in a way to make it easy
  12.    to extend to multi process systems like WinNT and OS/2.  */
  13.  
  14. #include <libc/stubs.h>
  15. #include <sys/types.h>
  16. #include <time.h>
  17. #include <dpmi.h>
  18. #include <errno.h>
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <libc/file.h>
  22. #include <libc/local.h>
  23. #include <libc/dosio.h>
  24. #include <sys/fsext.h>
  25.  
  26. inline static int
  27. fp_output_ready(FILE *fp)
  28. {
  29.   return !ferror(fp);
  30. }
  31.  
  32. /* This is as close as we get, I think.  For a file connected to a printer
  33.    we could of course go ask the BIOS, but this should be enough.  */
  34.  
  35. inline static int
  36. fp_except_ready(FILE *fp)
  37. {
  38.   return ferror (fp);
  39. }
  40.  
  41. inline static int
  42. fp_input_ready (FILE *fp)
  43. {
  44.   /* I think if there is something in the buffer, we should return
  45.      ``ready'', even if some error was encountered.  Let him consume
  46.      the buffered characters, *then* return ``not ready''.  */
  47.   if (fp->_cnt)
  48.     return 1;
  49.  
  50.   /* The `feof' part is only correct in a single-tasked environment.  */
  51.   if (ferror (fp) || feof (fp))
  52.     return 0;
  53.  
  54.   /* There is nothing in the buffer (perhaps because we read unbuffered).
  55.      We don't know if we are ready.  Return ``ready'' anyway and let
  56.      read() or write() tell the truth.  */
  57.   return 1;
  58. }
  59.  
  60. /* The Dos call 4407 always returns TRUE for disk files.  So the
  61.    following really is meaningful for character devices only...  */
  62.  
  63. inline static int
  64. fd_output_ready(int fd)
  65. {
  66.  
  67.   __dpmi_regs regs;
  68.  
  69.   regs.x.ax = 0x4407;
  70.   regs.x.bx = fd;
  71.   __dpmi_int (0x21, ®s);
  72.   if (regs.x.flags & 1)
  73.   {
  74.     errno = __doserr_to_errno (regs.x.ax);
  75.     return -1;
  76.   }
  77.   else
  78.     return regs.h.al == 0xff;
  79. }
  80.  
  81. inline static int
  82. fd_input_ready(int fd)
  83. {
  84.  
  85.   __dpmi_regs regs;
  86.  
  87.   regs.x.ax = 0x4406;
  88.   regs.x.bx = fd;
  89.   __dpmi_int (0x21, ®s);
  90.   if (regs.x.flags & 1)
  91.   {
  92.     errno = __doserr_to_errno (regs.x.ax);
  93.     return -1;
  94.   }
  95.   else
  96.     return regs.h.al == 0xff;
  97. }
  98.  
  99. int
  100. select(int nfds,
  101.     fd_set *readfds,
  102.     fd_set *writefds,
  103.     fd_set *exceptfds,
  104.     struct timeval *timeout)
  105. {
  106.   int ready;
  107.   fd_set oread, owrite, oexcept;
  108.   struct timeval now, then;
  109.  
  110.   if (nfds > FD_SETSIZE)
  111.   {
  112.     errno = EINVAL;
  113.     return -1;
  114.   }
  115.  
  116.   FD_ZERO (&oread);
  117.   FD_ZERO (&owrite);
  118.   FD_ZERO (&oexcept);
  119.   ready = 0;
  120.  
  121.   if (timeout)
  122.   {
  123.     if (timeout->tv_usec < 0)
  124.     {
  125.       errno = EINVAL;
  126.       return -1;
  127.     }
  128.     gettimeofday (&now, 0);
  129.     then.tv_usec = timeout->tv_usec + now.tv_usec;
  130.     then.tv_sec = timeout->tv_sec + now.tv_sec + then.tv_usec / 1000000;
  131.     then.tv_usec %= 1000000;
  132.   }
  133.  
  134.   do {
  135.     int i;
  136.     int fd0 = 0;
  137.     __file_rec *fr = __file_rec_list;
  138.     FILE *fp;
  139.  
  140.     /* First, check the file handles with low-level DOS calls.  */
  141.     for (i = 0; i < nfds; i++)
  142.     {
  143.       register int ioctl_result;
  144.       __FSEXT_Function *func = __FSEXT_get_function(i);
  145.       int fsext_ready = -1;
  146.  
  147.       if (func)
  148.     func(__FSEXT_ready, &fsext_ready, &i);
  149.  
  150.       if (readfds && FD_ISSET (i, readfds))
  151.       {
  152.     if (fsext_ready != -1)
  153.     {
  154.       if (fsext_ready & __FSEXT_ready_read)
  155.         ready++, FD_SET(i, &oread);
  156.     }
  157.         else if ((ioctl_result = fd_input_ready (i)) == -1)
  158.           return -1;
  159.         else if (ioctl_result)
  160.           ready++, FD_SET (i, &oread);
  161.       }
  162.       if (writefds && FD_ISSET (i, writefds))
  163.       {
  164.         if (fsext_ready != -1)
  165.     {
  166.       if (fsext_ready & __FSEXT_ready_write)
  167.         ready++, FD_SET(i, &owrite);
  168.     }
  169.         else if ((ioctl_result = fd_output_ready (i)) == -1)
  170.           return -1;
  171.         else if (ioctl_result)
  172.           ready++, FD_SET (i, &owrite);
  173.       }
  174.       if (exceptfds && FD_ISSET (i, exceptfds))
  175.       {
  176.         if (fsext_ready != -1)
  177.     {
  178.       if (fsext_ready & __FSEXT_ready_error)
  179.         ready++, FD_SET(i, &oexcept);
  180.     }
  181.       }
  182.     }
  183.  
  184.     /* Now look at the table of FILE ptrs and reset the bits for file
  185.        descriptors which we *thought* are ready, but for which the flags
  186.        say they're NOT ready.  */
  187.     for (i = 0; fr; i++)
  188.     {
  189.       if (i >= fd0 + fr->count) /* done with this subtable, go to next */
  190.       {
  191.     fd0 += fr->count;
  192.     fr = fr->next;
  193.       }
  194.       if (fr)
  195.       {
  196.         fp = fr->files[i - fd0];
  197.         if (fp->_flag)
  198.         {
  199.           int this_fd = fileno(fp);
  200.  
  201.           if (this_fd < nfds)
  202.           {
  203.             if (readfds && FD_ISSET (this_fd, readfds) &&
  204.                 FD_ISSET (this_fd, &oread) && !fp_input_ready (fp))
  205.               ready--, FD_CLR (this_fd, &oread);
  206.             if (writefds && FD_ISSET (this_fd, writefds) &&
  207.                 FD_ISSET (this_fd, &owrite) && !fp_output_ready (fp))
  208.               ready--, FD_CLR (this_fd, &owrite);
  209.  
  210.             /* For exceptional conditions, ferror() is the only one
  211.                which can tell us an exception is pending.  */
  212.             if (exceptfds && FD_ISSET (this_fd, exceptfds) &&
  213.                 fp_except_ready (fp))
  214.               ready++, FD_SET (this_fd, &oexcept);
  215.           }
  216.         }
  217.       }
  218.     }
  219.  
  220.     /* Exit if we found what we were waiting for.  */
  221.     if (ready > 0)
  222.     {
  223.       if (readfds)
  224.     *readfds = oread;
  225.       if (writefds)
  226.     *writefds = owrite;
  227.       if (exceptfds)
  228.     *exceptfds = oexcept;
  229.       return ready;
  230.     }
  231.  
  232.     /* Exit if we hit the time limit.  */
  233.     if (timeout)
  234.     {
  235.       gettimeofday (&now, 0);
  236.       if (now.tv_sec > then.tv_sec
  237.       || (now.tv_sec == then.tv_sec && now.tv_usec >= then.tv_usec))
  238.     return 0;
  239.     }
  240.  
  241.     /* We are busy-waiting, so give other processes a chance to run.  */
  242.     __dpmi_yield ();
  243.   } while (1);
  244. }
  245.  
  246. #ifdef  TEST
  247.  
  248. #include <stdio.h>
  249. #include <stdlib.h>
  250.  
  251. int
  252. main(void)
  253. {
  254.   struct timeval timeout;
  255.   fd_set read_fds, write_fds;
  256.   int i, select_result;
  257.  
  258.   timeout.tv_sec = 15;
  259.   timeout.tv_usec = 0;
  260.  
  261.   /* Display status of the 5 files open by default.  */
  262.   for (i = 0; i < 5; i++)
  263.     {
  264.  
  265.       FD_ZERO (&read_fds);
  266.       FD_SET (i, &read_fds);
  267.       select_result = select (i + 1, &read_fds, 0, 0, &timeout);
  268.       if (select_result == -1)
  269.         {
  270.           fprintf(stderr, "%d: Failure for input", i);
  271.           perror("");
  272.         }
  273.       else
  274.         fprintf(stderr,
  275.                 "%d: %s ready for input\n", i, select_result ? "" : "NOT");
  276.       FD_ZERO (&write_fds);
  277.       FD_SET (i, &write_fds);
  278.       select_result = select (i + 1, 0, &write_fds, 0, &timeout);
  279.       if (select_result == -1)
  280.         {
  281.           fprintf(stderr, "%d: Failure for output", i);
  282.           perror("");
  283.         }
  284.       else
  285.         fprintf(stderr,
  286.                 "%d: %s ready for output\n", i, select_result ? "" : "NOT");
  287.     }
  288.   return 0;
  289. }
  290.  
  291. #endif
  292.