Beispiel #1
0
static DWORD WINAPI
win32thr_wait (struct event_queue *evq)
{
    CRITICAL_SECTION *head_cs;
    HANDLE head_signal;
    struct win32thr wth;

    InitCriticalSection(&wth.cs);
    wth.state = WTHR_SLEEP;
    wth.n = 0;
    wth.tq = NULL;
    wth.handles[0] = wth.signal = ((struct win32thr_arg *) evq)->signal;
    wth.evq = evq = ((struct win32thr_arg *) evq)->evq;
    wth.next = evq->head.next;
    evq->head.next = &wth;
    head_cs = &evq->head.cs;
    head_signal = evq->head.signal;

    SetEvent(evq->ack_event);

    for (; ; ) {
	msec_t now;
	unsigned int res, n;

	WaitForSingleObject(wth.signal, INFINITE);
	if (!(n = wth.n)) break;

	EnterCriticalSection(head_cs);
	now = evq->now;
	if (--evq->nwakeup == 0)
	    SetEvent(evq->ack_event);  /* wake up poller */
	LeaveCriticalSection(head_cs);

	res = WaitForMultipleObjects(n + 1, wth.handles, FALSE,
	 timeout_get(wth.tq, TIMEOUT_INFINITE, now));
	wth.idx = res;
	res = (res == WAIT_TIMEOUT) || (res < (WAIT_OBJECT_0 + n));

	EnterCriticalSection(&wth.cs);
	if (wth.state == WTHR_ACK) {
	    SetEvent(evq->ack_event);
	    ResetEvent(wth.signal);
	}
	wth.state = res ? WTHR_READY : WTHR_SLEEP;
	LeaveCriticalSection(&wth.cs);

	if (res) {
	    EnterCriticalSection(head_cs);
	    wth.next_ready = evq->wth_ready;
	    evq->wth_ready = &wth;
	    evq->sig_ready |= (1 << EVQ_SIGEVQ);
	    SetEvent(head_signal);
	    LeaveCriticalSection(head_cs);
	}
    }
    CloseHandle(wth.signal);
    DeleteCriticalSection(&wth.cs);
    return 0;
}
Beispiel #2
0
/*-------------------------------------------------------------------------*\
* Select with int timeout in ms
\*-------------------------------------------------------------------------*/
int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds, 
        p_timeout tm) {
    struct timeval tv; 
    double t = timeout_get(tm);
    tv.tv_sec = (int) t;
    tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6);
    if (n <= 0) {
        Sleep((DWORD) (1000*t));
        return 0;
    } else return select(0, rfds, wfds, efds, t >= 0.0? &tv: NULL);
}
Beispiel #3
0
int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
    int ret;
    fd_set rfds, wfds, efds, *rp = NULL, *wp = NULL, *ep = NULL;
    struct timeval tv, *tp = NULL;
    double t;
    if (timeout_iszero(tm)) return IO_TIMEOUT;  /* optimize timeout == 0 case */
    if (sw & WAITFD_R) { 
        FD_ZERO(&rfds); 
        FD_SET(*ps, &rfds);
        rp = &rfds; 
    }
    if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(*ps, &wfds); wp = &wfds; }
    if (sw & WAITFD_C) { FD_ZERO(&efds); FD_SET(*ps, &efds); ep = &efds; }
    if ((t = timeout_get(tm)) >= 0.0) {
        tv.tv_sec = (int) t;
        tv.tv_usec = (int) ((t-tv.tv_sec)*1.0e6);
        tp = &tv;
    }
    ret = select(0, rp, wp, ep, tp);
    if (ret == -1) return WSAGetLastError();
    if (ret == 0) return IO_TIMEOUT;
    if (sw == WAITFD_C && FD_ISSET(*ps, &efds)) return IO_CLOSED;
    return IO_DONE;
}
Beispiel #4
0
EVQ_API int
evq_wait (struct event_queue *evq, msec_t timeout)
{
  struct event *ev_ready;
  struct kevent *kev = evq->kev_list;
  struct timespec ts, *tsp;
  int nready;

  if (timeout != 0L) {
    timeout = timeout_get(evq->tq, timeout, evq->now);
    if (timeout == 0L) {
      ev_ready = timeout_process(evq->tq, NULL, evq->now);
      goto end;
    }
  }
  if (timeout == TIMEOUT_INFINITE)
    tsp = NULL;
  else {
    ts.tv_sec = timeout / 1000;
    ts.tv_nsec = (timeout % 1000) * 1000000;
    tsp = &ts;
  }

  sys_vm_leave();
  nready = kevent(evq->kqueue_fd, kev, evq->nchanges, kev, NEVENT, tsp);
  sys_vm_enter();

  evq->nchanges = 0;
  evq->now = sys_milliseconds();

  if (nready == -1)
    return (errno == EINTR) ? 0 : EVQ_FAILED;

  if (tsp) {
    if (!nready) {
      ev_ready = !evq->tq ? NULL
       : timeout_process(evq->tq, NULL, evq->now);
      if (ev_ready) goto end;
      return EVQ_TIMEOUT;
    }

    timeout = evq->now;
  }

  ev_ready = NULL;
  for (; nready--; ++kev) {
    struct event *ev;
    const int flags = kev->flags;
    const int filter = kev->filter;

    if (flags & EV_ERROR)
      continue;

    if (filter == EVFILT_SIGNAL) {
      ev_ready = signal_process_actives(evq, kev->ident,
       ev_ready, timeout);
      continue;
    }

    ev = (struct event *) kev->udata;
    if (!ev) {
      ev_ready = signal_process_interrupt(evq, ev_ready, timeout);
      continue;
    }

    ev->flags |= (filter == EVFILT_READ ? EVENT_READ_RES : EVENT_WRITE_RES)
     | ((flags & EV_EOF) ? EVENT_EOF_RES : 0);

    if (ev->flags & EVENT_ACTIVE)
      continue;

    ev->flags |= EVENT_ACTIVE;
    if (ev->flags & EVENT_ONESHOT)
      evq_del(ev, 1);
    else if (ev->tq && !(ev->flags & EVENT_TIMEOUT_MANUAL))
      timeout_reset(ev, timeout);

    ev->next_ready = ev_ready;
    ev_ready = ev;
  }
  if (!ev_ready) return 0;
 end:
  evq->ev_ready = ev_ready;
  return 0;
}
Beispiel #5
0
EVQ_API int
evq_wait (struct event_queue *evq, msec_t timeout)
{
    struct event *ev_ready = NULL;
    struct win32thr *wth = &evq->head;
    struct win32thr *threads = wth->next;
    CRITICAL_SECTION *head_cs = &wth->cs;
    HANDLE head_signal = wth->signal;
    int n = wth->n;
    int sig_ready = 0;
    DWORD wait_res;

    if (threads && win32thr_poll(evq) && evq_is_empty(evq))
	return 0;

    if (timeout != 0L) {
	timeout = timeout_get(wth->tq, timeout, evq->now);
	if (timeout == 0L) {
	    ev_ready = timeout_process(wth->tq, NULL, evq->now);
	    goto end;
	}
    }

    if (is_WinNT) {
	if (!iocp_is_empty(evq))
	    ev_ready = win32iocp_process(evq, NULL, 0L);

	if (ev_ready) {
	    evq->ev_ready = ev_ready;
	    timeout = 0L;
	} else {
	    /* head_signal is resetted by IOCP WSARecv/WSASend */
	    EnterCriticalSection(head_cs);
	    if (evq->sig_ready)
		timeout = 0L;
	    LeaveCriticalSection(head_cs);
	}
    }

    sys_vm_leave();
    wait_res = MsgWaitForMultipleObjects(n + 1, wth->handles, FALSE, timeout,
     (evq->win_msg ? QS_ALLEVENTS : 0));
    sys_vm_enter();

    evq->now = sys_milliseconds();

    ev_ready = evq->ev_ready;

    if (wait_res == WAIT_TIMEOUT) {
	if (ev_ready) goto end;
	if (!wth->tq && !evq->sig_ready)
	    return EVQ_TIMEOUT;
    }
    if (wait_res == (DWORD) (WAIT_OBJECT_0 + n + 1)) {
	struct event *ev = evq->win_msg;
	if (ev && !(ev->flags & EVENT_ACTIVE)) {
	    ev->flags |= EVENT_ACTIVE;
	    ev->next_ready = ev_ready;
	    ev_ready = ev;
	}
	goto end;
    }
    if (wait_res == WAIT_FAILED)
	return EVQ_FAILED;

    timeout = evq->now;
    if (!iocp_is_empty(evq))
	ev_ready = win32iocp_process(evq, ev_ready, timeout);

    wth->idx = wait_res;

    if (threads) {
	EnterCriticalSection(head_cs);
	ResetEvent(head_signal);

	threads = evq->wth_ready;
	evq->wth_ready = NULL;

	sig_ready = evq->sig_ready;
	evq->sig_ready = 0;
	LeaveCriticalSection(head_cs);

	if (wait_res == (DWORD) (WAIT_OBJECT_0 + n))
	    wth = threads;
	else
	    wth->next_ready = threads;
    } else {
	wth->next_ready = NULL;

	if (evq->sig_ready) {
	    EnterCriticalSection(head_cs);
	    ResetEvent(head_signal);

	    sig_ready = evq->sig_ready;
	    evq->sig_ready = 0;
	    LeaveCriticalSection(head_cs);
	}
    }

    if (sig_ready)
	ev_ready = signal_process_interrupt(evq, sig_ready, ev_ready, timeout);

    for (; wth; wth = wth->next_ready) {
	HANDLE *hp;  /* event handles */
	const int idx = wth->idx;
	int i;

	wth->state = WTHR_SLEEP;

	if (wth->tq) {
	    if (idx == WAIT_TIMEOUT) {
		ev_ready = timeout_process(wth->tq, ev_ready, timeout);
		continue;
	    }
	}

	hp = &wth->handles[idx];
	n = wth->n;
	i = idx;
	if (i >= n) continue;  /* some events deleted? */

	/* Traverse array of events */
	for (; ; ) {
	    WSANETWORKEVENTS ne;
	    struct event *ev = wth->events[i];
	    const int ev_flags = ev->flags;
	    unsigned int res = 0;

	    if (!(ev_flags & EVENT_SOCKET)) {
		if (ev_flags & EVENT_PID) {
		    DWORD status;
		    GetExitCodeProcess(ev->fd, &status);
		    res = (status << EVENT_EOF_SHIFT_RES);
		} else
		    ResetEvent(ev->fd);  /* all events must be manual-reset */
		res |= EVENT_READ_RES;
	    } else if (!WSAEnumNetworkEvents((int) ev->fd, *hp, &ne)) {
		if ((ev_flags & EVENT_READ)
		 && (ne.lNetworkEvents & WFD_READ))
		    res = EVENT_READ_RES;
		if ((ev_flags & EVENT_WRITE)
		 && (ne.lNetworkEvents & WFD_WRITE))
		    res |= EVENT_WRITE_RES;
		if (ne.lNetworkEvents & FD_CLOSE)
		    res |= EVENT_EOF_RES;
	    }

	    if (res) {
		ev->flags |= EVENT_ACTIVE | res;
		ev->next_ready = ev_ready;
		ev_ready = ev;

		if (ev_flags & EVENT_ONESHOT) {
		    win32thr_del(wth, ev);
		    --i, --n, --hp;
		} else if (ev->tq && !(ev_flags & EVENT_TIMEOUT_MANUAL))
		    timeout_reset(ev, timeout);
	    }

	    /* skip inactive events */
	    do {
		if (++i == n)
		    goto end_thread;
	    } while (WaitForSingleObject(*(++hp), 0) != WAIT_OBJECT_0);
	}
 end_thread:
	((void) 0);  /* avoid warning */
    }

    /* always check window messages */
    {
	struct event *ev = evq->win_msg;

	if (ev && GetQueueStatus(QS_ALLEVENTS)) {
	    ev->next_ready = ev_ready;
	    ev_ready = ev;
	}
    }
    if (!ev_ready)
	return (wait_res == WAIT_TIMEOUT && !sig_ready)
	 ? EVQ_TIMEOUT : 0;
 end:
    evq->ev_ready = ev_ready;
    return 0;
}
Beispiel #6
0
EVQ_API int
evq_wait (struct event_queue *evq, msec_t timeout)
{
    struct event *ev_ready;
    struct event **events = evq->events;
    struct pollfd *fdset = evq->fdset;
    const int npolls = evq->npolls;
    int i, nready;

    if (timeout != 0L) {
	timeout = timeout_get(evq->tq, timeout, evq->now);
	if (timeout == 0L) {
	    ev_ready = timeout_process(evq->tq, NULL, evq->now);
	    goto end;
	}
    }

    sys_vm_leave();
    nready = poll(fdset, npolls, (int) timeout);
    sys_vm_enter();

    evq->now = get_milliseconds();

    if (nready == -1)
	return (errno == EINTR) ? 0 : EVQ_FAILED;

    if (timeout != TIMEOUT_INFINITE) {
	if (!nready) {
	    ev_ready = !evq->tq ? NULL
	     : timeout_process(evq->tq, NULL, evq->now);
	    if (ev_ready) goto end;
	    return EVQ_TIMEOUT;
	}

	timeout = evq->now;
    }

    ev_ready = NULL;
    if (fdset[0].revents & POLLIN) {
	fdset[0].revents = 0;
	ev_ready = signal_process_interrupt(evq, ev_ready, timeout);
	--nready;
    }

    for (i = 1; i < npolls; i++) {
	const int revents = fdset[i].revents;
	struct event *ev;
	unsigned int res;

	if (!revents) continue;

	fdset[i].revents = 0;
	ev = events[i];

	res = EVENT_ACTIVE;
	if ((revents & POLLFD_READ) && (ev->flags & EVENT_READ))
	    res |= EVENT_READ_RES;
	if ((revents & POLLFD_WRITE) && (ev->flags & EVENT_WRITE))
	    res |= EVENT_WRITE_RES;
	if (revents & POLLHUP)
	    res |= EVENT_EOF_RES;

	ev->flags |= res;
	if (ev->flags & EVENT_ONESHOT)
	    evq_del(ev, 1);
	else if (ev->tq && !(ev->flags & EVENT_TIMEOUT_MANUAL))
	    timeout_reset(ev, timeout);

	ev->next_ready = ev_ready;
	ev_ready = ev;

	if (!--nready) break;
    }
    if (!ev_ready) return 0;
 end:
    evq->ev_ready = ev_ready;
    return 0;
}
Beispiel #7
0
EVQ_API int
evq_wait (struct event_queue *evq, struct sys_thread *td, msec_t timeout)
{
  struct event *ev_ready;
  fd_set work_readset = evq->readset;
  fd_set work_writeset = evq->writeset;
  struct timeval tv, *tvp;
  struct event **events = evq->events;
  const int npolls = evq->npolls;
  int i, nready, max_fd;

  if (timeout != 0L) {
    timeout = timeout_get(evq->tq, timeout, evq->now);
    if (timeout == 0L) {
      ev_ready = timeout_process(evq->tq, NULL, evq->now);
      goto end;
    }
  }
  if (timeout == TIMEOUT_INFINITE)
    tvp = NULL;
  else {
    tv.tv_sec = timeout / 1000;
    tv.tv_usec = (timeout % 1000) * 1000;
    tvp = &tv;
  }

  max_fd = evq->max_fd;
  if (max_fd == -1) {
    for (i = 1; i < npolls; ++i) {
      struct event *ev = events[i];
      if (max_fd < ev->fd)
        max_fd = ev->fd;
    }
    evq->max_fd = max_fd;
  }

  if (td) sys_vm2_leave(td);
  nready = select(max_fd + 1, &work_readset, &work_writeset, NULL, tvp);
  if (td) sys_vm2_enter(td);

  evq->now = sys_milliseconds();

  if (nready == -1)
    return (errno == EINTR) ? 0 : -1;

  ev_ready = evq->ev_ready;
  if (tvp) {
    if (!nready) {
      if (evq->tq) {
        struct event *ev = timeout_process(evq->tq, ev_ready, evq->now);
        if (ev != ev_ready) {
          ev_ready = ev;
          goto end;
        }
      }
      return SYS_ERR_TIMEOUT;
    }

    timeout = evq->now;
  }

  if (FD_ISSET(evq->sig_fd[0], &work_readset)) {
    ev_ready = signal_process_interrupt(evq, ev_ready, timeout);
    --nready;
  }

  for (i = 1; i < npolls && nready; i++) {
    struct event *ev = events[i];
    unsigned int res = 0;

    if ((ev->flags & EVENT_READ) && FD_ISSET(ev->fd, &work_readset))
      res |= EVENT_READ_RES;
    else if ((ev->flags & EVENT_WRITE) && FD_ISSET(ev->fd, &work_writeset))
      res |= EVENT_WRITE_RES;

    if (!res) continue;

    ev->flags |= res;
    if (!(ev->flags & EVENT_ACTIVE)) {
      ev->flags |= EVENT_ACTIVE;
      if (ev->flags & EVENT_ONESHOT)
        evq_del(ev, 1);
      else if (ev->tq && !(ev->flags & EVENT_TIMEOUT_MANUAL))
        timeout_reset(ev, timeout);

      ev->next_ready = ev_ready;
      ev_ready = ev;
    }
    --nready;
  }
  if (!ev_ready) return 0;
 end:
  evq->ev_ready = ev_ready;
  return 0;
}