Exemple #1
0
EVQ_API int
evq_init (struct event_queue *evq)
{
    struct win32thr *wth = &evq->head;

    evq->ack_event = CreateEvent(NULL, FALSE, FALSE, NULL);
    if (evq->ack_event == NULL)
	return -1;

    wth->signal = CreateEvent(NULL, FALSE, FALSE, NULL);
    if (wth->signal == NULL) {
	CloseHandle(evq->ack_event);
	return -1;
    }
    wth->handles[0] = wth->signal;
    wth->evq = evq;

    InitCriticalSection(&wth->cs);

    if (is_WinNT) {
	evq->iocp.h = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
    }

    evq->now = sys_milliseconds();
    return 0;
}
Exemple #2
0
EVQ_API int
evq_init (struct event_queue *evq)
{
  evq->kqueue_fd = kqueue();
  if (evq->kqueue_fd == -1)
    return -1;

  pthread_mutex_init(&evq->cs, NULL);

  {
    fd_t *sig_fd = evq->sig_fd;
    struct kevent kev;

    memset(&kev, 0, sizeof(struct kevent));
    kev.filter = EVFILT_READ;
    kev.flags = EV_ADD;

    sig_fd[0] = sig_fd[1] = (fd_t) -1;
    if (pipe(sig_fd) || fcntl(sig_fd[0], F_SETFL, O_NONBLOCK))
      goto err;

    kev.ident = sig_fd[0];
    if (kevent(evq->kqueue_fd, &kev, 1, NULL, 0, NULL))
      goto err;
  }

  evq->now = sys_milliseconds();
  return 0;
 err:
  evq_done(evq);
  return -1;
}
Exemple #3
0
EVQ_API int
evq_init (struct event_queue *evq)
{
  pthread_mutex_init(&evq->sig_cs, NULL);

  {
    fd_t *sig_fd = evq->sig_fd;
    unsigned int fd;

    sig_fd[0] = sig_fd[1] = (fd_t) -1;
    if (pipe(sig_fd) || fcntl(sig_fd[0], F_SETFL, O_NONBLOCK))
      goto err;

    fd = (unsigned int) sig_fd[0];
    FD_SET(fd, &evq->readset);
    evq->max_fd = fd;
    evq->npolls++;
  }

  evq->now = sys_milliseconds();
  return 0;
 err:
  evq_done(evq);
  return -1;
}
Exemple #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;
}
Exemple #5
0
static struct event *
win32iocp_process (struct event_queue *evq, struct event *ev_ready, msec_t now)
{
    const HANDLE iocph = evq->iocp.h;
    OVERLAPPED_ENTRY entries[NENTRY];
    ULONG nentries = 0;

    for (; ; ) {
	struct win32overlapped *ov;
	struct event *ev;
	BOOL status;
	int cancelled = 0;

	if (pGetQueuedCompletionStatusEx) {
	    if (!nentries && !pGetQueuedCompletionStatusEx(iocph,
	     entries, NENTRY, &nentries, 0L, FALSE))
		break;

	    {
		const OVERLAPPED_ENTRY *ove = &entries[--nentries];
		const DWORD err = (DWORD) ove->lpOverlapped->Internal;

		ov = (struct win32overlapped *) ove->lpOverlapped;
		status = !err;
		cancelled = (err == STATUS_CANCELLED);
	    }
	} else {
	    ULONG_PTR key;
	    DWORD nr;

	    status = GetQueuedCompletionStatus(iocph, &nr, &key,
	     (OVERLAPPED **) &ov, 0L);
	    if (!status) {
		const DWORD err = GetLastError();

		if (err == WAIT_TIMEOUT)
		    break;
		cancelled = (err == ERROR_OPERATION_ABORTED);
	    }
	}

	if (!ov) {
	    if (pGetQueuedCompletionStatusEx) continue;
	    break;  /* error */
	}

	ev = ov->ev;
	cancelled = ev ? cancelled : 1;
	win32iocp_del_overlapped(evq, ov);
	if (cancelled)
	    continue;

	if (!status)
	    ev->flags |= EVENT_EOF_RES;
	else if (ov == ev->w.iocp.rov) {
	    ev->w.iocp.rov = NULL;
	    ev->flags |= EVENT_READ_RES;
	    ev->flags &= ~EVENT_RPENDING;  /* have to set IOCP read request */
	} else {
	    ev->w.iocp.wov = NULL;
	    ev->flags |= EVENT_WRITE_RES;
	    ev->flags &= ~EVENT_WPENDING;  /* have to set IOCP write request */
	}

	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)) {
	    if (now == 0L) {
		now = evq->now = sys_milliseconds();
	    }
	    timeout_reset(ev, now);
	}

	ev->next_ready = ev_ready;
	ev_ready = ev;
    }
    return ev_ready;
}
Exemple #6
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;
}
Exemple #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;
}