152 lines
3.5 KiB
C
152 lines
3.5 KiB
C
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include "ucore/clock.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->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;
|
|
}
|
|
}
|
|
|
|
int iomux_run(struct IOMux *mux)
|
|
{
|
|
for (;;) {
|
|
int rc;
|
|
struct timeval first_timer;
|
|
struct timeval timeout;
|
|
struct timeval *timeoutp;;
|
|
int has_timers = 0;
|
|
|
|
|
|
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);
|
|
timeoutp = &timeout;
|
|
/* TRACEF("now %d %d future %d %d interval %d %d\n", mux->now.tv_sec, mux->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);
|
|
|
|
has_timers = 1;
|
|
} else {
|
|
timeoutp = NULL; //no timeout
|
|
}
|
|
rc = mux->run_impl(mux, timeoutp);
|
|
if (rc < 0)
|
|
return rc;
|
|
|
|
if (rc == 0 && !has_timers) //no more events, ever
|
|
return 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
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->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->unregister_fd_impl(mux, fd);
|
|
}
|
|
|
|
int iomux_update_events(struct IOMux *mux, struct IOMuxFD *fd)
|
|
{
|
|
assert(mux != NULL);
|
|
assert(fd != NULL);
|
|
assert(fd->callback != NULL);
|
|
assert(fd->fd >= 0);
|
|
return mux->update_events_impl(mux, fd);
|
|
}
|
|
|
|
struct UCoreClock *iomux_get_clock(struct IOMux *mux)
|
|
{
|
|
return mux->uclock;
|
|
}
|
|
|
|
struct UCTimers *iomux_get_timers(struct IOMux *mux)
|
|
{
|
|
return &mux->timers;
|
|
}
|
|
|