/** * Set an external mutex for this thread * * @param mutexp Pointer to external mutex, NULL to use internal */ void re_set_mutex(void *mutexp) { #ifdef HAVE_PTHREAD struct re *re = re_get(); re->mutexp = mutexp ? mutexp : &re->mutex; #else (void)mutexp; #endif }
/** * Set async I/O polling method. This function can also be called while the * program is running. * * @param method New polling method * * @return 0 if success, otherwise errorcode */ int poll_method_set(enum poll_method method) { struct re *re = re_get(); int err; err = fd_setsize(DEFAULT_MAXFDS); if (err) return err; switch (method) { #ifdef HAVE_POLL case METHOD_POLL: break; #endif #ifdef HAVE_SELECT case METHOD_SELECT: if (re->maxfds > (int)FD_SETSIZE) { DEBUG_WARNING("SELECT: maxfds > FD_SETSIZE\n"); return EMFILE; } break; #endif #ifdef HAVE_EPOLL case METHOD_EPOLL: if (!epoll_check()) return EINVAL; break; #endif #ifdef HAVE_ACTSCHED case METHOD_ACTSCHED: break; #endif #ifdef HAVE_KQUEUE case METHOD_KQUEUE: break; #endif default: DEBUG_WARNING("poll method not supported: '%s'\n", poll_method_name(method)); return EINVAL; } re->method = method; re->update = true; DEBUG_INFO("Setting async I/O polling method to `%s'\n", poll_method_name(re->method)); err = poll_init(re); if (err) return err; return rebuild_fds(re); }
/** * Cancel the main polling loop */ void re_cancel(void) { struct re *re = re_get(); re->polling = false; #ifdef HAVE_ACTSCHED if (METHOD_ACTSCHED == re->method) { actsched_stop(); } #endif }
/** * Debug the main polling loop * * @param pf Print handler where debug output is printed to * @param unused Unused parameter * * @return 0 if success, otherwise errorcode */ int re_debug(struct re_printf *pf, void *unused) { struct re *re = re_get(); int err = 0; (void)unused; err |= re_hprintf(pf, "re main loop:\n"); err |= re_hprintf(pf, " maxfds: %d\n", re->maxfds); err |= re_hprintf(pf, " nfds: %d\n", re->nfds); err |= re_hprintf(pf, " method: %d (%s)\n", re->method, poll_method_name(re->method)); return err; }
/** * Print all file descriptors in-use */ void fd_debug(void) { const struct re *re = re_get(); int i; if (!re->fhs) return; for (i=0; i<re->nfds; i++) { if (!re->fhs[i].flags) continue; (void)re_fprintf(stderr, "fd %d in use: flags=%x fh=%p arg=%p\n", i, re->fhs[i].flags, re->fhs[i].fh, re->fhs[i].arg); } }
/** * Set the maximum number of file descriptors * * @param maxfds Max FDs. 0 to free. * * @return 0 if success, otherwise errorcode */ int fd_setsize(int maxfds) { struct re *re = re_get(); if (!maxfds) { fd_debug(); poll_close(re); return 0; } if (!re->maxfds) re->maxfds = maxfds; if (!re->fhs) { DEBUG_INFO("fd_setsize: maxfds=%d, allocating %u bytes\n", re->maxfds, re->maxfds * sizeof(*re->fhs)); re->fhs = mem_zalloc(re->maxfds * sizeof(*re->fhs), NULL); if (!re->fhs) return ENOMEM; } return 0; }
/** * 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; }
/* Thread-safe signal handling */ static void signal_handler(int sig) { (void)signal(sig, signal_handler); re_get()->sig = sig; }
/** * 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; } /* 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); 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; }
struct list *tmrl_get(void) { return &re_get()->tmrl; }
/** * Leave an 're' thread * * @note Must only be called from a non-re thread */ void re_thread_leave(void) { re_unlock(re_get()); }
/** * Enter an 're' thread * * @note Must only be called from a non-re thread */ void re_thread_enter(void) { re_lock(re_get()); }