1/* Copyright (c) 1993-2002 2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de) 3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de) 4 * Copyright (c) 1987 Oliver Laumann 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2, or (at your option) 9 * any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program (see the file COPYING); if not, write to the 18 * Free Software Foundation, Inc., 19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 20 * 21 **************************************************************** 22 */ 23 24#include <sys/types.h> 25#if !defined(sun) && !defined(B43) && !defined(ISC) && !defined(pyr) && !defined(_CX_UX) 26# include <time.h> 27#endif 28#include <sys/time.h> 29 30#include "config.h" 31#include "screen.h" 32#include "extern.h" 33 34static struct event *evs; 35static struct event *tevs; 36static struct event *nextev; 37static int calctimeout; 38 39static struct event *calctimo __P((void)); 40#if (defined(sgi) && defined(SVR4)) || defined(__osf__) || defined(M_UNIX) 41static int sgihack __P((void)); 42#endif 43 44void 45evenq(ev) 46struct event *ev; 47{ 48 struct event *evp, **evpp; 49 debug3("New event fd %d type %d queued %d\n", ev->fd, ev->type, ev->queued); 50 if (ev->queued) 51 return; 52 evpp = &evs; 53 if (ev->type == EV_TIMEOUT) 54 { 55 calctimeout = 1; 56 evpp = &tevs; 57 } 58 for (; (evp = *evpp); evpp = &evp->next) 59 if (ev->pri > evp->pri) 60 break; 61 ev->next = evp; 62 *evpp = ev; 63 ev->queued = 1; 64} 65 66void 67evdeq(ev) 68struct event *ev; 69{ 70 struct event *evp, **evpp; 71 debug3("Deq event fd %d type %d queued %d\n", ev->fd, ev->type, ev->queued); 72 if (!ev->queued) 73 return; 74 evpp = &evs; 75 if (ev->type == EV_TIMEOUT) 76 { 77 calctimeout = 1; 78 evpp = &tevs; 79 } 80 for (; (evp = *evpp); evpp = &evp->next) 81 if (evp == ev) 82 break; 83 ASSERT(evp); 84 *evpp = ev->next; 85 ev->queued = 0; 86 if (ev == nextev) 87 nextev = nextev->next; 88} 89 90static struct event * 91calctimo() 92{ 93 struct event *ev, *min; 94 long mins; 95 96 if ((min = tevs) == 0) 97 return 0; 98 mins = min->timeout.tv_sec; 99 for (ev = tevs->next; ev; ev = ev->next) 100 { 101 ASSERT(ev->type == EV_TIMEOUT); 102 if (mins < ev->timeout.tv_sec) 103 continue; 104 if (mins > ev->timeout.tv_sec || min->timeout.tv_usec > ev->timeout.tv_usec) 105 { 106 min = ev; 107 mins = ev->timeout.tv_sec; 108 } 109 } 110 return min; 111} 112 113void 114sched() 115{ 116 struct event *ev; 117 fd_set r, w, *set; 118 struct event *timeoutev = 0; 119 struct timeval timeout; 120 int nsel; 121 122 for (;;) 123 { 124 if (calctimeout) 125 timeoutev = calctimo(); 126 if (timeoutev) 127 { 128 gettimeofday(&timeout, NULL); 129 /* tp - timeout */ 130 timeout.tv_sec = timeoutev->timeout.tv_sec - timeout.tv_sec; 131 timeout.tv_usec = timeoutev->timeout.tv_usec - timeout.tv_usec; 132 if (timeout.tv_usec < 0) 133 { 134 timeout.tv_usec += 1000000; 135 timeout.tv_sec--; 136 } 137 if (timeout.tv_sec < 0) 138 { 139 timeout.tv_usec = 0; 140 timeout.tv_sec = 0; 141 } 142 } 143#ifdef DEBUG 144 debug("waiting for events"); 145 if (timeoutev) 146 debug2(" timeout %d secs %d usecs", timeout.tv_sec, timeout.tv_usec); 147 debug(":\n"); 148 for (ev = evs; ev; ev = ev->next) 149 debug3(" - fd %d type %d pri %d\n", ev->fd, ev->type, ev->pri); 150 if (tevs) 151 debug("timed events:\n"); 152 for (ev = tevs; ev; ev = ev->next) 153 debug3(" - pri %d sec %d usec %d\n", ev->pri, ev->timeout.tv_sec, ev->timeout.tv_usec); 154#endif 155 156 FD_ZERO(&r); 157 FD_ZERO(&w); 158 for (ev = evs; ev; ev = ev->next) 159 { 160 if (ev->condpos && *ev->condpos <= (ev->condneg ? *ev->condneg : 0)) 161 { 162 debug2(" - cond ev fd %d type %d failed\n", ev->fd, ev->type); 163 continue; 164 } 165 if (ev->type == EV_READ) 166 FD_SET(ev->fd, &r); 167 else if (ev->type == EV_WRITE) 168 FD_SET(ev->fd, &w); 169 } 170 171#ifdef DEBUG 172 debug("readfds:"); 173 for (nsel = 0; nsel < FD_SETSIZE; nsel++) 174 if (FD_ISSET(nsel, &r)) 175 debug1(" %d", nsel); 176 debug("\n"); 177 debug("writefds:"); 178 for (nsel = 0; nsel < FD_SETSIZE; nsel++) 179 if (FD_ISSET(nsel, &w)) 180 debug1(" %d", nsel); 181 debug("\n"); 182#endif 183 184 nsel = select(FD_SETSIZE, &r, &w, (fd_set *)0, timeoutev ? &timeout : (struct timeval *) 0); 185 if (nsel < 0) 186 { 187 if (errno != EINTR) 188 { 189#if defined(sgi) && defined(SVR4) 190 if (errno == EIO && sgihack()) 191 continue; 192#endif 193#if defined(__osf__) || defined(M_UNIX) 194 /* OSF/1 3.x, SCO bug: EBADF */ 195 /* OSF/1 4.x bug: EIO */ 196 if ((errno == EIO || errno == EBADF) && sgihack()) 197 continue; 198#endif 199 Panic(errno, "select"); 200 } 201 nsel = 0; 202 } 203 else if (nsel == 0) /* timeout */ 204 { 205 debug("TIMEOUT!\n"); 206 ASSERT(timeoutev); 207 evdeq(timeoutev); 208 timeoutev->handler(timeoutev, timeoutev->data); 209 } 210#ifdef SELECT_BROKEN 211 /* 212 * Sequents select emulation counts a descriptor which is 213 * readable and writeable only as one hit. Waaaaa. 214 */ 215 if (nsel) 216 nsel = 2 * FD_SETSIZE; 217#endif 218 219 for (ev = evs; ev; ev = nextev) 220 { 221 nextev = ev->next; 222 if (ev->type != EV_ALWAYS) 223 { 224 set = ev->type == EV_READ ? &r : &w; 225 if (nsel == 0 || !FD_ISSET(ev->fd, set)) 226 continue; 227 nsel--; 228 } 229 if (ev->condpos && *ev->condpos <= (ev->condneg ? *ev->condneg : 0)) 230 continue; 231 debug2(" + hit ev fd %d type %d!\n", ev->fd, ev->type); 232 ev->handler(ev, ev->data); 233 } 234 } 235} 236 237void 238SetTimeout(ev, timo) 239struct event *ev; 240int timo; 241{ 242 ASSERT(ev->type == EV_TIMEOUT); 243 debug2("event %x new timeout %d ms\n", ev, timo); 244 gettimeofday(&ev->timeout, NULL); 245 ev->timeout.tv_sec += timo / 1000; 246 ev->timeout.tv_usec += (timo % 1000) * 1000; 247 if (ev->timeout.tv_usec > 1000000) 248 { 249 ev->timeout.tv_usec -= 1000000; 250 ev->timeout.tv_sec++; 251 } 252 if (ev->queued) 253 calctimeout = 1; 254} 255 256 257#if (defined(sgi) && defined(SVR4)) || defined(__osf__) || defined(M_UNIX) 258 259extern struct display *display, *displays; 260static int sgihack() 261{ 262 fd_set r, w; 263 struct timeval tv; 264 265 debug("IRIX5.2 workaround: searching for bad display\n"); 266 for (display = displays; display; ) 267 { 268 FD_ZERO(&r); 269 FD_ZERO(&w); 270 FD_SET(D_userfd, &r); 271 FD_SET(D_userfd, &w); 272 tv.tv_sec = tv.tv_usec = 0; 273 if (select(FD_SETSIZE, &r, &w, (fd_set *)0, &tv) == -1) 274 { 275 if (errno == EINTR) 276 continue; 277 Hangup(); /* goodbye display */ 278 return 1; 279 } 280 display = display->d_next; 281 } 282 return 0; 283} 284 285#endif 286