2 % (c) The AQUA Project, Glasgow University, 1995
4 %************************************************************************
6 \section[Select.lc]{Select Available File Descriptors}
8 %************************************************************************
10 Handling of select() of read&write on file descriptors or timer expiry.
16 /* #define STK_CHK_DEBUG */
21 #define NON_POSIX_SOURCE
23 /* Should there be a POSIX alternative based on poll()? */
27 # if defined(HAVE_SYS_TYPES_H)
28 # include <sys/types.h>
31 # ifdef HAVE_SYS_TIME_H
32 # include <sys/time.h>
35 /* Counter holding the number of timer ticks seen during GC */
39 handleTimerExpiry is used to temporarily delay the handling of
40 timer ticks for threads delayed waiting for timeout. Disable
41 during GC, counting up the ticks , before updating the waiting
42 threads queue when finished GCing.
47 handleTimerExpiry(enable)
51 If we enable the handling of timer expiry, update the WaitingThreads
52 queue with the number of ticks we have accumulated since the handling
60 AwaitEvent((delayTicks-1) * RTSflags.ConcFlags.ctxtSwitchTime);
75 struct timeval tv,tv_before,tv_after;
77 min = delta == 0 ? 0x7fffffff : 0;
80 * Collect all of the fd's that we're interested in, and capture
81 * the minimum waiting time (in microseconds) for the delayed threads.
83 * (I_)TSO_EVENT(tso) < 0 => thread waiting on read on fd (-(I_)TSO_EVENT(tso))
85 * (I_)TSO_EVENT(tso) < -FD_SETSIZE => thread waiting on write on fd
86 * (FD_SETSIZE-(I_)TSO_EVENT(tso))
90 for(tso = WaitingThreadsHd; tso != PrelBase_Z91Z93_closure; tso = TSO_LINK(tso)) {
91 us = (I_) TSO_EVENT(tso);
93 /* Looking at a delay event */
96 } else if ( us <= (-(I_)FD_SETSIZE)) {
97 /* Looking at a waitWrite event */
99 maxfd = ((1-us)> maxfd) ? (1-us) : maxfd;
102 /* Looking at a waitRead event */
103 maxfd = ((1-us)> maxfd) ? (1-us) : maxfd;
108 /* Check for any interesting events */
110 tv.tv_sec = min / 1000000;
111 tv.tv_usec = min % 1000000;
113 gettimeofday(&tv_before, (struct timezone *) NULL);
115 while ((numFound = select(maxfd, &rfd, &wfd, NULL, &tv)) < 0) {
116 if (errno != EINTR) {
118 fprintf(stderr, "AwaitEvent: select failed\n");
125 File descriptors ready, but we have don't know how much time was spent
126 in the select(). To interpolate, we compare the time before and after the
130 gettimeofday(&tv_after, (struct timezone *) NULL);
131 delta = (tv_after.tv_sec - tv_before.tv_sec) * 1000000 +
132 tv_after.tv_usec - tv_before.tv_usec;
140 Step through the waiting queue, unblocking every thread that now has
141 a file descriptor in a ready state.
143 For the delayed threads, decrement the number of microsecs
144 we've been blocked for. Unblock the threads that have thusly expired.
148 for(tso = WaitingThreadsHd; tso != PrelBase_Z91Z93_closure; tso = next) {
149 next = TSO_LINK(tso);
150 us = (I_) TSO_EVENT(tso);
152 /* Looking at a delay event */
156 TSO_EVENT(tso) = (W_) us;
157 } else if ( us <= (-(I_)FD_SETSIZE)) {
158 /* Looking at a waitWrite event */
159 ready = FD_ISSET(((I_)FD_SETSIZE-us), &wfd);
161 /* Looking at a waitRead event */
162 ready = FD_ISSET((-us), &rfd);
167 if (ThreadQueueTl == PrelBase_Z91Z93_closure)
170 TSO_LINK(ThreadQueueTl) = tso;
172 TSO_LINK(tso) = PrelBase_Z91Z93_closure;
174 if (RunnableThreadsTl == PrelBase_Z91Z93_closure)
175 RunnableThreadsHd = tso;
177 TSO_LINK(RunnableThreadsTl) = tso;
178 RunnableThreadsTl = tso;
179 TSO_LINK(tso) = PrelBase_Z91Z93_closure;
183 WaitingThreadsHd = tso;
185 TSO_LINK(prev) = tso;
190 WaitingThreadsHd = WaitingThreadsTl = PrelBase_Z91Z93_closure;
192 TSO_LINK(prev) = PrelBase_Z91Z93_closure;
193 WaitingThreadsTl = prev;
197 #endif /* CONCURRENT */