[project @ 1998-11-26 09:17:22 by sof]
[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
20 #if !defined(_AIX)
21 #define NON_POSIX_SOURCE
22 #endif
23 /* Should there be a POSIX alternative based on poll()? */
24
25 #include "rtsdefs.h"
26
27 # if defined(HAVE_SYS_TYPES_H)
28 #  include <sys/types.h>
29 # endif
30
31 # ifdef HAVE_SYS_TIME_H
32 #  include <sys/time.h>
33 # endif
34
35 /* Counter holding the number of timer ticks seen during GC */
36 I_ delayTicks = 0;
37
38 /*
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.
43
44  */
45
46 void
47 handleTimerExpiry(enable)
48 rtsBool enable;
49 {
50   /*
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
53     was disabled.
54     */
55   if (!enable)
56     delayTicks = 1;
57   else {
58     if (delayTicks > 1) {
59        delayTicks = 0;
60        AwaitEvent((delayTicks-1) * RTSflags.ConcFlags.ctxtSwitchTime);
61     }
62   }
63 }
64
65 void
66 AwaitEvent(I_ delta)
67 {
68     P_ tso, prev, next;
69     rtsBool ready;
70     fd_set rfd,wfd;
71     I_ us;
72     I_ min, numFound;
73     I_ maxfd=0;
74    
75     struct timeval tv,tv_before,tv_after;
76
77     min = delta == 0 ? 0x7fffffff : 0;
78
79     /* 
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.
82      *
83      * (I_)TSO_EVENT(tso) < 0 => thread waiting on read on fd (-(I_)TSO_EVENT(tso))
84      *
85      * (I_)TSO_EVENT(tso) < -FD_SETSIZE => thread waiting on write on fd
86      *                                    (FD_SETSIZE-(I_)TSO_EVENT(tso))
87      */
88     FD_ZERO(&rfd);
89     FD_ZERO(&wfd);
90     for(tso = WaitingThreadsHd; tso != PrelBase_Z91Z93_closure; tso = TSO_LINK(tso)) {
91         us = (I_) TSO_EVENT(tso);
92         if (us > 0) {
93             /* Looking at a delay event */
94             if (us < min)
95                 min = us;
96         } else if ( us <= (-(I_)FD_SETSIZE)) {
97             /* Looking at a waitWrite event */
98             us += (I_)FD_SETSIZE;
99             maxfd = ((1-us)> maxfd) ? (1-us) : maxfd;
100             FD_SET((-us), &wfd);
101         } else {
102             /* Looking at a waitRead event */
103             maxfd = ((1-us)> maxfd) ? (1-us) : maxfd;
104             FD_SET((-us), &rfd);
105         }
106     }
107
108     /* Check for any interesting events */
109
110     tv.tv_sec = min / 1000000;
111     tv.tv_usec = min % 1000000;
112
113     gettimeofday(&tv_before, (struct timezone *) NULL);
114
115     while ((numFound = select(maxfd, &rfd, &wfd, NULL, &tv)) < 0) {
116         if (errno != EINTR) {
117             fflush(stdout);
118             fprintf(stderr, "AwaitEvent: select failed\n");
119             EXIT(EXIT_FAILURE);
120         }
121     }   
122
123     if (numFound != 0) { 
124       /* 
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
127         select(). 
128         */
129
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;
133
134     }
135
136     if (delta == 0)
137         delta=min;
138
139     /*
140       Step through the waiting queue, unblocking every thread that now has
141       a file descriptor in a ready state.
142
143       For the delayed threads, decrement the number of microsecs
144       we've been blocked for. Unblock the threads that have thusly expired.
145      */
146
147     prev = NULL;
148     for(tso = WaitingThreadsHd; tso != PrelBase_Z91Z93_closure; tso = next) {
149         next = TSO_LINK(tso);
150         us = (I_) TSO_EVENT(tso);
151         if (us > 0) {
152             /* Looking at a delay event */
153             us -= delta;
154             ready = (us <= 0);
155             if (!ready)
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);
160         } else {
161             /* Looking at a waitRead event */
162             ready = FD_ISSET((-us), &rfd);
163         }
164         if (ready) {
165
166 #if defined(GRAN)
167             if (ThreadQueueTl == PrelBase_Z91Z93_closure)
168                 ThreadQueueHd = tso;
169             else
170                 TSO_LINK(ThreadQueueTl) = tso;
171             ThreadQueueTl = tso;
172             TSO_LINK(tso) = PrelBase_Z91Z93_closure;
173 #else
174             if (RunnableThreadsTl == PrelBase_Z91Z93_closure)
175                 RunnableThreadsHd = tso;
176             else
177                 TSO_LINK(RunnableThreadsTl) = tso;
178             RunnableThreadsTl = tso;
179             TSO_LINK(tso) = PrelBase_Z91Z93_closure;
180 #endif
181         } else {
182             if (prev == NULL)
183                 WaitingThreadsHd = tso;
184             else
185                 TSO_LINK(prev) = tso;
186             prev = tso;
187         }
188     }
189     if (prev == NULL)
190         WaitingThreadsHd = WaitingThreadsTl = PrelBase_Z91Z93_closure;
191     else {
192         TSO_LINK(prev) = PrelBase_Z91Z93_closure;
193         WaitingThreadsTl = prev;
194     }
195 }
196
197 #endif /* CONCURRENT */
198 \end{code}