diff --git a/mio/lib/mio.c b/mio/lib/mio.c index 6c4249c..3495958 100644 --- a/mio/lib/mio.c +++ b/mio/lib/mio.c @@ -1045,7 +1045,7 @@ int mio_dev_watch (mio_dev_t* dev, mio_dev_watch_cmd_t cmd, int events) if (dev->dev_cap & MIO_DEV_CAP_VIRTUAL) return 0; /*ev.data.ptr = dev;*/ - dev_cap = dev->dev_cap & ~(DEV_CAP_ALL_WATCHED); + dev_cap = dev->dev_cap & ~(DEV_CAP_ALL_WATCHED | MIO_DEV_CAP_WATCH_SUSPENDED); /* UGLY to use MIO_DEV_CAP_WATCH_SUSPENDED here */ switch (cmd) { @@ -1116,7 +1116,8 @@ int mio_dev_watch (mio_dev_t* dev, mio_dev_watch_cmd_t cmd, int events) if (mio_sys_ctrlmux(mio, mux_cmd, dev, dev_cap) <= -1) return -1; } - dev->dev_cap = dev_cap; + /* UGLY. MIO_DEV_CAP_WATCH_SUSPENDED may be set/unset by mio_sys_ctrlmux. I need this to reflect it */ + dev->dev_cap = dev_cap | (dev->dev_cap & MIO_DEV_CAP_WATCH_SUSPENDED); return 0; } diff --git a/mio/lib/mio.h b/mio/lib/mio.h index 30a53de..7a71f68 100644 --- a/mio/lib/mio.h +++ b/mio/lib/mio.h @@ -390,7 +390,8 @@ enum mio_dev_cap_t MIO_DEV_CAP_HALTED = (1 << 16), MIO_DEV_CAP_ZOMBIE = (1 << 17), MIO_DEV_CAP_RENEW_REQUIRED = (1 << 18), - MIO_DEV_CAP_WATCH_STARTED = (1 << 19) + MIO_DEV_CAP_WATCH_STARTED = (1 << 19), + MIO_DEV_CAP_WATCH_SUSPENDED = (1 << 20) }; typedef enum mio_dev_cap_t mio_dev_cap_t; diff --git a/mio/lib/sys-mux.c b/mio/lib/sys-mux.c index d3dbe78..6f78744 100644 --- a/mio/lib/sys-mux.c +++ b/mio/lib/sys-mux.c @@ -186,7 +186,7 @@ int mio_sys_ctrlmux (mio_t* mio, mio_sys_mux_cmd_t cmd, mio_dev_t* dev, int dev_ MIO_ASSERT (mio, mux->pd.dptr[idx] == dev); mux->pd.pfd[idx].events = events; - + return 0; } @@ -235,26 +235,85 @@ int mio_sys_ctrlmux (mio_t* mio, mio_sys_mux_cmd_t cmd, mio_dev_t* dev, int dev_ } #elif defined(USE_EPOLL) mio_sys_mux_t* mux = &mio->sysdep->mux; - static int epoll_cmd[] = { EPOLL_CTL_ADD, EPOLL_CTL_MOD, EPOLL_CTL_DEL }; struct epoll_event ev; + mio_syshnd_t hnd; + mio_uint32_t events; + int x; MIO_ASSERT (mio, mio == dev->mio); + hnd = dev->dev_mth->getsyshnd(dev); - ev.data.ptr = dev; - ev.events = EPOLLHUP | EPOLLERR /*| EPOLLET*/; - + events = 0; if (dev_cap & MIO_DEV_CAP_IN_WATCHED) { - ev.events |= EPOLLIN; + events |= EPOLLIN; #if defined(EPOLLRDHUP) - ev.events |= EPOLLRDHUP; + events |= EPOLLRDHUP; #endif - if (dev_cap & MIO_DEV_CAP_PRI_WATCHED) ev.events |= EPOLLPRI; + if (dev_cap & MIO_DEV_CAP_PRI_WATCHED) events |= EPOLLPRI; + } + if (dev_cap & MIO_DEV_CAP_OUT_WATCHED) events |= EPOLLOUT; + + ev.events = events | EPOLLHUP | EPOLLERR /*| EPOLLET*/; + ev.data.ptr = dev; + + switch (cmd) + { + case MIO_SYS_MUX_CMD_INSERT: + if (MIO_UNLIKELY(dev->dev_cap & MIO_DEV_CAP_WATCH_SUSPENDED)) + { + mio_seterrnum (mio, MIO_EEXIST); + return -1; + } + + x = epoll_ctl(mux->hnd, EPOLL_CTL_ADD, hnd, &ev); + break; + + case MIO_SYS_MUX_CMD_UPDATE: + if (MIO_UNLIKELY(!events)) + { + if (dev->dev_cap & MIO_DEV_CAP_WATCH_SUSPENDED) + { + /* no change. keep suspended */ + return 0; + } + else + { + x = epoll_ctl(mux->hnd, EPOLL_CTL_DEL, hnd, &ev); + if (x >= 0) dev->dev_cap |= MIO_DEV_CAP_WATCH_SUSPENDED; + } + } + else + { + if (dev->dev_cap & MIO_DEV_CAP_WATCH_SUSPENDED) + { + x = epoll_ctl(mux->hnd, EPOLL_CTL_ADD, hnd, &ev); + if (x >= 0) dev->dev_cap &= ~MIO_DEV_CAP_WATCH_SUSPENDED; + } + else + { + x = epoll_ctl(mux->hnd, EPOLL_CTL_MOD, hnd, &ev); + } + } + break; + + case MIO_SYS_MUX_CMD_DELETE: + if (dev->dev_cap & MIO_DEV_CAP_WATCH_SUSPENDED) + { + /* clear the SUSPENDED bit because it's a normal deletion */ + dev->dev_cap &= ~MIO_DEV_CAP_WATCH_SUSPENDED; + return 0; + } + + x = epoll_ctl(mux->hnd, EPOLL_CTL_DEL, hnd, &ev); + break; + + default: + mio_seterrnum (mio, MIO_EINVAL); + return -1; } - if (dev_cap & MIO_DEV_CAP_OUT_WATCHED) ev.events |= EPOLLOUT; - - if (epoll_ctl(mux->hnd, epoll_cmd[cmd], dev->dev_mth->getsyshnd(dev), &ev) == -1) + if (x == -1) { mio_seterrwithsyserr (mio, 0, errno); return -1; diff --git a/mio/lib/sys-prv.h b/mio/lib/sys-prv.h index 7d1dde6..d1c946a 100644 --- a/mio/lib/sys-prv.h +++ b/mio/lib/sys-prv.h @@ -68,7 +68,7 @@ struct mio_sys_mux_t struct mio_sys_mux_t { int hnd; - struct epoll_event revs[100]; /* TODO: is it a good size? */ + struct epoll_event revs[128]; /* TODO: is it a good size? */ }; #endif