LCOV - code coverage report
Current view: top level - src/include/port/atomics - generic.h (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 100.0 % 37 37
Test Date: 2026-07-03 19:57:34 Functions: 100.0 % 15 15
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * generic.h
       4              :  *    Implement higher level operations based on some lower level atomic
       5              :  *    operations.
       6              :  *
       7              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       8              :  * Portions Copyright (c) 1994, Regents of the University of California
       9              :  *
      10              :  * src/include/port/atomics/generic.h
      11              :  *
      12              :  *-------------------------------------------------------------------------
      13              :  */
      14              : 
      15              : /* intentionally no include guards, should only be included by atomics.h */
      16              : #ifndef INSIDE_ATOMICS_H
      17              : #   error "should be included via atomics.h"
      18              : #endif
      19              : 
      20              : /*
      21              :  * If read or write barriers are undefined, we upgrade them to full memory
      22              :  * barriers.
      23              :  */
      24              : #if !defined(pg_read_barrier_impl)
      25              : #   define pg_read_barrier_impl pg_memory_barrier_impl
      26              : #endif
      27              : #if !defined(pg_write_barrier_impl)
      28              : #   define pg_write_barrier_impl pg_memory_barrier_impl
      29              : #endif
      30              : 
      31              : /* provide fallback */
      32              : #if !defined(PG_HAVE_ATOMIC_FLAG_SUPPORT) && defined(PG_HAVE_ATOMIC_U32_SUPPORT)
      33              : #define PG_HAVE_ATOMIC_FLAG_SUPPORT
      34              : typedef pg_atomic_uint32 pg_atomic_flag;
      35              : #endif
      36              : 
      37              : #ifndef PG_HAVE_ATOMIC_READ_U32
      38              : #define PG_HAVE_ATOMIC_READ_U32
      39              : static inline uint32
      40    376944980 : pg_atomic_read_u32_impl(volatile pg_atomic_uint32 *ptr)
      41              : {
      42    376944980 :     return ptr->value;
      43              : }
      44              : #endif
      45              : 
      46              : #ifndef PG_HAVE_ATOMIC_WRITE_U32
      47              : #define PG_HAVE_ATOMIC_WRITE_U32
      48              : static inline void
      49        77048 : pg_atomic_write_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val)
      50              : {
      51        77048 :     ptr->value = val;
      52        77048 : }
      53              : #endif
      54              : 
      55              : #ifndef PG_HAVE_ATOMIC_UNLOCKED_WRITE_U32
      56              : #define PG_HAVE_ATOMIC_UNLOCKED_WRITE_U32
      57              : static inline void
      58              : pg_atomic_unlocked_write_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val)
      59              : {
      60              :     ptr->value = val;
      61              : }
      62              : #endif
      63              : 
      64              : /*
      65              :  * provide fallback for test_and_set using atomic_exchange if available
      66              :  */
      67              : #if !defined(PG_HAVE_ATOMIC_TEST_SET_FLAG) && defined(PG_HAVE_ATOMIC_EXCHANGE_U32)
      68              : 
      69              : #define PG_HAVE_ATOMIC_INIT_FLAG
      70              : static inline void
      71              : pg_atomic_init_flag_impl(volatile pg_atomic_flag *ptr)
      72              : {
      73              :     pg_atomic_write_u32_impl(ptr, 0);
      74              : }
      75              : 
      76              : #define PG_HAVE_ATOMIC_TEST_SET_FLAG
      77              : static inline bool
      78              : pg_atomic_test_set_flag_impl(volatile pg_atomic_flag *ptr)
      79              : {
      80              :     return pg_atomic_exchange_u32_impl(ptr, 1) == 0;
      81              : }
      82              : 
      83              : #define PG_HAVE_ATOMIC_UNLOCKED_TEST_FLAG
      84              : static inline bool
      85              : pg_atomic_unlocked_test_flag_impl(volatile pg_atomic_flag *ptr)
      86              : {
      87              :     return pg_atomic_read_u32_impl(ptr) == 0;
      88              : }
      89              : 
      90              : 
      91              : #define PG_HAVE_ATOMIC_CLEAR_FLAG
      92              : static inline void
      93              : pg_atomic_clear_flag_impl(volatile pg_atomic_flag *ptr)
      94              : {
      95              :     /* XXX: release semantics suffice? */
      96              :     pg_memory_barrier_impl();
      97              :     pg_atomic_write_u32_impl(ptr, 0);
      98              : }
      99              : 
     100              : /*
     101              :  * provide fallback for test_and_set using atomic_compare_exchange if
     102              :  * available.
     103              :  */
     104              : #elif !defined(PG_HAVE_ATOMIC_TEST_SET_FLAG) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
     105              : 
     106              : #define PG_HAVE_ATOMIC_INIT_FLAG
     107              : static inline void
     108              : pg_atomic_init_flag_impl(volatile pg_atomic_flag *ptr)
     109              : {
     110              :     pg_atomic_write_u32_impl(ptr, 0);
     111              : }
     112              : 
     113              : #define PG_HAVE_ATOMIC_TEST_SET_FLAG
     114              : static inline bool
     115              : pg_atomic_test_set_flag_impl(volatile pg_atomic_flag *ptr)
     116              : {
     117              :     uint32 value = 0;
     118              :     return pg_atomic_compare_exchange_u32_impl(ptr, &value, 1);
     119              : }
     120              : 
     121              : #define PG_HAVE_ATOMIC_UNLOCKED_TEST_FLAG
     122              : static inline bool
     123              : pg_atomic_unlocked_test_flag_impl(volatile pg_atomic_flag *ptr)
     124              : {
     125              :     return pg_atomic_read_u32_impl(ptr) == 0;
     126              : }
     127              : 
     128              : #define PG_HAVE_ATOMIC_CLEAR_FLAG
     129              : static inline void
     130              : pg_atomic_clear_flag_impl(volatile pg_atomic_flag *ptr)
     131              : {
     132              :     /* XXX: release semantics suffice? */
     133              :     pg_memory_barrier_impl();
     134              :     pg_atomic_write_u32_impl(ptr, 0);
     135              : }
     136              : 
     137              : #elif !defined(PG_HAVE_ATOMIC_TEST_SET_FLAG)
     138              : #   error "No pg_atomic_test_and_set provided"
     139              : #endif /* !defined(PG_HAVE_ATOMIC_TEST_SET_FLAG) */
     140              : 
     141              : 
     142              : #ifndef PG_HAVE_ATOMIC_INIT_U32
     143              : #define PG_HAVE_ATOMIC_INIT_U32
     144              : static inline void
     145      4036577 : pg_atomic_init_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val_)
     146              : {
     147      4036577 :     ptr->value = val_;
     148      4036577 : }
     149              : #endif
     150              : 
     151              : #if !defined(PG_HAVE_ATOMIC_EXCHANGE_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
     152              : #define PG_HAVE_ATOMIC_EXCHANGE_U32
     153              : static inline uint32
     154              : pg_atomic_exchange_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 xchg_)
     155              : {
     156              :     uint32 old;
     157              :     old = ptr->value;            /* ok if read is not atomic */
     158              :     while (!pg_atomic_compare_exchange_u32_impl(ptr, &old, xchg_))
     159              :         /* skip */;
     160              :     return old;
     161              : }
     162              : #endif
     163              : 
     164              : #if !defined(PG_HAVE_ATOMIC_FETCH_ADD_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
     165              : #define PG_HAVE_ATOMIC_FETCH_ADD_U32
     166              : static inline uint32
     167              : pg_atomic_fetch_add_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_)
     168              : {
     169              :     uint32 old;
     170              :     old = ptr->value;            /* ok if read is not atomic */
     171              :     while (!pg_atomic_compare_exchange_u32_impl(ptr, &old, old + add_))
     172              :         /* skip */;
     173              :     return old;
     174              : }
     175              : #endif
     176              : 
     177              : #if !defined(PG_HAVE_ATOMIC_FETCH_SUB_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
     178              : #define PG_HAVE_ATOMIC_FETCH_SUB_U32
     179              : static inline uint32
     180              : pg_atomic_fetch_sub_u32_impl(volatile pg_atomic_uint32 *ptr, int32 sub_)
     181              : {
     182              :     return pg_atomic_fetch_add_u32_impl(ptr, -sub_);
     183              : }
     184              : #endif
     185              : 
     186              : #if !defined(PG_HAVE_ATOMIC_FETCH_AND_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
     187              : #define PG_HAVE_ATOMIC_FETCH_AND_U32
     188              : static inline uint32
     189              : pg_atomic_fetch_and_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 and_)
     190              : {
     191              :     uint32 old;
     192              :     old = ptr->value;            /* ok if read is not atomic */
     193              :     while (!pg_atomic_compare_exchange_u32_impl(ptr, &old, old & and_))
     194              :         /* skip */;
     195              :     return old;
     196              : }
     197              : #endif
     198              : 
     199              : #if !defined(PG_HAVE_ATOMIC_FETCH_OR_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
     200              : #define PG_HAVE_ATOMIC_FETCH_OR_U32
     201              : static inline uint32
     202              : pg_atomic_fetch_or_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 or_)
     203              : {
     204              :     uint32 old;
     205              :     old = ptr->value;            /* ok if read is not atomic */
     206              :     while (!pg_atomic_compare_exchange_u32_impl(ptr, &old, old | or_))
     207              :         /* skip */;
     208              :     return old;
     209              : }
     210              : #endif
     211              : 
     212              : #if !defined(PG_HAVE_ATOMIC_ADD_FETCH_U32) && defined(PG_HAVE_ATOMIC_FETCH_ADD_U32)
     213              : #define PG_HAVE_ATOMIC_ADD_FETCH_U32
     214              : static inline uint32
     215          897 : pg_atomic_add_fetch_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_)
     216              : {
     217          897 :     return pg_atomic_fetch_add_u32_impl(ptr, add_) + add_;
     218              : }
     219              : #endif
     220              : 
     221              : #if !defined(PG_HAVE_ATOMIC_SUB_FETCH_U32) && defined(PG_HAVE_ATOMIC_FETCH_SUB_U32)
     222              : #define PG_HAVE_ATOMIC_SUB_FETCH_U32
     223              : static inline uint32
     224    347625019 : pg_atomic_sub_fetch_u32_impl(volatile pg_atomic_uint32 *ptr, int32 sub_)
     225              : {
     226    347625019 :     return pg_atomic_fetch_sub_u32_impl(ptr, sub_) - sub_;
     227              : }
     228              : #endif
     229              : 
     230              : #if !defined(PG_HAVE_ATOMIC_READ_MEMBARRIER_U32) && defined(PG_HAVE_ATOMIC_FETCH_ADD_U32)
     231              : #define PG_HAVE_ATOMIC_READ_MEMBARRIER_U32
     232              : static inline uint32
     233           19 : pg_atomic_read_membarrier_u32_impl(volatile pg_atomic_uint32 *ptr)
     234              : {
     235           19 :     return pg_atomic_fetch_add_u32_impl(ptr, 0);
     236              : }
     237              : #endif
     238              : 
     239              : #if !defined(PG_HAVE_ATOMIC_WRITE_MEMBARRIER_U32) && defined(PG_HAVE_ATOMIC_EXCHANGE_U32)
     240              : #define PG_HAVE_ATOMIC_WRITE_MEMBARRIER_U32
     241              : static inline void
     242        24748 : pg_atomic_write_membarrier_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val)
     243              : {
     244        24748 :     (void) pg_atomic_exchange_u32_impl(ptr, val);
     245        24748 : }
     246              : #endif
     247              : 
     248              : #if !defined(PG_HAVE_ATOMIC_EXCHANGE_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64)
     249              : #define PG_HAVE_ATOMIC_EXCHANGE_U64
     250              : static inline uint64
     251              : pg_atomic_exchange_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 xchg_)
     252              : {
     253              :     uint64 old;
     254              :     old = ptr->value;            /* ok if read is not atomic */
     255              :     while (!pg_atomic_compare_exchange_u64_impl(ptr, &old, xchg_))
     256              :         /* skip */;
     257              :     return old;
     258              : }
     259              : #endif
     260              : 
     261              : #ifndef PG_HAVE_ATOMIC_WRITE_U64
     262              : #define PG_HAVE_ATOMIC_WRITE_U64
     263              : 
     264              : #if defined(PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY) && \
     265              :     !defined(PG_HAVE_ATOMIC_U64_SIMULATION)
     266              : 
     267              : static inline void
     268     21199021 : pg_atomic_write_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 val)
     269              : {
     270              :     /*
     271              :      * On this platform aligned 64bit writes are guaranteed to be atomic,
     272              :      * except if using the fallback implementation, where can't guarantee the
     273              :      * required alignment.
     274              :      */
     275              :     AssertPointerAlignment(ptr, 8);
     276     21199021 :     ptr->value = val;
     277     21199021 : }
     278              : 
     279              : #else
     280              : 
     281              : static inline void
     282              : pg_atomic_write_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 val)
     283              : {
     284              :     /*
     285              :      * 64 bit writes aren't safe on all platforms. In the generic
     286              :      * implementation implement them as an atomic exchange.
     287              :      */
     288              :     pg_atomic_exchange_u64_impl(ptr, val);
     289              : }
     290              : 
     291              : #endif /* PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY && !PG_HAVE_ATOMIC_U64_SIMULATION */
     292              : #endif /* PG_HAVE_ATOMIC_WRITE_U64 */
     293              : 
     294              : #ifndef PG_HAVE_ATOMIC_UNLOCKED_WRITE_U64
     295              : #define PG_HAVE_ATOMIC_UNLOCKED_WRITE_U64
     296              : static inline void
     297      5652574 : pg_atomic_unlocked_write_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 val)
     298              : {
     299      5652574 :     ptr->value = val;
     300      5652574 : }
     301              : #endif
     302              : 
     303              : #ifndef PG_HAVE_ATOMIC_READ_U64
     304              : #define PG_HAVE_ATOMIC_READ_U64
     305              : 
     306              : #if defined(PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY) && \
     307              :     !defined(PG_HAVE_ATOMIC_U64_SIMULATION)
     308              : 
     309              : static inline uint64
     310    574996472 : pg_atomic_read_u64_impl(volatile pg_atomic_uint64 *ptr)
     311              : {
     312              :     /*
     313              :      * On this platform aligned 64-bit reads are guaranteed to be atomic.
     314              :      */
     315              :     AssertPointerAlignment(ptr, 8);
     316    574996472 :     return ptr->value;
     317              : }
     318              : 
     319              : #else
     320              : 
     321              : static inline uint64
     322              : pg_atomic_read_u64_impl(volatile pg_atomic_uint64 *ptr)
     323              : {
     324              :     uint64 old = 0;
     325              : 
     326              :     /*
     327              :      * 64-bit reads aren't atomic on all platforms. In the generic
     328              :      * implementation implement them as a compare/exchange with 0. That'll
     329              :      * fail or succeed, but always return the old value. Possibly might store
     330              :      * a 0, but only if the previous value also was a 0 - i.e. harmless.
     331              :      */
     332              :     pg_atomic_compare_exchange_u64_impl(ptr, &old, 0);
     333              : 
     334              :     return old;
     335              : }
     336              : #endif /* PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY && !PG_HAVE_ATOMIC_U64_SIMULATION */
     337              : #endif /* PG_HAVE_ATOMIC_READ_U64 */
     338              : 
     339              : #ifndef PG_HAVE_ATOMIC_INIT_U64
     340              : #define PG_HAVE_ATOMIC_INIT_U64
     341              : static inline void
     342     15630139 : pg_atomic_init_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 val_)
     343              : {
     344     15630139 :     ptr->value = val_;
     345     15630139 : }
     346              : #endif
     347              : 
     348              : #if !defined(PG_HAVE_ATOMIC_FETCH_ADD_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64)
     349              : #define PG_HAVE_ATOMIC_FETCH_ADD_U64
     350              : static inline uint64
     351              : pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_)
     352              : {
     353              :     uint64 old;
     354              :     old = ptr->value;            /* ok if read is not atomic */
     355              :     while (!pg_atomic_compare_exchange_u64_impl(ptr, &old, old + add_))
     356              :         /* skip */;
     357              :     return old;
     358              : }
     359              : #endif
     360              : 
     361              : #if !defined(PG_HAVE_ATOMIC_FETCH_SUB_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64)
     362              : #define PG_HAVE_ATOMIC_FETCH_SUB_U64
     363              : static inline uint64
     364              : pg_atomic_fetch_sub_u64_impl(volatile pg_atomic_uint64 *ptr, int64 sub_)
     365              : {
     366              :     return pg_atomic_fetch_add_u64_impl(ptr, -sub_);
     367              : }
     368              : #endif
     369              : 
     370              : #if !defined(PG_HAVE_ATOMIC_FETCH_AND_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64)
     371              : #define PG_HAVE_ATOMIC_FETCH_AND_U64
     372              : static inline uint64
     373              : pg_atomic_fetch_and_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 and_)
     374              : {
     375              :     uint64 old;
     376              :     old = ptr->value;            /* ok if read is not atomic */
     377              :     while (!pg_atomic_compare_exchange_u64_impl(ptr, &old, old & and_))
     378              :         /* skip */;
     379              :     return old;
     380              : }
     381              : #endif
     382              : 
     383              : #if !defined(PG_HAVE_ATOMIC_FETCH_OR_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64)
     384              : #define PG_HAVE_ATOMIC_FETCH_OR_U64
     385              : static inline uint64
     386              : pg_atomic_fetch_or_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 or_)
     387              : {
     388              :     uint64 old;
     389              :     old = ptr->value;            /* ok if read is not atomic */
     390              :     while (!pg_atomic_compare_exchange_u64_impl(ptr, &old, old | or_))
     391              :         /* skip */;
     392              :     return old;
     393              : }
     394              : #endif
     395              : 
     396              : #if !defined(PG_HAVE_ATOMIC_ADD_FETCH_U64) && defined(PG_HAVE_ATOMIC_FETCH_ADD_U64)
     397              : #define PG_HAVE_ATOMIC_ADD_FETCH_U64
     398              : static inline uint64
     399          711 : pg_atomic_add_fetch_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_)
     400              : {
     401          711 :     return pg_atomic_fetch_add_u64_impl(ptr, add_) + add_;
     402              : }
     403              : #endif
     404              : 
     405              : #if !defined(PG_HAVE_ATOMIC_SUB_FETCH_U64) && defined(PG_HAVE_ATOMIC_FETCH_SUB_U64)
     406              : #define PG_HAVE_ATOMIC_SUB_FETCH_U64
     407              : static inline uint64
     408    114589778 : pg_atomic_sub_fetch_u64_impl(volatile pg_atomic_uint64 *ptr, int64 sub_)
     409              : {
     410    114589778 :     return pg_atomic_fetch_sub_u64_impl(ptr, sub_) - sub_;
     411              : }
     412              : #endif
     413              : 
     414              : #if !defined(PG_HAVE_ATOMIC_READ_MEMBARRIER_U64) && defined(PG_HAVE_ATOMIC_FETCH_ADD_U64)
     415              : #define PG_HAVE_ATOMIC_READ_MEMBARRIER_U64
     416              : static inline uint64
     417     11730995 : pg_atomic_read_membarrier_u64_impl(volatile pg_atomic_uint64 *ptr)
     418              : {
     419     11730995 :     return pg_atomic_fetch_add_u64_impl(ptr, 0);
     420              : }
     421              : #endif
     422              : 
     423              : #if !defined(PG_HAVE_ATOMIC_WRITE_MEMBARRIER_U64) && defined(PG_HAVE_ATOMIC_EXCHANGE_U64)
     424              : #define PG_HAVE_ATOMIC_WRITE_MEMBARRIER_U64
     425              : static inline void
     426       126767 : pg_atomic_write_membarrier_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 val)
     427              : {
     428       126767 :     (void) pg_atomic_exchange_u64_impl(ptr, val);
     429       126767 : }
     430              : #endif
        

Generated by: LCOV version 2.0-1