Disable signals in URCU background threads
[userspace-rcu.git] / src / urcu-call-rcu-impl.h
index 7e35651b6990c70e7a67f2df518644ed4daabe3a..9f85d55b403c5fa1f882947af021c6cae460d712 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)
 {
@@ -230,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;
 }
@@ -240,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);
@@ -274,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);
@@ -355,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;
@@ -417,6 +434,7 @@ static void call_rcu_data_init(struct call_rcu_data **crdpp,
 {
        struct call_rcu_data *crdp;
        int ret;
+       sigset_t newmask, oldmask;
 
        crdp = malloc(sizeof(*crdp));
        if (crdp == NULL)
@@ -431,9 +449,18 @@ static void call_rcu_data_init(struct call_rcu_data **crdpp,
        crdp->gp_count = 0;
        cmm_smp_mb();  /* Structure initialized before pointer is planted. */
        *crdpp = crdp;
+
+       ret = sigfillset(&newmask);
+       urcu_posix_assert(!ret);
+       ret = pthread_sigmask(SIG_BLOCK, &newmask, &oldmask);
+       urcu_posix_assert(!ret);
+
        ret = pthread_create(&crdp->tid, NULL, call_rcu_thread, crdp);
        if (ret)
                urcu_die(ret);
+
+       ret = pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
+       urcu_posix_assert(!ret);
 }
 
 /*
@@ -454,16 +481,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]);
 }
-URCU_ATTR_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
@@ -474,8 +499,6 @@ pthread_t get_call_rcu_thread(struct call_rcu_data *crdp)
 {
        return crdp->tid;
 }
-URCU_ATTR_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.
@@ -490,8 +513,6 @@ static struct call_rcu_data *__create_call_rcu_data(unsigned long flags,
        return crdp;
 }
 
-URCU_ATTR_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)
 {
@@ -522,7 +543,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;
@@ -548,8 +569,6 @@ int set_cpu_call_rcu_data(int cpu, struct call_rcu_data *crdp)
        call_rcu_unlock(&call_rcu_mutex);
        return 0;
 }
-URCU_ATTR_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
@@ -570,8 +589,6 @@ struct call_rcu_data *get_default_call_rcu_data(void)
        call_rcu_unlock(&call_rcu_mutex);
        return default_call_rcu_data;
 }
-URCU_ATTR_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
@@ -591,7 +608,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;
@@ -599,8 +616,6 @@ struct call_rcu_data *get_call_rcu_data(void)
 
        return get_default_call_rcu_data();
 }
-URCU_ATTR_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.
@@ -610,8 +625,6 @@ struct call_rcu_data *get_thread_call_rcu_data(void)
 {
        return URCU_TLS(thread_call_rcu_data);
 }
-URCU_ATTR_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
@@ -628,8 +641,6 @@ void set_thread_call_rcu_data(struct call_rcu_data *crdp)
 {
        URCU_TLS(thread_call_rcu_data) = crdp;
 }
-URCU_ATTR_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
@@ -648,7 +659,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;
        }
@@ -656,7 +667,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);
@@ -681,8 +692,6 @@ int create_all_cpu_call_rcu_data(unsigned long flags)
        }
        return 0;
 }
-URCU_ATTR_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
@@ -730,7 +739,6 @@ void call_rcu(struct rcu_head *head,
        _call_rcu(head, func, crdp);
        _rcu_read_unlock();
 }
-URCU_ATTR_ALIAS(urcu_stringify(call_rcu)) void alias_call_rcu();
 
 /*
  * Free up the specified call_rcu_data structure, terminating the
@@ -789,8 +797,6 @@ void call_rcu_data_free(struct call_rcu_data *crdp)
 
        free(crdp);
 }
-URCU_ATTR_ALIAS(urcu_stringify(call_rcu_data_free))
-void alias_call_rcu_data_free();
 
 /*
  * Clean up all the per-CPU call_rcu threads.
@@ -801,10 +807,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 +819,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 +830,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
-URCU_ATTR_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
-URCU_ATTR_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 +928,6 @@ online:
        if (was_online)
                rcu_thread_online();
 }
-URCU_ATTR_ALIAS(urcu_stringify(rcu_barrier))
-void alias_rcu_barrier();
 
 /*
  * Acquire the call_rcu_mutex in order to ensure that the child sees
@@ -962,8 +956,6 @@ void call_rcu_before_fork(void)
                        (void) poll(NULL, 0, 1);
        }
 }
-URCU_ATTR_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 +978,6 @@ void call_rcu_after_fork_parent(void)
                atfork->after_fork_parent(atfork->priv);
        call_rcu_unlock(&call_rcu_mutex);
 }
-URCU_ATTR_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 +1008,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 +1025,6 @@ void call_rcu_after_fork_child(void)
                call_rcu_data_free(crdp);
        }
 }
-URCU_ATTR_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 +1035,8 @@ void urcu_register_rculfhash_atfork(struct urcu_atfork *atfork)
 end:
        call_rcu_unlock(&call_rcu_mutex);
 }
-URCU_ATTR_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 +1045,3 @@ void urcu_unregister_rculfhash_atfork(struct urcu_atfork *atfork)
 end:
        call_rcu_unlock(&call_rcu_mutex);
 }
-URCU_ATTR_ALIAS(urcu_stringify(urcu_unregister_rculfhash_atfork))
-void alias_urcu_unregister_rculfhash_atfork();
This page took 0.028361 seconds and 4 git commands to generate.