fix: sysconf(_SC_NPROCESSORS_CONF) can be less than max cpu id
[urcu.git] / src / urcu-call-rcu-impl.h
index f7844cc17f6dc49f774650cba20bbdc8ecf825b0..e9366b42355b8b0db313cca083b121017192852b 100644 (file)
@@ -24,7 +24,6 @@
 #include <stdio.h>
 #include <pthread.h>
 #include <signal.h>
-#include <assert.h>
 #include <stdlib.h>
 #include <stdint.h>
 #include <string.h>
@@ -35,6 +34,7 @@
 #include <sched.h>
 
 #include "compat-getcpu.h"
+#include <urcu/assert.h>
 #include <urcu/wfcqueue.h>
 #include <urcu/call-rcu.h>
 #include <urcu/pointer.h>
@@ -44,6 +44,7 @@
 #include <urcu/ref.h>
 #include "urcu-die.h"
 #include "urcu-utils.h"
+#include "compat-smp.h"
 
 #define SET_AFFINITY_CHECK_PERIOD              (1U << 8)       /* 256 */
 #define SET_AFFINITY_CHECK_PERIOD_MASK         (SET_AFFINITY_CHECK_PERIOD - 1)
@@ -120,11 +121,11 @@ static unsigned long registered_rculfhash_atfork_refcount;
  */
 
 static struct call_rcu_data **per_cpu_call_rcu_data;
-static long maxcpus;
+static long cpus_array_len;
 
-static void maxcpus_reset(void)
+static void cpus_array_len_reset(void)
 {
-       maxcpus = 0;
+       cpus_array_len = 0;
 }
 
 /* Allocate the array if it has not already been allocated. */
@@ -134,15 +135,15 @@ static void alloc_cpu_call_rcu_data(void)
        struct call_rcu_data **p;
        static int warned = 0;
 
-       if (maxcpus != 0)
+       if (cpus_array_len != 0)
                return;
-       maxcpus = sysconf(_SC_NPROCESSORS_CONF);
-       if (maxcpus <= 0) {
+       cpus_array_len = get_possible_cpus_array_len();
+       if (cpus_array_len <= 0) {
                return;
        }
-       p = malloc(maxcpus * sizeof(*per_cpu_call_rcu_data));
+       p = malloc(cpus_array_len * sizeof(*per_cpu_call_rcu_data));
        if (p != NULL) {
-               memset(p, '\0', maxcpus * sizeof(*per_cpu_call_rcu_data));
+               memset(p, '\0', cpus_array_len * sizeof(*per_cpu_call_rcu_data));
                rcu_set_pointer(&per_cpu_call_rcu_data, p);
        } else {
                if (!warned) {
@@ -160,9 +161,9 @@ static void alloc_cpu_call_rcu_data(void)
  * constant.
  */
 static struct call_rcu_data **per_cpu_call_rcu_data = NULL;
-static const long maxcpus = -1;
+static const long cpus_array_len = -1;
 
-static void maxcpus_reset(void)
+static void cpus_array_len_reset(void)
 {
 }
 
@@ -199,7 +200,7 @@ static void call_rcu_unlock(pthread_mutex_t *pmp)
  * Losing affinity can be caused by CPU hotunplug/hotplug, or by
  * cpuset(7).
  */
-#if HAVE_SCHED_SETAFFINITY
+#ifdef HAVE_SCHED_SETAFFINITY
 static
 int set_thread_cpu_affinity(struct call_rcu_data *crdp)
 {
@@ -215,11 +216,8 @@ int set_thread_cpu_affinity(struct call_rcu_data *crdp)
 
        CPU_ZERO(&mask);
        CPU_SET(crdp->cpu_affinity, &mask);
-#if SCHED_SETAFFINITY_ARGS == 2
-       ret = sched_setaffinity(0, &mask);
-#else
        ret = sched_setaffinity(0, sizeof(mask), &mask);
-#endif
+
        /*
         * EINVAL is fine: can be caused by hotunplugged CPUs, or by
         * cpuset(7). This is why we should always retry if we detect
@@ -233,7 +231,7 @@ int set_thread_cpu_affinity(struct call_rcu_data *crdp)
 }
 #else
 static
-int set_thread_cpu_affinity(struct call_rcu_data *crdp)
+int set_thread_cpu_affinity(struct call_rcu_data *crdp __attribute__((unused)))
 {
        return 0;
 }
@@ -243,17 +241,25 @@ static void call_rcu_wait(struct call_rcu_data *crdp)
 {
        /* Read call_rcu list before read futex */
        cmm_smp_mb();
-       if (uatomic_read(&crdp->futex) != -1)
-               return;
-       while (futex_async(&crdp->futex, FUTEX_WAIT, -1,
-                       NULL, NULL, 0)) {
+       while (uatomic_read(&crdp->futex) == -1) {
+               if (!futex_async(&crdp->futex, FUTEX_WAIT, -1, NULL, NULL, 0)) {
+                       /*
+                        * Prior queued wakeups queued by unrelated code
+                        * using the same address can cause futex wait to
+                        * return 0 even through the futex value is still
+                        * -1 (spurious wakeups). Check the value again
+                        * in user-space to validate whether it really
+                        * differs from -1.
+                        */
+                       continue;
+               }
                switch (errno) {
-               case EWOULDBLOCK:
+               case EAGAIN:
                        /* Value already changed. */
                        return;
                case EINTR:
                        /* Retry if interrupted by signal. */
-                       break;  /* Get out of switch. */
+                       break;  /* Get out of switch. Check again. */
                default:
                        /* Unexpected error. */
                        urcu_die(errno);
@@ -277,17 +283,25 @@ static void call_rcu_completion_wait(struct call_rcu_completion *completion)
 {
        /* Read completion barrier count before read futex */
        cmm_smp_mb();
-       if (uatomic_read(&completion->futex) != -1)
-               return;
-       while (futex_async(&completion->futex, FUTEX_WAIT, -1,
-                       NULL, NULL, 0)) {
+       while (uatomic_read(&completion->futex) == -1) {
+               if (!futex_async(&completion->futex, FUTEX_WAIT, -1, NULL, NULL, 0)) {
+                       /*
+                        * Prior queued wakeups queued by unrelated code
+                        * using the same address can cause futex wait to
+                        * return 0 even through the futex value is still
+                        * -1 (spurious wakeups). Check the value again
+                        * in user-space to validate whether it really
+                        * differs from -1.
+                        */
+                       continue;
+               }
                switch (errno) {
-               case EWOULDBLOCK:
+               case EAGAIN:
                        /* Value already changed. */
                        return;
                case EINTR:
                        /* Retry if interrupted by signal. */
-                       break;  /* Get out of switch. */
+                       break;  /* Get out of switch. Check again. */
                default:
                        /* Unexpected error. */
                        urcu_die(errno);
@@ -358,8 +372,8 @@ static void *call_rcu_thread(void *arg)
                cds_wfcq_init(&cbs_tmp_head, &cbs_tmp_tail);
                splice_ret = __cds_wfcq_splice_blocking(&cbs_tmp_head,
                        &cbs_tmp_tail, &crdp->cbs_head, &crdp->cbs_tail);
-               assert(splice_ret != CDS_WFCQ_RET_WOULDBLOCK);
-               assert(splice_ret != CDS_WFCQ_RET_DEST_NON_EMPTY);
+               urcu_posix_assert(splice_ret != CDS_WFCQ_RET_WOULDBLOCK);
+               urcu_posix_assert(splice_ret != CDS_WFCQ_RET_DEST_NON_EMPTY);
                if (splice_ret != CDS_WFCQ_RET_SRC_EMPTY) {
                        synchronize_rcu();
                        cbcount = 0;
@@ -457,16 +471,14 @@ struct call_rcu_data *get_cpu_call_rcu_data(int cpu)
        pcpu_crdp = rcu_dereference(per_cpu_call_rcu_data);
        if (pcpu_crdp == NULL)
                return NULL;
-       if (!warned && maxcpus > 0 && (cpu < 0 || maxcpus <= cpu)) {
+       if (!warned && cpus_array_len > 0 && (cpu < 0 || cpus_array_len <= cpu)) {
                fprintf(stderr, "[error] liburcu: get CPU # out of range\n");
                warned = 1;
        }
-       if (cpu < 0 || maxcpus <= cpu)
+       if (cpu < 0 || cpus_array_len <= cpu)
                return NULL;
        return rcu_dereference(pcpu_crdp[cpu]);
 }
-__attribute__((alias(urcu_stringify(get_cpu_call_rcu_data))))
-struct call_rcu_data *alias_get_cpu_call_rcu_data();
 
 /*
  * Return the tid corresponding to the call_rcu thread whose
@@ -477,8 +489,6 @@ pthread_t get_call_rcu_thread(struct call_rcu_data *crdp)
 {
        return crdp->tid;
 }
-__attribute__((alias(urcu_stringify(get_call_rcu_thread))))
-pthread_t alias_get_call_rcu_thread();
 
 /*
  * Create a call_rcu_data structure (with thread) and return a pointer.
@@ -493,8 +503,6 @@ static struct call_rcu_data *__create_call_rcu_data(unsigned long flags,
        return crdp;
 }
 
-__attribute__((alias(urcu_stringify(create_call_rcu_data))))
-struct call_rcu_data *alias_create_call_rcu_data();
 struct call_rcu_data *create_call_rcu_data(unsigned long flags,
                                           int cpu_affinity)
 {
@@ -525,7 +533,7 @@ int set_cpu_call_rcu_data(int cpu, struct call_rcu_data *crdp)
 
        call_rcu_lock(&call_rcu_mutex);
        alloc_cpu_call_rcu_data();
-       if (cpu < 0 || maxcpus <= cpu) {
+       if (cpu < 0 || cpus_array_len <= cpu) {
                if (!warned) {
                        fprintf(stderr, "[error] liburcu: set CPU # out of range\n");
                        warned = 1;
@@ -551,8 +559,6 @@ int set_cpu_call_rcu_data(int cpu, struct call_rcu_data *crdp)
        call_rcu_unlock(&call_rcu_mutex);
        return 0;
 }
-__attribute__((alias(urcu_stringify(set_cpu_call_rcu_data))))
-int alias_set_cpu_call_rcu_data();
 
 /*
  * Return a pointer to the default call_rcu_data structure, creating
@@ -573,8 +579,6 @@ struct call_rcu_data *get_default_call_rcu_data(void)
        call_rcu_unlock(&call_rcu_mutex);
        return default_call_rcu_data;
 }
-__attribute__((alias(urcu_stringify(get_default_call_rcu_data))))
-struct call_rcu_data *alias_get_default_call_rcu_data();
 
 /*
  * Return the call_rcu_data structure that applies to the currently
@@ -594,7 +598,7 @@ struct call_rcu_data *get_call_rcu_data(void)
        if (URCU_TLS(thread_call_rcu_data) != NULL)
                return URCU_TLS(thread_call_rcu_data);
 
-       if (maxcpus > 0) {
+       if (cpus_array_len > 0) {
                crd = get_cpu_call_rcu_data(urcu_sched_getcpu());
                if (crd)
                        return crd;
@@ -602,8 +606,6 @@ struct call_rcu_data *get_call_rcu_data(void)
 
        return get_default_call_rcu_data();
 }
-__attribute__((alias(urcu_stringify(get_call_rcu_data))))
-struct call_rcu_data *alias_get_call_rcu_data();
 
 /*
  * Return a pointer to this task's call_rcu_data if there is one.
@@ -613,8 +615,6 @@ struct call_rcu_data *get_thread_call_rcu_data(void)
 {
        return URCU_TLS(thread_call_rcu_data);
 }
-__attribute__((alias(urcu_stringify(get_thread_call_rcu_data))))
-struct call_rcu_data *alias_get_thread_call_rcu_data();
 
 /*
  * Set this task's call_rcu_data structure as specified, regardless
@@ -631,8 +631,6 @@ void set_thread_call_rcu_data(struct call_rcu_data *crdp)
 {
        URCU_TLS(thread_call_rcu_data) = crdp;
 }
-__attribute__((alias(urcu_stringify(set_thread_call_rcu_data))))
-void alias_set_thread_call_rcu_data();
 
 /*
  * Create a separate call_rcu thread for each CPU.  This does not
@@ -651,7 +649,7 @@ int create_all_cpu_call_rcu_data(unsigned long flags)
        call_rcu_lock(&call_rcu_mutex);
        alloc_cpu_call_rcu_data();
        call_rcu_unlock(&call_rcu_mutex);
-       if (maxcpus <= 0) {
+       if (cpus_array_len <= 0) {
                errno = EINVAL;
                return -EINVAL;
        }
@@ -659,7 +657,7 @@ int create_all_cpu_call_rcu_data(unsigned long flags)
                errno = ENOMEM;
                return -ENOMEM;
        }
-       for (i = 0; i < maxcpus; i++) {
+       for (i = 0; i < cpus_array_len; i++) {
                call_rcu_lock(&call_rcu_mutex);
                if (get_cpu_call_rcu_data(i)) {
                        call_rcu_unlock(&call_rcu_mutex);
@@ -684,8 +682,6 @@ int create_all_cpu_call_rcu_data(unsigned long flags)
        }
        return 0;
 }
-__attribute__((alias(urcu_stringify(create_all_cpu_call_rcu_data))))
-int alias_create_all_cpu_call_rcu_data();
 
 /*
  * Wake up the call_rcu thread corresponding to the specified
@@ -733,7 +729,6 @@ void call_rcu(struct rcu_head *head,
        _call_rcu(head, func, crdp);
        _rcu_read_unlock();
 }
-__attribute__((alias(urcu_stringify(call_rcu)))) void alias_call_rcu();
 
 /*
  * Free up the specified call_rcu_data structure, terminating the
@@ -772,9 +767,13 @@ void call_rcu_data_free(struct call_rcu_data *crdp)
                while ((uatomic_read(&crdp->flags) & URCU_CALL_RCU_STOPPED) == 0)
                        (void) poll(NULL, 0, 1);
        }
+       call_rcu_lock(&call_rcu_mutex);
        if (!cds_wfcq_empty(&crdp->cbs_head, &crdp->cbs_tail)) {
-               /* Create default call rcu data if need be */
+               call_rcu_unlock(&call_rcu_mutex);
+               /* Create default call rcu data if need be. */
+               /* CBs queued here will be handed to the default list. */
                (void) get_default_call_rcu_data();
+               call_rcu_lock(&call_rcu_mutex);
                __cds_wfcq_splice_blocking(&default_call_rcu_data->cbs_head,
                        &default_call_rcu_data->cbs_tail,
                        &crdp->cbs_head, &crdp->cbs_tail);
@@ -783,14 +782,11 @@ void call_rcu_data_free(struct call_rcu_data *crdp)
                wake_call_rcu_thread(default_call_rcu_data);
        }
 
-       call_rcu_lock(&call_rcu_mutex);
        cds_list_del(&crdp->list);
        call_rcu_unlock(&call_rcu_mutex);
 
        free(crdp);
 }
-__attribute__((alias(urcu_stringify(call_rcu_data_free))))
-void alias_call_rcu_data_free();
 
 /*
  * Clean up all the per-CPU call_rcu threads.
@@ -801,10 +797,10 @@ void free_all_cpu_call_rcu_data(void)
        struct call_rcu_data **crdp;
        static int warned = 0;
 
-       if (maxcpus <= 0)
+       if (cpus_array_len <= 0)
                return;
 
-       crdp = malloc(sizeof(*crdp) * maxcpus);
+       crdp = malloc(sizeof(*crdp) * cpus_array_len);
        if (!crdp) {
                if (!warned) {
                        fprintf(stderr, "[error] liburcu: unable to allocate per-CPU pointer array\n");
@@ -813,7 +809,7 @@ void free_all_cpu_call_rcu_data(void)
                return;
        }
 
-       for (cpu = 0; cpu < maxcpus; cpu++) {
+       for (cpu = 0; cpu < cpus_array_len; cpu++) {
                crdp[cpu] = get_cpu_call_rcu_data(cpu);
                if (crdp[cpu] == NULL)
                        continue;
@@ -824,23 +820,13 @@ void free_all_cpu_call_rcu_data(void)
         * call_rcu_data to become quiescent.
         */
        synchronize_rcu();
-       for (cpu = 0; cpu < maxcpus; cpu++) {
+       for (cpu = 0; cpu < cpus_array_len; cpu++) {
                if (crdp[cpu] == NULL)
                        continue;
                call_rcu_data_free(crdp[cpu]);
        }
        free(crdp);
 }
-#ifdef RCU_QSBR
-/* ABI6 has a non-namespaced free_all_cpu_call_rcu_data for qsbr */
-#undef free_all_cpu_call_rcu_data
-__attribute__((alias("urcu_qsbr_free_all_cpu_call_rcu_data")))
-void free_all_cpu_call_rcu_data();
-#define free_all_cpu_call_rcu_data urcu_qsbr_free_all_cpu_call_rcu_data
-#else
-__attribute__((alias(urcu_stringify(free_all_cpu_call_rcu_data))))
-void alias_free_all_cpu_call_rcu_data();
-#endif
 
 static
 void free_completion(struct urcu_ref *ref)
@@ -932,8 +918,6 @@ online:
        if (was_online)
                rcu_thread_online();
 }
-__attribute__((alias(urcu_stringify(rcu_barrier))))
-void alias_rcu_barrier();
 
 /*
  * Acquire the call_rcu_mutex in order to ensure that the child sees
@@ -962,8 +946,6 @@ void call_rcu_before_fork(void)
                        (void) poll(NULL, 0, 1);
        }
 }
-__attribute__((alias(urcu_stringify(call_rcu_before_fork))))
-void alias_call_rcu_before_fork();
 
 /*
  * Clean up call_rcu data structures in the parent of a successful fork()
@@ -986,8 +968,6 @@ void call_rcu_after_fork_parent(void)
                atfork->after_fork_parent(atfork->priv);
        call_rcu_unlock(&call_rcu_mutex);
 }
-__attribute__((alias(urcu_stringify(call_rcu_after_fork_parent))))
-void alias_call_rcu_after_fork_parent();
 
 /*
  * Clean up call_rcu data structures in the child of a successful fork()
@@ -1018,7 +998,7 @@ void call_rcu_after_fork_child(void)
        (void)get_default_call_rcu_data();
 
        /* Cleanup call_rcu_data pointers before use */
-       maxcpus_reset();
+       cpus_array_len_reset();
        free(per_cpu_call_rcu_data);
        rcu_set_pointer(&per_cpu_call_rcu_data, NULL);
        URCU_TLS(thread_call_rcu_data) = NULL;
@@ -1035,8 +1015,6 @@ void call_rcu_after_fork_child(void)
                call_rcu_data_free(crdp);
        }
 }
-__attribute__((alias(urcu_stringify(call_rcu_after_fork_child))))
-void alias_call_rcu_after_fork_child();
 
 void urcu_register_rculfhash_atfork(struct urcu_atfork *atfork)
 {
@@ -1047,10 +1025,8 @@ void urcu_register_rculfhash_atfork(struct urcu_atfork *atfork)
 end:
        call_rcu_unlock(&call_rcu_mutex);
 }
-__attribute__((alias(urcu_stringify(urcu_register_rculfhash_atfork))))
-void alias_urcu_register_rculfhash_atfork();
 
-void urcu_unregister_rculfhash_atfork(struct urcu_atfork *atfork)
+void urcu_unregister_rculfhash_atfork(struct urcu_atfork *atfork __attribute__((unused)))
 {
        call_rcu_lock(&call_rcu_mutex);
        if (--registered_rculfhash_atfork_refcount)
@@ -1059,5 +1035,3 @@ void urcu_unregister_rculfhash_atfork(struct urcu_atfork *atfork)
 end:
        call_rcu_unlock(&call_rcu_mutex);
 }
-__attribute__((alias(urcu_stringify(urcu_unregister_rculfhash_atfork))))
-void alias_urcu_unregister_rculfhash_atfork();
This page took 0.03081 seconds and 4 git commands to generate.