#include #include #include #include #include "ucore/clock.h" #include "ucore/backtrace.h" #include "iomux_impl.h" //dispatchers for the IOMux implementations */ struct IOMux *iomux_create(enum IOMUX_TYPE type) { return iomux_create_ex(type, &uc_timeofday_clock); } struct IOMux *iomux_create_ex(enum IOMUX_TYPE type, struct UCoreClock *uclock) { struct IOMux *mux = calloc(1, sizeof *mux); int rc = -1; switch (type) { case IOMUX_TYPE_DEFAULT: case IOMUX_TYPE_EPOLL: rc = iomux_epoll_init(mux); break; case IOMUX_TYPE_SELECT: rc = iomux_select_init(mux); break; } if (rc != 0) { //try fallback to select rc = iomux_select_init(mux); } if (rc == 0) { mux->uclock = uclock; uc_timers_init_ex(&mux->timers, mux->uclock); } else { free(mux); mux = NULL; } return mux; } void iomux_delete(struct IOMux *mux) { mux->ops.delete_impl(mux); memset(mux, 0xfa, sizeof *mux); free(mux); } //convert the difference between future and now static inline void future_to_interval(const struct timeval *future, const struct timeval *now, struct timeval *result) { if (timercmp(future, now, >)) { timersub(future, now, result); } else { result->tv_sec = 0; result->tv_usec = 0; } } static int iomux_run_timers(struct IOMux *mux, struct timeval *timeout) { struct timeval first_timer; if (uc_timers_first(&mux->timers, &first_timer) == 0) { struct timeval now; mux->uclock->now(mux->uclock, &now); future_to_interval(&first_timer, &now, timeout); /*TRACEF("now %d %d future %d %d interval %d %d\n", now.tv_sec, now.tv_usec, first_timer.tv_sec, first_timer.tv_usec, timeout->tv_sec, timeout->tv_usec); */ assert(timeout->tv_sec >= 0); assert(timeout->tv_usec >= 0); return 1; } return 0; } int iomux_run(struct IOMux *mux) { for (;;) { int rc; struct timeval timeout; struct timeval *timeoutp; if (iomux_run_timers(mux, &timeout)) { timeoutp = &timeout; } else { timeoutp = NULL; } rc = mux->ops.run_impl(mux, timeoutp); if (rc < 0) return rc; if (rc == 0 && timeoutp == NULL) //no more fd or timer events, ever return 0; } UC_NOT_REACED(); return -44; } int iomux_timers_run(struct IOMux *mux) { int event_cnt; event_cnt = uc_timers_run(&mux->timers); assert(event_cnt >= 0); return event_cnt; } int iomux_register_fd(struct IOMux *mux, struct IOMuxFD *fd) { assert(mux != NULL); assert(fd != NULL); assert(fd->callback != NULL); assert(fd->fd >= 0); return mux->ops.register_fd_impl(mux, fd); } int iomux_unregister_fd(struct IOMux *mux, struct IOMuxFD *fd) { assert(mux != NULL); assert(fd != NULL); assert(fd->fd >= 0); return mux->ops.unregister_fd_impl(mux, fd); } int iomux_update_events(struct IOMux *mux, struct IOMuxFD *fd, unsigned int what) { int rc = 0; assert(mux != NULL); assert(fd != NULL); assert(fd->callback != NULL); assert(fd->fd >= 0); if (fd->what != what) { rc = mux->ops.update_events_impl(mux, fd); } return rc; } struct UCoreClock *iomux_get_clock(struct IOMux *mux) { return mux->uclock; } struct UCTimers *iomux_get_timers(struct IOMux *mux) { return &mux->timers; } struct IOMux *iomux_from_timers(struct UCTimers *timers) { return (struct IOMux*)timers; //timers is the 1. member of IOMux }