Serenity Operating System
1/*
2 * Copyright (c) 2021, the SerenityOS developers.
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#pragma once
8
9#include <Kernel/Locking/Spinlock.h>
10
11namespace Kernel {
12
13template<typename T, LockRank Rank>
14class SpinlockProtected {
15 AK_MAKE_NONCOPYABLE(SpinlockProtected);
16 AK_MAKE_NONMOVABLE(SpinlockProtected);
17
18private:
19 template<typename U>
20 class Locked {
21 AK_MAKE_NONCOPYABLE(Locked);
22 AK_MAKE_NONMOVABLE(Locked);
23
24 public:
25 Locked(U& value, RecursiveSpinlock<Rank>& spinlock)
26 : m_value(value)
27 , m_locker(spinlock)
28 {
29 }
30
31 ALWAYS_INLINE U const* operator->() const { return &m_value; }
32 ALWAYS_INLINE U const& operator*() const { return m_value; }
33
34 ALWAYS_INLINE U* operator->() { return &m_value; }
35 ALWAYS_INLINE U& operator*() { return m_value; }
36
37 ALWAYS_INLINE U const& get() const { return m_value; }
38 ALWAYS_INLINE U& get() { return m_value; }
39
40 private:
41 U& m_value;
42 SpinlockLocker<RecursiveSpinlock<Rank>> m_locker;
43 };
44
45 auto lock_const() const { return Locked<T const>(m_value, m_spinlock); }
46 auto lock_mutable() { return Locked<T>(m_value, m_spinlock); }
47
48public:
49 template<typename... Args>
50 SpinlockProtected(Args&&... args)
51 : m_value(forward<Args>(args)...)
52 {
53 }
54
55 template<typename Callback>
56 decltype(auto) with(Callback callback) const
57 {
58 auto lock = lock_const();
59 return callback(*lock);
60 }
61
62 template<typename Callback>
63 decltype(auto) with(Callback callback)
64 {
65 auto lock = lock_mutable();
66 return callback(*lock);
67 }
68
69 template<typename Callback>
70 void for_each_const(Callback callback) const
71 {
72 with([&](auto const& value) {
73 for (auto& item : value)
74 callback(item);
75 });
76 }
77
78 template<typename Callback>
79 void for_each(Callback callback)
80 {
81 with([&](auto& value) {
82 for (auto& item : value)
83 callback(item);
84 });
85 }
86
87private:
88 T m_value;
89 RecursiveSpinlock<Rank> mutable m_spinlock;
90 static constexpr LockRank const m_rank { Rank };
91};
92
93}