[PATCH 1/2] add signalfd support

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

 



We use threads and pipe for event notification (I/O completion); I/O
threads signal the main thread when I/Os are complete. signalfd is
faster than it (signalfd is supported as of 2.6.22).

Signed-off-by: FUJITA Tomonori <fujita.tomonori@xxxxxxxxxxxxx>
---
 usr/bs.c   |  104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------
 usr/list.h |   23 +++++++++++++
 usr/util.h |   34 ++++++++++++++++++--
 3 files changed, 148 insertions(+), 13 deletions(-)

diff --git a/usr/bs.c b/usr/bs.c
index cd19b86..df0aab8 100644
--- a/usr/bs.c
+++ b/usr/bs.c
@@ -23,7 +23,15 @@
 #include <string.h>
 #include <inttypes.h>
 #include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <syscall.h>
+#include <sys/types.h>
 #include <sys/epoll.h>
+#include <linux/types.h>
+#include <linux/signalfd.h>
 
 #include "list.h"
 #include "tgtd.h"
@@ -33,6 +41,10 @@
 
 static LIST_HEAD(bst_list);
 
+static int sig_fd = -1;
+static LIST_HEAD(sig_finished_list);
+static pthread_mutex_t sig_finished_lock;
+
 int register_backingstore_template(struct backingstore_template *bst)
 {
 	list_add(&bst->backingstore_siblings, &bst_list);
@@ -140,10 +152,39 @@ rewrite:
 	}
 }
 
+void bs_sig_request_done(int fd, int events, void *data)
+{
+	int ret;
+	struct scsi_cmd *cmd;
+	struct signalfd_siginfo siginfo[16];
+	LIST_HEAD(list);
+
+	ret = read(fd, (char *)siginfo, sizeof(siginfo));
+	if (ret <= 0) {
+		return;
+	}
+
+	pthread_mutex_lock(&sig_finished_lock);
+	list_splice_init(&sig_finished_list, &list);
+	pthread_mutex_unlock(&sig_finished_lock);
+
+	while (!list_empty(&list)) {
+		cmd = list_first_entry(&list, struct scsi_cmd, bs_list);
+
+		list_del(&cmd->bs_list);
+
+		cmd->scsi_cmd_done(cmd, scsi_get_result(cmd));
+	}
+}
+
 static void *bs_thread_worker_fn(void *arg)
 {
 	struct bs_thread_info *info = arg;
 	struct scsi_cmd *cmd;
+	sigset_t set;
+
+	sigfillset(&set);
+	sigprocmask(SIG_BLOCK, &set, NULL);
 
 	pthread_mutex_lock(&info->startup_lock);
 	dprintf("started this thread\n");
@@ -171,21 +212,58 @@ static void *bs_thread_worker_fn(void *arg)
 
 		info->request_fn(cmd);
 
-		pthread_mutex_lock(&info->finished_lock);
-		list_add(&cmd->bs_list, &info->finished_list);
-		pthread_mutex_unlock(&info->finished_lock);
+		if (sig_fd < 0) {
+			pthread_mutex_lock(&info->finished_lock);
+			list_add(&cmd->bs_list, &info->finished_list);
+			pthread_mutex_unlock(&info->finished_lock);
 
-		pthread_cond_signal(&info->finished_cond);
+			pthread_cond_signal(&info->finished_cond);
+		} else {
+			pthread_mutex_lock(&sig_finished_lock);
+			list_add_tail(&cmd->bs_list, &sig_finished_list);
+			pthread_mutex_unlock(&sig_finished_lock);
+
+			kill(getpid(), SIGUSR2);
+		}
 	}
 
 	pthread_exit(NULL);
 }
 
+static void bs_init(void)
+{
+	static int done = 0;
+	sigset_t mask;
+	int ret;
+
+	if (done)
+		return;
+	done++;
+
+	sigemptyset(&mask);
+	sigaddset(&mask, SIGUSR2);
+	sigprocmask(SIG_BLOCK, &mask, NULL);
+
+	sig_fd = __signalfd(-1, &mask, 0);
+	if (sig_fd < 0)
+		return;
+
+	ret = tgt_event_add(sig_fd, EPOLLIN, bs_sig_request_done, NULL);
+	if (ret < 0) {
+		close (sig_fd);
+		sig_fd = -1;
+	}
+
+	pthread_mutex_init(&sig_finished_lock, NULL);
+}
+
 int bs_thread_open(struct bs_thread_info *info, request_func_t *rfn,
 		   int nr_threads)
 {
 	int i, ret;
 
+	bs_init();
+
 	info->request_fn = rfn;
 
 	INIT_LIST_HEAD(&info->ack_list);
@@ -211,10 +289,13 @@ int bs_thread_open(struct bs_thread_info *info, request_func_t *rfn,
 		goto close_command_fd;
 	}
 
-	ret = tgt_event_add(info->done_fd[0], EPOLLIN, bs_thread_request_done, info);
-	if (ret) {
-		eprintf("failed to add epoll event\n");
-		goto close_done_fd;
+	if (sig_fd < 0) {
+		ret = tgt_event_add(info->done_fd[0], EPOLLIN, bs_thread_request_done,
+				    info);
+		if (ret) {
+			eprintf("failed to add epoll event\n");
+			goto close_done_fd;
+		}
 	}
 
 	ret = pthread_create(&info->ack_thread, NULL, bs_thread_ack_fn, info);
@@ -263,7 +344,9 @@ destroy_threads:
 		eprintf("stopped the worker thread %d\n", i - 1);
 	}
 event_del:
-	tgt_event_del(info->done_fd[0]);
+	if (sig_fd < 0)
+		tgt_event_del(info->done_fd[0]);
+
 close_done_fd:
 	close(info->done_fd[0]);
 	close(info->done_fd[1]);
@@ -300,7 +383,8 @@ void bs_thread_close(struct bs_thread_info *info)
 	pthread_mutex_destroy(&info->pending_lock);
 	pthread_mutex_destroy(&info->startup_lock);
 
-	tgt_event_del(info->done_fd[0]);
+	if (sig_fd < 0)
+		tgt_event_del(info->done_fd[0]);
 
 	close(info->done_fd[0]);
 	close(info->done_fd[1]);
diff --git a/usr/list.h b/usr/list.h
index 4d76057..f66ff36 100644
--- a/usr/list.h
+++ b/usr/list.h
@@ -92,4 +92,27 @@ static inline void list_del_init(struct list_head *entry)
 	INIT_LIST_HEAD(entry);
 }
 
+static inline void __list_splice(const struct list_head *list,
+				 struct list_head *prev,
+				 struct list_head *next)
+{
+	struct list_head *first = list->next;
+	struct list_head *last = list->prev;
+
+	first->prev = prev;
+	prev->next = first;
+
+	last->next = next;
+	next->prev = last;
+}
+
+static inline void list_splice_init(struct list_head *list,
+				    struct list_head *head)
+{
+	if (!list_empty(list)) {
+		__list_splice(list, head, head->next);
+		INIT_LIST_HEAD(list);
+	}
+}
+
 #endif
diff --git a/usr/util.h b/usr/util.h
index c941b37..ae22ec0 100644
--- a/usr/util.h
+++ b/usr/util.h
@@ -2,12 +2,13 @@
 #define __UTIL_H__
 
 #include <byteswap.h>
+#include <endian.h>
+#include <errno.h>
 #include <fcntl.h>
+#include <signal.h>
 #include <syscall.h>
 #include <unistd.h>
-#include <errno.h>
-#include <endian.h>
-#include <sys/syscall.h>
+
 #include "be_byteshift.h"
 
 #define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
@@ -115,4 +116,31 @@ static inline int __sync_file_range(int fd, __off64_t offset, __off64_t bytes)
 #define __sync_file_range(fd, offset, bytes) fsync(fd)
 #endif
 
+#if defined(__NR_signalfd)
+static inline int __signalfd(int fd, const sigset_t *mask, int flags)
+{
+	int fd2, ret;
+
+	fd2 = syscall(__NR_signalfd, fd, mask, _NSIG / 8);
+	if (fd2 < 0)
+		return fd2;
+
+	ret = fcntl(fd2, F_GETFL);
+	if (ret < 0) {
+		close(fd2);
+		return -1;
+	}
+
+	ret = fcntl(fd2, F_SETFL, ret | O_NONBLOCK);
+	if (ret < 0) {
+		close(fd2);
+		return -1;
+	}
+
+	return fd2;
+}
+#else
+#define __signalfd() (-1)
+#endif
+
 #endif
-- 
1.6.0.6

--
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