Add lttng_waiter utils
authorJérémie Galarneau <jeremie.galarneau@efficios.com>
Wed, 17 May 2017 15:16:33 +0000 (11:16 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Fri, 19 May 2017 14:23:32 +0000 (10:23 -0400)
This utils is adapted from userspace-rcu's urcu-wait.h

Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
src/common/Makefile.am
src/common/waiter.c [new file with mode: 0644]
src/common/waiter.h [new file with mode: 0644]

index 2cf497262fff100db47e2ca35d66add1ddbe955e..bdba28f19f2fadcc851babfa11ef950a2d3ae518 100644 (file)
@@ -78,7 +78,8 @@ libcommon_la_SOURCES = error.h error.c utils.c utils.h runas.c runas.h \
                        action.c notify.c condition.c buffer-usage.c \
                        evaluation.c notification.c trigger.c endpoint.c \
                        dynamic-buffer.h dynamic-buffer.c \
-                       buffer-view.h buffer-view.c
+                       buffer-view.h buffer-view.c \
+                       waiter.h waiter.c
 
 libcommon_la_LIBADD = \
                $(top_builddir)/src/common/config/libconfig.la
diff --git a/src/common/waiter.c b/src/common/waiter.c
new file mode 100644 (file)
index 0000000..c5a2829
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *               2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * This code is originally adapted from userspace-rcu's urcu-wait.h
+ */
+
+#include "waiter.h"
+#include <urcu/uatomic.h>
+#include <urcu/futex.h>
+#include <assert.h>
+#include "error.h"
+#include <poll.h>
+
+/*
+ * Number of busy-loop attempts before waiting on futex.
+ */
+#define WAIT_ATTEMPTS 1000
+
+enum waiter_state {
+       /* WAITER_WAITING is compared directly (futex compares it). */
+       WAITER_WAITING =        0,
+       /* non-zero are used as masks. */
+       WAITER_WOKEN_UP =       (1 << 0),
+       WAITER_RUNNING =        (1 << 1),
+       WAITER_TEARDOWN =       (1 << 2),
+};
+
+LTTNG_HIDDEN
+void lttng_waiter_init(struct lttng_waiter *waiter)
+{
+       cds_wfs_node_init(&waiter->wait_queue_node);
+       uatomic_set(&waiter->state, WAITER_WAITING);
+       cmm_smp_mb();
+}
+
+/*
+ * User must init "waiter" before passing its memory to waker thread.
+ */
+LTTNG_HIDDEN
+void lttng_waiter_wait(struct lttng_waiter *waiter)
+{
+       unsigned int i;
+
+       DBG("Beginning of waiter wait period");
+       /* Load and test condition before read state */
+       cmm_smp_rmb();
+       for (i = 0; i < WAIT_ATTEMPTS; i++) {
+               if (uatomic_read(&waiter->state) != WAITER_WAITING) {
+                       goto skip_futex_wait;
+               }
+               caa_cpu_relax();
+       }
+       while (futex_noasync(&waiter->state, FUTEX_WAIT, WAITER_WAITING,
+                       NULL, NULL, 0)) {
+               switch (errno) {
+               case EWOULDBLOCK:
+                       /* Value already changed. */
+                       goto skip_futex_wait;
+               case EINTR:
+                       /* Retry if interrupted by signal. */
+                       break;  /* Get out of switch. */
+               default:
+                       /* Unexpected error. */
+                       PERROR("futex_noasync");
+                       abort();
+               }
+       }
+skip_futex_wait:
+
+       /* Tell waker thread than we are running. */
+       uatomic_or(&waiter->state, WAITER_RUNNING);
+
+       /*
+        * Wait until waker thread lets us know it's ok to tear down
+        * memory allocated for struct lttng_waiter.
+        */
+       for (i = 0; i < WAIT_ATTEMPTS; i++) {
+               if (uatomic_read(&waiter->state) & WAITER_TEARDOWN) {
+                       break;
+               }
+               caa_cpu_relax();
+       }
+       while (!(uatomic_read(&waiter->state) & WAITER_TEARDOWN)) {
+               poll(NULL, 0, 10);
+       }
+       assert(uatomic_read(&waiter->state) & WAITER_TEARDOWN);
+       DBG("End of waiter wait period");
+}
+
+/*
+ * Note: lttng_waiter_wake needs waiter to stay allocated throughout its
+ * execution. In this scheme, the waiter owns the node memory, and we only allow
+ * it to free this memory when it sees the WAITER_TEARDOWN flag.
+ */
+LTTNG_HIDDEN
+void lttng_waiter_wake_up(struct lttng_waiter *waiter)
+{
+       cmm_smp_mb();
+       assert(uatomic_read(&waiter->state) == WAITER_WAITING);
+       uatomic_set(&waiter->state, WAITER_WOKEN_UP);
+       if (!(uatomic_read(&waiter->state) & WAITER_RUNNING)) {
+               if (futex_noasync(&waiter->state, FUTEX_WAKE, 1,
+                               NULL, NULL, 0) < 0) {
+                       PERROR("futex_noasync");
+                       abort();
+               }
+       }
+       /* Allow teardown of struct urcu_wait memory. */
+       uatomic_or(&waiter->state, WAITER_TEARDOWN);
+}
diff --git a/src/common/waiter.h b/src/common/waiter.h
new file mode 100644 (file)
index 0000000..30eb38f
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *               2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * This code is originally adapted from userspace-rcu's urcu-wait.h
+ */
+
+#ifndef LTTNG_WAITER_H
+#define LTTNG_WAITER_H
+
+#define _LGPL_SOURCE
+
+#include <stdint.h>
+#include <urcu/wfstack.h>
+#include <stdbool.h>
+#include "macros.h"
+
+struct lttng_waiter {
+       struct cds_wfs_node wait_queue_node;
+       int32_t state;
+};
+
+LTTNG_HIDDEN
+void lttng_waiter_init(struct lttng_waiter *waiter);
+
+LTTNG_HIDDEN
+void lttng_waiter_wait(struct lttng_waiter *waiter);
+
+/*
+ * lttng_waiter_wake_up must only be called by a single waker.
+ * It is invalid for multiple "wake" operations to be invoked
+ * on a single waiter without re-initializing it before.
+ */
+LTTNG_HIDDEN
+void lttng_waiter_wake_up(struct lttng_waiter *waiter);
+
+#endif /* LTTNG_WAITER_H */
This page took 0.028508 seconds and 5 git commands to generate.