LCOV - code coverage report
Current view: top level - vppinfra - lock.h (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 52 63 82.5 %
Date: 2023-07-05 22:20:52 Functions: 12 14 85.7 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2017 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : 
      16             : #ifndef included_clib_lock_h
      17             : #define included_clib_lock_h
      18             : 
      19             : #include <vppinfra/clib.h>
      20             : #include <vppinfra/atomics.h>
      21             : 
      22             : #if __x86_64__
      23             : #define CLIB_PAUSE() __builtin_ia32_pause ()
      24             : #elif defined (__aarch64__) || defined (__arm__)
      25             : #define CLIB_PAUSE() __asm__ ("yield")
      26             : #else
      27             : #define CLIB_PAUSE()
      28             : #endif
      29             : 
      30             : #if CLIB_DEBUG > 1
      31             : #define CLIB_LOCK_DBG(_p)                               \
      32             : do {                                                    \
      33             :     (*_p)->frame_address = __builtin_frame_address (0);      \
      34             :     (*_p)->pid = getpid ();                          \
      35             :     (*_p)->thread_index = os_get_thread_index ();    \
      36             : } while (0)
      37             : #define CLIB_LOCK_DBG_CLEAR(_p)                         \
      38             : do {                                                    \
      39             :     (*_p)->frame_address = 0;                                \
      40             :     (*_p)->pid = 0;                                  \
      41             :     (*_p)->thread_index = 0;                         \
      42             : } while (0)
      43             : #else
      44             : #define CLIB_LOCK_DBG(_p)
      45             : #define CLIB_LOCK_DBG_CLEAR(_p)
      46             : #endif
      47             : 
      48             : #define CLIB_SPINLOCK_IS_LOCKED(_p) (*(_p))->lock
      49             : #define CLIB_SPINLOCK_ASSERT_LOCKED(_p) ASSERT(CLIB_SPINLOCK_IS_LOCKED((_p)))
      50             : 
      51             : struct clib_spinlock_s
      52             : {
      53             :   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
      54             :   u32 lock;
      55             : #if CLIB_DEBUG > 0
      56             :   pid_t pid;
      57             :   uword thread_index;
      58             :   void *frame_address;
      59             : #endif
      60             : };
      61             : 
      62             : typedef struct clib_spinlock_s *clib_spinlock_t;
      63             : 
      64             : static inline void
      65       54797 : clib_spinlock_init (clib_spinlock_t * p)
      66             : {
      67       54797 :   *p = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES);
      68       54797 :   clib_memset ((void *) *p, 0, CLIB_CACHE_LINE_BYTES);
      69       54797 : }
      70             : 
      71             : static inline void
      72        1030 : clib_spinlock_free (clib_spinlock_t * p)
      73             : {
      74        1030 :   if (*p)
      75             :     {
      76         987 :       clib_mem_free ((void *) *p);
      77         987 :       *p = 0;
      78             :     }
      79        1030 : }
      80             : 
      81             : static_always_inline void
      82   752153847 : clib_spinlock_lock (clib_spinlock_t * p)
      83             : {
      84   752153847 :   u32 free = 0;
      85   752175859 :   while (!clib_atomic_cmp_and_swap_acq_relax_n (&(*p)->lock, &free, 1, 0))
      86             :     {
      87             :       /* atomic load limits number of compare_exchange executions */
      88      302838 :       while (clib_atomic_load_relax_n (&(*p)->lock))
      89      281652 :         CLIB_PAUSE ();
      90             :       /* on failure, compare_exchange writes (*p)->lock into free */
      91       21186 :       free = 0;
      92             :     }
      93             :   CLIB_LOCK_DBG (p);
      94   752157848 : }
      95             : 
      96             : static_always_inline int
      97           0 : clib_spinlock_trylock (clib_spinlock_t * p)
      98             : {
      99           0 :   if (PREDICT_FALSE (CLIB_SPINLOCK_IS_LOCKED (p)))
     100           0 :     return 0;
     101           0 :   clib_spinlock_lock (p);
     102           0 :   return 1;
     103             : }
     104             : 
     105             : static_always_inline void
     106   521714357 : clib_spinlock_lock_if_init (clib_spinlock_t * p)
     107             : {
     108   521714357 :   if (PREDICT_FALSE (*p != 0))
     109     5306190 :     clib_spinlock_lock (p);
     110   521714428 : }
     111             : 
     112             : static_always_inline int
     113           0 : clib_spinlock_trylock_if_init (clib_spinlock_t * p)
     114             : {
     115           0 :   if (PREDICT_FALSE (*p != 0))
     116           0 :     return clib_spinlock_trylock (p);
     117           0 :   return 1;
     118             : }
     119             : 
     120             : static_always_inline void
     121   752153899 : clib_spinlock_unlock (clib_spinlock_t * p)
     122             : {
     123             :   CLIB_LOCK_DBG_CLEAR (p);
     124             :   /* Make sure all reads/writes are complete before releasing the lock */
     125   752153899 :   clib_atomic_release (&(*p)->lock);
     126   752153899 : }
     127             : 
     128             : static_always_inline void
     129   521714408 : clib_spinlock_unlock_if_init (clib_spinlock_t * p)
     130             : {
     131   521714408 :   if (PREDICT_FALSE (*p != 0))
     132     5306237 :     clib_spinlock_unlock (p);
     133   521714408 : }
     134             : 
     135             : /*
     136             :  * Readers-Writer Lock
     137             :  */
     138             : 
     139             : typedef struct clib_rw_lock_
     140             : {
     141             :   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
     142             :   /* -1 when W lock held, > 0 when R lock held */
     143             :   volatile i32 rw_cnt;
     144             : #if CLIB_DEBUG > 0
     145             :   pid_t pid;
     146             :   uword thread_index;
     147             :   void *frame_address;
     148             : #endif
     149             : } *clib_rwlock_t;
     150             : 
     151             : always_inline void
     152        1682 : clib_rwlock_init (clib_rwlock_t * p)
     153             : {
     154        1682 :   *p = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES);
     155        1682 :   clib_memset ((void *) *p, 0, CLIB_CACHE_LINE_BYTES);
     156        1682 : }
     157             : 
     158             : always_inline void
     159         124 : clib_rwlock_free (clib_rwlock_t * p)
     160             : {
     161         124 :   if (*p)
     162             :     {
     163         124 :       clib_mem_free ((void *) *p);
     164         124 :       *p = 0;
     165             :     }
     166         124 : }
     167             : 
     168             : always_inline void
     169       10599 : clib_rwlock_reader_lock (clib_rwlock_t * p)
     170             : {
     171             :   i32 cnt;
     172             :   do
     173             :     {
     174             :       /* rwlock held by a writer */
     175       10599 :       while ((cnt = clib_atomic_load_relax_n (&(*p)->rw_cnt)) < 0)
     176           0 :         CLIB_PAUSE ();
     177             :     }
     178       10599 :   while (!clib_atomic_cmp_and_swap_acq_relax_n
     179             :          (&(*p)->rw_cnt, &cnt, cnt + 1, 1));
     180             :   CLIB_LOCK_DBG (p);
     181       10599 : }
     182             : 
     183             : always_inline void
     184       10599 : clib_rwlock_reader_unlock (clib_rwlock_t * p)
     185             : {
     186       10599 :   ASSERT ((*p)->rw_cnt > 0);
     187             :   CLIB_LOCK_DBG_CLEAR (p);
     188       10599 :   clib_atomic_fetch_sub_rel (&(*p)->rw_cnt, 1);
     189       10599 : }
     190             : 
     191             : always_inline void
     192        1219 : clib_rwlock_writer_lock (clib_rwlock_t * p)
     193             : {
     194        1219 :   i32 cnt = 0;
     195             :   do
     196             :     {
     197             :       /* rwlock held by writer or reader(s) */
     198        1219 :       while ((cnt = clib_atomic_load_relax_n (&(*p)->rw_cnt)) != 0)
     199           0 :         CLIB_PAUSE ();
     200             :     }
     201        1219 :   while (!clib_atomic_cmp_and_swap_acq_relax_n (&(*p)->rw_cnt, &cnt, -1, 1));
     202             :   CLIB_LOCK_DBG (p);
     203        1219 : }
     204             : 
     205             : always_inline void
     206        1219 : clib_rwlock_writer_unlock (clib_rwlock_t * p)
     207             : {
     208             :   CLIB_LOCK_DBG_CLEAR (p);
     209        1219 :   clib_atomic_release (&(*p)->rw_cnt);
     210        1219 : }
     211             : 
     212             : #endif
     213             : 
     214             : /*
     215             :  * fd.io coding-style-patch-verification: ON
     216             :  *
     217             :  * Local Variables:
     218             :  * eval: (c-set-style "gnu")
     219             :  * End:
     220             :  */

Generated by: LCOV version 1.14