Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  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 <errno.h>
  17. #include <stdio.h>
  18. #include <string.h>
  19. #include <libc/file.h>
  20. #include <libc/local.h>
  21. #include <libc/dosio.h>
  22. #include <sys/fsext.h>
  23.  
  24. inline static int fp_output_ready(FILE *fp)
  25. {
  26.   return !ferror(fp);
  27. }
  28.  
  29. /* This is as close as we get, I think.  For a file connected to a printer
  30.    we could of course go ask the BIOS, but this should be enough.  */
  31.  
  32. inline static int fp_except_ready(FILE *fp)
  33. {
  34.   return ferror (fp);
  35. }
  36.  
  37. inline static int fp_input_ready (FILE *fp)
  38. {
  39.   /* I think if there is something in the buffer, we should return
  40.      ``ready'', even if some error was encountered.  Let him consume
  41.      the buffered characters, *then* return ``not ready''.  */
  42.   if (fp->_cnt)
  43.     return 1;
  44.  
  45.   /* The `feof' part is only correct in a single-tasked environment.  */
  46.   if (ferror (fp) || feof (fp))
  47.     return 0;
  48.  
  49.   /* There is nothing in the buffer (perhaps because we read unbuffered).
  50.      We don't know if we are ready.  Return ``ready'' anyway and let
  51.      read() or write() tell the truth.  */
  52.   return 1;
  53. }
  54.  
  55. /* The Dos call 4407 always returns TRUE for disk files.  So the
  56.    following really is meaningful for character devices only...  */
  57.  
  58. inline static int fd_output_ready(int fd)
  59. {
  60.  return 0;
  61. }
  62.  
  63. inline static int fd_input_ready(int fd)
  64. {
  65.  return 0;
  66. }
  67.  
  68. int select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,
  69.         struct timeval *timeout)
  70. {
  71.   int ready;
  72.   fd_set oread, owrite, oexcept;
  73.   struct timeval now, then;
  74.  
  75.   if (nfds > FD_SETSIZE)
  76.   {
  77.     errno = EINVAL;
  78.     return -1;
  79.   }
  80.  
  81.   FD_ZERO (&oread);
  82.   FD_ZERO (&owrite);
  83.   FD_ZERO (&oexcept);
  84.   ready = 0;
  85.  
  86.   if (timeout)
  87.   {
  88.     if (timeout->tv_usec < 0)
  89.     {
  90.       errno = EINVAL;
  91.       return -1;
  92.     }
  93.     gettimeofday (&now, 0);
  94.     then.tv_usec = timeout->tv_usec + now.tv_usec;
  95.     then.tv_sec = timeout->tv_sec + now.tv_sec + then.tv_usec / 1000000;
  96.     then.tv_usec %= 1000000;
  97.   }
  98.  
  99.   do {
  100.     int i;
  101.     int fd0 = 0;
  102.     __file_rec *fr = __file_rec_list;
  103.     FILE *fp;
  104.  
  105.     /* First, check the file handles with low-level DOS calls.  */
  106.     for (i = 0; i < nfds; i++)
  107.     {
  108.       register int ioctl_result;
  109.       __FSEXT_Function *func = __FSEXT_get_function(i);
  110.       int fsext_ready = -1;
  111.  
  112.       if (func)
  113.         func(__FSEXT_ready, &fsext_ready, &i);
  114.  
  115.       if (readfds && FD_ISSET (i, readfds))
  116.       {
  117.         if (fsext_ready != -1)
  118.         {
  119.           if (fsext_ready & __FSEXT_ready_read)
  120.             ready++, FD_SET(i, &oread);
  121.         }
  122.         else if ((ioctl_result = fd_input_ready (i)) == -1)
  123.           return -1;
  124.         else if (ioctl_result)
  125.           ready++, FD_SET (i, &oread);
  126.       }
  127.       if (writefds && FD_ISSET (i, writefds))
  128.       {
  129.         if (fsext_ready != -1)
  130.         {
  131.           if (fsext_ready & __FSEXT_ready_write)
  132.             ready++, FD_SET(i, &owrite);
  133.         }
  134.         else if ((ioctl_result = fd_output_ready (i)) == -1)
  135.           return -1;
  136.         else if (ioctl_result)
  137.           ready++, FD_SET (i, &owrite);
  138.       }
  139.       if (exceptfds && FD_ISSET (i, exceptfds))
  140.       {
  141.         if (fsext_ready != -1)
  142.         {
  143.           if (fsext_ready & __FSEXT_ready_error)
  144.             ready++, FD_SET(i, &oexcept);
  145.         }
  146.       }
  147.     }
  148.  
  149.     /* Now look at the table of FILE ptrs and reset the bits for file
  150.        descriptors which we *thought* are ready, but for which the flags
  151.        say they're NOT ready.  */
  152.     for (i = 0; fr; i++)
  153.     {
  154.       if (i >= fd0 + fr->count) /* done with this subtable, go to next */
  155.       {
  156.         fd0 += fr->count;
  157.         fr = fr->next;
  158.       }
  159.       if (fr)
  160.       {
  161.         fp = fr->files[i - fd0];
  162.         if (fp->_flag)
  163.         {
  164.           int this_fd = fileno(fp);
  165.  
  166.           if (this_fd < nfds)
  167.           {
  168.             if (readfds && FD_ISSET (this_fd, readfds) &&
  169.                 FD_ISSET (this_fd, &oread) && !fp_input_ready (fp))
  170.               ready--, FD_CLR (this_fd, &oread);
  171.             if (writefds && FD_ISSET (this_fd, writefds) &&
  172.                 FD_ISSET (this_fd, &owrite) && !fp_output_ready (fp))
  173.               ready--, FD_CLR (this_fd, &owrite);
  174.  
  175.             /* For exceptional conditions, ferror() is the only one
  176.                which can tell us an exception is pending.  */
  177.             if (exceptfds && FD_ISSET (this_fd, exceptfds) &&
  178.                 fp_except_ready (fp))
  179.               ready++, FD_SET (this_fd, &oexcept);
  180.           }
  181.         }
  182.       }
  183.     }
  184.  
  185.     /* Exit if we found what we were waiting for.  */
  186.     if (ready > 0)
  187.     {
  188.       if (readfds)
  189.         *readfds = oread;
  190.       if (writefds)
  191.         *writefds = owrite;
  192.       if (exceptfds)
  193.         *exceptfds = oexcept;
  194.       return ready;
  195.     }
  196.  
  197.     /* Exit if we hit the time limit.  */
  198.     if (timeout)
  199.     {
  200.       gettimeofday (&now, 0);
  201.       if (now.tv_sec > then.tv_sec
  202.           || (now.tv_sec = then.tv_sec && now.tv_usec >= then.tv_usec))
  203.         return 0;
  204.     }
  205.   } while (1);
  206. }
  207.