Files
libucore/src/iomux_impl.c
T
2015-12-10 12:30:21 +01:00

174 lines
3.8 KiB
C

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#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) {
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
}