#include #include #include #include #include "ucore/iomux_waker.h" static void uc_waker_pipe_cb(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event) { char buf[256]; struct IOMuxWaker *wk; int rc; assert(event & MUX_EV_READ); assert((event & MUX_EV_WRITE) == 0); wk = fd->cookie_ptr; //we want to to drain the pipe and process all //events do { rc = read(fd->fd, buf, sizeof buf); if (rc < (int)sizeof buf) { //avoid unneeded read()s break; } } while (rc > 0); // if we get EINTR, we rather handle it next round if (rc == -1 && errno != EWOULDBLOCK && errno != EINTR) { assert(0); } wk->wake_cb(wk); } static int uc_install_wake_handler(struct IOMuxWaker *wk, int rfd) { struct IOMuxFD *fd = &wk->read_fd; memset(fd, 0, sizeof *fd); fd->fd = rfd; fd->callback = uc_waker_pipe_cb; fd->cookie_ptr = wk; fd->what = MUX_EV_READ; return iomux_register_fd(wk->mux, fd); } int uc_iomux_waker_init(struct IOMux *mux, struct IOMuxWaker *wk, uc_waker_cb cb) { int rc; int pfds[2]; assert(wk != NULL); assert(cb != NULL); memset(wk, 0 , sizeof *wk); rc = pipe(pfds); if (rc != 0) { return errno; } wk->mux = mux; wk->wake_cb = cb; wk->signaller.fd = pfds[1]; if (uc_install_wake_handler(wk, pfds[0]) == 0) { return 0; } else { int saved_errno; saved_errno = errno; close(pfds[0]); close(pfds[1]); return saved_errno; } } int uc_iomux_waker_destroy(struct IOMuxWaker *wk) { int rc; assert(wk != NULL); rc = iomux_unregister_fd(wk->mux, &wk->read_fd); assert(rc == 0); close(wk->signaller.fd); close(wk->read_fd.fd); wk->mux = NULL; wk->wake_cb = NULL; wk->signaller.fd = -1; assert(rc == 0); return rc; } int uc_iomux_waker_signal(struct IOMuxSignaller *signaller) { int rc; static const char x = 'X'; assert(signaller != NULL); do { rc = write(signaller->fd, &x, 1); } while (rc == -1 && errno == EINTR); //if we would have blocked, the pipe is already //signalled and it should wake up anyhow if (rc == -1 && errno != EWOULDBLOCK) { return errno; } else if (rc == 0) { //Can't happen assert(0); } return 0; }