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 */
19 #define NON_POSIX_SOURCE
20 /* Should there be a POSIX alternative based on poll()? */
24 # if defined(HAVE_SYS_TYPES_H)
25 # include <sys/types.h>
28 # ifdef HAVE_SYS_TIME_H
29 # include <sys/time.h>
32 /* Counter holding the number of timer ticks seen during GC */
36 handleTimerExpiry is used to temporarily delay the handling of
37 timer ticks for threads delayed waiting for timeout. Disable
38 during GC, counting up the ticks , before updating the waiting
39 threads queue when finished GCing.
44 handleTimerExpiry(enable)
48 If we enable the handling of timer expiry, update the WaitingThreads
49 queue with the number of ticks we have accumulated since the handling
57 AwaitEvent((delayTicks-1) * RTSflags.ConcFlags.ctxtSwitchTime);
72 struct timeval tv,tv_before,tv_after;
74 min = delta == 0 ? 0x7fffffff : 0;
77 * Collect all of the fd's that we're interested in, and capture
78 * the minimum waiting time (in microseconds) for the delayed threads.
80 * (I_)TSO_EVENT(tso) < 0 => thread waiting on read on fd (-(I_)TSO_EVENT(tso))
82 * (I_)TSO_EVENT(tso) < -FD_SETSIZE => thread waiting on write on fd
83 * (FD_SETSIZE-(I_)TSO_EVENT(tso))
87 for(tso = WaitingThreadsHd; tso != Prelude_Z91Z93_closure; tso = TSO_LINK(tso)) {
88 us = (I_) TSO_EVENT(tso);
90 /* Looking at a delay event */
93 } else if ( us <= (-(I_)FD_SETSIZE)) {
94 /* Looking at a waitWrite event */
96 maxfd = ((1-us)> maxfd) ? (1-us) : maxfd;
99 /* Looking at a waitRead event */
100 maxfd = ((1-us)> maxfd) ? (1-us) : maxfd;
105 /* Check for any interesting events */
107 tv.tv_sec = min / 1000000;
108 tv.tv_usec = min % 1000000;
110 gettimeofday(&tv_before, (struct timezone *) NULL);
112 while ((numFound = select(maxfd, &rfd, &wfd, NULL, &tv)) < 0) {
113 if (errno != EINTR) {
115 fprintf(stderr, "AwaitEvent: select failed\n");
122 File descriptors ready, but we have don't know how much time was spent
123 in the select(). To interpolate, we compare the time before and after the
127 gettimeofday(&tv_after, (struct timezone *) NULL);
128 delta = (tv_after.tv_sec - tv_before.tv_sec) * 1000000 +
129 tv_after.tv_usec - tv_before.tv_usec;
137 Step through the waiting queue, unblocking every thread that now has
138 a file descriptor in a ready state.
140 For the delayed threads, decrement the number of microsecs
141 we've been blocked for. Unblock the threads that have thusly expired.
145 for(tso = WaitingThreadsHd; tso != Prelude_Z91Z93_closure; tso = next) {
146 next = TSO_LINK(tso);
147 us = (I_) TSO_EVENT(tso);
149 /* Looking at a delay event */
153 TSO_EVENT(tso) = (W_) us;
154 } else if ( us <= (-(I_)FD_SETSIZE)) {
155 /* Looking at a waitWrite event */
156 ready = FD_ISSET(((I_)FD_SETSIZE-us), &wfd);
158 /* Looking at a waitRead event */
159 ready = FD_ISSET((-us), &rfd);
164 if (ThreadQueueTl == Prelude_Z91Z93_closure)
167 TSO_LINK(ThreadQueueTl) = tso;
169 TSO_LINK(tso) = Prelude_Z91Z93_closure;
171 if (RunnableThreadsTl == Prelude_Z91Z93_closure)
172 RunnableThreadsHd = tso;
174 TSO_LINK(RunnableThreadsTl) = tso;
175 RunnableThreadsTl = tso;
176 TSO_LINK(tso) = Prelude_Z91Z93_closure;
180 WaitingThreadsHd = tso;
182 TSO_LINK(prev) = tso;
187 WaitingThreadsHd = WaitingThreadsTl = Prelude_Z91Z93_closure;
189 TSO_LINK(prev) = Prelude_Z91Z93_closure;
190 WaitingThreadsTl = prev;
194 #endif /* CONCURRENT */