1 /* -----------------------------------------------------------------------------
2 * $Id: Select.c,v 1.1 1999/08/25 16:37:42 simonmar Exp $
4 * (c) The GHC Team 1995-1999
6 * Support for concurrent non-blocking I/O and thread waiting.
8 * ---------------------------------------------------------------------------*/
10 /* we're outside the realms of POSIX here... */
11 #define NON_POSIX_SOURCE
19 # if defined(HAVE_SYS_TYPES_H)
20 # include <sys/types.h>
23 # ifdef HAVE_SYS_TIME_H
24 # include <sys/time.h>
27 nat ticks_since_select = 0;
29 /* Argument 'wait' says whether to wait for I/O to become available,
30 * or whether to just check and return immediately. If there are
31 * other threads ready to run, we normally do the non-waiting variety,
32 * otherwise we wait (see Schedule.c).
35 awaitEvent(rtsBool wait)
37 StgTSO *tso, *prev, *next;
40 int min, numFound, delta;
43 struct timeval tv,tv_before,tv_after;
45 IF_DEBUG(scheduler,belch("Checking for threads blocked on I/O...\n"));
47 /* see how long it's been since we last checked the blocked queue.
48 * ToDo: make this check atomic, so we don't lose any ticks.
50 delta = ticks_since_select;
51 ticks_since_select = 0;
52 delta = delta * TICK_MILLISECS * 1000;
54 min = wait == rtsTrue ? 0x7fffffff : 0;
57 * Collect all of the fd's that we're interested in, and capture
58 * the minimum waiting time (in microseconds) for the delayed threads.
63 for(tso = blocked_queue_hd; tso != END_TSO_QUEUE; tso = next) {
66 switch (tso->why_blocked) {
69 int fd = tso->block_info.fd;
70 maxfd = (fd > maxfd) ? fd : maxfd;
77 int fd = tso->block_info.fd;
78 maxfd = (fd > maxfd) ? fd : maxfd;
85 if ((int)tso->block_info.delay < min)
86 min = tso->block_info.delay;
95 /* Check for any interesting events */
97 tv.tv_sec = min / 1000000;
98 tv.tv_usec = min % 1000000;
100 gettimeofday(&tv_before, (struct timezone *) NULL);
102 while ((numFound = select(maxfd+1, &rfd, &wfd, NULL, &tv)) < 0) {
103 if (errno != EINTR) {
104 /* fflush(stdout); */
105 fprintf(stderr, "awaitEvent: select failed\n");
106 stg_exit(EXIT_FAILURE);
112 File descriptors ready, but we don't know how much time was spent
113 in the select(). To interpolate, we compare the time before
114 and after the select().
117 gettimeofday(&tv_after, (struct timezone *) NULL);
118 delta += (tv_after.tv_sec - tv_before.tv_sec) * 1000000 +
119 tv_after.tv_usec - tv_before.tv_usec;
126 Step through the waiting queue, unblocking every thread that now has
127 a file descriptor in a ready state.
129 For the delayed threads, decrement the number of microsecs
130 we've been blocked for. Unblock the threads that have thusly expired.
134 for(tso = blocked_queue_hd; tso != END_TSO_QUEUE; tso = next) {
136 switch (tso->why_blocked) {
138 ready = FD_ISSET(tso->block_info.fd, &rfd);
142 ready = FD_ISSET(tso->block_info.fd, &wfd);
146 tso->block_info.delay -= delta;
147 ready = (tso->block_info.delay <= 0);
155 IF_DEBUG(scheduler,belch("Waking up thread %d\n", tso->id));
156 tso->why_blocked = NotBlocked;
157 tso->link = END_TSO_QUEUE;
158 PUSH_ON_RUN_QUEUE(tso);
161 blocked_queue_hd = tso;
169 blocked_queue_hd = blocked_queue_tl = END_TSO_QUEUE;
171 prev->link = END_TSO_QUEUE;
172 blocked_queue_tl = prev;