1 // Copyright 2020 The Pigweed Authors
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
7 // https://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
18 #include "pw_preprocessor/util.h"
22 #include "pw_sync_backend/spin_lock_native.h"
26 // The SpinLock is a synchronization primitive that can be used to protect
27 // shared data from being simultaneously accessed by multiple threads and/or
28 // IRQs as a targeted global lock (except for NMIs).
29 // It offers exclusive, non-recursive ownership semantics where IRQs up to a
30 // backend defined level of "NMIs" will be masked to solve priority-inversion.
32 // NOTE: This SpinLock relies on built-in local interrupt masking to make it IRQ
33 // safe without requiring the caller to mask interrupts manually when using this
36 // Unlike global interrupt locks, this also works safely and efficiently on SMP
37 // systems. This entire API is IRQ safe.
39 // WARNING: Code that holds a specific SpinLock must not try to re-acquire it
40 // or it will deadlock. However, it is okay to nest distinct spinlocks.
42 // WARNING: In order to support global statically constructed SpinLocks, the
43 // backend MUST ensure that any initialization required in your environment
44 // prior to the creation and/or initialization of the native semaphore
45 // (e.g. kernel initialization), is done before or during the invocation of the
46 // global static C++ constructors.
49 using native_handle_type = backend::NativeSpinLockHandle;
52 ~SpinLock() = default;
53 SpinLock(const SpinLock&) = delete;
54 SpinLock(SpinLock&&) = delete;
55 SpinLock& operator=(const SpinLock&) = delete;
56 SpinLock& operator=(SpinLock&&) = delete;
58 // Locks the spinlock, blocking indefinitely. Failures are fatal.
61 // Attempts to lock the spinlock in a non-blocking manner.
62 // Returns true if the spinlock was successfully acquired.
65 // Unlocks the spinlock. Failures are fatal.
68 native_handle_type native_handle();
71 // This may be a wrapper around a native type with additional members.
72 backend::NativeSpinLock native_type_;
75 } // namespace pw::sync
77 #include "pw_sync_backend/spin_lock_inline.h"
79 using pw_sync_SpinLock = pw::sync::SpinLock;
81 #else // !defined(__cplusplus)
83 typedef struct pw_sync_SpinLock pw_sync_SpinLock;
89 void pw_sync_SpinLock_Lock(pw_sync_SpinLock* spin_lock);
90 bool pw_sync_SpinLock_TryLock(pw_sync_SpinLock* spin_lock);
91 void pw_sync_SpinLock_Unlock(pw_sync_SpinLock* spin_lock);