X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=src%2Furcu.c;h=76c8720c288b5d5ce52eacdd58714126513645c4;hb=0e2125fb7b2c7a92d7030b41df5fb372a7706c32;hp=59f2e8f18fdddc5a781e25d2478ca86e18a9fee5;hpb=a18d0428065b301086d4e8a85bc057dc39946891;p=userspace-rcu.git diff --git a/src/urcu.c b/src/urcu.c index 59f2e8f..76c8720 100644 --- a/src/urcu.c +++ b/src/urcu.c @@ -1,25 +1,11 @@ +// SPDX-FileCopyrightText: 2009 Mathieu Desnoyers +// SPDX-FileCopyrightText: 2009 Paul E. McKenney, IBM Corporation. +// +// SPDX-License-Identifier: LGPL-2.1-or-later + /* - * urcu.c - * * Userspace RCU library * - * Copyright (c) 2009 Mathieu Desnoyers - * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * * IBM's contributions to this file may be relicensed under LGPLv2 or later. */ @@ -38,6 +24,7 @@ #include #include +#include #include #include #include @@ -109,9 +96,13 @@ void rcu_init(void) static int init_done; void __attribute__((constructor)) rcu_init(void); -void __attribute__((destructor)) rcu_exit(void); + +static DEFINE_URCU_TLS(int, rcu_signal_was_blocked); #endif +void __attribute__((destructor)) rcu_exit(void); +static void urcu_call_rcu_exit(void); + /* * rcu_gp_lock ensures mutual exclusion between threads calling * synchronize_rcu(). @@ -296,7 +287,8 @@ end: */ static void wait_for_readers(struct cds_list_head *input_readers, struct cds_list_head *cur_snap_readers, - struct cds_list_head *qsreaders) + struct cds_list_head *qsreaders, + cmm_annotate_t *group) { unsigned int wait_loops = 0; struct urcu_reader *index, *tmp; @@ -319,7 +311,7 @@ static void wait_for_readers(struct cds_list_head *input_readers, } cds_list_for_each_entry_safe(index, tmp, input_readers, node) { - switch (urcu_common_reader_state(&rcu_gp, &index->ctr)) { + switch (urcu_common_reader_state(&rcu_gp, &index->ctr, group)) { case URCU_READER_ACTIVE_CURRENT: if (cur_snap_readers) { cds_list_move(&index->node, @@ -403,6 +395,8 @@ static void wait_for_readers(struct cds_list_head *input_readers, void synchronize_rcu(void) { + cmm_annotate_define(acquire_group); + cmm_annotate_define(release_group); CDS_LIST_HEAD(cur_snap_readers); CDS_LIST_HEAD(qsreaders); DEFINE_URCU_WAIT_NODE(wait, URCU_WAIT_WAITING); @@ -417,10 +411,11 @@ void synchronize_rcu(void) * queue before their insertion into the wait queue. */ if (urcu_wait_add(&gp_waiters, &wait) != 0) { - /* Not first in queue: will be awakened by another thread. */ + /* + * Not first in queue: will be awakened by another thread. + * Implies a memory barrier after grace period. + */ urcu_adaptative_busy_wait(&wait); - /* Order following memory accesses after grace period. */ - cmm_smp_mb(); return; } /* We won't need to wake ourself up */ @@ -445,13 +440,14 @@ void synchronize_rcu(void) */ /* Write new ptr before changing the qparity */ smp_mb_master(); + cmm_annotate_group_mb_release(&release_group); /* * Wait for readers to observe original parity or be quiescent. * wait_for_readers() can release and grab again rcu_registry_lock * internally. */ - wait_for_readers(®istry, &cur_snap_readers, &qsreaders); + wait_for_readers(®istry, &cur_snap_readers, &qsreaders, &acquire_group); /* * Must finish waiting for quiescent state for original parity before @@ -470,7 +466,8 @@ void synchronize_rcu(void) cmm_smp_mb(); /* Switch parity: 0 -> 1, 1 -> 0 */ - CMM_STORE_SHARED(rcu_gp.ctr, rcu_gp.ctr ^ URCU_GP_CTR_PHASE); + cmm_annotate_group_mem_release(&release_group, &rcu_gp.ctr); + uatomic_store(&rcu_gp.ctr, rcu_gp.ctr ^ URCU_GP_CTR_PHASE, CMM_RELAXED); /* * Must commit rcu_gp.ctr update to memory before waiting for quiescent @@ -493,7 +490,7 @@ void synchronize_rcu(void) * wait_for_readers() can release and grab again rcu_registry_lock * internally. */ - wait_for_readers(&cur_snap_readers, NULL, &qsreaders); + wait_for_readers(&cur_snap_readers, NULL, &qsreaders, &acquire_group); /* * Put quiescent reader list back into registry. @@ -506,6 +503,7 @@ void synchronize_rcu(void) * iterates on reader threads. */ smp_mb_master(); + cmm_annotate_group_mb_acquire(&acquire_group); out: mutex_unlock(&rcu_registry_lock); mutex_unlock(&rcu_gp_lock); @@ -537,8 +535,52 @@ int rcu_read_ongoing(void) return _rcu_read_ongoing(); } +#ifdef RCU_SIGNAL +/* + * Make sure the signal used by the urcu-signal flavor is unblocked + * while the thread is registered. + */ +static +void urcu_signal_unblock(void) +{ + sigset_t mask, oldmask; + int ret; + + ret = sigemptyset(&mask); + urcu_posix_assert(!ret); + ret = sigaddset(&mask, SIGRCU); + urcu_posix_assert(!ret); + ret = pthread_sigmask(SIG_UNBLOCK, &mask, &oldmask); + urcu_posix_assert(!ret); + URCU_TLS(rcu_signal_was_blocked) = sigismember(&oldmask, SIGRCU); +} + +static +void urcu_signal_restore(void) +{ + sigset_t mask; + int ret; + + if (!URCU_TLS(rcu_signal_was_blocked)) + return; + ret = sigemptyset(&mask); + urcu_posix_assert(!ret); + ret = sigaddset(&mask, SIGRCU); + urcu_posix_assert(!ret); + ret = pthread_sigmask(SIG_BLOCK, &mask, NULL); + urcu_posix_assert(!ret); +} +#else +static +void urcu_signal_unblock(void) { } +static +void urcu_signal_restore(void) { } +#endif + void rcu_register_thread(void) { + urcu_signal_unblock(); + URCU_TLS(rcu_reader).tid = pthread_self(); urcu_posix_assert(URCU_TLS(rcu_reader).need_mb == 0); urcu_posix_assert(!(URCU_TLS(rcu_reader).ctr & URCU_GP_CTR_NEST_MASK)); @@ -558,6 +600,8 @@ void rcu_unregister_thread(void) URCU_TLS(rcu_reader).registered = 0; cds_list_del(&URCU_TLS(rcu_reader).node); mutex_unlock(&rcu_registry_lock); + + urcu_signal_restore(); } #ifdef RCU_MEMBARRIER @@ -648,21 +692,24 @@ void rcu_init(void) urcu_die(errno); } +/* + * Don't unregister the SIGRCU signal handler anymore, because + * call_rcu threads could still be using it shortly before the + * application exits. + * Assertion disabled because call_rcu threads are now rcu + * readers, and left running at exit. + * urcu_posix_assert(cds_list_empty(®istry)); + */ + +#endif /* #ifdef RCU_SIGNAL */ + void rcu_exit(void) { - /* - * Don't unregister the SIGRCU signal handler anymore, because - * call_rcu threads could still be using it shortly before the - * application exits. - * Assertion disabled because call_rcu threads are now rcu - * readers, and left running at exit. - * urcu_posix_assert(cds_list_empty(®istry)); - */ + urcu_call_rcu_exit(); } -#endif /* #ifdef RCU_SIGNAL */ - DEFINE_RCU_FLAVOR(rcu_flavor); #include "urcu-call-rcu-impl.h" #include "urcu-defer-impl.h" +#include "urcu-poll-impl.h"