Home | History | Annotate | Line # | Download | only in static
      1  1.1  christos // SPDX-FileCopyrightText: 2009 Mathieu Desnoyers <mathieu.desnoyers (at) efficios.com>
      2  1.1  christos // SPDX-FileCopyrightText: 2009 Paul E. McKenney, IBM Corporation.
      3  1.1  christos //
      4  1.1  christos // SPDX-License-Identifier: LGPL-2.1-or-later
      5  1.1  christos 
      6  1.1  christos #ifndef _URCU_MEMB_STATIC_H
      7  1.1  christos #define _URCU_MEMB_STATIC_H
      8  1.1  christos 
      9  1.1  christos /*
     10  1.1  christos  * Userspace RCU header.
     11  1.1  christos  *
     12  1.1  christos  * TO BE INCLUDED ONLY IN CODE THAT IS TO BE RECOMPILED ON EACH LIBURCU
     13  1.1  christos  * RELEASE. See urcu.h for linking dynamically with the userspace rcu library.
     14  1.1  christos  *
     15  1.1  christos  * IBM's contributions to this file may be relicensed under LGPLv2 or later.
     16  1.1  christos  */
     17  1.1  christos 
     18  1.1  christos #include <stdlib.h>
     19  1.1  christos #include <pthread.h>
     20  1.1  christos #include <unistd.h>
     21  1.1  christos #include <stdint.h>
     22  1.1  christos 
     23  1.1  christos #include <urcu/annotate.h>
     24  1.1  christos #include <urcu/debug.h>
     25  1.1  christos #include <urcu/config.h>
     26  1.1  christos #include <urcu/compiler.h>
     27  1.1  christos #include <urcu/arch.h>
     28  1.1  christos #include <urcu/system.h>
     29  1.1  christos #include <urcu/uatomic.h>
     30  1.1  christos #include <urcu/list.h>
     31  1.1  christos #include <urcu/futex.h>
     32  1.1  christos #include <urcu/tls-compat.h>
     33  1.1  christos #include <urcu/static/urcu-common.h>
     34  1.1  christos 
     35  1.1  christos #ifdef __cplusplus
     36  1.1  christos extern "C" {
     37  1.1  christos #endif
     38  1.1  christos 
     39  1.1  christos /*
     40  1.1  christos  * This code section can only be included in LGPL 2.1 compatible source code.
     41  1.1  christos  * See below for the function call wrappers which can be used in code meant to
     42  1.1  christos  * be only linked with the Userspace RCU library. This comes with a small
     43  1.1  christos  * performance degradation on the read-side due to the added function calls.
     44  1.1  christos  * This is required to permit relinking with newer versions of the library.
     45  1.1  christos  */
     46  1.1  christos 
     47  1.1  christos /*
     48  1.1  christos  * Slave barriers are only guaranteed to be ordered wrt master barriers.
     49  1.1  christos  *
     50  1.1  christos  * The pair ordering is detailed as (O: ordered, X: not ordered) :
     51  1.1  christos  *               slave  master
     52  1.1  christos  *        slave    X      O
     53  1.1  christos  *        master   O      O
     54  1.1  christos  */
     55  1.1  christos 
     56  1.1  christos #ifdef CONFIG_RCU_FORCE_SYS_MEMBARRIER
     57  1.1  christos #define urcu_memb_has_sys_membarrier		1
     58  1.1  christos #else
     59  1.1  christos extern int urcu_memb_has_sys_membarrier;
     60  1.1  christos #endif
     61  1.1  christos 
     62  1.1  christos static inline void urcu_memb_smp_mb_slave(void)
     63  1.1  christos {
     64  1.1  christos 	if (caa_likely(urcu_memb_has_sys_membarrier))
     65  1.1  christos 		cmm_barrier();
     66  1.1  christos 	else
     67  1.1  christos 		cmm_smp_mb();
     68  1.1  christos }
     69  1.1  christos 
     70  1.1  christos extern struct urcu_gp urcu_memb_gp;
     71  1.1  christos 
     72  1.1  christos extern DECLARE_URCU_TLS(struct urcu_reader, urcu_memb_reader);
     73  1.1  christos 
     74  1.1  christos /*
     75  1.1  christos  * Helper for _rcu_read_lock().  The format of urcu_memb_gp.ctr (as well as
     76  1.1  christos  * the per-thread rcu_reader.ctr) has the lower-order bits containing a count of
     77  1.1  christos  * _rcu_read_lock() nesting, and a single high-order URCU_BP_GP_CTR_PHASE bit
     78  1.1  christos  * that contains either zero or one.  The smp_mb_slave() ensures that the accesses in
     79  1.1  christos  * _rcu_read_lock() happen before the subsequent read-side critical section.
     80  1.1  christos  */
     81  1.1  christos static inline void _urcu_memb_read_lock_update(unsigned long tmp)
     82  1.1  christos {
     83  1.1  christos 	unsigned long *ctr = &URCU_TLS(urcu_memb_reader).ctr;
     84  1.1  christos 
     85  1.1  christos 	if (caa_likely(!(tmp & URCU_GP_CTR_NEST_MASK))) {
     86  1.1  christos 		unsigned long *pgctr = &urcu_memb_gp.ctr;
     87  1.1  christos 		unsigned long gctr = uatomic_load(pgctr, CMM_RELAXED);
     88  1.1  christos 
     89  1.1  christos 		/* Paired with following mb slave. */
     90  1.1  christos 		cmm_annotate_mem_acquire(pgctr);
     91  1.1  christos 		uatomic_store(ctr, gctr, CMM_RELAXED);
     92  1.1  christos 
     93  1.1  christos 		urcu_memb_smp_mb_slave();
     94  1.1  christos 	} else {
     95  1.1  christos 		uatomic_store(ctr, tmp + URCU_GP_COUNT, CMM_RELAXED);
     96  1.1  christos 	}
     97  1.1  christos }
     98  1.1  christos 
     99  1.1  christos /*
    100  1.1  christos  * Enter an RCU read-side critical section.
    101  1.1  christos  *
    102  1.1  christos  * The first cmm_barrier() call ensures that the compiler does not reorder
    103  1.1  christos  * the body of _rcu_read_lock() with a mutex.
    104  1.1  christos  *
    105  1.1  christos  * This function and its helper are both less than 10 lines long.  The
    106  1.1  christos  * intent is that this function meets the 10-line criterion in LGPL,
    107  1.1  christos  * allowing this function to be invoked directly from non-LGPL code.
    108  1.1  christos  */
    109  1.1  christos static inline void _urcu_memb_read_lock(void)
    110  1.1  christos {
    111  1.1  christos 	unsigned long tmp;
    112  1.1  christos 
    113  1.1  christos 	urcu_assert_debug(URCU_TLS(urcu_memb_reader).registered);
    114  1.1  christos 	cmm_barrier();
    115  1.1  christos 	tmp = URCU_TLS(urcu_memb_reader).ctr;
    116  1.1  christos 	urcu_assert_debug((tmp & URCU_GP_CTR_NEST_MASK) != URCU_GP_CTR_NEST_MASK);
    117  1.1  christos 	_urcu_memb_read_lock_update(tmp);
    118  1.1  christos }
    119  1.1  christos 
    120  1.1  christos /*
    121  1.1  christos  * This is a helper function for _rcu_read_unlock().
    122  1.1  christos  *
    123  1.1  christos  * The first smp_mb_slave() call ensures that the critical section is
    124  1.1  christos  * seen to precede the store to rcu_reader.ctr.
    125  1.1  christos  * The second smp_mb_slave() call ensures that we write to rcu_reader.ctr
    126  1.1  christos  * before reading the update-side futex.
    127  1.1  christos  */
    128  1.1  christos static inline void _urcu_memb_read_unlock_update_and_wakeup(unsigned long tmp)
    129  1.1  christos {
    130  1.1  christos 	unsigned long *ctr = &URCU_TLS(urcu_memb_reader).ctr;
    131  1.1  christos 
    132  1.1  christos 	if (caa_likely((tmp & URCU_GP_CTR_NEST_MASK) == URCU_GP_COUNT)) {
    133  1.1  christos 		urcu_memb_smp_mb_slave();
    134  1.1  christos 		cmm_annotate_mem_release(ctr);
    135  1.1  christos 		uatomic_store(ctr, tmp - URCU_GP_COUNT, CMM_RELAXED);
    136  1.1  christos 		urcu_memb_smp_mb_slave();
    137  1.1  christos 		urcu_common_wake_up_gp(&urcu_memb_gp);
    138  1.1  christos 	} else {
    139  1.1  christos 		uatomic_store(ctr, tmp - URCU_GP_COUNT, CMM_RELAXED);
    140  1.1  christos 	}
    141  1.1  christos }
    142  1.1  christos 
    143  1.1  christos /*
    144  1.1  christos  * Exit an RCU read-side critical section.  Both this function and its
    145  1.1  christos  * helper are smaller than 10 lines of code, and are intended to be
    146  1.1  christos  * usable by non-LGPL code, as called out in LGPL.
    147  1.1  christos  */
    148  1.1  christos static inline void _urcu_memb_read_unlock(void)
    149  1.1  christos {
    150  1.1  christos 	unsigned long tmp;
    151  1.1  christos 
    152  1.1  christos 	urcu_assert_debug(URCU_TLS(urcu_memb_reader).registered);
    153  1.1  christos 	tmp = URCU_TLS(urcu_memb_reader).ctr;
    154  1.1  christos 	urcu_assert_debug(tmp & URCU_GP_CTR_NEST_MASK);
    155  1.1  christos 	_urcu_memb_read_unlock_update_and_wakeup(tmp);
    156  1.1  christos 	cmm_barrier();	/* Ensure the compiler does not reorder us with mutex */
    157  1.1  christos }
    158  1.1  christos 
    159  1.1  christos /*
    160  1.1  christos  * Returns whether within a RCU read-side critical section.
    161  1.1  christos  *
    162  1.1  christos  * This function is less than 10 lines long.  The intent is that this
    163  1.1  christos  * function meets the 10-line criterion for LGPL, allowing this function
    164  1.1  christos  * to be invoked directly from non-LGPL code.
    165  1.1  christos  */
    166  1.1  christos static inline int _urcu_memb_read_ongoing(void)
    167  1.1  christos {
    168  1.1  christos 	return URCU_TLS(urcu_memb_reader).ctr & URCU_GP_CTR_NEST_MASK;
    169  1.1  christos }
    170  1.1  christos 
    171  1.1  christos #ifdef __cplusplus
    172  1.1  christos }
    173  1.1  christos #endif
    174  1.1  christos 
    175  1.1  christos #endif /* _URCU_MEMB_STATIC_H */
    176