124 lines
2.4 KiB
C
124 lines
2.4 KiB
C
#include <errno.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <assert.h>
|
|
#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;
|
|
}
|
|
|