static void
_sched_init (void)
{
  int i;

  for (i = 0; i < MAX_PRIORITY; i++)
    thread_queue_init (&_runq[i]);

  thread_queue_init (&_waitq);
  thread_queue_init (&_deadq);

  _thread_num_wait = 0;
  _thread_num_dead = 0;
  _thread_num_runnable = 0;
  _thread_num_total = 1;

#ifdef EXPIRIMENTAL
  _timerq = timer_queue_allocate ();
  timer_queue_update (_timerq, timer_queue_time_elapsed (_timerq));
  io_init ();
#endif
}
/*
 *  This is the idle task, that runs at the lowest possible priority.
 *  It's only called when there are no other fibers ready for scheduling.
 */
void
_fiber_event_loop (void)
{
  /* These are all static, to minimize stack usage */
  static fd_set readfds;
  static fd_set writefds;
  static int nreadfds;
  static int nwritefds;
  static int nfds;
  static thread_t *thr, *next;
  static TVAL timeout;
  static struct timeval tv, *ptv;
  static int rc;

  for (;;)
    {
      timeout = timer_queue_update (_timerq,
	  timer_queue_time_elapsed (_timerq));
      if (_thread_num_runnable)
	return;

      FD_ZERO (&readfds);
      FD_ZERO (&writefds);

      for (thr = (thread_t *) _waitq.thq_head.thr_next;
	  thr != (thread_t *) &_waitq.thq_head;
	  thr = (thread_t *) thr->thr_hdr.thr_next)
	{
	  if (thr->thr_nfds)
	    {
	      nreadfds = _fd_set_or (&readfds, &thr->thr_rfds);
	      nwritefds = _fd_set_or (&writefds, &thr->thr_wfds);
	    }
	}
      nfds = MAX (nreadfds, nwritefds);

      if (timeout == 0)
	ptv = NULL;
      else
	{
	  tv.tv_sec = timeout / 1000;
	  tv.tv_usec = (timeout % 1000) * 1000;
	  ptv = &tv;
	}
      rc = select (nfds, &readfds, &writefds, NULL, ptv);
      if (rc == -1)
	{
	  if (errno != EINTR)
	    GPF_T1 ("select() returned -1");
	  continue;
	}
      timer_queue_update (_timerq, timer_queue_time_elapsed (_timerq));

      if (rc > 0)
	{
	  /* Wake up waiting fibers for which an event occurred */
	  for (thr = (thread_t *) _waitq.thq_head.thr_next;
	      thr != (thread_t *) &_waitq.thq_head;
	      thr = next)
	    {
	      next = (thread_t *) thr->thr_hdr.thr_next;
	      if (thr->thr_nfds == 0)
		continue;
	      if (_fd_set_intersect (&thr->thr_rfds, &readfds) ||
		  _fd_set_intersect (&thr->thr_wfds, &writefds))
		{
		  _fd_set_and (&thr->thr_rfds, &readfds);
		  _fd_set_and (&thr->thr_wfds, &writefds);
		  thr->thr_event = NULL;
		  thr->thr_retcode = 1;
		  _fiber_status (thr, RUNNABLE);
		}
	    }
	}
      break;
    }
}