LCOV - code coverage report
Current view: top level - src/include/port - atomics.h (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 90 90 100.0 %
Date: 2017-09-29 15:12:54 Functions: 27 27 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * atomics.h
       4             :  *    Atomic operations.
       5             :  *
       6             :  * Hardware and compiler dependent functions for manipulating memory
       7             :  * atomically and dealing with cache coherency. Used to implement locking
       8             :  * facilities and lockless algorithms/data structures.
       9             :  *
      10             :  * To bring up postgres on a platform/compiler at the very least
      11             :  * implementations for the following operations should be provided:
      12             :  * * pg_compiler_barrier(), pg_write_barrier(), pg_read_barrier()
      13             :  * * pg_atomic_compare_exchange_u32(), pg_atomic_fetch_add_u32()
      14             :  * * pg_atomic_test_set_flag(), pg_atomic_init_flag(), pg_atomic_clear_flag()
      15             :  * * PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY should be defined if appropriate.
      16             :  *
      17             :  * There exist generic, hardware independent, implementations for several
      18             :  * compilers which might be sufficient, although possibly not optimal, for a
      19             :  * new platform. If no such generic implementation is available spinlocks (or
      20             :  * even OS provided semaphores) will be used to implement the API.
      21             :  *
      22             :  * Implement _u64 atomics if and only if your platform can use them
      23             :  * efficiently (and obviously correctly).
      24             :  *
      25             :  * Use higher level functionality (lwlocks, spinlocks, heavyweight locks)
      26             :  * whenever possible. Writing correct code using these facilities is hard.
      27             :  *
      28             :  * For an introduction to using memory barriers within the PostgreSQL backend,
      29             :  * see src/backend/storage/lmgr/README.barrier
      30             :  *
      31             :  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
      32             :  * Portions Copyright (c) 1994, Regents of the University of California
      33             :  *
      34             :  * src/include/port/atomics.h
      35             :  *
      36             :  *-------------------------------------------------------------------------
      37             :  */
      38             : #ifndef ATOMICS_H
      39             : #define ATOMICS_H
      40             : 
      41             : #ifdef FRONTEND
      42             : #error "atomics.h may not be included from frontend code"
      43             : #endif
      44             : 
      45             : #define INSIDE_ATOMICS_H
      46             : 
      47             : #include <limits.h>
      48             : 
      49             : /*
      50             :  * First a set of architecture specific files is included.
      51             :  *
      52             :  * These files can provide the full set of atomics or can do pretty much
      53             :  * nothing if all the compilers commonly used on these platforms provide
      54             :  * usable generics.
      55             :  *
      56             :  * Don't add an inline assembly of the actual atomic operations if all the
      57             :  * common implementations of your platform provide intrinsics. Intrinsics are
      58             :  * much easier to understand and potentially support more architectures.
      59             :  *
      60             :  * It will often make sense to define memory barrier semantics here, since
      61             :  * e.g. generic compiler intrinsics for x86 memory barriers can't know that
      62             :  * postgres doesn't need x86 read/write barriers do anything more than a
      63             :  * compiler barrier.
      64             :  *
      65             :  */
      66             : #if defined(__arm__) || defined(__arm) || \
      67             :     defined(__aarch64__) || defined(__aarch64)
      68             : #include "port/atomics/arch-arm.h"
      69             : #elif defined(__i386__) || defined(__i386) || defined(__x86_64__)
      70             : #include "port/atomics/arch-x86.h"
      71             : #elif defined(__ia64__) || defined(__ia64)
      72             : #include "port/atomics/arch-ia64.h"
      73             : #elif defined(__ppc__) || defined(__powerpc__) || defined(__ppc64__) || defined(__powerpc64__)
      74             : #include "port/atomics/arch-ppc.h"
      75             : #elif defined(__hppa) || defined(__hppa__)
      76             : #include "port/atomics/arch-hppa.h"
      77             : #endif
      78             : 
      79             : /*
      80             :  * Compiler specific, but architecture independent implementations.
      81             :  *
      82             :  * Provide architecture independent implementations of the atomic
      83             :  * facilities. At the very least compiler barriers should be provided, but a
      84             :  * full implementation of
      85             :  * * pg_compiler_barrier(), pg_write_barrier(), pg_read_barrier()
      86             :  * * pg_atomic_compare_exchange_u32(), pg_atomic_fetch_add_u32()
      87             :  * using compiler intrinsics are a good idea.
      88             :  */
      89             : /*
      90             :  * Given a gcc-compatible xlc compiler, prefer the xlc implementation.  The
      91             :  * ppc64le "IBM XL C/C++ for Linux, V13.1.2" implements both interfaces, but
      92             :  * __sync_lock_test_and_set() of one-byte types elicits SIGSEGV.
      93             :  */
      94             : #if defined(__IBMC__) || defined(__IBMCPP__)
      95             : #include "port/atomics/generic-xlc.h"
      96             : /* gcc or compatible, including clang and icc */
      97             : #elif defined(__GNUC__) || defined(__INTEL_COMPILER)
      98             : #include "port/atomics/generic-gcc.h"
      99             : #elif defined(_MSC_VER)
     100             : #include "port/atomics/generic-msvc.h"
     101             : #elif defined(__hpux) && defined(__ia64) && !defined(__GNUC__)
     102             : #include "port/atomics/generic-acc.h"
     103             : #elif defined(__SUNPRO_C) && !defined(__GNUC__)
     104             : #include "port/atomics/generic-sunpro.h"
     105             : #else
     106             : /*
     107             :  * Unsupported compiler, we'll likely use slower fallbacks... At least
     108             :  * compiler barriers should really be provided.
     109             :  */
     110             : #endif
     111             : 
     112             : /*
     113             :  * Provide a full fallback of the pg_*_barrier(), pg_atomic**_flag and
     114             :  * pg_atomic_* APIs for platforms without sufficient spinlock and/or atomics
     115             :  * support. In the case of spinlock backed atomics the emulation is expected
     116             :  * to be efficient, although less so than native atomics support.
     117             :  */
     118             : #include "port/atomics/fallback.h"
     119             : 
     120             : /*
     121             :  * Provide additional operations using supported infrastructure. These are
     122             :  * expected to be efficient if the underlying atomic operations are efficient.
     123             :  */
     124             : #include "port/atomics/generic.h"
     125             : 
     126             : 
     127             : /*
     128             :  * pg_compiler_barrier - prevent the compiler from moving code across
     129             :  *
     130             :  * A compiler barrier need not (and preferably should not) emit any actual
     131             :  * machine code, but must act as an optimization fence: the compiler must not
     132             :  * reorder loads or stores to main memory around the barrier.  However, the
     133             :  * CPU may still reorder loads or stores at runtime, if the architecture's
     134             :  * memory model permits this.
     135             :  */
     136             : #define pg_compiler_barrier()   pg_compiler_barrier_impl()
     137             : 
     138             : /*
     139             :  * pg_memory_barrier - prevent the CPU from reordering memory access
     140             :  *
     141             :  * A memory barrier must act as a compiler barrier, and in addition must
     142             :  * guarantee that all loads and stores issued prior to the barrier are
     143             :  * completed before any loads or stores issued after the barrier.  Unless
     144             :  * loads and stores are totally ordered (which is not the case on most
     145             :  * architectures) this requires issuing some sort of memory fencing
     146             :  * instruction.
     147             :  */
     148             : #define pg_memory_barrier() pg_memory_barrier_impl()
     149             : 
     150             : /*
     151             :  * pg_(read|write)_barrier - prevent the CPU from reordering memory access
     152             :  *
     153             :  * A read barrier must act as a compiler barrier, and in addition must
     154             :  * guarantee that any loads issued prior to the barrier are completed before
     155             :  * any loads issued after the barrier.  Similarly, a write barrier acts
     156             :  * as a compiler barrier, and also orders stores.  Read and write barriers
     157             :  * are thus weaker than a full memory barrier, but stronger than a compiler
     158             :  * barrier.  In practice, on machines with strong memory ordering, read and
     159             :  * write barriers may require nothing more than a compiler barrier.
     160             :  */
     161             : #define pg_read_barrier()   pg_read_barrier_impl()
     162             : #define pg_write_barrier()  pg_write_barrier_impl()
     163             : 
     164             : /*
     165             :  * Spinloop delay - Allow CPU to relax in busy loops
     166             :  */
     167             : #define pg_spin_delay() pg_spin_delay_impl()
     168             : 
     169             : /*
     170             :  * pg_atomic_init_flag - initialize atomic flag.
     171             :  *
     172             :  * No barrier semantics.
     173             :  */
     174             : static inline void
     175           1 : pg_atomic_init_flag(volatile pg_atomic_flag *ptr)
     176             : {
     177             :     AssertPointerAlignment(ptr, sizeof(*ptr));
     178             : 
     179           1 :     pg_atomic_init_flag_impl(ptr);
     180           1 : }
     181             : 
     182             : /*
     183             :  * pg_atomic_test_and_set_flag - TAS()
     184             :  *
     185             :  * Returns true if the flag has successfully been set, false otherwise.
     186             :  *
     187             :  * Acquire (including read barrier) semantics.
     188             :  */
     189             : static inline bool
     190           3 : pg_atomic_test_set_flag(volatile pg_atomic_flag *ptr)
     191             : {
     192             :     AssertPointerAlignment(ptr, sizeof(*ptr));
     193             : 
     194           3 :     return pg_atomic_test_set_flag_impl(ptr);
     195             : }
     196             : 
     197             : /*
     198             :  * pg_atomic_unlocked_test_flag - Check if the lock is free
     199             :  *
     200             :  * Returns true if the flag currently is not set, false otherwise.
     201             :  *
     202             :  * No barrier semantics.
     203             :  */
     204             : static inline bool
     205           3 : pg_atomic_unlocked_test_flag(volatile pg_atomic_flag *ptr)
     206             : {
     207             :     AssertPointerAlignment(ptr, sizeof(*ptr));
     208             : 
     209           3 :     return pg_atomic_unlocked_test_flag_impl(ptr);
     210             : }
     211             : 
     212             : /*
     213             :  * pg_atomic_clear_flag - release lock set by TAS()
     214             :  *
     215             :  * Release (including write barrier) semantics.
     216             :  */
     217             : static inline void
     218           2 : pg_atomic_clear_flag(volatile pg_atomic_flag *ptr)
     219             : {
     220             :     AssertPointerAlignment(ptr, sizeof(*ptr));
     221             : 
     222           2 :     pg_atomic_clear_flag_impl(ptr);
     223           2 : }
     224             : 
     225             : 
     226             : /*
     227             :  * pg_atomic_init_u32 - initialize atomic variable
     228             :  *
     229             :  * Has to be done before any concurrent usage..
     230             :  *
     231             :  * No barrier semantics.
     232             :  */
     233             : static inline void
     234      203363 : pg_atomic_init_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
     235             : {
     236      203363 :     AssertPointerAlignment(ptr, 4);
     237             : 
     238      203363 :     pg_atomic_init_u32_impl(ptr, val);
     239      203363 : }
     240             : 
     241             : /*
     242             :  * pg_atomic_read_u32 - unlocked read from atomic variable.
     243             :  *
     244             :  * The read is guaranteed to return a value as it has been written by this or
     245             :  * another process at some point in the past. There's however no cache
     246             :  * coherency interaction guaranteeing the value hasn't since been written to
     247             :  * again.
     248             :  *
     249             :  * No barrier semantics.
     250             :  */
     251             : static inline uint32
     252    24105873 : pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr)
     253             : {
     254    24105873 :     AssertPointerAlignment(ptr, 4);
     255    24105873 :     return pg_atomic_read_u32_impl(ptr);
     256             : }
     257             : 
     258             : /*
     259             :  * pg_atomic_write_u32 - write to atomic variable.
     260             :  *
     261             :  * The write is guaranteed to succeed as a whole, i.e. it's not possible to
     262             :  * observe a partial write for any reader.  Note that this correctly interacts
     263             :  * with pg_atomic_compare_exchange_u32, in contrast to
     264             :  * pg_atomic_unlocked_write_u32().
     265             :  *
     266             :  * No barrier semantics.
     267             :  */
     268             : static inline void
     269      322366 : pg_atomic_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
     270             : {
     271      322366 :     AssertPointerAlignment(ptr, 4);
     272             : 
     273      322366 :     pg_atomic_write_u32_impl(ptr, val);
     274      322366 : }
     275             : 
     276             : /*
     277             :  * pg_atomic_unlocked_write_u32 - unlocked write to atomic variable.
     278             :  *
     279             :  * The write is guaranteed to succeed as a whole, i.e. it's not possible to
     280             :  * observe a partial write for any reader.  But note that writing this way is
     281             :  * not guaranteed to correctly interact with read-modify-write operations like
     282             :  * pg_atomic_compare_exchange_u32.  This should only be used in cases where
     283             :  * minor performance regressions due to atomics emulation are unacceptable.
     284             :  *
     285             :  * No barrier semantics.
     286             :  */
     287             : static inline void
     288       71730 : pg_atomic_unlocked_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
     289             : {
     290       71730 :     AssertPointerAlignment(ptr, 4);
     291             : 
     292       71730 :     pg_atomic_unlocked_write_u32_impl(ptr, val);
     293       71730 : }
     294             : 
     295             : /*
     296             :  * pg_atomic_exchange_u32 - exchange newval with current value
     297             :  *
     298             :  * Returns the old value of 'ptr' before the swap.
     299             :  *
     300             :  * Full barrier semantics.
     301             :  */
     302             : static inline uint32
     303         397 : pg_atomic_exchange_u32(volatile pg_atomic_uint32 *ptr, uint32 newval)
     304             : {
     305         397 :     AssertPointerAlignment(ptr, 4);
     306             : 
     307         397 :     return pg_atomic_exchange_u32_impl(ptr, newval);
     308             : }
     309             : 
     310             : /*
     311             :  * pg_atomic_compare_exchange_u32 - CAS operation
     312             :  *
     313             :  * Atomically compare the current value of ptr with *expected and store newval
     314             :  * iff ptr and *expected have the same value. The current value of *ptr will
     315             :  * always be stored in *expected.
     316             :  *
     317             :  * Return true if values have been exchanged, false otherwise.
     318             :  *
     319             :  * Full barrier semantics.
     320             :  */
     321             : static inline bool
     322    21814680 : pg_atomic_compare_exchange_u32(volatile pg_atomic_uint32 *ptr,
     323             :                                uint32 *expected, uint32 newval)
     324             : {
     325    21814680 :     AssertPointerAlignment(ptr, 4);
     326    21814680 :     AssertPointerAlignment(expected, 4);
     327             : 
     328    21814680 :     return pg_atomic_compare_exchange_u32_impl(ptr, expected, newval);
     329             : }
     330             : 
     331             : /*
     332             :  * pg_atomic_fetch_add_u32 - atomically add to variable
     333             :  *
     334             :  * Returns the value of ptr before the arithmetic operation.
     335             :  *
     336             :  * Full barrier semantics.
     337             :  */
     338             : static inline uint32
     339       16656 : pg_atomic_fetch_add_u32(volatile pg_atomic_uint32 *ptr, int32 add_)
     340             : {
     341       16656 :     AssertPointerAlignment(ptr, 4);
     342       16656 :     return pg_atomic_fetch_add_u32_impl(ptr, add_);
     343             : }
     344             : 
     345             : /*
     346             :  * pg_atomic_fetch_sub_u32 - atomically subtract from variable
     347             :  *
     348             :  * Returns the value of ptr before the arithmetic operation. Note that sub_
     349             :  * may not be INT_MIN due to platform limitations.
     350             :  *
     351             :  * Full barrier semantics.
     352             :  */
     353             : static inline uint32
     354           2 : pg_atomic_fetch_sub_u32(volatile pg_atomic_uint32 *ptr, int32 sub_)
     355             : {
     356           2 :     AssertPointerAlignment(ptr, 4);
     357           2 :     Assert(sub_ != INT_MIN);
     358           2 :     return pg_atomic_fetch_sub_u32_impl(ptr, sub_);
     359             : }
     360             : 
     361             : /*
     362             :  * pg_atomic_fetch_and_u32 - atomically bit-and and_ with variable
     363             :  *
     364             :  * Returns the value of ptr before the arithmetic operation.
     365             :  *
     366             :  * Full barrier semantics.
     367             :  */
     368             : static inline uint32
     369     1394658 : pg_atomic_fetch_and_u32(volatile pg_atomic_uint32 *ptr, uint32 and_)
     370             : {
     371     1394658 :     AssertPointerAlignment(ptr, 4);
     372     1394658 :     return pg_atomic_fetch_and_u32_impl(ptr, and_);
     373             : }
     374             : 
     375             : /*
     376             :  * pg_atomic_fetch_or_u32 - atomically bit-or or_ with variable
     377             :  *
     378             :  * Returns the value of ptr before the arithmetic operation.
     379             :  *
     380             :  * Full barrier semantics.
     381             :  */
     382             : static inline uint32
     383     1720462 : pg_atomic_fetch_or_u32(volatile pg_atomic_uint32 *ptr, uint32 or_)
     384             : {
     385     1720462 :     AssertPointerAlignment(ptr, 4);
     386     1720462 :     return pg_atomic_fetch_or_u32_impl(ptr, or_);
     387             : }
     388             : 
     389             : /*
     390             :  * pg_atomic_add_fetch_u32 - atomically add to variable
     391             :  *
     392             :  * Returns the value of ptr after the arithmetic operation.
     393             :  *
     394             :  * Full barrier semantics.
     395             :  */
     396             : static inline uint32
     397          47 : pg_atomic_add_fetch_u32(volatile pg_atomic_uint32 *ptr, int32 add_)
     398             : {
     399          47 :     AssertPointerAlignment(ptr, 4);
     400          47 :     return pg_atomic_add_fetch_u32_impl(ptr, add_);
     401             : }
     402             : 
     403             : /*
     404             :  * pg_atomic_sub_fetch_u32 - atomically subtract from variable
     405             :  *
     406             :  * Returns the value of ptr after the arithmetic operation. Note that sub_ may
     407             :  * not be INT_MIN due to platform limitations.
     408             :  *
     409             :  * Full barrier semantics.
     410             :  */
     411             : static inline uint32
     412    14180330 : pg_atomic_sub_fetch_u32(volatile pg_atomic_uint32 *ptr, int32 sub_)
     413             : {
     414    14180330 :     AssertPointerAlignment(ptr, 4);
     415    14180330 :     Assert(sub_ != INT_MIN);
     416    14180330 :     return pg_atomic_sub_fetch_u32_impl(ptr, sub_);
     417             : }
     418             : 
     419             : /* ----
     420             :  * The 64 bit operations have the same semantics as their 32bit counterparts
     421             :  * if they are available. Check the corresponding 32bit function for
     422             :  * documentation.
     423             :  * ----
     424             :  */
     425             : static inline void
     426          14 : pg_atomic_init_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
     427             : {
     428             :     /*
     429             :      * Can't necessarily enforce alignment - and don't need it - when using
     430             :      * the spinlock based fallback implementation. Therefore only assert when
     431             :      * not using it.
     432             :      */
     433             : #ifndef PG_HAVE_ATOMIC_U64_SIMULATION
     434          14 :     AssertPointerAlignment(ptr, 8);
     435             : #endif
     436          14 :     pg_atomic_init_u64_impl(ptr, val);
     437          14 : }
     438             : 
     439             : static inline uint64
     440           4 : pg_atomic_read_u64(volatile pg_atomic_uint64 *ptr)
     441             : {
     442             : #ifndef PG_HAVE_ATOMIC_U64_SIMULATION
     443           4 :     AssertPointerAlignment(ptr, 8);
     444             : #endif
     445           4 :     return pg_atomic_read_u64_impl(ptr);
     446             : }
     447             : 
     448             : static inline void
     449           4 : pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
     450             : {
     451             : #ifndef PG_HAVE_ATOMIC_U64_SIMULATION
     452           4 :     AssertPointerAlignment(ptr, 8);
     453             : #endif
     454           4 :     pg_atomic_write_u64_impl(ptr, val);
     455           4 : }
     456             : 
     457             : static inline uint64
     458           2 : pg_atomic_exchange_u64(volatile pg_atomic_uint64 *ptr, uint64 newval)
     459             : {
     460             : #ifndef PG_HAVE_ATOMIC_U64_SIMULATION
     461           2 :     AssertPointerAlignment(ptr, 8);
     462             : #endif
     463           2 :     return pg_atomic_exchange_u64_impl(ptr, newval);
     464             : }
     465             : 
     466             : static inline bool
     467           3 : pg_atomic_compare_exchange_u64(volatile pg_atomic_uint64 *ptr,
     468             :                                uint64 *expected, uint64 newval)
     469             : {
     470             : #ifndef PG_HAVE_ATOMIC_U64_SIMULATION
     471           3 :     AssertPointerAlignment(ptr, 8);
     472           3 :     AssertPointerAlignment(expected, 8);
     473             : #endif
     474           3 :     return pg_atomic_compare_exchange_u64_impl(ptr, expected, newval);
     475             : }
     476             : 
     477             : static inline uint64
     478        3165 : pg_atomic_fetch_add_u64(volatile pg_atomic_uint64 *ptr, int64 add_)
     479             : {
     480             : #ifndef PG_HAVE_ATOMIC_U64_SIMULATION
     481        3165 :     AssertPointerAlignment(ptr, 8);
     482             : #endif
     483        3165 :     return pg_atomic_fetch_add_u64_impl(ptr, add_);
     484             : }
     485             : 
     486             : static inline uint64
     487           1 : pg_atomic_fetch_sub_u64(volatile pg_atomic_uint64 *ptr, int64 sub_)
     488             : {
     489             : #ifndef PG_HAVE_ATOMIC_U64_SIMULATION
     490           1 :     AssertPointerAlignment(ptr, 8);
     491             : #endif
     492           1 :     Assert(sub_ != PG_INT64_MIN);
     493           1 :     return pg_atomic_fetch_sub_u64_impl(ptr, sub_);
     494             : }
     495             : 
     496             : static inline uint64
     497           3 : pg_atomic_fetch_and_u64(volatile pg_atomic_uint64 *ptr, uint64 and_)
     498             : {
     499             : #ifndef PG_HAVE_ATOMIC_U64_SIMULATION
     500           3 :     AssertPointerAlignment(ptr, 8);
     501             : #endif
     502           3 :     return pg_atomic_fetch_and_u64_impl(ptr, and_);
     503             : }
     504             : 
     505             : static inline uint64
     506           2 : pg_atomic_fetch_or_u64(volatile pg_atomic_uint64 *ptr, uint64 or_)
     507             : {
     508             : #ifndef PG_HAVE_ATOMIC_U64_SIMULATION
     509           2 :     AssertPointerAlignment(ptr, 8);
     510             : #endif
     511           2 :     return pg_atomic_fetch_or_u64_impl(ptr, or_);
     512             : }
     513             : 
     514             : static inline uint64
     515           1 : pg_atomic_add_fetch_u64(volatile pg_atomic_uint64 *ptr, int64 add_)
     516             : {
     517             : #ifndef PG_HAVE_ATOMIC_U64_SIMULATION
     518           1 :     AssertPointerAlignment(ptr, 8);
     519             : #endif
     520           1 :     return pg_atomic_add_fetch_u64_impl(ptr, add_);
     521             : }
     522             : 
     523             : static inline uint64
     524           1 : pg_atomic_sub_fetch_u64(volatile pg_atomic_uint64 *ptr, int64 sub_)
     525             : {
     526             : #ifndef PG_HAVE_ATOMIC_U64_SIMULATION
     527           1 :     AssertPointerAlignment(ptr, 8);
     528             : #endif
     529           1 :     Assert(sub_ != PG_INT64_MIN);
     530           1 :     return pg_atomic_sub_fetch_u64_impl(ptr, sub_);
     531             : }
     532             : 
     533             : #undef INSIDE_ATOMICS_H
     534             : 
     535             : #endif                          /* ATOMICS_H */

Generated by: LCOV version 1.11