Added timerfd-backed work scheduler where the kernel supports it. Otherwise signal-based timer mechanism is used. Using timerfd leads to less cpu usage compared with the signal-based scheduler. This patch needs to be applied on the top of: http://lists.wpkg.org/pipermail/stgt/2011-January/004380.html Signed-off-by: Alexander Nezhinsky <alexandern@xxxxxxxxxxxx> Signed-off-by: FUJITA Tomonori <fujita.tomonori@xxxxxxxxxxxxx> --- usr/Makefile | 4 ++ usr/work.c | 145 +++++++++++++++++++++++++++++++++++----------------------- usr/work.h | 33 ++++++++++++- 3 files changed, 123 insertions(+), 59 deletions(-) diff --git a/usr/Makefile b/usr/Makefile index a138f98..024f7bf 100644 --- a/usr/Makefile +++ b/usr/Makefile @@ -4,6 +4,10 @@ ifneq ($(shell test -e /usr/include/linux/signalfd.h && echo 1),) CFLAGS += -DUSE_SIGNALFD endif +ifneq ($(shell test -e /usr/include/sys/timerfd.h && echo 1),) +CFLAGS += -DUSE_TIMERFD +endif + ifneq ($(IBMVIO),) CFLAGS += -DIBMVIO -DUSE_KERNEL TGTD_OBJS += $(addprefix ibmvio/, ibmvio.o) diff --git a/usr/work.c b/usr/work.c index c3e1f34..f753bec 100644 --- a/usr/work.c +++ b/usr/work.c @@ -24,6 +24,7 @@ #include <stdint.h> #include <signal.h> #include <sys/epoll.h> +#include <sys/time.h> #include "list.h" #include "util.h" @@ -31,18 +32,17 @@ #include "work.h" #include "tgtd.h" -#define WORK_TIMER_INT_SEC 0 #define WORK_TIMER_INT_MSEC 500 #define WORK_TIMER_INT_USEC (WORK_TIMER_INT_MSEC * 1000) static struct itimerval work_timer = { - {WORK_TIMER_INT_SEC, WORK_TIMER_INT_USEC}, - {WORK_TIMER_INT_SEC, WORK_TIMER_INT_USEC} + {0, WORK_TIMER_INT_USEC}, + {0, WORK_TIMER_INT_USEC} }; -static int elapsed_msecs; +static unsigned int elapsed_msecs; static int timer_pending; -static int timer_fd[2]; +static int timer_fd[2] = {-1, -1}; static LIST_HEAD(active_work_list); static LIST_HEAD(inactive_work_list); @@ -76,23 +76,58 @@ static void work_timer_sig_handler(int data) static void work_timer_evt_handler(int fd, int events, void *data) { - unsigned int n; int err; + static int first = 1; - err = read(timer_fd[0], &n, sizeof(n)); - if (err < 0) { - eprintf("Failed to read from pipe, %m\n"); - return; - } + if (timer_fd[1] == -1) { + unsigned long long s; + struct timeval cur_time; + + err = read(timer_fd[0], &s, sizeof(s)); + if (err < 0) { + if (err != -EAGAIN) + eprintf("failed to read from timerfd, %m\n"); + return; + } - timer_pending = 0; + if (first) { + first = 0; + err = gettimeofday(&cur_time, NULL); + if (err) { + eprintf("gettimeofday failed, %m\n"); + exit(1); + } + elapsed_msecs = timeval_to_msecs(cur_time); + return; + } + + elapsed_msecs += (unsigned int)s * WORK_TIMER_INT_MSEC; + } else { + unsigned int n; + struct timeval cur_time; + + err = read(timer_fd[0], &n, sizeof(n)); + if (err < 0) { + eprintf("Failed to read from pipe, %m\n"); + return; + } + + timer_pending = 0; + + err = gettimeofday(&cur_time, NULL); + if (err) { + eprintf("gettimeofday failed, %m\n"); + exit(1); + } + + elapsed_msecs = timeval_to_msecs(cur_time); + } execute_work(); } int work_timer_start(void) { - struct sigaction s; struct timeval t; int err; @@ -106,37 +141,44 @@ int work_timer_start(void) } elapsed_msecs = timeval_to_msecs(t); - sigemptyset(&s.sa_mask); - sigaddset(&s.sa_mask, SIGALRM); - s.sa_flags = 0; - s.sa_handler = work_timer_sig_handler; - err = sigaction(SIGALRM, &s, NULL); - if (err) { - eprintf("Failed to setup timer handler\n"); - goto timer_err; - } + timer_fd[0] = __timerfd_create(WORK_TIMER_INT_USEC); + if (timer_fd[0] > 0) + eprintf("use timer_fd based scheduler\n"); + else { + struct sigaction s; - err = setitimer(ITIMER_REAL, &work_timer, 0); - if (err) { - eprintf("Failed to set timer\n"); - goto timer_err; - } + eprintf("use signal based scheduler\n"); - err = pipe(timer_fd); - if (err) { - eprintf("Failed to open timer pipe\n"); - goto timer_err; + sigemptyset(&s.sa_mask); + sigaddset(&s.sa_mask, SIGALRM); + s.sa_flags = 0; + s.sa_handler = work_timer_sig_handler; + err = sigaction(SIGALRM, &s, NULL); + if (err) { + eprintf("Failed to setup timer handler\n"); + goto timer_err; + } + + err = setitimer(ITIMER_REAL, &work_timer, 0); + if (err) { + eprintf("Failed to set timer\n"); + goto timer_err; + } + + err = pipe(timer_fd); + if (err) { + eprintf("Failed to open timer pipe\n"); + goto timer_err; + } } - err = tgt_event_add(timer_fd[0], EPOLLIN, - work_timer_evt_handler, NULL); + err = tgt_event_add(timer_fd[0], EPOLLIN, work_timer_evt_handler, NULL); if (err) { eprintf("failed to add timer event, fd:%d\n", timer_fd[0]); goto timer_err; } - dprintf("started, timeout: %d sec %d msec\n", - WORK_TIMER_INT_SEC, WORK_TIMER_INT_MSEC); + dprintf("started, timeout: %d msec\n", WORK_TIMER_INT_MSEC); return 0; timer_err: @@ -144,12 +186,10 @@ timer_err: return err; } -int work_timer_stop(void) +void work_timer_stop(void) { - int err; - if (!elapsed_msecs) - return 0; + return; elapsed_msecs = 0; @@ -157,16 +197,17 @@ int work_timer_stop(void) if (timer_fd[0] > 0) close(timer_fd[0]); - if (timer_fd[1] > 0) - close(timer_fd[1]); - err = setitimer(ITIMER_REAL, 0, 0); - if (err) - eprintf("Failed to stop timer\n"); - else - dprintf("Timer stopped\n"); + if (timer_fd[1] > 0) { + int ret; + close(timer_fd[1]); - return err; + ret = setitimer(ITIMER_REAL, 0, 0); + if (ret) + eprintf("Failed to stop timer\n"); + else + dprintf("Timer stopped\n"); + } } void add_work(struct tgt_work *work, unsigned int second) @@ -202,17 +243,7 @@ void del_work(struct tgt_work *work) static void execute_work() { - struct timeval cur_time; struct tgt_work *work, *n; - int err; - - err = gettimeofday(&cur_time, NULL); - if (err) { - eprintf("gettimeofday failed, %m\n"); - exit(1); - } - - elapsed_msecs = timeval_to_msecs(cur_time); list_for_each_entry_safe(work, n, &inactive_work_list, entry) { if (before(elapsed_msecs, work->when)) diff --git a/usr/work.h b/usr/work.h index 98a28d5..b3fc50e 100644 --- a/usr/work.h +++ b/usr/work.h @@ -1,7 +1,36 @@ #ifndef __SCHED_H #define __SCHED_H -#include <sys/time.h> +#if defined(__NR_timerfd) && defined(USE_TIMERFD) + +#include <sys/timerfd.h> + +static inline int __timerfd_create(unsigned int usec) +{ + struct itimerspec new_t, old_t; + int fd, err; + + fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK); + if (fd < 0) + return -1; + + new_t.it_value.tv_sec = 0; + new_t.it_value.tv_nsec = 1; + + new_t.it_interval.tv_sec = 0; + new_t.it_interval.tv_nsec = usec * 1000; + + err = timerfd_settime(fd, TFD_TIMER_ABSTIME, &new_t, &old_t); + if (err < 0) { + close(fd); + return -1; + } + return fd; +} + +#else + #define __timerfd_create(usec) (-1) +#endif struct tgt_work { struct list_head entry; @@ -11,7 +40,7 @@ struct tgt_work { }; extern int work_timer_start(void); -extern int work_timer_stop(void); +extern void work_timer_stop(void); extern void add_work(struct tgt_work *work, unsigned int second); extern void del_work(struct tgt_work *work); -- 1.7.3 -- To unsubscribe from this list: send the line "unsubscribe stgt" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html