Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/include/synch/spinlock.h

    r4f84ee42 r8df5f20  
    11/*
    22 * Copyright (c) 2001-2004 Jakub Jermar
    3  * Copyright (c) 2023 Jiří Zárevúcky
    43 * All rights reserved.
    54 *
     
    3736#define KERN_SPINLOCK_H_
    3837
     38#include <assert.h>
    3939#include <stdatomic.h>
    4040#include <stdbool.h>
    41 
    42 #include <arch/types.h>
    43 #include <assert.h>
     41#include <preemption.h>
     42#include <arch/asm.h>
     43
     44#ifdef CONFIG_SMP
     45
     46typedef struct spinlock {
     47        atomic_flag flag;
     48
     49#ifdef CONFIG_DEBUG_SPINLOCK
     50        const char *name;
     51#endif /* CONFIG_DEBUG_SPINLOCK */
     52} spinlock_t;
     53
     54/*
     55 * SPINLOCK_DECLARE is to be used for dynamically allocated spinlocks,
     56 * where the lock gets initialized in run time.
     57 */
     58#define SPINLOCK_DECLARE(lock_name)  spinlock_t lock_name
     59#define SPINLOCK_EXTERN(lock_name)   extern spinlock_t lock_name
     60
     61/*
     62 * SPINLOCK_INITIALIZE and SPINLOCK_STATIC_INITIALIZE are to be used
     63 * for statically allocated spinlocks. They declare (either as global
     64 * or static) symbol and initialize the lock.
     65 */
     66#ifdef CONFIG_DEBUG_SPINLOCK
     67
     68#define SPINLOCK_INITIALIZE_NAME(lock_name, desc_name) \
     69        spinlock_t lock_name = { \
     70                .name = desc_name, \
     71                .flag = ATOMIC_FLAG_INIT \
     72        }
     73
     74#define SPINLOCK_STATIC_INITIALIZE_NAME(lock_name, desc_name) \
     75        static spinlock_t lock_name = { \
     76                .name = desc_name, \
     77                .flag = ATOMIC_FLAG_INIT \
     78        }
     79
     80#define ASSERT_SPINLOCK(expr, lock) \
     81        assert_verbose(expr, (lock)->name)
     82
     83#define spinlock_lock(lock)    spinlock_lock_debug((lock))
     84#define spinlock_unlock(lock)  spinlock_unlock_debug((lock))
     85
     86#else /* CONFIG_DEBUG_SPINLOCK */
     87
     88#define SPINLOCK_INITIALIZE_NAME(lock_name, desc_name) \
     89        spinlock_t lock_name = { \
     90                .flag = ATOMIC_FLAG_INIT \
     91        }
     92
     93#define SPINLOCK_STATIC_INITIALIZE_NAME(lock_name, desc_name) \
     94        static spinlock_t lock_name = { \
     95                .flag = ATOMIC_FLAG_INIT \
     96        }
     97
     98#define ASSERT_SPINLOCK(expr, lock) \
     99        assert(expr)
     100
     101/** Acquire spinlock
     102 *
     103 * @param lock  Pointer to spinlock_t structure.
     104 */
     105_NO_TRACE static inline void spinlock_lock(spinlock_t *lock)
     106{
     107        preemption_disable();
     108        while (atomic_flag_test_and_set_explicit(&lock->flag,
     109            memory_order_acquire))
     110                ;
     111}
     112
     113/** Release spinlock
     114 *
     115 * @param lock  Pointer to spinlock_t structure.
     116 */
     117_NO_TRACE static inline void spinlock_unlock(spinlock_t *lock)
     118{
     119        atomic_flag_clear_explicit(&lock->flag, memory_order_release);
     120        preemption_enable();
     121}
     122
     123#endif /* CONFIG_DEBUG_SPINLOCK */
     124
     125#define SPINLOCK_INITIALIZE(lock_name) \
     126        SPINLOCK_INITIALIZE_NAME(lock_name, #lock_name)
     127
     128#define SPINLOCK_STATIC_INITIALIZE(lock_name) \
     129        SPINLOCK_STATIC_INITIALIZE_NAME(lock_name, #lock_name)
     130
     131extern void spinlock_initialize(spinlock_t *, const char *);
     132extern bool spinlock_trylock(spinlock_t *);
     133extern void spinlock_lock_debug(spinlock_t *);
     134extern void spinlock_unlock_debug(spinlock_t *);
     135extern bool spinlock_locked(spinlock_t *);
     136
     137#ifdef CONFIG_DEBUG_SPINLOCK
     138
     139#include <log.h>
    44140
    45141#define DEADLOCK_THRESHOLD  100000000
    46 
    47 #if defined(CONFIG_SMP) && defined(CONFIG_DEBUG_SPINLOCK)
    48 
    49 #include <log.h>
    50142
    51143#define DEADLOCK_PROBE_INIT(pname)  size_t pname = 0
     
    67159#endif /* CONFIG_DEBUG_SPINLOCK */
    68160
    69 typedef struct spinlock {
    70 #ifdef CONFIG_SMP
    71         atomic_flag flag;
    72 
    73 #ifdef CONFIG_DEBUG_SPINLOCK
    74         const char *name;
    75 #endif /* CONFIG_DEBUG_SPINLOCK */
    76 #endif
    77 } spinlock_t;
    78 
    79 /*
    80  * SPINLOCK_DECLARE is to be used for dynamically allocated spinlocks,
    81  * where the lock gets initialized in run time.
    82  */
    83 #define SPINLOCK_DECLARE(lock_name)  spinlock_t lock_name
    84 #define SPINLOCK_EXTERN(lock_name)   extern spinlock_t lock_name
    85 
    86 #ifdef CONFIG_SMP
    87 #ifdef CONFIG_DEBUG_SPINLOCK
    88 #define SPINLOCK_INITIALIZER(desc_name) { .name = (desc_name), .flag = ATOMIC_FLAG_INIT }
    89 #else
    90 #define SPINLOCK_INITIALIZER(desc_name) { .flag = ATOMIC_FLAG_INIT }
    91 #endif
    92 #else
    93 #define SPINLOCK_INITIALIZER(desc_name) {}
    94 #endif
    95 
    96 /*
    97  * SPINLOCK_INITIALIZE and SPINLOCK_STATIC_INITIALIZE are to be used
    98  * for statically allocated spinlocks. They declare (either as global
    99  * or static) symbol and initialize the lock.
    100  */
    101 #define SPINLOCK_INITIALIZE_NAME(lock_name, desc_name) \
    102         spinlock_t lock_name = SPINLOCK_INITIALIZER(desc_name)
    103 
    104 #define SPINLOCK_STATIC_INITIALIZE_NAME(lock_name, desc_name) \
    105         static spinlock_t lock_name = SPINLOCK_INITIALIZER(desc_name)
    106 
    107 #if defined(CONFIG_SMP) && defined(CONFIG_DEBUG_SPINLOCK)
    108 #define ASSERT_SPINLOCK(expr, lock) assert_verbose(expr, (lock)->name)
    109 #else /* CONFIG_DEBUG_SPINLOCK */
    110 #define ASSERT_SPINLOCK(expr, lock) assert(expr)
    111 #endif /* CONFIG_DEBUG_SPINLOCK */
    112 
    113 #define SPINLOCK_INITIALIZE(lock_name) \
    114         SPINLOCK_INITIALIZE_NAME(lock_name, #lock_name)
    115 
    116 #define SPINLOCK_STATIC_INITIALIZE(lock_name) \
    117         SPINLOCK_STATIC_INITIALIZE_NAME(lock_name, #lock_name)
    118 
    119 #ifdef CONFIG_SMP
    120 
    121 extern void spinlock_initialize(spinlock_t *, const char *);
    122 extern bool spinlock_trylock(spinlock_t *);
    123 extern void spinlock_lock(spinlock_t *);
    124 extern void spinlock_unlock(spinlock_t *);
    125 extern bool spinlock_locked(spinlock_t *);
    126 
    127 #else
    128 
    129 #include <preemption.h>
    130 
    131 static inline void spinlock_initialize(spinlock_t *l, const char *name)
    132 {
    133 }
    134 
    135 static inline bool spinlock_trylock(spinlock_t *l)
    136 {
    137         preemption_disable();
    138         return true;
    139 }
    140 
    141 static inline void spinlock_lock(spinlock_t *l)
    142 {
    143         preemption_disable();
    144 }
    145 
    146 static inline void spinlock_unlock(spinlock_t *l)
    147 {
    148         preemption_enable();
    149 }
    150 
    151 static inline bool spinlock_locked(spinlock_t *l)
    152 {
    153         return true;
    154 }
    155 
    156 #endif
     161#else /* CONFIG_SMP */
     162
     163/* On UP systems, spinlocks are effectively left out. */
     164
     165/* Allow the use of spinlock_t as an incomplete type. */
     166typedef struct spinlock spinlock_t;
     167
     168#define SPINLOCK_DECLARE(name)
     169#define SPINLOCK_EXTERN(name)
     170
     171#define SPINLOCK_INITIALIZE(name)
     172#define SPINLOCK_STATIC_INITIALIZE(name)
     173
     174#define SPINLOCK_INITIALIZE_NAME(name, desc_name)
     175#define SPINLOCK_STATIC_INITIALIZE_NAME(name, desc_name)
     176
     177#define ASSERT_SPINLOCK(expr, lock)  assert(expr)
     178
     179#define spinlock_initialize(lock, name)
     180
     181#define spinlock_lock(lock)     preemption_disable()
     182#define spinlock_trylock(lock)  ({ preemption_disable(); 1; })
     183#define spinlock_unlock(lock)   preemption_enable()
     184#define spinlock_locked(lock)   1
     185#define spinlock_unlocked(lock) 1
     186
     187#define DEADLOCK_PROBE_INIT(pname)
     188#define DEADLOCK_PROBE(pname, value)
     189
     190#endif /* CONFIG_SMP */
    157191
    158192typedef struct {
    159         spinlock_t lock;              /**< Spinlock */
    160         bool guard;                   /**< Flag whether ipl is valid */
    161         ipl_t ipl;                    /**< Original interrupt level */
    162 #ifdef CONFIG_DEBUG_SPINLOCK
    163         _Atomic(struct cpu *) owner;  /**< Which cpu currently owns this lock */
    164 #endif
     193        SPINLOCK_DECLARE(lock);  /**< Spinlock */
     194        bool guard;              /**< Flag whether ipl is valid */
     195        ipl_t ipl;               /**< Original interrupt level */
    165196} irq_spinlock_t;
    166197
     
    168199#define IRQ_SPINLOCK_EXTERN(lock_name)   extern irq_spinlock_t lock_name
    169200
     201#ifdef CONFIG_SMP
     202
    170203#define ASSERT_IRQ_SPINLOCK(expr, irq_lock) \
    171204        ASSERT_SPINLOCK(expr, &((irq_lock)->lock))
    172 
    173 #define IRQ_SPINLOCK_INITIALIZER(desc_name) \
    174         { \
    175                 .lock = SPINLOCK_INITIALIZER(desc_name), \
    176                 .guard = false, \
    177                 .ipl = 0, \
    178         }
    179205
    180206/*
     
    183209 * as global or static symbol) and initialize the lock.
    184210 */
     211#ifdef CONFIG_DEBUG_SPINLOCK
     212
    185213#define IRQ_SPINLOCK_INITIALIZE_NAME(lock_name, desc_name) \
    186         irq_spinlock_t lock_name = IRQ_SPINLOCK_INITIALIZER(desc_name)
     214        irq_spinlock_t lock_name = { \
     215                .lock = { \
     216                        .name = desc_name, \
     217                        .flag = ATOMIC_FLAG_INIT \
     218                }, \
     219                .guard = false, \
     220                .ipl = 0 \
     221        }
    187222
    188223#define IRQ_SPINLOCK_STATIC_INITIALIZE_NAME(lock_name, desc_name) \
    189         static irq_spinlock_t lock_name = IRQ_SPINLOCK_INITIALIZER(desc_name)
     224        static irq_spinlock_t lock_name = { \
     225                .lock = { \
     226                        .name = desc_name, \
     227                        .flag = ATOMIC_FLAG_INIT \
     228                }, \
     229                .guard = false, \
     230                .ipl = 0 \
     231        }
     232
     233#else /* CONFIG_DEBUG_SPINLOCK */
     234
     235#define IRQ_SPINLOCK_INITIALIZE_NAME(lock_name, desc_name) \
     236        irq_spinlock_t lock_name = { \
     237                .lock = { \
     238                        .flag = ATOMIC_FLAG_INIT \
     239                }, \
     240                .guard = false, \
     241                .ipl = 0 \
     242        }
     243
     244#define IRQ_SPINLOCK_STATIC_INITIALIZE_NAME(lock_name, desc_name) \
     245        static irq_spinlock_t lock_name = { \
     246                .lock = { \
     247                        .flag = ATOMIC_FLAG_INIT \
     248                }, \
     249                .guard = false, \
     250                .ipl = 0 \
     251        }
     252
     253#endif /* CONFIG_DEBUG_SPINLOCK */
     254
     255#else /* CONFIG_SMP */
     256
     257/*
     258 * Since the spinlocks are void on UP systems, we also need
     259 * to have a special variant of interrupts-disabled spinlock
     260 * macros which take this into account.
     261 */
     262
     263#define ASSERT_IRQ_SPINLOCK(expr, irq_lock) \
     264        ASSERT_SPINLOCK(expr, NULL)
     265
     266#define IRQ_SPINLOCK_INITIALIZE_NAME(lock_name, desc_name) \
     267        irq_spinlock_t lock_name = { \
     268                .guard = false, \
     269                .ipl = 0 \
     270        }
     271
     272#define IRQ_SPINLOCK_STATIC_INITIALIZE_NAME(lock_name, desc_name) \
     273        static irq_spinlock_t lock_name = { \
     274                .guard = false, \
     275                .ipl = 0 \
     276        }
     277
     278#endif /* CONFIG_SMP */
    190279
    191280#define IRQ_SPINLOCK_INITIALIZE(lock_name) \
Note: See TracChangeset for help on using the changeset viewer.