[stgt] [PATCH] add timerfd work scheduler support
Alexander Nezhinsky
alexandern at Voltaire.COM
Thu Jan 20 17:41:54 CET 2011
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 at voltaire.com>
Signed-off-by: FUJITA Tomonori <fujita.tomonori at lab.ntt.co.jp>
---
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 at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
More information about the stgt
mailing list