Remove #include <stdio.h>. Add #include <string.h>.
[bpt/guile.git] / libguile / iselect.c
CommitLineData
1cbf4dea 1/* Copyright (C) 1997, 1998, 2000 Free Software Foundation, Inc.
3666451e
MD
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
40 * If you do not wish that, delete this exception notice. */
41\f
3666451e
MD
42#include <limits.h>
43#include <string.h>
44
a26f1191
MV
45#ifdef HAVE_UNISTD_H
46#include <unistd.h>
47#endif
48
a0599745
MD
49#include "libguile/_scm.h"
50#include "libguile/async.h"
3666451e 51
a0599745 52#include "libguile/iselect.h"
1cbf4dea
MD
53
54#ifdef GUILE_ISELECT
55
a0599745 56#include "libguile/coop-threads.h"
3666451e 57
4d3bacdd 58#ifdef MISSING_BZERO_DECL
b8ff5fe9
MD
59extern void bzero (void *, size_t);
60#endif
61
3666451e
MD
62\f
63
a48b6916 64/* COOP queue macros */
3666451e
MD
65#define QEMPTYP(q) (q.t.next == &q.t)
66#define QFIRST(q) (q.t.next)
67
a48b6916 68/* These macros count the number of bits in a word. */
3666451e 69#define SCM_BITS_PER_LONG (8 * sizeof (unsigned long))
95f44da9
MD
70/* Use LONG_MAX instead of ULONG_MAX here since not all systems define
71 ULONG_MAX */
72#if LONG_MAX >> 16 == 0
3666451e
MD
73#define SCM_NLONGBITS(p) (bc[((unsigned char *)(p))[0]]\
74 + bc[((unsigned char *)(p))[1]])
c5070877 75#elif LONG_MAX >> 32 == 0 || LONG_MAX == 2147483647L /* bug in Sun CC 4.2 */
3666451e
MD
76#define SCM_NLONGBITS(p) (bc[((unsigned char *)(p))[0]]\
77 + bc[((unsigned char *)(p))[1]]\
78 + bc[((unsigned char *)(p))[2]]\
79 + bc[((unsigned char *)(p))[3]])
95f44da9 80#elif LONG_MAX >> 64 == 0
3666451e
MD
81#define SCM_NLONGBITS(p) (bc[((unsigned char *)(p))[0]]\
82 + bc[((unsigned char *)(p))[1]]\
83 + bc[((unsigned char *)(p))[2]]\
84 + bc[((unsigned char *)(p))[3]]\
85 + bc[((unsigned char *)(p))[4]]\
86 + bc[((unsigned char *)(p))[5]]\
87 + bc[((unsigned char *)(p))[6]]\
88 + bc[((unsigned char *)(p))[7]])
c5070877
MD
89#else
90#error Could not determine suitable definition for SCM_NLONGBITS
3666451e
MD
91#endif
92
93#ifdef HAVE_BZERO
94#define FD_ZERO_N(pos, n) bzero ((pos), (n))
95#else
96#define FD_ZERO_N(pos, n) memset ((void *) (pos), 0, (n))
97#endif
98
99typedef unsigned long *ulongptr;
100
101static char bc[256]; /* Bit counting array. bc[x] is the number of
102 bits in x. */
103
c69dfa65
MD
104int scm_I_am_dead;
105
a48b6916
MD
106/* This flag indicates that several threads are waiting on the same
107 file descriptor. When this is the case, the common fd sets are
108 updated in a more inefficient way. */
109int collisionp;
110
111/* These are the common fd sets. When new select calls are made,
112 those sets are merged into these. */
3666451e
MD
113int gnfds;
114SELECT_TYPE greadfds;
115SELECT_TYPE gwritefds;
116SELECT_TYPE gexceptfds;
a48b6916
MD
117
118/* These are the result sets. They are used when we call OS select.
119 We couldn't use the common fd sets above, since that would destroy
120 them. */
3666451e
MD
121SELECT_TYPE rreadfds;
122SELECT_TYPE rwritefds;
123SELECT_TYPE rexceptfds;
a48b6916
MD
124
125/* Constant timeval struct representing a zero timeout which we use
126 when polling. */
3666451e
MD
127static struct timeval timeout0;
128
3666451e 129/* As select, but doesn't destroy the file descriptor sets passed as
a48b6916 130 arguments. The results are stored into the result sets. */
3666451e
MD
131static int
132safe_select (int nfds,
133 SELECT_TYPE *readfds,
134 SELECT_TYPE *writefds,
135 SELECT_TYPE *exceptfds,
136 struct timeval *timeout)
137{
138 int n = (nfds + 7) / 8;
139 /* Copy file descriptor sets to result area */
140 if (readfds == NULL)
141 FD_ZERO (&rreadfds);
142 else
143 {
144 memcpy (&rreadfds, readfds, n);
145 FD_ZERO_N ((char *) &rreadfds + n, SELECT_SET_SIZE / 8 - n);
146 }
147 if (writefds == NULL)
148 FD_ZERO (&rwritefds);
149 else
150 {
151 memcpy (&rwritefds, writefds, n);
152 FD_ZERO_N ((char *) &rwritefds + n, SELECT_SET_SIZE / 8 - n);
153 }
154 if (exceptfds == NULL)
155 FD_ZERO (&rexceptfds);
156 else
157 {
158 memcpy (&rexceptfds, exceptfds, n);
159 FD_ZERO_N ((char *) &rexceptfds + n, SELECT_SET_SIZE / 8 - n);
160 }
161 return select (nfds, &rreadfds, &rwritefds, &rexceptfds, timeout);
162}
163
a48b6916
MD
164/* Merge new file descriptor sets into the common sets. */
165static void
166add_fd_sets (coop_t *t)
3666451e 167{
a48b6916
MD
168 int n = (t->nfds + SCM_BITS_PER_LONG - 1) / SCM_BITS_PER_LONG;
169 int i;
170
171 /* Detect if the fd sets of the thread have any bits in common with
172 the rest of the waiting threads. If that is so, set the
173 collision flag. This causes a more time consuming handling of
174 the common fd sets---they need to recalculated every time a
175 thread wakes up. */
176 if (!collisionp)
177 for (i = 0; i < n; ++i)
178 if ((t->readfds != NULL
179 && (((ulongptr) t->readfds)[i] & ((ulongptr) &greadfds)[i]) != 0)
180 || (t->writefds != NULL
181 && ((((ulongptr) t->writefds)[i] & ((ulongptr) &gwritefds)[i])
182 != 0))
183 || (t->exceptfds != NULL
184 && ((((ulongptr) t->exceptfds)[i] & ((ulongptr) &gexceptfds)[i])
185 != 0)))
186 {
187 collisionp = 1;
188 break;
189 }
190
191 /* We recalculate nfds below. The cost for this can be paid back
192 with a great bonus since many programs are lazy with the nfds
193 arg. Many even pass 1024 when using one of the lowest fd:s!
194
195 We approach from above, checking for non-zero bits. As soon as
196 we have determined the value of nfds, we jump down to code below
197 which concludes the updating of the common sets. */
198 t->nfds = 0;
199 i = n;
3666451e
MD
200 while (i > 0)
201 {
202 --i;
a48b6916 203 if (t->readfds != NULL && ((ulongptr) t->readfds)[i] != 0)
3666451e 204 {
a48b6916 205 ((ulongptr) &greadfds)[i] |= ((ulongptr) t->readfds)[i];
3666451e 206 n = (i + 1) * SCM_BITS_PER_LONG;
a48b6916 207 t->nfds = n;
3666451e
MD
208 if (n > gnfds)
209 gnfds = n;
210 goto cont_read;
211 }
a48b6916 212 if (t->writefds != NULL && ((ulongptr) t->writefds)[i] != 0)
3666451e 213 {
a48b6916 214 ((ulongptr) &gwritefds)[i] |= ((ulongptr) t->writefds)[i];
3666451e 215 n = (i + 1) * SCM_BITS_PER_LONG;
a48b6916 216 t->nfds = n;
3666451e
MD
217 if (n > gnfds)
218 gnfds = n;
219 goto cont_write;
220 }
a48b6916 221 if (t->exceptfds != NULL && ((ulongptr) t->exceptfds)[i] != 0)
3666451e 222 {
a48b6916 223 ((ulongptr) &gexceptfds)[i] |= ((ulongptr) t->exceptfds)[i];
3666451e 224 n = (i + 1) * SCM_BITS_PER_LONG;
a48b6916 225 t->nfds = n;
3666451e
MD
226 if (n > gnfds)
227 gnfds = n;
228 goto cont_except;
229 }
230 }
a48b6916
MD
231 return;
232
233 /* nfds is now determined. Just finish updating the common sets. */
3666451e
MD
234 while (i > 0)
235 {
236 --i;
a48b6916
MD
237 if (t->readfds != NULL && ((ulongptr) t->readfds)[i] != 0)
238 ((ulongptr) &greadfds)[i] |= ((ulongptr) t->readfds)[i];
3666451e 239 cont_read:
a48b6916
MD
240 if (t->writefds != NULL && ((ulongptr) t->writefds)[i] != 0)
241 ((ulongptr) &gwritefds)[i] |= ((ulongptr) t->writefds)[i];
3666451e 242 cont_write:
a48b6916
MD
243 if (t->exceptfds != NULL && ((ulongptr) t->exceptfds)[i] != 0)
244 ((ulongptr) &gexceptfds)[i] |= ((ulongptr) t->exceptfds)[i];
3666451e 245 cont_except:
26cbcbf9 246 ;
3666451e 247 }
3666451e
MD
248}
249
a48b6916
MD
250/* Update the fd sets pointed to by the thread so that they reflect
251 the status of the file descriptors which the thread was interested
252 in. Also clear those bits in the common sets. This function is
253 only called when there are no bit collisions. */
3666451e
MD
254static void
255finalize_fd_sets (coop_t *t)
256{
257 int i = (t->nfds + SCM_BITS_PER_LONG - 1) / SCM_BITS_PER_LONG;
258 int n_ones = 0;
259 register unsigned long s;
a48b6916 260
3666451e
MD
261 if (t->nfds == gnfds)
262 {
a48b6916
MD
263 /* This thread is the one responsible for the current high value
264 of gnfds. First do our other jobs while at the same time
265 trying to decrease gnfds. */
3666451e
MD
266 while (i > 0)
267 {
268 --i;
269 if (t->readfds != NULL && (s = ((ulongptr) t->readfds)[i]) != 0)
270 {
271 ((ulongptr) t->readfds)[i] &= ((ulongptr) &rreadfds)[i];
272 ((ulongptr) &greadfds)[i] &= ~s;
273 n_ones += SCM_NLONGBITS (&((ulongptr) t->readfds)[i]);
274 }
275 if (((ulongptr) &greadfds)[i] != 0)
276 {
277 gnfds = (i + 1) * SCM_BITS_PER_LONG;
278 goto cont_read;
279 }
280 if (t->writefds != NULL && (s = ((ulongptr) t->writefds)[i]) != 0)
281 {
282 ((ulongptr) t->writefds)[i] &= ((ulongptr) &rwritefds)[i];
283 ((ulongptr) &gwritefds)[i] &= ~s;
284 n_ones += SCM_NLONGBITS (&((ulongptr) t->writefds)[i]);
285 }
286 if (((ulongptr) &gwritefds)[i] != 0)
287 {
288 gnfds = (i + 1) * SCM_BITS_PER_LONG;
289 goto cont_write;
290 }
291 if (t->exceptfds != NULL && (s = ((ulongptr) t->exceptfds)[i]) != 0)
292 {
293 ((ulongptr) t->exceptfds)[i] &= ((ulongptr) &rexceptfds)[i];
294 ((ulongptr) &gexceptfds)[i] &= ~s;
295 n_ones += SCM_NLONGBITS (&((ulongptr) t->exceptfds)[i]);
296 }
297 if (((ulongptr) &gexceptfds)[i] != 0)
298 {
299 gnfds = (i + 1) * SCM_BITS_PER_LONG;
300 goto cont_except;
301 }
302 }
303 gnfds = 0;
304 t->retval = n_ones;
305 return;
306 }
a48b6916
MD
307
308 /* Either this thread wasn't responsible for gnfds or gnfds has been
309 determined. */
3666451e
MD
310 while (i > 0)
311 {
312 --i;
313 if (t->readfds != NULL && (s = ((ulongptr) t->readfds)[i]) != 0)
314 {
315 ((ulongptr) t->readfds)[i] &= ((ulongptr) &rreadfds)[i];
316 ((ulongptr) &greadfds)[i] &= ~s;
317 n_ones += SCM_NLONGBITS (&((ulongptr) t->readfds)[i]);
318 }
319 cont_read:
320 if (t->writefds != NULL && (s = ((ulongptr) t->writefds)[i]) != 0)
321 {
322 ((ulongptr) t->writefds)[i] &= ((ulongptr) &rwritefds)[i];
323 ((ulongptr) &gwritefds)[i] &= ~s;
cafc12ff 324 n_ones += SCM_NLONGBITS (&((ulongptr) t->writefds)[i]);
3666451e
MD
325 }
326 cont_write:
327 if (t->exceptfds != NULL && (s = ((ulongptr) t->exceptfds)[i]) != 0)
328 {
329 ((ulongptr) t->exceptfds)[i] &= ((ulongptr) &rexceptfds)[i];
330 ((ulongptr) &gexceptfds)[i] &= ~s;
cafc12ff 331 n_ones += SCM_NLONGBITS (&((ulongptr) t->exceptfds)[i]);
3666451e
MD
332 }
333 cont_except:
95f44da9 334 ;
3666451e
MD
335 }
336 t->retval = n_ones;
337}
338
a48b6916
MD
339/* Just like finalize_fd_sets except that we don't have to update the
340 global fd sets. Those will be recalulated elsewhere. */
341static void
342finalize_fd_sets_lazily (coop_t *t)
343{
344 int i = (t->nfds + SCM_BITS_PER_LONG - 1) / SCM_BITS_PER_LONG;
345 int n_ones = 0;
a48b6916
MD
346 while (i > 0)
347 {
348 --i;
3237b129 349 if (t->readfds != NULL && ((ulongptr) t->readfds)[i] != 0)
a48b6916
MD
350 {
351 ((ulongptr) t->readfds)[i] &= ((ulongptr) &rreadfds)[i];
352 n_ones += SCM_NLONGBITS (&((ulongptr) t->readfds)[i]);
353 }
3237b129 354 if (t->writefds != NULL && ((ulongptr) t->writefds)[i] != 0)
a48b6916
MD
355 {
356 ((ulongptr) t->writefds)[i] &= ((ulongptr) &rwritefds)[i];
357 n_ones += SCM_NLONGBITS (&((ulongptr) t->writefds)[i]);
358 }
3237b129 359 if (t->exceptfds != NULL && ((ulongptr) t->exceptfds)[i] != 0)
a48b6916
MD
360 {
361 ((ulongptr) t->exceptfds)[i] &= ((ulongptr) &rexceptfds)[i];
362 n_ones += SCM_NLONGBITS (&((ulongptr) t->exceptfds)[i]);
363 }
364 }
365 t->retval = n_ones;
366}
367
368/* Return first fd with a non-zero bit in any of the result sets. */
3666451e
MD
369static int
370first_interesting_fd (void)
371{
372 int i = 0;
373 SELECT_TYPE *s;
374 while (1)
375 {
376 if (((ulongptr) &rreadfds)[i] != 0)
377 {
378 s = &rreadfds;
379 break;
380 }
381 if (((ulongptr) &rwritefds)[i] != 0)
382 {
383 s = &rwritefds;
384 break;
385 }
386 if (((ulongptr) &rexceptfds)[i] != 0)
387 {
388 s = &rexceptfds;
389 break;
390 }
391 ++i;
392 }
393 i *= SCM_BITS_PER_LONG;
394 while (i < gnfds)
395 {
396 if (FD_ISSET (i, s))
397 return i;
398 ++i;
399 }
400 fprintf (stderr, "first_interesting_fd: internal error\n");
401 exit (1);
402}
403
a48b6916 404/* Revive all threads with an error status. */
c69dfa65
MD
405void
406scm_error_revive_threads (void)
3666451e
MD
407{
408 coop_t *t;
409
410 while ((t = coop_qget (&coop_global_sleepq)) != NULL)
411 {
c44bfbc9 412 t->_errno = errno;
3666451e 413 t->retval = -1;
c69dfa65
MD
414 if (t != coop_global_curr)
415 coop_qput (&coop_global_runq, t);
3666451e 416 }
c69dfa65 417 collisionp = 0;
3666451e
MD
418 gnfds = 0;
419 FD_ZERO (&greadfds);
420 FD_ZERO (&gwritefds);
421 FD_ZERO (&gexceptfds);
422}
423
a48b6916
MD
424/* Given the result of a call to safe_select and the current time,
425 try to wake up some threads and return the first one. Return NULL
426 if we couldn't find any. */
3666451e 427static coop_t *
c69dfa65 428find_thread (int n, struct timeval *now, int sleepingp)
3666451e
MD
429{
430 coop_t *t;
431 int fd;
432
c69dfa65
MD
433 if (n < 0)
434 /* An error or a signal has occured. Wake all threads. Since we
435 don't care to calculate if there is a sinner we report the
436 error to all of them. */
437 {
438 scm_error_revive_threads ();
439 if (!scm_I_am_dead)
440 return coop_global_curr;
441 }
442 else if (n == 0)
3666451e
MD
443 {
444 while (!QEMPTYP (coop_global_sleepq)
445 && (t = QFIRST (coop_global_sleepq))->timeoutp
446 && (t->wakeup_time.tv_sec < now->tv_sec
447 || (t->wakeup_time.tv_sec == now->tv_sec
448 && t->wakeup_time.tv_usec <= now->tv_usec)))
449 {
450 coop_qget (&coop_global_sleepq);
a48b6916
MD
451 if (collisionp)
452 finalize_fd_sets_lazily (t);
453 else
454 finalize_fd_sets (t);
3666451e
MD
455 coop_qput (&coop_global_runq, t);
456 }
a48b6916
MD
457 if (collisionp)
458 {
459 while ((t = coop_qget (&coop_global_sleepq)) != NULL)
460 coop_qput (&coop_tmp_queue, t);
461 goto rebuild_global_fd_sets;
462 }
3666451e
MD
463 }
464 else if (n > 0)
465 {
466 /* Find the first interesting file descriptor */
467 fd = first_interesting_fd ();
468 /* Check the sleeping queue for this file descriptor.
469 Other file descriptors will be handled next time
470 coop_next_runnable_thread is called. */
471 /* This code is inefficient. We'll improve it later. */
472 while ((t = coop_qget (&coop_global_sleepq)) != NULL)
473 {
474 if ((t->readfds && FD_ISSET (fd, t->readfds))
475 || (t->writefds && FD_ISSET (fd, t->writefds))
476 || (t->exceptfds && FD_ISSET (fd, t->exceptfds))
477 || (t->timeoutp
478 && (t->wakeup_time.tv_sec < now->tv_sec
479 || (t->wakeup_time.tv_sec == now->tv_sec
480 && t->wakeup_time.tv_usec <= now->tv_usec))))
481 {
a48b6916
MD
482 if (collisionp)
483 finalize_fd_sets_lazily (t);
484 else
485 finalize_fd_sets (t);
3666451e
MD
486 coop_qput (&coop_global_runq, t);
487 }
488 else
489 coop_qput(&coop_tmp_queue, t);
490 }
a48b6916
MD
491 if (collisionp)
492 {
493 rebuild_global_fd_sets:
494 collisionp = 0;
495 gnfds = 0;
496 FD_ZERO (&greadfds);
497 FD_ZERO (&gwritefds);
498 FD_ZERO (&gexceptfds);
499 while ((t = coop_qget (&coop_tmp_queue)) != NULL)
500 {
501 add_fd_sets (t);
502 coop_qput (&coop_global_sleepq, t);
503 }
504 }
505 else
506 {
507 while ((t = coop_qget (&coop_tmp_queue)) != NULL)
508 coop_qput (&coop_global_sleepq, t);
509 }
3666451e 510 }
3666451e
MD
511
512 return coop_qget (&coop_global_runq);
513}
514
515/* Return next runnable thread on the run queue.
516 * First update the queue with possible I/O or timeouts.
517 * If no thread is found, return NULL.
518 */
519coop_t *
520coop_next_runnable_thread ()
521{
81e81a5c 522 coop_t *t;
3666451e
MD
523 struct timeval now;
524 int n;
525
526 /* Just return next thread on the runq if the sleepq is empty. */
527 if (QEMPTYP (coop_global_sleepq))
c69dfa65
MD
528 {
529 if (QEMPTYP (coop_global_runq))
530 return coop_global_curr;
531 else
532 return coop_qget (&coop_global_runq);
533 }
3666451e
MD
534
535 if (gnfds > 0)
536 n = safe_select (gnfds, &greadfds, &gwritefds, &gexceptfds, &timeout0);
537 else
538 n = 0;
539 if (QFIRST (coop_global_sleepq)->timeoutp)
540 {
541 gettimeofday (&now, NULL);
c69dfa65 542 t = find_thread (n, &now, 0);
3666451e 543 }
81e81a5c 544 else
c69dfa65
MD
545 t = find_thread (n, 0, 0);
546 return t == NULL ? coop_global_curr : t;
3666451e
MD
547}
548
549coop_t *
550coop_wait_for_runnable_thread_now (struct timeval *now)
551{
552 int n;
553 coop_t *t;
554
555 if (gnfds > 0)
556 n = safe_select (gnfds, &greadfds, &gwritefds, &gexceptfds, &timeout0);
557 else
558 n = 0;
559 /* Is there any other runnable thread? */
c69dfa65 560 t = find_thread (n, now, 1);
3666451e
MD
561 while (t == NULL)
562 {
563 /* No. Let the process go to sleep. */
564 if ((t = QFIRST (coop_global_sleepq))->timeoutp)
565 {
566 now->tv_sec = t->wakeup_time.tv_sec - now->tv_sec;
567 if (now->tv_usec > t->wakeup_time.tv_usec)
568 {
569 --now->tv_sec;
570 now->tv_usec = 1000000 + t->wakeup_time.tv_usec - now->tv_usec;
571 }
572 else
573 now->tv_usec = t->wakeup_time.tv_usec - now->tv_usec;
574 n = safe_select (gnfds, &greadfds, &gwritefds, &gexceptfds, now);
575 }
576 else
577 n = safe_select (gnfds, &greadfds, &gwritefds, &gexceptfds, NULL);
578 gettimeofday (now, NULL);
c69dfa65 579 t = find_thread (n, now, 1);
3666451e
MD
580 }
581
582 return t;
583}
584
585coop_t *
586coop_wait_for_runnable_thread ()
587{
588 struct timeval now;
589
590 if (QEMPTYP (coop_global_sleepq))
c69dfa65
MD
591 {
592 if (QEMPTYP (coop_global_runq))
593 return coop_global_curr;
594 else
595 return coop_qget (&coop_global_runq);
596 }
3666451e
MD
597
598 if (QFIRST (coop_global_sleepq)->timeoutp)
599 gettimeofday (&now, NULL);
600
601 return coop_wait_for_runnable_thread_now (&now);
602}
603
1cbf4dea
MD
604/* Initialize bit counting array */
605static void init_bc (int bit, int i, int n)
606{
607 if (bit == 0)
608 bc[i] = n;
609 else
610 {
611 init_bc (bit >> 1, i, n);
612 init_bc (bit >> 1, i | bit, n + 1);
613 }
614}
615
616void
617scm_init_iselect ()
618{
619#if 0 /* This is just symbolic */
620 collisionp = 0;
621 gnfds = 0;
622 FD_ZERO (&greadfds);
623 FD_ZERO (&gwritefds);
624 FD_ZERO (&gexceptfds);
625 timeout0.tv_sec = 0;
626 timeout0.tv_usec = 0;
627#endif
628 init_bc (0x80, 0, 0);
8dc9439f 629#ifndef SCM_MAGIC_SNARFER
a0599745 630#include "libguile/iselect.x"
8dc9439f 631#endif
1cbf4dea
MD
632}
633
634#endif /* GUILE_ISELECT */
635
3666451e
MD
636int
637scm_internal_select (int nfds,
638 SELECT_TYPE *readfds,
639 SELECT_TYPE *writefds,
640 SELECT_TYPE *exceptfds,
641 struct timeval *timeout)
642{
1cbf4dea
MD
643#ifndef GUILE_ISELECT
644 int res = select (nfds, readfds, writefds, exceptfds, timeout);
645 SCM_ASYNC_TICK;
646 return res;
647#else /* GUILE_ISELECT */
3666451e
MD
648 struct timeval now;
649 coop_t *t, *curr = coop_global_curr;
c69dfa65 650
3666451e
MD
651 /* If the timeout is 0, we're polling and can handle it quickly. */
652 if (timeout != NULL
653 && timeout->tv_sec == 0
654 && timeout->tv_usec == 0)
655 return select (nfds, readfds, writefds, exceptfds, timeout);
656
c69dfa65 657 SCM_DEFER_INTS;
c718cb07 658
3666451e 659 /* Add our file descriptor flags to the common set. */
3237b129
MD
660 curr->nfds = nfds;
661 curr->readfds = readfds;
662 curr->writefds = writefds;
663 curr->exceptfds = exceptfds;
664 add_fd_sets (curr);
3666451e
MD
665
666 /* Place ourselves on the sleep queue and get a new thread to run. */
667 if (timeout == NULL)
668 {
669 curr->timeoutp = 0;
670 coop_qput (&coop_global_sleepq, curr);
671 t = coop_wait_for_runnable_thread ();
672 }
673 else
674 {
675 gettimeofday (&now, NULL);
676 curr->timeoutp = 1;
677 curr->wakeup_time.tv_sec = now.tv_sec + timeout->tv_sec;
678 curr->wakeup_time.tv_usec = now.tv_usec + timeout->tv_usec;
679 if (curr->wakeup_time.tv_usec >= 1000000)
680 {
681 ++curr->wakeup_time.tv_sec;
682 curr->wakeup_time.tv_usec -= 1000000;
683 }
684 /* Insert the current thread at the right place in the sleep queue */
685 coop_timeout_qinsert (&coop_global_sleepq, curr);
686 t = coop_wait_for_runnable_thread_now (&now);
687 }
688
689 /* If the new thread is the same as the sleeping thread, do nothing */
c69dfa65 690 if (t != coop_global_curr)
3666451e
MD
691 {
692 /* Do a context switch. */
693 coop_global_curr = t;
694 QT_BLOCK (coop_sleephelp, curr, NULL, t->sp);
695 }
696
c69dfa65
MD
697 if (coop_global_curr->retval == -1)
698 errno = coop_global_curr->_errno;
699 SCM_ALLOW_INTS;
1cbf4dea 700 SCM_ASYNC_TICK;
c69dfa65 701 return coop_global_curr->retval;
1cbf4dea 702#endif /* GUILE_ISELECT */
3666451e 703}
89e00824
ML
704
705/*
706 Local Variables:
707 c-file-style: "gnu"
708 End:
709*/