Qore Programming Language 1.19.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 - 2023 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 {
42private:
43 DLLLOCAL RNotifier(const RNotifier&);
44 DLLLOCAL RNotifier& operator=(const RNotifier&);
45
46public:
47 bool setp;
50
51 DLLLOCAL RNotifier() : setp(false) {
52 }
53
54 DLLLOCAL ~RNotifier() {
55 assert(!setp);
56 }
57
58 DLLLOCAL void done() {
59 AutoLocker al(m);
60 assert(setp);
61 setp = false;
62 c.signal();
63 }
64
65 DLLLOCAL void set() {
66 AutoLocker al(m);
67 assert(!setp);
68 setp = true;
69 }
70
71 DLLLOCAL void wait() {
72 AutoLocker al(m);
73
74 while (setp)
75 c.wait(m);
76 }
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 {
85private:
86 // not implemented, listed here to prevent implicit usage
87 qore_rsection_priv(const qore_rsection_priv&) = delete;
88 qore_rsection_priv& operator=(const qore_rsection_priv&) = delete;
89
90protected:
91 // tid of thread holding the rsection lock
92 int rs_tid;
93
94 // number of threads waiting on the rsection lock
95 int rsection_waiting;
96
97 // rsection condition variablt
98 QoreCondition rsection_cond;
99
100 // list of ObjectRSetHelper objects for notifications for rsection management
101 n_list_t list;
102
103 // notify rsection threads that the rsection lock has been released
104 DLLLOCAL virtual void notifyIntern() {
105 for (n_list_t::iterator i = list.begin(), e = list.end(); i != e; ++i)
106 (*i)->done();
107 list.clear();
108 }
109
110 DLLLOCAL void setNotificationIntern(RNotifier* rn) {
111 assert(write_tid != -1 || rs_tid != -1);
112 list.push_back(rn);
113 rn->set();
114 //printd(5, "qrp::sNI t: %p r: %p\n", this, rn);
115 }
116
117public:
118 DLLLOCAL qore_rsection_priv() : rs_tid(-1), rsection_waiting(0) {
119 has_notify = true;
120 }
121
122 DLLLOCAL virtual ~qore_rsection_priv() {
123 assert(rs_tid == -1);
124 assert(list.empty());
125 }
126
127 // does not block if there is an rsection conflict, returns -1 if the lock cannot be acquired and sets a notification
128 DLLLOCAL int tryRSectionLockNotifyWaitRead(RNotifier* rn);
129
130 DLLLOCAL void upgradeReadToRSection(int tid = q_gettid()) {
131 AutoLocker al(l);
132 assert(write_tid == -1);
133
134 while (rs_tid != -1) {
135 ++rsection_waiting;
136 rsection_cond.wait(l);
137 --rsection_waiting;
138 }
139
140 rs_tid = tid;
141 }
142
143 DLLLOCAL void rSectionUnlock() {
144 AutoLocker al(l);
145 assert(write_tid == -1);
146 assert(rs_tid == q_gettid());
147 assert(readers);
148
149 // unlock rsection
150 rs_tid = -1;
151
152 qore_rsection_priv::notifyIntern();
153
154 if (rsection_waiting)
155 rsection_cond.signal();
156
157 if (!--readers)
158 unlock_read_signal();
159 }
160
161 DLLLOCAL bool hasRSectionLock(int tid = q_gettid()) {
162 return rs_tid == tid;
163 }
164
165 DLLLOCAL bool checkRSectionExclusive(int tid = q_gettid()) {
166 return (rs_tid == tid || write_tid == tid);
167 }
168
169 DLLLOCAL int rSectionTid() const {
170 return rs_tid;
171 }
172};
173
174class RSectionLock : public QoreVarRWLock {
175public:
176 DLLLOCAL RSectionLock() : QoreVarRWLock(new qore_rsection_priv) {
177 }
178
179 DLLLOCAL ~RSectionLock() {
180 }
181
182 // does not block under any circumstances, returns -1 if the lock cannot be acquired and sets a notification
183 DLLLOCAL int tryRSectionLockNotifyWaitRead(RNotifier* rn) {
184 return static_cast<qore_rsection_priv*>(priv)->tryRSectionLockNotifyWaitRead(rn);
185 }
186
187 DLLLOCAL void rSectionUnlock() {
188 static_cast<qore_rsection_priv*>(priv)->rSectionUnlock();
189 }
190
191 DLLLOCAL bool hasRSectionLock(int tid = q_gettid()) {
192 return static_cast<qore_rsection_priv*>(priv)->hasRSectionLock(tid);
193 }
194
195 DLLLOCAL bool checkRSectionExclusive(int tid = q_gettid()) {
196 return static_cast<qore_rsection_priv*>(priv)->checkRSectionExclusive(tid);
197 }
198
199 DLLLOCAL void upgradeReadToRSection(int tid = q_gettid()) {
200 static_cast<qore_rsection_priv*>(priv)->upgradeReadToRSection(tid);
201 }
202
203 DLLLOCAL int rSectionTid() const {
204 return static_cast<qore_rsection_priv*>(priv)->rSectionTid();
205 }
206};
207
208class QoreSafeRSectionReadLocker : private QoreSafeVarRWReadLocker {
209public:
210 DLLLOCAL QoreSafeRSectionReadLocker(RSectionLock& n_l) : QoreSafeVarRWReadLocker(n_l), has_rsection(false) {
211 }
212
213 DLLLOCAL ~QoreSafeRSectionReadLocker() {
214 if (locked && has_rsection) {
215 static_cast<RSectionLock*>(l)->rSectionUnlock();
216 locked = false;
217 }
218 }
219
220 DLLLOCAL void acquireRSection(int tid = q_gettid()) {
221 static_cast<RSectionLock*>(l)->upgradeReadToRSection(tid);
222 has_rsection = true;
223 }
224
226 DLLLOCAL void unlock() {
227 assert(locked);
228 locked = false;
229
230 if (has_rsection)
231 static_cast<RSectionLock*>(l)->rSectionUnlock();
232 else
233 l->unlock();
234 }
235
236private:
237 bool has_rsection;
238};
239
240class QoreRSectionLocker : private QoreSafeVarRWReadLocker {
241public:
242 DLLLOCAL QoreRSectionLocker(RSectionLock& n_l) : QoreSafeVarRWReadLocker(n_l) {
243 static_cast<RSectionLock*>(l)->upgradeReadToRSection();
244 }
245
246 DLLLOCAL ~QoreRSectionLocker() {
247 static_cast<RSectionLock*>(l)->rSectionUnlock();
248 locked = false;
249 }
250};
251
252#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