[sheepdog] [PATCH 2/3] event: add deferred event register/unregister mechanism

Hitoshi Mitake mitake.hitoshi at gmail.com
Mon Jan 13 09:40:38 CET 2014


This patch introduces deferred event register/unregister
mechanism. Newly added APIs are:
 - deferred_register_event(): thread safe register_event()
 - deferred_register_event_prio(): thread safe register_event_prio()
 - deferred_unregister_event(): thread safe unregister_event()

These functions can be called by worker threads safely. They allocate
data structure which represents registering/unregistering event add
queue it to the list shared with the main thread. After queuing,
the main thread registers and unregisters events in a safe way.

Signed-off-by: Hitoshi Mitake <mitake.hitoshi at lab.ntt.co.jp>
---
 include/event.h |   5 +++
 lib/event.c     | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 124 insertions(+), 13 deletions(-)

diff --git a/include/event.h b/include/event.h
index 8f8b21f..b64b06e 100644
--- a/include/event.h
+++ b/include/event.h
@@ -32,4 +32,9 @@ static inline int register_event(int fd, event_handler_t h, void *data)
 	return register_event_prio(fd, h, data, EVENT_PRIO_DEFAULT);
 }
 
+void deferred_register_event_prio(int fd, event_handler_t h, void *data,
+				  int prio);
+void deferred_register_event(int fd, event_handler_t h, void *data);
+void deferred_unregister_event(int fd);
+
 #endif
diff --git a/lib/event.c b/lib/event.c
index 88078f4..2549dcd 100644
--- a/lib/event.c
+++ b/lib/event.c
@@ -76,19 +76,6 @@ static int event_cmp(const struct event_info *e1, const struct event_info *e2)
 	return intcmp(e1->fd, e2->fd);
 }
 
-int init_event(int nr)
-{
-	nr_events = nr;
-	events = xcalloc(nr_events, sizeof(struct epoll_event));
-
-	efd = epoll_create(nr);
-	if (efd < 0) {
-		sd_err("failed to create epoll fd");
-		return -1;
-	}
-	return 0;
-}
-
 static struct event_info *lookup_event(int fd)
 {
 	struct event_info key = { .fd = fd };
@@ -224,3 +211,122 @@ void event_loop_prio(int timeout)
 {
 	do_event_loop(timeout, true);
 }
+
+struct deferred_event_info {
+	bool is_register;	/* true: register, false: unregister */
+
+	int fd;
+	event_handler_t h;
+	void *data;
+	int prio;
+
+	struct list_node list;
+};
+
+static LIST_HEAD(deferred_event_list);
+static struct sd_mutex deferred_event_mutex = SD_MUTEX_INITIALIZER;
+
+static int deferred_event_fd;
+
+static void add_deferred_event_info(struct deferred_event_info *info)
+{
+	sd_mutex_lock(&deferred_event_mutex);
+	list_add_tail(&info->list, &deferred_event_list);
+	sd_mutex_unlock(&deferred_event_mutex);
+
+	eventfd_xwrite(deferred_event_fd, 1);
+	event_force_refresh();
+}
+
+void deferred_register_event_prio(int fd, event_handler_t h, void *data,
+				  int prio)
+{
+	struct deferred_event_info *info = xzalloc(sizeof(*info));
+
+	info->is_register = true;
+
+	info->fd = fd;
+	info->h = h;
+	info->data = data;
+	info->prio = prio;
+
+	add_deferred_event_info(info);
+}
+
+void deferred_register_event(int fd, event_handler_t h, void *data)
+{
+	deferred_register_event_prio(fd, h, data, EVENT_PRIO_DEFAULT);
+}
+
+void deferred_unregister_event(int fd)
+{
+	struct deferred_event_info *info = xzalloc(sizeof(*info));
+
+	info->is_register = false;
+	info->fd = fd;
+
+	add_deferred_event_info(info);
+}
+
+static void deferred_event_handler(int fd, int _events, void *data)
+{
+	LIST_HEAD(list);
+
+	assert(fd == deferred_event_fd);
+	eventfd_xread(fd);
+
+	sd_mutex_lock(&deferred_event_mutex);
+	list_splice_init(&deferred_event_list, &list);
+	sd_mutex_unlock(&deferred_event_mutex);
+
+	while (!list_empty(&list)) {
+		int ret;
+		struct deferred_event_info *info;
+
+		info = list_first_entry(&list, struct deferred_event_info,
+					list);
+
+		if (info->is_register) {
+			ret = register_event_prio(info->fd, info->h,
+						  info->data, info->prio);
+			if (ret < 0)
+				sd_err("failed to register event."
+				       " fd: %d, handler: %p",
+				       info->fd, info->h);
+		} else
+			unregister_event(info->fd);
+
+		list_del(&info->list);
+		free(info);
+	}
+}
+
+int init_event(int nr)
+{
+	int ret;
+
+	nr_events = nr;
+	events = xcalloc(nr_events, sizeof(struct epoll_event));
+
+	efd = epoll_create(nr);
+	if (efd < 0) {
+		sd_err("failed to create epoll fd");
+		return -1;
+	}
+
+	deferred_event_fd = eventfd(0, EFD_NONBLOCK);
+	if (deferred_event_fd < 0) {
+		sd_err("failed to create eventfd for deferred event"
+		       " register/unregister: %m");
+		return -1;
+	}
+
+	ret = register_event_prio(deferred_event_fd, deferred_event_handler,
+				  NULL, EVENT_PRIO_MAX);
+	if (ret < 0) {
+		sd_err("failed to register deferred_event_handler()");
+		return -1;
+	}
+
+	return 0;
+}
-- 
1.8.3.2



More information about the sheepdog mailing list