home *** CD-ROM | disk | FTP | other *** search
- head 1.1;
- access;
- symbols
- version39-41:1.1;
- locks;
- comment @ * @;
-
-
- 1.1
- date 92.05.14.19.55.40; author mwild; state Exp;
- branches;
- next ;
-
-
- desc
- @select(2) dispatcher
- @
-
-
- 1.1
- log
- @Initial revision
- @
- text
- @/*
- * This file is part of ixemul.library for the Amiga.
- * Copyright (C) 1991, 1992 Markus M. Wild
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * $Id$
- *
- * $Log$
- */
-
- #define KERNEL
- #include "ixemul.h"
-
- #include <sys/time.h>
-
- #include "select.h"
-
- #define __time_req (u.u_time_req)
- #define __tport (u.u_sync_mp)
-
- static void inline setcopy(int nfd, u_int *ifd, u_int *ofd)
- {
- /* this procedure is here, because it's "normal" that if you only
- * want to select on fd 0,1,2 eg. you only pass a long to select,
- * not a whole fd_set, so we can't simply copy over results in the
- * full size of an fd_set.. */
-
- /* we have to copy that many longs... */
- nfd = (nfd+31) >> 5;
- while (nfd--) *ofd++ = *ifd++;
- }
-
- int
- select(int nfd, fd_set *ifd, fd_set *ofd, fd_set *efd, struct timeval *timeout)
- {
- struct file *f;
- int i, waitin, waitout, waitexc, dotout;
- int result, omask;
- u_int wait_sigs;
- struct timeval end_time;
-
- /* as long as I don't support anything similar to a network, I surely
- * won't get any exceptional conditions, so *efd is mapped into
- * *ifd, if it's set. */
-
- /* first check, that all included descriptors are valid and support
- * the requested operation. If the user included a request to wait
- * for a descriptor to be ready to read, while the descriptor was only
- * opened for writing, the requested bit is immediately cleared
- */
- waitin = waitout = waitexc = 0;
- if (nfd > NOFILE) nfd = NOFILE;
-
- for (i = 0; i < nfd; i++)
- {
- if (ifd && FD_ISSET(i, ifd) && (f = u.u_ofile[i]))
- {
- if (!f->f_read || !f->f_select)
- FD_CLR(i, ifd);
- else
- ++waitin;
- }
- if (ofd && FD_ISSET(i, ofd) && (f = u.u_ofile[i]))
- {
- if (!f->f_write || !f->f_select)
- FD_CLR(i, ofd);
- else
- ++waitout;
- }
- if (efd && FD_ISSET(i, efd) && (f = u.u_ofile[i]))
- {
- /* question: can an exceptional condition also occur on a
- * write-only fd?? */
- if (!f->f_read || !f->f_select)
- FD_CLR(i, efd);
- else
- ++waitout;
- }
- }
-
- if (0)
- {
- /* this belongs logically here, not at the end of the function */
- badfd:
- errno = EBADF;
- return -1;
- }
-
-
- /* now, if we see, that we're not waiting for anything, AND if
- * timeout is NULL (not 0 seconds!), than select() is just something
- * like a very complex pause() call ;-)) */
- if (waitin + waitout + waitexc == 0 && !timeout)
- return syscall (SYS_pause);
-
- if (dotout=(timeout && timerisset(timeout)))
- {
- /* remember the time we have to leave (timeout) */
- syscall (SYS_gettimeofday, &end_time, 0);
- end_time.tv_usec += timeout->tv_usec;
- /* this conversion should be cheaper than a division and a modulo.. */
- while (end_time.tv_usec >= 1000000)
- {
- end_time.tv_usec -= 1000000;
- end_time.tv_sec++;
- }
- end_time.tv_sec += timeout->tv_sec;
- }
-
- /* have to make sure we can clean up the timer-request ! */
- omask = syscall (SYS_sigsetmask, ~0);
-
- for (;;)
- {
- fd_set readyin, readyout, readyexc;
- int tout, readydesc;
-
- FD_ZERO(&readyin);
- FD_ZERO(&readyout);
- FD_ZERO(&readyexc);
-
- tout =
- readydesc = 0;
-
- /* have to always wait for the `traditional' ^C and the library internal
- * sleep_sig as well */
- wait_sigs = SIGBREAKF_CTRL_C | (1 << u.u_sleep_sig);
-
- /* note: we never post a timeout request of less than SELTIMEOUT, so
- * select() precision depends on SELTIMEOUT. However, considering that
- * this call emulates a Unix syscall, this comes quite near to Unix
- * precision, if not better ;-)) */
- if (dotout)
- {
- __time_req->tr_time.tv_sec = 0;
- __time_req->tr_time.tv_usec = SELTIMEOUT;
- __time_req->tr_node.io_Command = TR_ADDREQUEST;
- SendIO((struct IORequest *)__time_req);
- wait_sigs |= 1 << __tport->mp_SigBit;
- }
-
- /* have all watched files get prepared for selecting */
- for (i = 0; i < nfd; i++)
- {
- if (ifd && FD_ISSET (i, ifd) && (f = u.u_ofile[i]))
- wait_sigs |= f->f_select (f, SELCMD_PREPARE, SELMODE_IN);
- if (ofd && FD_ISSET (i, ofd) && (f = u.u_ofile[i]))
- wait_sigs |= f->f_select (f, SELCMD_PREPARE, SELMODE_OUT);
- if (efd && FD_ISSET (i, efd) && (f = u.u_ofile[i]))
- wait_sigs |= f->f_select (f, SELCMD_PREPARE, SELMODE_EXC);
- }
-
- /* now wait for all legally possible signals, this includes BSD
- * signals (but want at least one signal set!) */
- while (! Wait (wait_sigs)) ;
-
- /* no matter what caused Wait() to return, wait for all requests to
- * complete (we CAN'T abort a DOS packet, sigh..) */
- if (dotout)
- {
- /* IMPORTANT: unqueue the timer request BEFORE polling the fd's,
- * or __wait_packet() will treat the timer request
- * as a packet... */
-
- if (! CheckIO ((struct IORequest *)__time_req))
- AbortIO ((struct IORequest *)__time_req);
- WaitIO ((struct IORequest *)__time_req);
- }
-
- /* collect information from the file descriptors */
- for (i = 0; i < nfd; i++)
- {
- if (ifd && FD_ISSET (i, ifd) && (f = u.u_ofile[i])
- && f->f_select (f, SELCMD_CHECK, SELMODE_IN))
- {
- FD_SET (i, &readyin);
- ++ readydesc;
- }
- if (ofd && FD_ISSET (i, ofd) && (f = u.u_ofile[i])
- && f->f_select (f, SELCMD_CHECK, SELMODE_OUT))
- {
- FD_SET (i, &readyout);
- ++ readydesc;
- }
- if (ofd && FD_ISSET (i, efd) && (f = u.u_ofile[i])
- && f->f_select (f, SELCMD_CHECK, SELMODE_EXC))
- {
- FD_SET (i, &readyexc);
- ++ readydesc;
- }
- }
-
- /* we have a timeout condition, if readydesc == 0, dotout == 1 and
- * end_time < current time */
- if (!readydesc && dotout)
- {
- struct timeval current_time;
-
- syscall (SYS_gettimeofday, ¤t_time, 0);
- tout = timercmp (&end_time, ¤t_time, <);
- }
-
- if (readydesc || tout)
- {
- if (ifd) setcopy(nfd, (u_int *)&readyin, (u_int *)ifd);
- if (ofd) setcopy(nfd, (u_int *)&readyout, (u_int *)ofd);
- if (efd) setcopy(nfd, (u_int *)&readyexc, (u_int *)efd);
- result = readydesc; /* ok for tout, since then readydesc is already 0 */
- break;
- }
-
- /* make interrupts possible */
- syscall (SYS_sigsetmask, omask);
- omask = syscall (SYS_sigsetmask);
- }
-
- syscall (SYS_sigsetmask, omask);
-
- return result;
- }
- @
-