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; }
/*-------------------------------------------------------------------------*\ * 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); }
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; }
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; }
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; }
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; }
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; }