Serenity Operating System
1/*
2 * Copyright (c) 2021, the SerenityOS developers.
3 * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 */
7
8#pragma once
9
10#include <Kernel/Locking/Mutex.h>
11
12namespace Kernel {
13
14template<typename T>
15class MutexProtected {
16 AK_MAKE_NONCOPYABLE(MutexProtected);
17 AK_MAKE_NONMOVABLE(MutexProtected);
18
19private:
20 template<typename U, LockMode lock_mode>
21 class Locked {
22 AK_MAKE_NONCOPYABLE(Locked);
23 AK_MAKE_NONMOVABLE(Locked);
24
25 public:
26 Locked(U& value, Mutex& mutex, LockLocation const& location)
27 : m_value(value)
28 , m_locker(mutex, lock_mode, location)
29 {
30 }
31
32 ALWAYS_INLINE U const* operator->() const { return &m_value; }
33 ALWAYS_INLINE U const& operator*() const { return m_value; }
34
35 ALWAYS_INLINE U* operator->()
36 requires(!IsConst<U>)
37 {
38 return &m_value;
39 }
40 ALWAYS_INLINE U& operator*()
41 requires(!IsConst<U>)
42 {
43 return m_value;
44 }
45
46 ALWAYS_INLINE U const& get() const { return &m_value; }
47 ALWAYS_INLINE U& get()
48 requires(!IsConst<U>)
49 {
50 return &m_value;
51 }
52
53 private:
54 U& m_value;
55 MutexLocker m_locker;
56 };
57
58 auto lock_shared(LockLocation const& location) const { return Locked<T const, LockMode::Shared>(m_value, m_mutex, location); }
59 auto lock_exclusive(LockLocation const& location) { return Locked<T, LockMode::Exclusive>(m_value, m_mutex, location); }
60
61public:
62 MutexProtected() = default;
63
64 template<typename Callback>
65 decltype(auto) with_shared(Callback callback, LockLocation const& location = LockLocation::current()) const
66 {
67 auto lock = lock_shared(location);
68 return callback(*lock);
69 }
70
71 template<typename Callback>
72 decltype(auto) with_exclusive(Callback callback, LockLocation const& location = LockLocation::current())
73 {
74 auto lock = lock_exclusive(location);
75 return callback(*lock);
76 }
77
78 template<typename Callback>
79 void for_each_shared(Callback callback, LockLocation const& location = LockLocation::current()) const
80 {
81 with_shared([&](auto const& value) {
82 for (auto& item : value)
83 callback(item);
84 },
85 location);
86 }
87
88 template<typename Callback>
89 void for_each_exclusive(Callback callback, LockLocation const& location = LockLocation::current())
90 {
91 with_exclusive([&](auto& value) {
92 for (auto& item : value)
93 callback(item);
94 },
95 location);
96 }
97
98private:
99 T m_value;
100 Mutex mutable m_mutex;
101};
102
103}