[PATCH] add timerfd work scheduler support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


[Index of Archives]     [Linux SCSI]     [Linux RAID]     [Linux Clusters]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]

  Powered by Linux