--- /dev/null
+/*
+ * BIRD Library -- Read-Copy-Update Basic Operations
+ *
+ * (c) 2021 Maria Matejka <mq@jmq.cz>
+ * (c) 2021 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ * Note: all the relevant patents shall be expired.
+ *
+ * Using the Supplementary Material for User-Level Implementations of Read-Copy-Update
+ * by Matthieu Desnoyers, Paul E. McKenney, Alan S. Stern, Michel R. Dagenais and Jonathan Walpole
+ * obtained from https://www.efficios.com/pub/rcu/urcu-supp-accepted.pdf
+ */
+
+#include "lib/rcu.h"
+#include "lib/coro.h"
+#include "lib/locking.h"
+
+_Atomic uint rcu_gp_ctl = RCU_NEST_CNT;
+_Thread_local struct rcu_coro *this_rcu_coro = NULL;
+
+static list rcu_coro_list;
+
+static struct rcu_coro main_rcu_coro;
+
+DEFINE_DOMAIN(resource);
+static DOMAIN(resource) rcu_domain;
+
+static int
+rcu_gp_ongoing(_Atomic uint *ctl)
+{
+ uint val = atomic_load(ctl);
+ return (val & RCU_NEST_CNT) && ((val ^ rcu_gp_ctl) & RCU_GP_PHASE);
+}
+
+static void
+update_counter_and_wait(void)
+{
+ atomic_fetch_xor(&rcu_gp_ctl, RCU_GP_PHASE);
+ struct rcu_coro *rc;
+ WALK_LIST(rc, rcu_coro_list)
+ while (rcu_gp_ongoing(&rc->ctl))
+ coro_yield();
+}
+
+void
+synchronize_rcu(void)
+{
+ LOCK_DOMAIN(resource, rcu_domain);
+ update_counter_and_wait();
+ update_counter_and_wait();
+ UNLOCK_DOMAIN(resource, rcu_domain);
+}
+
+void
+rcu_coro_start(struct rcu_coro *rc)
+{
+ LOCK_DOMAIN(resource, rcu_domain);
+ add_tail(&rcu_coro_list, &rc->n);
+ this_rcu_coro = rc;
+ UNLOCK_DOMAIN(resource, rcu_domain);
+}
+
+void
+rcu_coro_stop(struct rcu_coro *rc)
+{
+ LOCK_DOMAIN(resource, rcu_domain);
+ this_rcu_coro = NULL;
+ rem_node(&rc->n);
+ UNLOCK_DOMAIN(resource, rcu_domain);
+}
+
+void
+rcu_init(void)
+{
+ rcu_domain = DOMAIN_NEW(resource, "Read-Copy-Update");
+ init_list(&rcu_coro_list);
+ rcu_coro_start(&main_rcu_coro);
+}
--- /dev/null
+/*
+ * BIRD Library -- Read-Copy-Update Basic Operations
+ *
+ * (c) 2021 Maria Matejka <mq@jmq.cz>
+ * (c) 2021 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ * Note: all the relevant patents shall be expired.
+ */
+
+#ifndef _BIRD_RCU_H_
+#define _BIRD_RCU_H_
+
+#include "lib/birdlib.h"
+#include "lib/lists.h"
+#include <stdatomic.h>
+
+#define RCU_GP_PHASE 0x100000
+#define RCU_NEST_MASK 0x0fffff
+#define RCU_NEST_CNT 0x000001
+
+extern _Atomic uint rcu_gp_ctl;
+
+struct rcu_coro {
+ node n;
+ _Atomic uint ctl;
+};
+
+extern _Thread_local struct rcu_coro *this_rcu_coro;
+
+static inline void rcu_read_lock(void)
+{
+ uint cmp = atomic_load_explicit(&this_rcu_coro->ctl, memory_order_acquire);
+
+ if (cmp & RCU_NEST_MASK)
+ atomic_store_explicit(&this_rcu_coro->ctl, cmp + RCU_NEST_CNT, memory_order_relaxed);
+ else
+ atomic_store(&this_rcu_coro->ctl, atomic_load_explicit(&rcu_gp_ctl, memory_order_acquire));
+}
+
+static inline void rcu_read_unlock(void)
+{
+ atomic_fetch_sub(&this_rcu_coro->ctl, RCU_NEST_CNT);
+}
+
+void synchronize_rcu(void);
+
+/* Registering and unregistering a coroutine. To be called from coroutine implementation */
+void rcu_coro_start(struct rcu_coro *);
+void rcu_coro_stop(struct rcu_coro *);
+
+/* Run this from resource init */
+void rcu_init(void);
+
+#endif
#include "lib/birdlib.h"
#include "lib/locking.h"
#include "lib/coro.h"
+#include "lib/rcu.h"
#include "lib/resource.h"
#include "lib/timer.h"
resource r;
pthread_t id;
pthread_attr_t attr;
+ struct rcu_coro rcu;
void (*entry)(void *);
void *data;
};
static void coro_free(resource *r)
{
struct coroutine *c = (void *) r;
+ rcu_coro_stop(&c->rcu);
ASSERT_DIE(pthread_equal(pthread_self(), c->id));
pthread_attr_destroy(&c->attr);
coro_cleaned_up = 1;
ASSERT_DIE(c->entry);
this_coro = c;
+ rcu_coro_start(&c->rcu);
c->entry(c->data);
ASSERT_DIE(coro_cleaned_up);
return c;
}
+
+void
+coro_yield(void)
+{
+ usleep(100);
+}