/** * Main polling loop for async I/O events. This function will only return when * re_cancel() is called or an error occured. * * @param signalh Optional Signal handler * * @return 0 if success, otherwise errorcode */ int re_main(re_signal_h *signalh) { struct re *re = re_get(); int err; #ifdef HAVE_SIGNAL if (signalh) { (void)signal(SIGINT, signal_handler); (void)signal(SIGALRM, signal_handler); (void)signal(SIGTERM, signal_handler); } #endif if (re->polling) { DEBUG_WARNING("main loop already polling\n"); return EALREADY; } err = poll_setup(re); if (err) goto out; DEBUG_INFO("Using async I/O polling method: `%s'\n", poll_method_name(re->method)); re->polling = true; #ifdef HAVE_ACTSCHED if (METHOD_ACTSCHED == re->method) { err = actsched_start(); goto out; } #endif re_lock(re); for (;;) { if (re->sig) { if (signalh) signalh(re->sig); re->sig = 0; } if (!re->polling) { err = 0; break; } err = fd_poll(re); if (err) { if (EINTR == err) continue; #ifdef DARWIN /* NOTE: workaround for Darwin */ if (EBADF == err) continue; #endif break; } tmr_poll(&re->tmrl); } re_unlock(re); out: re->polling = false; return err; }
/** * Enter an 're' thread * * @note Must only be called from a non-re thread */ void re_thread_enter(void) { re_lock(re_get()); }
/** * Polling loop * * @param re Poll state. * * @return 0 if success, otherwise errorcode */ static int fd_poll(struct re *re) { const uint64_t to = tmr_next_timeout(&re->tmrl); int i, n; #ifdef HAVE_SELECT fd_set rfds, wfds, efds; #endif DEBUG_INFO("next timer: %llu ms\n", to); /* Wait for I/O */ switch (re->method) { #ifdef HAVE_POLL case METHOD_POLL: re_unlock(re); n = poll(re->fds, re->nfds, to ? (int)to : -1); re_lock(re); break; #endif #ifdef HAVE_SELECT case METHOD_SELECT: { struct timeval tv; /* Clear and update fd sets */ FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); for (i=0; i<re->nfds; i++) { if (!re->fhs[i].fh) continue; if (re->fhs[i].flags & FD_READ) FD_SET(i, &rfds); if (re->fhs[i].flags & FD_WRITE) FD_SET(i, &wfds); if (re->fhs[i].flags & FD_EXCEPT) FD_SET(i, &efds); } #ifdef WIN32 tv.tv_sec = (long) to / 1000; #else tv.tv_sec = (time_t) to / 1000; #endif tv.tv_usec = (uint32_t) (to % 1000) * 1000; re_unlock(re); n = select(re->nfds, &rfds, &wfds, &efds, to ? &tv : NULL); re_lock(re); } break; #endif #ifdef HAVE_EPOLL case METHOD_EPOLL: re_unlock(re); n = epoll_wait(re->epfd, re->events, re->maxfds, to ? (int)to : -1); re_lock(re); break; #endif default: (void)to; DEBUG_WARNING("no polling method set\n"); return EINVAL; } if (n < 0) return errno; /* Check for events */ for (i=0; (n > 0) && (i < re->nfds); i++) { int fd, flags = 0; switch (re->method) { #ifdef HAVE_POLL case METHOD_POLL: fd = i; if (re->fds[fd].revents & POLLIN) flags |= FD_READ; if (re->fds[fd].revents & POLLOUT) flags |= FD_WRITE; if (re->fds[fd].revents & (POLLERR|POLLHUP|POLLNVAL)) flags |= FD_EXCEPT; if (re->fds[fd].revents & POLLNVAL) { DEBUG_WARNING("event: fd=%d POLLNVAL" " (fds.fd=%d," " fds.events=0x%02x)\n", fd, re->fds[fd].fd, re->fds[fd].events); } /* Clear events */ re->fds[fd].revents = 0; break; #endif #ifdef HAVE_SELECT case METHOD_SELECT: fd = i; if (FD_ISSET(fd, &rfds)) flags |= FD_READ; if (FD_ISSET(fd, &wfds)) flags |= FD_WRITE; if (FD_ISSET(fd, &efds)) flags |= FD_EXCEPT; break; #endif #ifdef HAVE_EPOLL case METHOD_EPOLL: fd = re->events[i].data.fd; if (re->events[i].events & EPOLLIN) flags |= FD_READ; if (re->events[i].events & EPOLLOUT) flags |= FD_WRITE; if (re->events[i].events & EPOLLERR) flags |= FD_EXCEPT; if (!flags) { DEBUG_WARNING("epoll: no flags fd=%d\n", fd); } break; #endif default: return EINVAL; } if (!flags) continue; if (re->fhs[fd].fh) { #if MAIN_DEBUG fd_handler(re, fd, flags); #else re->fhs[fd].fh(flags, re->fhs[fd].arg); #endif } /* Check if polling method was changed */ if (re->update) { re->update = false; return 0; } --n; } return 0; }
/** * Listen for events on a file descriptor * * @param fd File descriptor * @param flags Wanted event flags * @param fh Event handler * @param arg Handler argument * * @return 0 if success, otherwise errorcode */ int fd_listen(int fd, int flags, fd_h *fh, void *arg) { struct re *re = re_get(); int err = 0; DEBUG_INFO("fd_listen: fd=%d flags=0x%02x\n", fd, flags); if (fd < 0) { DEBUG_WARNING("fd_listen: corrupt fd %d\n", fd); return EBADF; } if (flags || fh) { err = poll_setup(re); if (err) return err; } if (fd >= re->maxfds) { if (flags) { DEBUG_WARNING("fd_listen: fd=%d flags=0x%02x" " - Max %d fds\n", fd, flags, re->maxfds); } return EMFILE; } re_lock(re); /* Update fh set */ if (re->fhs) { re->fhs[fd].flags = flags; re->fhs[fd].fh = fh; re->fhs[fd].arg = arg; } re->nfds = max(re->nfds, fd+1); re_unlock(re); switch (re->method) { #ifdef HAVE_POLL case METHOD_POLL: err = set_poll_fds(re, fd, flags); break; #endif #ifdef HAVE_EPOLL case METHOD_EPOLL: if (re->epfd <= 0) return EBADFD; err = set_epoll_fds(re, fd, flags); break; #endif default: break; } if (err) { if (flags && fh) { fd_close(fd); DEBUG_WARNING("fd_listen: fd=%d flags=0x%02x (%m)\n", fd, flags, err); } } return err; }