Add missing rcu_cmpxchg_pointer define
[urcu.git] / urcu-defer.c
index 5e4650ff003b4c8d97ff0fb240a0d14fa4d8660a..ccf35116d2b73e63634730a475d09feeb650ae38 100644 (file)
@@ -28,7 +28,6 @@
 #include <string.h>
 #include <errno.h>
 #include <poll.h>
-#include <linux/futex.h>
 #include <sys/time.h>
 #include <syscall.h>
 #include <unistd.h>
@@ -38,6 +37,8 @@
 #include "urcu-defer.h"
 
 #define futex(...)     syscall(__NR_futex, __VA_ARGS__)
+#define FUTEX_WAIT             0
+#define FUTEX_WAKE             1
 
 void __attribute__((destructor)) urcu_defer_exit(void);
 
@@ -49,13 +50,13 @@ extern void synchronize_rcu(void);
 static pthread_mutex_t urcu_defer_mutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_mutex_t defer_thread_mutex = PTHREAD_MUTEX_INITIALIZER;
 
-int defer_thread_futex;
+static int defer_thread_futex;
 
 /*
  * Written to only by each individual deferer. Read by both the deferer and
  * the reclamation tread.
  */
-struct defer_queue __thread defer_queue;
+static struct defer_queue __thread defer_queue;
 
 /* Thread IDs of registered deferers */
 #define INIT_NUM_THREADS 4
@@ -71,28 +72,6 @@ static int num_deferers, alloc_deferers;
 
 static pthread_t tid_defer;
 
-/*
- * Wake-up any waiting defer thread. Called from many concurrent threads.
- */
-static void wake_up_defer(void)
-{
-       if (unlikely(atomic_read(&defer_thread_futex) == -1))
-               atomic_set(&defer_thread_futex, 0);
-               futex(&defer_thread_futex, FUTEX_WAKE,
-                     0, NULL, NULL, 0);
-}
-
-/*
- * Defer thread waiting. Single thread.
- */
-static void wait_defer(void)
-{
-       atomic_dec(&defer_thread_futex);
-       if (atomic_read(&defer_thread_futex) == -1)
-               futex(&defer_thread_futex, FUTEX_WAIT, -1,
-                     NULL, NULL, 0);
-}
-
 static void internal_urcu_lock(pthread_mutex_t *mutex)
 {
        int ret;
@@ -127,6 +106,51 @@ static void internal_urcu_unlock(pthread_mutex_t *mutex)
        }
 }
 
+/*
+ * Wake-up any waiting defer thread. Called from many concurrent threads.
+ */
+static void wake_up_defer(void)
+{
+       if (unlikely(atomic_read(&defer_thread_futex) == -1)) {
+               atomic_set(&defer_thread_futex, 0);
+               futex(&defer_thread_futex, FUTEX_WAKE, 1,
+                     NULL, NULL, 0);
+       }
+}
+
+static unsigned long rcu_defer_num_callbacks(void)
+{
+       unsigned long num_items = 0, head;
+       struct deferer_registry *index;
+
+       internal_urcu_lock(&urcu_defer_mutex);
+       for (index = registry; index < registry + num_deferers; index++) {
+               head = LOAD_SHARED(index->defer_queue->head);
+               num_items += head - index->defer_queue->tail;
+       }
+       internal_urcu_unlock(&urcu_defer_mutex);
+       return num_items;
+}
+
+/*
+ * Defer thread waiting. Single thread.
+ */
+static void wait_defer(void)
+{
+       atomic_dec(&defer_thread_futex);
+       smp_mb();       /* Write futex before read queue */
+       if (rcu_defer_num_callbacks()) {
+               smp_mb();       /* Read queue before write futex */
+               /* Callbacks are queued, don't wait. */
+               atomic_set(&defer_thread_futex, 0);
+       } else {
+               smp_rmb();      /* Read queue before read futex */
+               if (atomic_read(&defer_thread_futex) == -1)
+                       futex(&defer_thread_futex, FUTEX_WAIT, -1,
+                             NULL, NULL, 0);
+       }
+}
+
 /*
  * Must be called after Q.S. is reached.
  */
@@ -279,6 +303,7 @@ void _rcu_defer_queue(void (*fct)(void *p), void *p)
        smp_wmb();      /* Publish new pointer before head */
                        /* Write q[] before head. */
        STORE_SHARED(defer_queue.head, head);
+       smp_mb();       /* Write queue head before read futex */
        /*
         * Wake-up any waiting defer thread.
         */
@@ -289,21 +314,15 @@ void *thr_defer(void *args)
 {
        for (;;) {
                pthread_testcancel();
-               printf("a\n");
                /*
                 * "Be green". Don't wake up the CPU if there is no RCU work
                 * to perform whatsoever. Aims at saving laptop battery life by
                 * leaving the processor in sleep state when idle.
                 */
-               printf("b\n");
                wait_defer();
-               printf("e\n");
                /* Sleeping after wait_defer to let many callbacks enqueue */
-               //TEST poll(NULL,0,100);        /* wait for 100ms */
-               printf("f\n");
+               poll(NULL,0,100);       /* wait for 100ms */
                rcu_defer_barrier();
-               printf("perform deferred call_rcu() from worker thread %lu.\n",
-                       time(NULL));
        }
 
        return NULL;
This page took 0.02787 seconds and 4 git commands to generate.