[project @ 1996-07-25 20:43:49 by partain]
[ghc-hetmet.git] / ghc / runtime / main / Select.lc
1 %
2 % (c) The AQUA Project, Glasgow University, 1995
3 %
4 %************************************************************************
5 %*                                                                      *
6 \section[Select.lc]{Select Available File Descriptors}
7 %*                                                                      *
8 %************************************************************************
9
10 Handling of select() of read&write on file descriptors or timer expiry.
11
12 \begin{code}
13
14 #ifdef CONCURRENT
15
16 /* #define STK_CHK_DEBUG */
17
18 #define NULL_REG_MAP
19 #define NON_POSIX_SOURCE
20 /* Should there be a POSIX alternative based on poll()? */
21
22 #include "rtsdefs.h"
23
24 # if defined(HAVE_SYS_TYPES_H)
25 #  include <sys/types.h>
26 # endif
27
28 # ifdef HAVE_SYS_TIME_H
29 #  include <sys/time.h>
30 # endif
31
32 /* Counter holding the number of timer ticks seen during GC */
33 I_ delayTicks = 0;
34
35 /*
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.
40
41  */
42
43 void
44 handleTimerExpiry(enable)
45 rtsBool enable;
46 {
47   /*
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
50     was disabled.
51     */
52   if (!enable)
53     delayTicks = 1;
54   else {
55     if (delayTicks > 1) {
56        delayTicks = 0;
57        AwaitEvent((delayTicks-1) * RTSflags.ConcFlags.ctxtSwitchTime);
58     }
59   }
60 }
61
62 void
63 AwaitEvent(I_ delta)
64 {
65     P_ tso, prev, next;
66     rtsBool ready;
67     fd_set rfd,wfd;
68     I_ us;
69     I_ min, numFound;
70     I_ maxfd=0;
71    
72     struct timeval tv,tv_before,tv_after;
73
74     min = delta == 0 ? 0x7fffffff : 0;
75
76     /* 
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.
79      *
80      * (I_)TSO_EVENT(tso) < 0 => thread waiting on read on fd (-(I_)TSO_EVENT(tso))
81      *
82      * (I_)TSO_EVENT(tso) < -FD_SETSIZE => thread waiting on write on fd
83      *                                    (FD_SETSIZE-(I_)TSO_EVENT(tso))
84      */
85     FD_ZERO(&rfd);
86     FD_ZERO(&wfd);
87     for(tso = WaitingThreadsHd; tso != Prelude_Z91Z93_closure; tso = TSO_LINK(tso)) {
88         us = (I_) TSO_EVENT(tso);
89         if (us > 0) {
90             /* Looking at a delay event */
91             if (us < min)
92                 min = us;
93         } else if ( us <= (-(I_)FD_SETSIZE)) {
94             /* Looking at a waitWrite event */
95             us += (I_)FD_SETSIZE;
96             maxfd = ((1-us)> maxfd) ? (1-us) : maxfd;
97             FD_SET((-us), &wfd);
98         } else {
99             /* Looking at a waitRead event */
100             maxfd = ((1-us)> maxfd) ? (1-us) : maxfd;
101             FD_SET((-us), &rfd);
102         }
103     }
104
105     /* Check for any interesting events */
106
107     tv.tv_sec = min / 1000000;
108     tv.tv_usec = min % 1000000;
109
110     gettimeofday(&tv_before, (struct timezone *) NULL);
111
112     while ((numFound = select(maxfd, &rfd, &wfd, NULL, &tv)) < 0) {
113         if (errno != EINTR) {
114             fflush(stdout);
115             fprintf(stderr, "AwaitEvent: select failed\n");
116             EXIT(EXIT_FAILURE);
117         }
118     }   
119
120     if (numFound != 0) { 
121       /* 
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
124         select(). 
125         */
126
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;
130
131     }
132
133     if (delta == 0)
134         delta=min;
135
136     /*
137       Step through the waiting queue, unblocking every thread that now has
138       a file descriptor in a ready state.
139
140       For the delayed threads, decrement the number of microsecs
141       we've been blocked for. Unblock the threads that have thusly expired.
142      */
143
144     prev = NULL;
145     for(tso = WaitingThreadsHd; tso != Prelude_Z91Z93_closure; tso = next) {
146         next = TSO_LINK(tso);
147         us = (I_) TSO_EVENT(tso);
148         if (us > 0) {
149             /* Looking at a delay event */
150             us -= delta;
151             ready = (us <= 0);
152             if (!ready)
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);
157         } else {
158             /* Looking at a waitRead event */
159             ready = FD_ISSET((-us), &rfd);
160         }
161         if (ready) {
162
163 #if defined(GRAN)
164             if (ThreadQueueTl == Prelude_Z91Z93_closure)
165                 ThreadQueueHd = tso;
166             else
167                 TSO_LINK(ThreadQueueTl) = tso;
168             ThreadQueueTl = tso;
169             TSO_LINK(tso) = Prelude_Z91Z93_closure;
170 #else
171             if (RunnableThreadsTl == Prelude_Z91Z93_closure)
172                 RunnableThreadsHd = tso;
173             else
174                 TSO_LINK(RunnableThreadsTl) = tso;
175             RunnableThreadsTl = tso;
176             TSO_LINK(tso) = Prelude_Z91Z93_closure;
177 #endif
178         } else {
179             if (prev == NULL)
180                 WaitingThreadsHd = tso;
181             else
182                 TSO_LINK(prev) = tso;
183             prev = tso;
184         }
185     }
186     if (prev == NULL)
187         WaitingThreadsHd = WaitingThreadsTl = Prelude_Z91Z93_closure;
188     else {
189         TSO_LINK(prev) = Prelude_Z91Z93_closure;
190         WaitingThreadsTl = prev;
191     }
192 }
193
194 #endif /* CONCURRENT */
195 \end{code}