KallistiOS git master
Independent SDK for the Sega Dreamcast
Loading...
Searching...
No Matches
spinlock.h
Go to the documentation of this file.
1/* KallistiOS ##version##
2
3 include/kos/spinlock.h
4 Copyright (C) 2001 Megan Potter
5
6*/
7
8/** \file kos/spinlock.h
9 \brief Simple locking.
10 \ingroup kthreads
11
12 This file contains definitions for very simple locks. Most of the time, you
13 will probably not use such low-level locking, but will opt for something
14 more fully featured like mutexes, semaphores, or reader-writer semaphores.
15
16 \author Megan Potter
17
18 \see kos/sem.h
19 \see kos/mutex.h
20 \see kos/rwsem.h
21*/
22
23#ifndef __KOS_SPINLOCK_H
24#define __KOS_SPINLOCK_H
25
26#include <kos/cdefs.h>
27
28/* These can only be used in C */
29#if !defined(__cplusplus)
30
31#include <stdatomic.h>
32#include <stdbool.h>
33#include <kos/thread.h>
34
35
36/** \brief Spinlock data type. */
37typedef volatile int spinlock_t;
38
39/** \brief Spinlock initializer.
40
41 All created spinlocks should be initialized with this initializer so that
42 they are in a sane state, ready to be used.
43*/
44#define SPINLOCK_INITIALIZER 0
45
46/** \brief Initialize a spinlock.
47
48 This function abstracts initializing a spinlock, in case the
49 initializer is not applicable to what you are doing.
50
51 \param lock A pointer to the spinlock to be initialized.
52*/
53static inline void spinlock_init(spinlock_t *lock) {
55}
56
57/* Note here that even if threads aren't enabled, we'll still set the
58 lock so that it can be used for anti-IRQ protection (e.g., malloc) */
59
60/** \brief Try to lock, without spinning.
61
62 This function will attempt to lock the lock, but will not spin. Instead, it
63 will return whether the lock was obtained or not.
64
65 \param lock A pointer to the spinlock to be locked.
66 \return False if the lock is held by another thread. True if
67 the lock was successfully obtained.
68*/
69static inline bool spinlock_trylock(spinlock_t *lock) {
70 int locked = 0;
71 return atomic_compare_exchange_strong_explicit(
72 lock,
73 &locked,
74 1,
75 memory_order_acquire,
76 memory_order_relaxed
77 );
78}
79
80/** \brief Spin on a lock.
81
82 This function will spin on the lock, and will not return until the lock has
83 been obtained for the calling thread.
84
85 \param lock A pointer to the spinlock to be locked.
86*/
87static inline void spinlock_lock(spinlock_t *lock) {
88 while(!spinlock_trylock(lock))
89 thd_pass();
90}
91
92/** \brief Spin on a lock.
93
94 This function will spin on the lock, and will not return until the lock has
95 been obtained for the calling thread, unless it is called from within an
96 interrupt context.
97
98 \param lock A pointer to the spinlock to be locked.
99 \return True if the spinlock could be locked, false otherwise.
100*/
102 if(irq_inside_int())
103 return spinlock_trylock(lock);
104
106 return true;
107}
108
109/** \brief Free a lock.
110
111 This function will unlock the lock that is currently held by the calling
112 thread. Do not use this function unless you actually hold the lock!
113
114 \param lock A pointer to the spinlock to be unlocked.
115*/
116static inline void spinlock_unlock(spinlock_t *lock) {
117 *lock = 0;
118}
119
120/** \brief Determine if a lock is locked.
121
122 This function will return whether or not the lock specified is actually locked
123 when it is called. This is NOT a thread-safe way of determining if a lock
124 will be locked when you get around to locking it!
125
126 \param lock A pointer to the spinlock to be checked.
127 \return True if the spinlock is locked, false otherwise.
128*/
129static inline bool spinlock_is_locked(const spinlock_t *lock) {
130 return *lock != 0;
131}
132
133/** \cond INTERNAL */
134static inline void __spinlock_scoped_cleanup(spinlock_t **lock) {
136}
137
138#define ___spinlock_lock_scoped(m, l) \
139 spinlock_t *__scoped_spinlock_##l __attribute__((cleanup(__spinlock_scoped_cleanup))) = (spinlock_lock(m), (m))
140#define __spinlock_lock_scoped(m, l) ___spinlock_lock_scoped(m, l)
141/** \endcond */
142
143/** \brief Spin on a lock with scope management.
144
145 This macro will spin on the lock, similar to spinlock_lock(), with the
146 difference that the lock will automatically be freed once the execution
147 exits the functional block in which the macro was called.
148
149 \param lock A pointer to the spinlock to be locked.
150*/
151#define spinlock_lock_scoped(lock) \
152 __spinlock_lock_scoped((lock), __LINE__)
153
154#endif /* !defined(__cplusplus) */
155
156#endif /* __KOS_SPINLOCK_H */
Various common macros used throughout the codebase.
static bool irq_inside_int(void)
Returns whether inside of an interrupt context.
Definition irq.h:137
void thd_pass(void)
Throw away the current thread's timeslice.
static void spinlock_unlock(spinlock_t *lock)
Free a lock.
Definition spinlock.h:116
static bool spinlock_trylock(spinlock_t *lock)
Try to lock, without spinning.
Definition spinlock.h:69
static void spinlock_init(spinlock_t *lock)
Initialize a spinlock.
Definition spinlock.h:53
static bool spinlock_is_locked(const spinlock_t *lock)
Determine if a lock is locked.
Definition spinlock.h:129
#define SPINLOCK_INITIALIZER
Spinlock initializer.
Definition spinlock.h:44
volatile int spinlock_t
Spinlock data type.
Definition spinlock.h:37
static void spinlock_lock(spinlock_t *lock)
Spin on a lock.
Definition spinlock.h:87
static bool spinlock_lock_irqsafe(spinlock_t *lock)
Spin on a lock.
Definition spinlock.h:101
static mutex_t lock
Definition once_test.c:30
Threading support.