home *** CD-ROM | disk | FTP | other *** search
/ Super PC 34 / Super PC 34 (Shareware).iso / spc / UTIL / DJGPP2 / V2 / DJLSR200.ZIP / src / libc / compat / time / select.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-11-25  |  7.0 KB  |  291 lines

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