home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 3 / CDPDIII.bin / pd / programming / gnuc / library / rcs / select.c,v < prev    next >
Encoding:
Text File  |  1992-07-04  |  7.1 KB  |  259 lines

  1. head    1.1;
  2. access;
  3. symbols
  4.     version39-41:1.1;
  5. locks;
  6. comment    @ *  @;
  7.  
  8.  
  9. 1.1
  10. date    92.05.14.19.55.40;    author mwild;    state Exp;
  11. branches;
  12. next    ;
  13.  
  14.  
  15. desc
  16. @select(2) dispatcher
  17. @
  18.  
  19.  
  20. 1.1
  21. log
  22. @Initial revision
  23. @
  24. text
  25. @/*
  26.  *  This file is part of ixemul.library for the Amiga.
  27.  *  Copyright (C) 1991, 1992  Markus M. Wild
  28.  *
  29.  *  This library is free software; you can redistribute it and/or
  30.  *  modify it under the terms of the GNU Library General Public
  31.  *  License as published by the Free Software Foundation; either
  32.  *  version 2 of the License, or (at your option) any later version.
  33.  *
  34.  *  This library is distributed in the hope that it will be useful,
  35.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  36.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  37.  *  Library General Public License for more details.
  38.  *
  39.  *  You should have received a copy of the GNU Library General Public
  40.  *  License along with this library; if not, write to the Free
  41.  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  42.  *
  43.  *  $Id$
  44.  *
  45.  *  $Log$
  46.  */
  47.  
  48. #define KERNEL
  49. #include "ixemul.h"
  50.  
  51. #include <sys/time.h>
  52.  
  53. #include "select.h"
  54.  
  55. #define __time_req (u.u_time_req)
  56. #define __tport    (u.u_sync_mp)
  57.  
  58. static void inline setcopy(int nfd, u_int *ifd, u_int *ofd)
  59. {
  60.   /* this procedure is here, because it's "normal" that if you only
  61.    * want to select on fd 0,1,2 eg. you only pass a long to select,
  62.    * not a whole fd_set, so we can't simply copy over results in the
  63.    * full size of an fd_set.. */
  64.   
  65.   /* we have to copy that many longs... */
  66.   nfd = (nfd+31) >> 5;
  67.   while (nfd--) *ofd++ = *ifd++;
  68. }
  69.  
  70. int
  71. select(int nfd, fd_set *ifd, fd_set *ofd, fd_set *efd, struct timeval *timeout)
  72. {
  73.   struct file *f;
  74.   int i, waitin, waitout, waitexc, dotout;
  75.   int result, omask;
  76.   u_int wait_sigs;
  77.   struct timeval end_time;
  78.  
  79.   /* as long as I don't support anything similar to a network, I surely
  80.    * won't get any exceptional conditions, so *efd is mapped into 
  81.    * *ifd, if it's set. */
  82.    
  83.   /* first check, that all included descriptors are valid and support
  84.    * the requested operation. If the user included a request to wait
  85.    * for a descriptor to be ready to read, while the descriptor was only
  86.    * opened for writing, the requested bit is immediately cleared
  87.    */
  88.   waitin = waitout = waitexc = 0;
  89.   if (nfd > NOFILE) nfd = NOFILE;
  90.  
  91.   for (i = 0; i < nfd; i++)
  92.     {
  93.       if (ifd && FD_ISSET(i, ifd) && (f = u.u_ofile[i]))
  94.     {
  95.       if (!f->f_read || !f->f_select)
  96.         FD_CLR(i, ifd);
  97.       else
  98.         ++waitin;
  99.     }
  100.       if (ofd && FD_ISSET(i, ofd) && (f = u.u_ofile[i]))
  101.     {
  102.       if (!f->f_write || !f->f_select)
  103.         FD_CLR(i, ofd);
  104.       else
  105.         ++waitout;
  106.     }
  107.       if (efd && FD_ISSET(i, efd) && (f = u.u_ofile[i]))
  108.     {
  109.       /* question: can an exceptional condition also occur on a 
  110.        * write-only fd?? */
  111.       if (!f->f_read || !f->f_select)
  112.         FD_CLR(i, efd);
  113.       else
  114.         ++waitout;
  115.     }
  116.     }
  117.  
  118.   if (0)
  119.     {
  120.       /* this belongs logically here, not at the end of the function */
  121. badfd:
  122.       errno = EBADF;
  123.       return -1;
  124.     }
  125.  
  126.  
  127.   /* now, if we see, that we're not waiting for anything, AND if
  128.    * timeout is NULL (not 0 seconds!), than select() is just something
  129.    * like a very complex pause() call ;-)) */
  130.   if (waitin + waitout + waitexc == 0 && !timeout)
  131.     return syscall (SYS_pause);
  132.  
  133.   if (dotout=(timeout && timerisset(timeout)))
  134.     {
  135.       /* remember the time we have to leave (timeout) */
  136.       syscall (SYS_gettimeofday, &end_time, 0);
  137.       end_time.tv_usec += timeout->tv_usec;
  138.       /* this conversion should be cheaper than a division and a modulo.. */
  139.       while (end_time.tv_usec >= 1000000)
  140.         {
  141.       end_time.tv_usec -= 1000000;
  142.       end_time.tv_sec++;
  143.     }
  144.       end_time.tv_sec += timeout->tv_sec;
  145.     }
  146.  
  147.   /* have to make sure we can clean up the timer-request ! */
  148.   omask = syscall (SYS_sigsetmask, ~0);
  149.  
  150.   for (;;)
  151.     {
  152.       fd_set readyin, readyout, readyexc;
  153.       int tout, readydesc;
  154.  
  155.       FD_ZERO(&readyin);
  156.       FD_ZERO(&readyout);
  157.       FD_ZERO(&readyexc);
  158.  
  159.       tout = 
  160.         readydesc = 0;
  161.  
  162.       /* have to always wait for the `traditional' ^C and the library internal
  163.        * sleep_sig as well */
  164.       wait_sigs = SIGBREAKF_CTRL_C | (1 << u.u_sleep_sig);
  165.  
  166.       /* note: we never post a timeout request of less than SELTIMEOUT, so
  167.        * select() precision depends on SELTIMEOUT. However, considering that
  168.        * this call emulates a Unix syscall, this comes quite near to Unix
  169.        * precision, if not better ;-)) */
  170.       if (dotout)
  171.     {
  172.       __time_req->tr_time.tv_sec = 0;
  173.       __time_req->tr_time.tv_usec = SELTIMEOUT;
  174.           __time_req->tr_node.io_Command = TR_ADDREQUEST;
  175.           SendIO((struct IORequest *)__time_req);
  176.       wait_sigs |= 1 << __tport->mp_SigBit;
  177.         }
  178.  
  179.       /* have all watched files get prepared for selecting */
  180.       for (i = 0; i < nfd; i++)
  181.     {
  182.       if (ifd && FD_ISSET (i, ifd) && (f = u.u_ofile[i]))
  183.         wait_sigs |= f->f_select (f, SELCMD_PREPARE, SELMODE_IN);
  184.       if (ofd && FD_ISSET (i, ofd) && (f = u.u_ofile[i]))
  185.         wait_sigs |= f->f_select (f, SELCMD_PREPARE, SELMODE_OUT);
  186.       if (efd && FD_ISSET (i, efd) && (f = u.u_ofile[i]))
  187.         wait_sigs |= f->f_select (f, SELCMD_PREPARE, SELMODE_EXC);
  188.     }
  189.  
  190.       /* now wait for all legally possible signals, this includes BSD
  191.        * signals (but want at least one signal set!) */
  192.       while (! Wait (wait_sigs)) ;
  193.  
  194.       /* no matter what caused Wait() to return, wait for all requests to
  195.        * complete (we CAN'T abort a DOS packet, sigh..) */
  196.       if (dotout)
  197.         {
  198.       /* IMPORTANT: unqueue the timer request BEFORE polling the fd's,
  199.        *            or __wait_packet() will treat the timer request
  200.        *            as a packet... */
  201.  
  202.       if (! CheckIO ((struct IORequest *)__time_req))
  203.             AbortIO ((struct IORequest *)__time_req);
  204.           WaitIO ((struct IORequest *)__time_req);
  205.         }
  206.  
  207.       /* collect information from the file descriptors */
  208.       for (i = 0; i < nfd; i++)
  209.     {
  210.       if (ifd && FD_ISSET (i, ifd) && (f = u.u_ofile[i])
  211.           && f->f_select (f, SELCMD_CHECK, SELMODE_IN))
  212.         {
  213.           FD_SET (i, &readyin);
  214.           ++ readydesc;
  215.         }
  216.       if (ofd && FD_ISSET (i, ofd) && (f = u.u_ofile[i])
  217.           && f->f_select (f, SELCMD_CHECK, SELMODE_OUT))
  218.         {
  219.           FD_SET (i, &readyout);
  220.           ++ readydesc;
  221.         }
  222.       if (ofd && FD_ISSET (i, efd) && (f = u.u_ofile[i])
  223.               && f->f_select (f, SELCMD_CHECK, SELMODE_EXC))
  224.         {
  225.           FD_SET (i, &readyexc);
  226.           ++ readydesc;
  227.         }
  228.     }
  229.  
  230.       /* we have a timeout condition, if readydesc == 0, dotout == 1 and 
  231.        * end_time < current time */
  232.       if (!readydesc && dotout)
  233.         {
  234.           struct timeval current_time;
  235.           
  236.           syscall (SYS_gettimeofday, ¤t_time, 0);
  237.           tout = timercmp (&end_time, ¤t_time, <);
  238.     }
  239.  
  240.       if (readydesc || tout)
  241.     {
  242.       if (ifd) setcopy(nfd, (u_int *)&readyin,  (u_int *)ifd);
  243.       if (ofd) setcopy(nfd, (u_int *)&readyout, (u_int *)ofd);
  244.       if (efd) setcopy(nfd, (u_int *)&readyexc, (u_int *)efd);
  245.       result = readydesc; /* ok for tout, since then readydesc is already 0 */
  246.       break;
  247.     }
  248.  
  249.       /* make interrupts possible */
  250.       syscall (SYS_sigsetmask, omask);
  251.       omask = syscall (SYS_sigsetmask);
  252.     }
  253.  
  254.   syscall (SYS_sigsetmask, omask);
  255.  
  256.   return result;
  257. }
  258. @
  259.