CPPMyth
Library to interoperate with MythTV server
Loading...
Searching...
No Matches
latch.h
1#pragma once
2/*
3 * Copyright (C) 2026 Jean-Luc Barriere
4 *
5 * This library is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published
7 * by the Free Software Foundation; either version 3, or (at your option)
8 * any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this library; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1301 USA
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23#include "os-threads.h"
24#include "atomic.h"
25
26#ifdef NSROOT
27namespace NSROOT {
28#endif
29namespace OS
30{
31
32 class Latch
33 {
34 public:
35 Latch();
36 Latch(bool _px);
37 ~Latch();
38
39 /* Locks the latch for exclusive ownership,
40 * blocks if the latch is not available
41 */
42 void lock();
43
44 /* Unlocks the latch (exclusive ownership) */
45 void unlock();
46
47 /* Locks the latch for shared ownership,
48 * blocks if the latch is not available
49 */
50 void lock_shared();
51
52 /* Unlocks the latch (shared ownership) */
53 void unlock_shared();
54
55 /* Tries to lock the latch for shared ownership,
56 * returns true if the latch has no exclusive ownership or any request for
57 * exclusive ownership, else false
58 */
59 bool try_lock_shared();
60
61 // Prevent copy
62 Latch(const Latch& other) = delete;
63 Latch& operator=(const Latch& other) = delete;
64
65 private:
66 mutable Atomic s_spin;
67 thread_t x_owner;
68
69 int x_wait; /* counts requests in wait for X */
70 int x_flag; /* X status: 0, 1, 2, or 3 */
71
72 mutex_t x_gate_lock;
73 condition_t x_gate; /* wait for release of X */
74 mutex_t s_gate_lock;
75 condition_t s_gate; /* wait for release of S */
76
77 bool px; /* enable X precedence */
78
79 struct TNode {
80 TNode * _prev;
81 TNode * _next;
82 thread_t id;
83 int count;
84 };
85 TNode * s_freed;
86 TNode * s_nodes;
87
88 void spin_lock()
89 {
90 while (s_spin.increment() != 1)
91 {
92 do
93 {
94 sched_yield();
95 } while (s_spin.load() != 0);
96 }
97 }
98 void spin_unlock() { s_spin.store(0); }
99
100 void init();
101 TNode * find_node(const thread_t& id);
102 TNode * new_node(const thread_t& id);
103 void free_node(TNode * n);
104 };
105
106 class ReadLock
107 {
108 private:
109 Latch *p;
110 bool owns;
111
112 public:
113
114 static struct adopt_lock_t { } adopt_lock;
115
116 ReadLock() : p(nullptr), owns(false) { }
117
118 ReadLock(Latch& latch) : p(&latch), owns(true) { latch.lock_shared(); }
119
120 /* Assume the calling thread already has ownership of the shared lock */
121 ReadLock(Latch& latch, adopt_lock_t) : p(&latch), owns(true) { }
122
123 ~ReadLock()
124 {
125 if (owns)
126 {
127 p->unlock_shared();
128 }
129 }
130
131 void swap(ReadLock& rl)
132 {
133 Latch * _p = p;
134 bool _owns = owns;
135 p = rl.p;
136 owns = rl.owns;
137 rl.p = _p;
138 rl.owns = _owns;
139 }
140
141 bool owns_lock() const
142 {
143 return owns;
144 }
145
146 void lock()
147 {
148 if (!owns && p != nullptr)
149 {
150 p->lock_shared();
151 owns = true;
152 }
153 }
154
155 void unlock()
156 {
157 if (owns)
158 {
159 owns = false;
160 p->unlock_shared();
161 }
162 }
163
164 bool try_lock()
165 {
166 if (!owns && p != nullptr)
167 {
168 owns = p->try_lock_shared();
169 }
170 return owns;
171 }
172
173 ReadLock(const ReadLock& other) = delete;
174 ReadLock& operator=(const ReadLock& other) = delete;
175 };
176
177 class WriteLock
178 {
179 private:
180 Latch *p;
181 bool owns;
182
183 public:
184
185 WriteLock() : p(nullptr), owns(false) { }
186
187 explicit WriteLock(Latch& latch) : p(&latch), owns(true) { latch.lock(); }
188
189 ~WriteLock()
190 {
191 if (owns)
192 {
193 p->unlock();
194 }
195 }
196
197 void swap(WriteLock& wl)
198 {
199 Latch * _p = p;
200 bool _owns = owns;
201 p = wl.p;
202 owns = wl.owns;
203 wl.p = _p;
204 wl.owns = _owns;
205 }
206
207 bool owns_lock() const
208 {
209 return owns;
210 }
211
212 void lock()
213 {
214 if (!owns && p != nullptr)
215 {
216 p->lock();
217 owns = true;
218 }
219 }
220
221 void unlock()
222 {
223 if (owns)
224 {
225 owns = false;
226 p->unlock();
227 }
228 }
229
230 WriteLock(const WriteLock& other) = delete;
231 WriteLock& operator=(const WriteLock& other) = delete;
232 };
233
234}
235#ifdef NSROOT
236}
237#endif