Qore Programming Language 2.1.1
Loading...
Searching...
No Matches
RSection.h
1/* -*- mode: c++; indent-tabs-mode: nil -*- */
2/*
3 RSection.h
4
5 Qore Programming Language
6
7 Copyright (C) 2003 - 2024 Qore Technologies, s.r.o.
8
9 Permission is hereby granted, free of charge, to any person obtaining a
10 copy of this software and associated documentation files (the "Software"),
11 to deal in the Software without restriction, including without limitation
12 the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 and/or sell copies of the Software, and to permit persons to whom the
14 Software is furnished to do so, subject to the following conditions:
15
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 DEALINGS IN THE SOFTWARE.
26
27 Note that the Qore library is released under a choice of three open-source
28 licenses: MIT (as above), LGPL 2+, or GPL 2+; see README-LICENSE for more
29 information.
30*/
31
32#ifndef _QORE_INTERN_RSECTION_H
33
34#define _QORE_INTERN_RSECTION_H
35
36#include "qore/intern/qore_var_rwlock_priv.h"
37
38// forward references
39class qore_rsection_priv;
40
41class RNotifier {
42public:
43 bool setp = false;
46
47 DLLLOCAL RNotifier() {
48 }
49
50 DLLLOCAL ~RNotifier() {
51 assert(!setp);
52 }
53
54 DLLLOCAL void done() {
55 AutoLocker al(m);
56 assert(setp);
57 setp = false;
58 c.signal();
59 }
60
61 DLLLOCAL void set() {
62 AutoLocker al(m);
63 assert(!setp);
64 setp = true;
65 }
66
67 DLLLOCAL void wait() {
68 AutoLocker al(m);
69 while (setp) {
70 c.wait(m);
71 }
72 }
73
74private:
75 RNotifier(const RNotifier&) = delete;
76 RNotifier& operator=(const RNotifier&) = delete;
77 };
78
79typedef std::list<RNotifier*> n_list_t;
80
81// rwlock with standard read and write lock handling and special "rsection" handling
82// the rsection is grabbed with the read lock but only one thread can have the rsection lock at once
83// leaving other threads to read the object normally
84class qore_rsection_priv : public qore_var_rwlock_priv {
85public:
86 DLLLOCAL qore_rsection_priv() {
87 has_notify = true;
88 }
89
90 DLLLOCAL virtual ~qore_rsection_priv() {
91 assert(rs_tid == -1);
92 assert(list.empty());
93 }
94
95 // does not block if there is an rsection conflict, returns -1 if the lock cannot be acquired and sets a
96 // notification
97 DLLLOCAL int tryRSectionLockNotifyWaitRead(RNotifier* rn);
98
99 DLLLOCAL void upgradeReadToRSection(int tid = q_gettid()) {
100 AutoLocker al(l);
101 assert(write_tid == -1);
102
103 while (rs_tid != -1) {
104 ++rsection_waiting;
105 rsection_cond.wait(l);
106 --rsection_waiting;
107 }
108
109 rs_tid = tid;
110 }
111
112 DLLLOCAL void rSectionUnlock() {
113 AutoLocker al(l);
114 assert(write_tid == -1);
115 assert(rs_tid == q_gettid());
116 assert(readers);
117
118 // unlock rsection
119 rs_tid = -1;
120
121 qore_rsection_priv::notifyIntern();
122
123 if (rsection_waiting)
124 rsection_cond.signal();
125
126 if (!--readers)
127 unlock_read_signal();
128 }
129
130 DLLLOCAL bool hasRSectionLock(int tid = q_gettid()) {
131 return rs_tid == tid;
132 }
133
134 DLLLOCAL bool checkRSectionExclusive(int tid = q_gettid()) {
135 return (rs_tid == tid || write_tid == tid);
136 }
137
138 DLLLOCAL int rSectionTid() const {
139 return rs_tid;
140 }
141
142protected:
143 // tid of thread holding the rsection lock
144 int rs_tid = -1;
145
146 // number of threads waiting on the rsection lock
147 int rsection_waiting = 0;
148
149 // rsection condition variablt
150 QoreCondition rsection_cond;
151
152 // list of ObjectRSetHelper objects for notifications for rsection management
153 n_list_t list;
154
155 // notify rsection threads that the rsection lock has been released
156 DLLLOCAL virtual void notifyIntern() {
157 for (n_list_t::iterator i = list.begin(), e = list.end(); i != e; ++i) {
158 (*i)->done();
159 }
160 list.clear();
161 }
162
163 DLLLOCAL void setNotificationIntern(RNotifier* rn) {
164 assert(write_tid != -1 || rs_tid != -1);
165 list.push_back(rn);
166 rn->set();
167 //printd(5, "qrp::sNI t: %p r: %p\n", this, rn);
168 }
169
170private:
171 qore_rsection_priv(const qore_rsection_priv&) = delete;
172 qore_rsection_priv& operator=(const qore_rsection_priv&) = delete;
173};
174
175class RSectionLock : public QoreVarRWLock {
176public:
177 DLLLOCAL RSectionLock() : QoreVarRWLock(new qore_rsection_priv) {
178 }
179
180 DLLLOCAL ~RSectionLock() {
181 }
182
183 // does not block under any circumstances, returns -1 if the lock cannot be acquired and sets a notification
184 DLLLOCAL int tryRSectionLockNotifyWaitRead(RNotifier* rn) {
185 assert(priv->write_tid >= -1);
186 return static_cast<qore_rsection_priv*>(priv)->tryRSectionLockNotifyWaitRead(rn);
187 }
188
189 DLLLOCAL void rSectionUnlock() {
190 assert(priv->write_tid >= -1);
191 static_cast<qore_rsection_priv*>(priv)->rSectionUnlock();
192 }
193
194 DLLLOCAL bool hasRSectionLock(int tid = q_gettid()) {
195 assert(priv->write_tid >= -1);
196 return static_cast<qore_rsection_priv*>(priv)->hasRSectionLock(tid);
197 }
198
199 DLLLOCAL bool checkRSectionExclusive(int tid = q_gettid()) {
200 assert(priv->write_tid >= -1);
201 return static_cast<qore_rsection_priv*>(priv)->checkRSectionExclusive(tid);
202 }
203
204 DLLLOCAL void upgradeReadToRSection(int tid = q_gettid()) {
205 assert(priv->write_tid >= -1);
206 static_cast<qore_rsection_priv*>(priv)->upgradeReadToRSection(tid);
207 }
208
209 DLLLOCAL int rSectionTid() const {
210 assert(priv->write_tid >= -1);
211 return static_cast<qore_rsection_priv*>(priv)->rSectionTid();
212 }
213};
214
215class QoreSafeRSectionReadLocker : private QoreSafeVarRWReadLocker {
216public:
217 DLLLOCAL QoreSafeRSectionReadLocker(RSectionLock& n_l) : QoreSafeVarRWReadLocker(n_l), has_rsection(false) {
218 }
219
220 DLLLOCAL ~QoreSafeRSectionReadLocker() {
221 if (locked && has_rsection) {
222 static_cast<RSectionLock*>(l)->rSectionUnlock();
223 locked = false;
224 }
225 }
226
227 DLLLOCAL void acquireRSection(int tid = q_gettid()) {
228 static_cast<RSectionLock*>(l)->upgradeReadToRSection(tid);
229 has_rsection = true;
230 }
231
233 DLLLOCAL void unlock() {
234 assert(locked);
235 locked = false;
236
237 if (has_rsection) {
238 static_cast<RSectionLock*>(l)->rSectionUnlock();
239 } else {
240 l->unlock();
241 }
242 }
243
244private:
245 bool has_rsection;
246};
247
248class QoreRSectionLocker : private QoreSafeVarRWReadLocker {
249public:
250 DLLLOCAL QoreRSectionLocker(RSectionLock& n_l) : QoreSafeVarRWReadLocker(n_l) {
251 static_cast<RSectionLock*>(l)->upgradeReadToRSection();
252 }
253
254 DLLLOCAL ~QoreRSectionLocker() {
255 static_cast<RSectionLock*>(l)->rSectionUnlock();
256 locked = false;
257 }
258};
259
260#endif
provides a safe and exception-safe way to hold locks in Qore, only to be used on the stack,...
Definition QoreThreadLock.h:136
a thread condition class implementing a wrapper for pthread_cond_t
Definition QoreCondition.h:45
DLLEXPORT int wait(pthread_mutex_t *m)
blocks a thread on a mutex until the condition is signaled
DLLEXPORT int signal()
signals a single waiting thread to wake up
provides a mutually-exclusive thread lock
Definition QoreThreadLock.h:49
DLLEXPORT int q_gettid() noexcept
returns the current TID number