LCOV - differential code coverage report
Current view: top level - src/include/port - atomics.h (source / functions) Coverage Total Hit GIC CBC ECB
Current: Differential Code Coverage HEAD vs 15 Lines: 100.0 % 90 90 76 14 76
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 27 27 27 27
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  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-2023, 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) || defined(__aarch64__)
      67                 : #include "port/atomics/arch-arm.h"
      68                 : #elif defined(__i386__) || defined(__i386) || defined(__x86_64__)
      69                 : #include "port/atomics/arch-x86.h"
      70                 : #elif defined(__ppc__) || defined(__powerpc__) || defined(__ppc64__) || defined(__powerpc64__)
      71                 : #include "port/atomics/arch-ppc.h"
      72                 : #elif defined(__hppa) || defined(__hppa__)
      73                 : #include "port/atomics/arch-hppa.h"
      74                 : #endif
      75                 : 
      76                 : /*
      77                 :  * Compiler specific, but architecture independent implementations.
      78                 :  *
      79                 :  * Provide architecture independent implementations of the atomic
      80                 :  * facilities. At the very least compiler barriers should be provided, but a
      81                 :  * full implementation of
      82                 :  * * pg_compiler_barrier(), pg_write_barrier(), pg_read_barrier()
      83                 :  * * pg_atomic_compare_exchange_u32(), pg_atomic_fetch_add_u32()
      84                 :  * using compiler intrinsics are a good idea.
      85                 :  */
      86                 : /*
      87                 :  * gcc or compatible, including clang and icc.  Exclude xlc.  The ppc64le "IBM
      88                 :  * XL C/C++ for Linux, V13.1.2" emulates gcc, but __sync_lock_test_and_set()
      89                 :  * of one-byte types elicits SIGSEGV.  That bug was gone by V13.1.5 (2016-12).
      90                 :  */
      91                 : #if (defined(__GNUC__) || defined(__INTEL_COMPILER)) && !(defined(__IBMC__) || defined(__IBMCPP__))
      92                 : #include "port/atomics/generic-gcc.h"
      93                 : #elif defined(_MSC_VER)
      94                 : #include "port/atomics/generic-msvc.h"
      95                 : #elif defined(__SUNPRO_C) && !defined(__GNUC__)
      96                 : #include "port/atomics/generic-sunpro.h"
      97                 : #else
      98                 : /*
      99                 :  * Unsupported compiler, we'll likely use slower fallbacks... At least
     100                 :  * compiler barriers should really be provided.
     101                 :  */
     102                 : #endif
     103                 : 
     104                 : /*
     105                 :  * Provide a full fallback of the pg_*_barrier(), pg_atomic**_flag and
     106                 :  * pg_atomic_* APIs for platforms without sufficient spinlock and/or atomics
     107                 :  * support. In the case of spinlock backed atomics the emulation is expected
     108                 :  * to be efficient, although less so than native atomics support.
     109                 :  */
     110                 : #include "port/atomics/fallback.h"
     111                 : 
     112                 : /*
     113                 :  * Provide additional operations using supported infrastructure. These are
     114                 :  * expected to be efficient if the underlying atomic operations are efficient.
     115                 :  */
     116                 : #include "port/atomics/generic.h"
     117                 : 
     118                 : 
     119                 : /*
     120                 :  * pg_compiler_barrier - prevent the compiler from moving code across
     121                 :  *
     122                 :  * A compiler barrier need not (and preferably should not) emit any actual
     123                 :  * machine code, but must act as an optimization fence: the compiler must not
     124                 :  * reorder loads or stores to main memory around the barrier.  However, the
     125                 :  * CPU may still reorder loads or stores at runtime, if the architecture's
     126                 :  * memory model permits this.
     127                 :  */
     128                 : #define pg_compiler_barrier()   pg_compiler_barrier_impl()
     129                 : 
     130                 : /*
     131                 :  * pg_memory_barrier - prevent the CPU from reordering memory access
     132                 :  *
     133                 :  * A memory barrier must act as a compiler barrier, and in addition must
     134                 :  * guarantee that all loads and stores issued prior to the barrier are
     135                 :  * completed before any loads or stores issued after the barrier.  Unless
     136                 :  * loads and stores are totally ordered (which is not the case on most
     137                 :  * architectures) this requires issuing some sort of memory fencing
     138                 :  * instruction.
     139                 :  */
     140                 : #define pg_memory_barrier() pg_memory_barrier_impl()
     141                 : 
     142                 : /*
     143                 :  * pg_(read|write)_barrier - prevent the CPU from reordering memory access
     144                 :  *
     145                 :  * A read barrier must act as a compiler barrier, and in addition must
     146                 :  * guarantee that any loads issued prior to the barrier are completed before
     147                 :  * any loads issued after the barrier.  Similarly, a write barrier acts
     148                 :  * as a compiler barrier, and also orders stores.  Read and write barriers
     149                 :  * are thus weaker than a full memory barrier, but stronger than a compiler
     150                 :  * barrier.  In practice, on machines with strong memory ordering, read and
     151                 :  * write barriers may require nothing more than a compiler barrier.
     152                 :  */
     153                 : #define pg_read_barrier()   pg_read_barrier_impl()
     154                 : #define pg_write_barrier()  pg_write_barrier_impl()
     155                 : 
     156                 : /*
     157                 :  * Spinloop delay - Allow CPU to relax in busy loops
     158                 :  */
     159                 : #define pg_spin_delay() pg_spin_delay_impl()
     160                 : 
     161                 : /*
     162 ECB             :  * pg_atomic_init_flag - initialize atomic flag.
     163                 :  *
     164                 :  * No barrier semantics.
     165                 :  */
     166                 : static inline void
     167 GIC        5481 : pg_atomic_init_flag(volatile pg_atomic_flag *ptr)
     168                 : {
     169            5481 :     pg_atomic_init_flag_impl(ptr);
     170            5481 : }
     171                 : 
     172                 : /*
     173                 :  * pg_atomic_test_set_flag - TAS()
     174                 :  *
     175 ECB             :  * Returns true if the flag has successfully been set, false otherwise.
     176                 :  *
     177                 :  * Acquire (including read barrier) semantics.
     178                 :  */
     179                 : static inline bool
     180 GIC         325 : pg_atomic_test_set_flag(volatile pg_atomic_flag *ptr)
     181                 : {
     182             325 :     return pg_atomic_test_set_flag_impl(ptr);
     183                 : }
     184                 : 
     185                 : /*
     186                 :  * pg_atomic_unlocked_test_flag - Check if the lock is free
     187                 :  *
     188 ECB             :  * Returns true if the flag currently is not set, false otherwise.
     189                 :  *
     190                 :  * No barrier semantics.
     191                 :  */
     192                 : static inline bool
     193 GIC         742 : pg_atomic_unlocked_test_flag(volatile pg_atomic_flag *ptr)
     194                 : {
     195             742 :     return pg_atomic_unlocked_test_flag_impl(ptr);
     196                 : }
     197                 : 
     198                 : /*
     199 ECB             :  * pg_atomic_clear_flag - release lock set by TAS()
     200                 :  *
     201                 :  * Release (including write barrier) semantics.
     202                 :  */
     203                 : static inline void
     204 GIC          22 : pg_atomic_clear_flag(volatile pg_atomic_flag *ptr)
     205                 : {
     206              22 :     pg_atomic_clear_flag_impl(ptr);
     207              22 : }
     208                 : 
     209                 : 
     210                 : /*
     211                 :  * pg_atomic_init_u32 - initialize atomic variable
     212                 :  *
     213 ECB             :  * Has to be done before any concurrent usage..
     214                 :  *
     215                 :  * No barrier semantics.
     216                 :  */
     217                 : static inline void
     218 CBC    44166133 : pg_atomic_init_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
     219                 : {
     220 GIC    44166133 :     AssertPointerAlignment(ptr, 4);
     221                 : 
     222        44166133 :     pg_atomic_init_u32_impl(ptr, val);
     223        44166133 : }
     224                 : 
     225                 : /*
     226                 :  * pg_atomic_read_u32 - unlocked read from atomic variable.
     227                 :  *
     228                 :  * The read is guaranteed to return a value as it has been written by this or
     229                 :  * another process at some point in the past. There's however no cache
     230                 :  * coherency interaction guaranteeing the value hasn't since been written to
     231 ECB             :  * again.
     232                 :  *
     233                 :  * No barrier semantics.
     234                 :  */
     235                 : static inline uint32
     236 GIC   512772941 : pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr)
     237                 : {
     238       512772941 :     AssertPointerAlignment(ptr, 4);
     239       512772941 :     return pg_atomic_read_u32_impl(ptr);
     240                 : }
     241                 : 
     242                 : /*
     243                 :  * pg_atomic_write_u32 - write to atomic variable.
     244                 :  *
     245                 :  * The write is guaranteed to succeed as a whole, i.e. it's not possible to
     246                 :  * observe a partial write for any reader.  Note that this correctly interacts
     247                 :  * with pg_atomic_compare_exchange_u32, in contrast to
     248 ECB             :  * pg_atomic_unlocked_write_u32().
     249                 :  *
     250                 :  * No barrier semantics.
     251                 :  */
     252                 : static inline void
     253 CBC    51791743 : pg_atomic_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
     254                 : {
     255 GIC    51791743 :     AssertPointerAlignment(ptr, 4);
     256                 : 
     257        51791743 :     pg_atomic_write_u32_impl(ptr, val);
     258        51791743 : }
     259                 : 
     260                 : /*
     261                 :  * pg_atomic_unlocked_write_u32 - unlocked write to atomic variable.
     262                 :  *
     263                 :  * The write is guaranteed to succeed as a whole, i.e. it's not possible to
     264                 :  * observe a partial write for any reader.  But note that writing this way is
     265                 :  * not guaranteed to correctly interact with read-modify-write operations like
     266                 :  * pg_atomic_compare_exchange_u32.  This should only be used in cases where
     267 ECB             :  * minor performance regressions due to atomics emulation are unacceptable.
     268                 :  *
     269                 :  * No barrier semantics.
     270                 :  */
     271                 : static inline void
     272 CBC     1917968 : pg_atomic_unlocked_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
     273                 : {
     274 GIC     1917968 :     AssertPointerAlignment(ptr, 4);
     275                 : 
     276         1917968 :     pg_atomic_unlocked_write_u32_impl(ptr, val);
     277         1917968 : }
     278                 : 
     279                 : /*
     280                 :  * pg_atomic_exchange_u32 - exchange newval with current value
     281                 :  *
     282 ECB             :  * Returns the old value of 'ptr' before the swap.
     283                 :  *
     284                 :  * Full barrier semantics.
     285                 :  */
     286                 : static inline uint32
     287 GIC       10910 : pg_atomic_exchange_u32(volatile pg_atomic_uint32 *ptr, uint32 newval)
     288                 : {
     289           10910 :     AssertPointerAlignment(ptr, 4);
     290                 : 
     291           10910 :     return pg_atomic_exchange_u32_impl(ptr, newval);
     292                 : }
     293                 : 
     294                 : /*
     295                 :  * pg_atomic_compare_exchange_u32 - CAS operation
     296                 :  *
     297                 :  * Atomically compare the current value of ptr with *expected and store newval
     298                 :  * iff ptr and *expected have the same value. The current value of *ptr will
     299                 :  * always be stored in *expected.
     300                 :  *
     301 ECB             :  * Return true if values have been exchanged, false otherwise.
     302                 :  *
     303                 :  * Full barrier semantics.
     304                 :  */
     305                 : static inline bool
     306 GIC   457749013 : pg_atomic_compare_exchange_u32(volatile pg_atomic_uint32 *ptr,
     307 ECB             :                                uint32 *expected, uint32 newval)
     308                 : {
     309 GIC   457749013 :     AssertPointerAlignment(ptr, 4);
     310       457749013 :     AssertPointerAlignment(expected, 4);
     311                 : 
     312       457749013 :     return pg_atomic_compare_exchange_u32_impl(ptr, expected, newval);
     313                 : }
     314                 : 
     315                 : /*
     316                 :  * pg_atomic_fetch_add_u32 - atomically add to variable
     317                 :  *
     318 ECB             :  * Returns the value of ptr before the arithmetic operation.
     319                 :  *
     320                 :  * Full barrier semantics.
     321                 :  */
     322                 : static inline uint32
     323 GIC     5315983 : pg_atomic_fetch_add_u32(volatile pg_atomic_uint32 *ptr, int32 add_)
     324                 : {
     325         5315983 :     AssertPointerAlignment(ptr, 4);
     326         5315983 :     return pg_atomic_fetch_add_u32_impl(ptr, add_);
     327                 : }
     328                 : 
     329                 : /*
     330                 :  * pg_atomic_fetch_sub_u32 - atomically subtract from variable
     331                 :  *
     332                 :  * Returns the value of ptr before the arithmetic operation. Note that sub_
     333 ECB             :  * may not be INT_MIN due to platform limitations.
     334                 :  *
     335                 :  * Full barrier semantics.
     336                 :  */
     337                 : static inline uint32
     338 GIC      585947 : pg_atomic_fetch_sub_u32(volatile pg_atomic_uint32 *ptr, int32 sub_)
     339                 : {
     340          585947 :     AssertPointerAlignment(ptr, 4);
     341          585947 :     Assert(sub_ != INT_MIN);
     342          585947 :     return pg_atomic_fetch_sub_u32_impl(ptr, sub_);
     343                 : }
     344                 : 
     345                 : /*
     346                 :  * pg_atomic_fetch_and_u32 - atomically bit-and and_ with variable
     347                 :  *
     348 ECB             :  * Returns the value of ptr before the arithmetic operation.
     349                 :  *
     350                 :  * Full barrier semantics.
     351                 :  */
     352                 : static inline uint32
     353 GIC    23209419 : pg_atomic_fetch_and_u32(volatile pg_atomic_uint32 *ptr, uint32 and_)
     354                 : {
     355        23209419 :     AssertPointerAlignment(ptr, 4);
     356        23209419 :     return pg_atomic_fetch_and_u32_impl(ptr, and_);
     357                 : }
     358                 : 
     359                 : /*
     360                 :  * pg_atomic_fetch_or_u32 - atomically bit-or or_ with variable
     361                 :  *
     362 ECB             :  * Returns the value of ptr before the arithmetic operation.
     363                 :  *
     364                 :  * Full barrier semantics.
     365                 :  */
     366                 : static inline uint32
     367 GIC    75071978 : pg_atomic_fetch_or_u32(volatile pg_atomic_uint32 *ptr, uint32 or_)
     368                 : {
     369        75071978 :     AssertPointerAlignment(ptr, 4);
     370        75071978 :     return pg_atomic_fetch_or_u32_impl(ptr, or_);
     371                 : }
     372                 : 
     373                 : /*
     374                 :  * pg_atomic_add_fetch_u32 - atomically add to variable
     375                 :  *
     376 ECB             :  * Returns the value of ptr after the arithmetic operation.
     377                 :  *
     378                 :  * Full barrier semantics.
     379                 :  */
     380                 : static inline uint32
     381 GIC         438 : pg_atomic_add_fetch_u32(volatile pg_atomic_uint32 *ptr, int32 add_)
     382                 : {
     383             438 :     AssertPointerAlignment(ptr, 4);
     384             438 :     return pg_atomic_add_fetch_u32_impl(ptr, add_);
     385                 : }
     386                 : 
     387                 : /*
     388                 :  * pg_atomic_sub_fetch_u32 - atomically subtract from variable
     389                 :  *
     390                 :  * Returns the value of ptr after the arithmetic operation. Note that sub_ may
     391 ECB             :  * not be INT_MIN due to platform limitations.
     392                 :  *
     393                 :  * Full barrier semantics.
     394                 :  */
     395                 : static inline uint32
     396 GIC   295493445 : pg_atomic_sub_fetch_u32(volatile pg_atomic_uint32 *ptr, int32 sub_)
     397                 : {
     398       295493445 :     AssertPointerAlignment(ptr, 4);
     399       295493445 :     Assert(sub_ != INT_MIN);
     400       295493445 :     return pg_atomic_sub_fetch_u32_impl(ptr, sub_);
     401                 : }
     402                 : 
     403                 : /* ----
     404                 :  * The 64 bit operations have the same semantics as their 32bit counterparts
     405 ECB             :  * if they are available. Check the corresponding 32bit function for
     406                 :  * documentation.
     407                 :  * ----
     408                 :  */
     409                 : static inline void
     410 GIC     2561651 : pg_atomic_init_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
     411                 : {
     412                 :     /*
     413 ECB             :      * Can't necessarily enforce alignment - and don't need it - when using
     414                 :      * the spinlock based fallback implementation. Therefore only assert when
     415                 :      * not using it.
     416                 :      */
     417                 : #ifndef PG_HAVE_ATOMIC_U64_SIMULATION
     418 GIC     2561651 :     AssertPointerAlignment(ptr, 8);
     419 ECB             : #endif
     420 GIC     2561651 :     pg_atomic_init_u64_impl(ptr, val);
     421         2561651 : }
     422 ECB             : 
     423                 : static inline uint64
     424 CBC    14079661 : pg_atomic_read_u64(volatile pg_atomic_uint64 *ptr)
     425                 : {
     426                 : #ifndef PG_HAVE_ATOMIC_U64_SIMULATION
     427 GIC    14079661 :     AssertPointerAlignment(ptr, 8);
     428 ECB             : #endif
     429 GIC    14079661 :     return pg_atomic_read_u64_impl(ptr);
     430                 : }
     431 ECB             : 
     432                 : static inline void
     433 CBC     3135764 : pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
     434 ECB             : {
     435                 : #ifndef PG_HAVE_ATOMIC_U64_SIMULATION
     436 GIC     3135764 :     AssertPointerAlignment(ptr, 8);
     437 ECB             : #endif
     438 GIC     3135764 :     pg_atomic_write_u64_impl(ptr, val);
     439         3135764 : }
     440 ECB             : 
     441                 : static inline uint64
     442 CBC           6 : pg_atomic_exchange_u64(volatile pg_atomic_uint64 *ptr, uint64 newval)
     443                 : {
     444                 : #ifndef PG_HAVE_ATOMIC_U64_SIMULATION
     445 GIC           6 :     AssertPointerAlignment(ptr, 8);
     446 ECB             : #endif
     447 GIC           6 :     return pg_atomic_exchange_u64_impl(ptr, newval);
     448                 : }
     449                 : 
     450 ECB             : static inline bool
     451 CBC     1481951 : pg_atomic_compare_exchange_u64(volatile pg_atomic_uint64 *ptr,
     452                 :                                uint64 *expected, uint64 newval)
     453 ECB             : {
     454                 : #ifndef PG_HAVE_ATOMIC_U64_SIMULATION
     455 GIC     1481951 :     AssertPointerAlignment(ptr, 8);
     456         1481951 :     AssertPointerAlignment(expected, 8);
     457 ECB             : #endif
     458 GIC     1481951 :     return pg_atomic_compare_exchange_u64_impl(ptr, expected, newval);
     459                 : }
     460 ECB             : 
     461                 : static inline uint64
     462 CBC       93056 : pg_atomic_fetch_add_u64(volatile pg_atomic_uint64 *ptr, int64 add_)
     463                 : {
     464                 : #ifndef PG_HAVE_ATOMIC_U64_SIMULATION
     465 GIC       93056 :     AssertPointerAlignment(ptr, 8);
     466 ECB             : #endif
     467 GIC       93056 :     return pg_atomic_fetch_add_u64_impl(ptr, add_);
     468                 : }
     469 ECB             : 
     470                 : static inline uint64
     471 CBC         660 : pg_atomic_fetch_sub_u64(volatile pg_atomic_uint64 *ptr, int64 sub_)
     472 ECB             : {
     473                 : #ifndef PG_HAVE_ATOMIC_U64_SIMULATION
     474 GIC         660 :     AssertPointerAlignment(ptr, 8);
     475                 : #endif
     476 CBC         660 :     Assert(sub_ != PG_INT64_MIN);
     477 GIC         660 :     return pg_atomic_fetch_sub_u64_impl(ptr, sub_);
     478                 : }
     479 ECB             : 
     480                 : static inline uint64
     481 CBC           9 : pg_atomic_fetch_and_u64(volatile pg_atomic_uint64 *ptr, uint64 and_)
     482                 : {
     483                 : #ifndef PG_HAVE_ATOMIC_U64_SIMULATION
     484 GIC           9 :     AssertPointerAlignment(ptr, 8);
     485 ECB             : #endif
     486 GIC           9 :     return pg_atomic_fetch_and_u64_impl(ptr, and_);
     487                 : }
     488 ECB             : 
     489                 : static inline uint64
     490 CBC           6 : pg_atomic_fetch_or_u64(volatile pg_atomic_uint64 *ptr, uint64 or_)
     491                 : {
     492                 : #ifndef PG_HAVE_ATOMIC_U64_SIMULATION
     493 GIC           6 :     AssertPointerAlignment(ptr, 8);
     494 ECB             : #endif
     495 GIC           6 :     return pg_atomic_fetch_or_u64_impl(ptr, or_);
     496                 : }
     497 ECB             : 
     498                 : static inline uint64
     499 CBC          59 : pg_atomic_add_fetch_u64(volatile pg_atomic_uint64 *ptr, int64 add_)
     500                 : {
     501                 : #ifndef PG_HAVE_ATOMIC_U64_SIMULATION
     502 GIC          59 :     AssertPointerAlignment(ptr, 8);
     503 ECB             : #endif
     504 GIC          59 :     return pg_atomic_add_fetch_u64_impl(ptr, add_);
     505                 : }
     506 ECB             : 
     507                 : static inline uint64
     508 CBC           3 : pg_atomic_sub_fetch_u64(volatile pg_atomic_uint64 *ptr, int64 sub_)
     509 ECB             : {
     510                 : #ifndef PG_HAVE_ATOMIC_U64_SIMULATION
     511 GIC           3 :     AssertPointerAlignment(ptr, 8);
     512                 : #endif
     513               3 :     Assert(sub_ != PG_INT64_MIN);
     514               3 :     return pg_atomic_sub_fetch_u64_impl(ptr, sub_);
     515                 : }
     516                 : 
     517                 : #undef INSIDE_ATOMICS_H
     518                 : 
     519                 : #endif                          /* ATOMICS_H */
        

Generated by: LCOV version v1.16-55-g56c0a2a