/* N.B. Special return value of -1 indicates a signal was delivered prior to the select. */ static int IOMGR_CheckDescriptors(int PollingCheck) { int result, nfds, rf, wf, ef; fd_set readfds, writefds, exceptfds; struct TM_Elem *earliest; struct timeval timeout, tmp_timeout; earliest = TM_GetEarliest(Requests); if (earliest == NULL) return(0); /* Merge active descriptors. */ rf = wf = ef = 0; /* set whenever a fd in a fd_set is set */ nfds = 0; FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds); FOR_ALL_ELTS(r, Requests, { int i; struct IoRequest *req; req = (struct IoRequest *) r -> BackPointer; for (i = 0; i < req->nfds; i++) { if (FD_ISSET(i, &req->readfds)) { FD_SET(i, &readfds); rf = 1; } if (FD_ISSET(i, &req->writefds)) { FD_SET(i, &writefds); wf = 1; } if (FD_ISSET(i, &req->exceptfds)) { FD_SET(i, &exceptfds); ef = 1; } } if (req->nfds > nfds) nfds = req->nfds; });
/* Await the earliest future event or a packet. Returns active fd if packet came, -1 if earliest event expired */ static int PacketCame(void) { struct TM_Elem *t; /* Obtain earliest event */ t = TM_GetEarliest(rpc2_TimerQueue); /* Yield control */ say(999, RPC2_DebugLevel, "About to enter IOMGR_Select()\n"); return rpc2_CheckFDs(IOMGR_Select, t ? &t->TimeLeft : NULL); }
static void *IOMGR(void *dummy) { for (;;) { int code; struct TM_Elem *earliest; struct timeval timeout, junk; bool woke_someone; FD_ZERO(&IOMGR_readfds); FD_ZERO(&IOMGR_writefds); FD_ZERO(&IOMGR_exceptfds); IOMGR_nfds = 0; /* Wake up anyone who has expired or who has received a Unix signal between executions. Keep going until we run out. */ do { woke_someone = FALSE; /* Wake up anyone waiting on signals. */ /* Note: SignalSignals() may yield! */ if (anySigsDelivered && SignalSignals ()) woke_someone = TRUE; FT_GetTimeOfDay(&junk, 0); /* force accurate time check */ TM_Rescan(Requests); for (;;) { struct IoRequest *req; struct TM_Elem *expired; expired = TM_GetExpired(Requests); if (expired == NULL) break; woke_someone = TRUE; req = (struct IoRequest *) expired -> BackPointer; #ifdef DEBUG if (lwp_debug != 0) puts("[Polling SELECT]"); #endif /* DEBUG */ /* no data ready */ if (req->readfds) FD_N_ZERO(req->nfds, req->readfds); if (req->writefds) FD_N_ZERO(req->nfds, req->writefds); if (req->exceptfds) FD_N_ZERO(req->nfds, req->exceptfds); req->nfds = 0; req->result = 0; /* no fds ready */ TM_Remove(Requests, &req->timeout); #ifdef DEBUG req -> timeout.Next = (struct TM_Elem *) 2; req -> timeout.Prev = (struct TM_Elem *) 2; #endif /* DEBUG */ LWP_QSignal(req->pid); req->pid->iomgrRequest = 0; } if (woke_someone) LWP_DispatchProcess(); } while (woke_someone); /* Collect requests & update times */ FD_ZERO(&IOMGR_readfds); FD_ZERO(&IOMGR_writefds); FD_ZERO(&IOMGR_exceptfds); IOMGR_nfds = 0; FOR_ALL_ELTS(r, Requests, { struct IoRequest *req; req = (struct IoRequest *) r -> BackPointer; FDSetSet(req->nfds, &IOMGR_readfds, req->readfds); FDSetSet(req->nfds, &IOMGR_writefds, req->writefds); FDSetSet(req->nfds, &IOMGR_exceptfds, req->exceptfds); if (req->nfds > IOMGR_nfds) IOMGR_nfds = req->nfds; }) earliest = TM_GetEarliest(Requests); if (earliest != NULL) { timeout = earliest -> TimeLeft; /* Do select */ #ifdef DEBUG if (lwp_debug != 0) { #ifdef AFS_NT40_ENV int idbg; printf("[Read Select:"); if (IOMGR_readfds.fd_count == 0) printf(" none]\n"); else { for (idbg=0; idbg<IOMGR_readfds.fd_count; idbg++) printf(" %d", IOMGR_readfds.fd_array[idbg]); printf("]\n"); } printf("[Write Select:"); if (IOMGR_writefds.fd_count == 0) printf(" none]\n"); else { for (idbg=0; idbg<IOMGR_writefds.fd_count; idbg++) printf(" %d", IOMGR_writefds.fd_array[idbg]); printf("]\n"); } printf("[Except Select:"); if (IOMGR_exceptfds.fd_count == 0) printf(" none]\n"); else { for (idbg=0; idbg<IOMGR_exceptfds.fd_count; idbg++) printf(" %d", IOMGR_exceptfds.fd_array[idbg]); printf("]\n"); } #else /* Only prints first 32. */ printf("[select(%d, 0x%x, 0x%x, 0x%x, ", IOMGR_nfds, *(int*)&IOMGR_readfds, *(int*)&IOMGR_writefds, *(int*)&IOMGR_exceptfds); #endif /* AFS_NT40_ENV */ if (timeout.tv_sec == -1 && timeout.tv_usec == -1) puts("INFINITE)]"); else printf("<%d, %d>)]\n", timeout.tv_sec, timeout.tv_usec); } #endif /* DEBUG */ iomgr_timeout = timeout; if (timeout.tv_sec == -1 && timeout.tv_usec == -1) { /* infinite, sort of */ iomgr_timeout.tv_sec = 100000000; iomgr_timeout.tv_usec = 0; } #if defined(AFS_NT40_ENV) || defined(AFS_LINUX24_ENV) /* On NT, signals don't interrupt a select call. So this can potentially * lead to long wait times before a signal is honored. To avoid this we * dont do select() for longer than IOMGR_MAXWAITTIME (5 secs) */ /* Whereas Linux seems to sometimes "lose" signals */ if (iomgr_timeout.tv_sec > (IOMGR_MAXWAITTIME - 1)) { iomgr_timeout.tv_sec = IOMGR_MAXWAITTIME; iomgr_timeout.tv_usec = 0; } #endif /* NT40 */ /* Check one last time for a signal delivery. If one comes after this, the signal handler will set iomgr_timeout to zero, causing the select to return immediately. The timer package won't return a zero timeval because all of those guys were handled above. I'm assuming that the kernel masks signals while it's picking up the parameters to select. This may a bad assumption. -DN */ if (anySigsDelivered) continue; /* go to the top and handle them. */ #ifdef AFS_NT40_ENV if (IOMGR_readfds.fd_count == 0 && IOMGR_writefds.fd_count == 0 && IOMGR_exceptfds.fd_count == 0) { DWORD stime; code = 0; if (iomgr_timeout.tv_sec || iomgr_timeout.tv_usec) { stime = iomgr_timeout.tv_sec * 1000 + iomgr_timeout.tv_usec/1000; if (!stime) stime = 1; Sleep(stime); } } else #endif { /* select runs much faster if 0's are passed instead of &0s */ code = select(IOMGR_nfds, (FDSetEmpty(IOMGR_nfds, &IOMGR_readfds)) ? (fd_set*)0 : &IOMGR_readfds, (FDSetEmpty(IOMGR_nfds, &IOMGR_writefds)) ? (fd_set*)0 : &IOMGR_writefds, (FDSetEmpty(IOMGR_nfds, &IOMGR_exceptfds)) ? (fd_set*)0 : &IOMGR_exceptfds, &iomgr_timeout); } if (code < 0) { int e=1; #if defined(AFS_SUN_ENV) /* Tape drives on Sun boxes do not support select and return ENXIO */ if (errno == ENXIO) e=0, code=1; #endif #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_AIX32_ENV) /* For SGI and SVR4 - poll & select can return EAGAIN ... */ if (errno == EAGAIN) e=0; #endif #if defined(AFS_SUN5_ENV) /* On sun4x_55, select doesn't block signal. It could be interupted by a signal that changes iomgr_timeout, and then select returns with EINVAL. In this case, we need to retry. */ if (errno==EINVAL && anySigsDelivered) e = 0; #endif /* AFS_SUN5_ENV */ if ((errno != EINTR) && e) { #ifndef AFS_NT40_ENV int i; for(i=0; i<FD_SETSIZE; i++) { if (fcntl(i, F_GETFD, 0) < 0 && errno == EBADF) FD_SET(i, &openMask); } #endif iomgr_errno = errno; opr_abort(); } } /* See what happened */ if (code > 0) { /* Action -- wake up everyone involved */ SignalIO(IOMGR_nfds, &IOMGR_readfds, &IOMGR_writefds, &IOMGR_exceptfds, code); } else if (code == 0 && (iomgr_timeout.tv_sec != 0 || iomgr_timeout.tv_usec != 0)) { /* Real timeout only if signal handler hasn't set iomgr_timeout to zero. */ #if defined(AFS_NT40_ENV) || defined(AFS_LINUX24_ENV) /* On NT, real timeout only if above and if iomgr_timeout * interval is equal to timeout interval (i.e., not adjusted * to check for pseudo-signals). */ /* And also for Linux as above */ if (iomgr_timeout.tv_sec != timeout.tv_sec || iomgr_timeout.tv_usec != timeout.tv_usec) { /* signal check interval timed out; not real timeout */ continue; } #endif /* AFS_NT40_ENV */ FT_GetTimeOfDay(&junk, 0); SignalTimeout(code, &timeout); } } LWP_DispatchProcess(); }