1 /*
2  * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 #ifndef SQUID_CBC_POINTER_H
10 #define SQUID_CBC_POINTER_H
11 
12 #include "base/TextException.h"
13 #include "cbdata.h"
14 #include "Debug.h"
15 
16 /**
17  \ingroup CBDATAAPI
18  *
19  * Safely points to a cbdata-protected class (cbc), such as an AsyncJob.
20  * When a cbc we communicate with disappears without
21  * notice or a notice has not reached us yet, this class prevents
22  * dereferencing the pointer to the gone cbc object.
23  */
24 template<class Cbc>
25 class CbcPointer
26 {
27 public:
28     CbcPointer(); // a nil pointer
29     CbcPointer(Cbc *aCbc);
30     CbcPointer(const CbcPointer &p);
31     CbcPointer(CbcPointer &&);
32     ~CbcPointer();
33 
34     Cbc *raw() const; ///< a temporary raw Cbc pointer; may be invalid
35     Cbc *get() const; ///< a temporary valid raw Cbc pointer or NULL
36     Cbc &operator *() const; ///< a valid Cbc reference or exception
37     Cbc *operator ->() const; ///< a valid Cbc pointer or exception
38 
39     // no bool operator because set() != valid()
set()40     bool set() const { return cbc != NULL; } ///< was set but may be invalid
valid()41     Cbc *valid() const { return get(); } ///< was set and is valid
42     bool operator !() const { return !valid(); } ///< invalid or was not set
43     bool operator ==(const CbcPointer<Cbc> &o) const { return lock == o.lock; }
44 
45     CbcPointer &operator =(const CbcPointer &p);
46     CbcPointer &operator =(CbcPointer &&);
47 
48     /// support converting a child cbc pointer into a parent cbc pointer
49     template <typename Other>
CbcPointer(const CbcPointer<Other> & o)50     CbcPointer(const CbcPointer<Other> &o): cbc(o.raw()), lock(NULL) {
51         if (o.valid())
52             lock = cbdataReference(o->toCbdata());
53     }
54 
55     /// support assigning a child cbc pointer to a parent cbc pointer
56     template <typename Other>
57     CbcPointer &operator =(const CbcPointer<Other> &o) {
58         if (this != &o) { // assignment to self
59             clear();
60             cbc = o.raw(); // so that set() is accurate
61             if (o.valid())
62                 lock = cbdataReference(o->toCbdata());
63         }
64         return *this;
65     }
66 
67     void clear(); ///< make pointer not set; does not invalidate cbdata
68 
69     std::ostream &print(std::ostream &os) const;
70 
71 private:
72     Cbc *cbc; // a possibly invalid pointer to a cbdata class
73     void *lock; // a valid pointer to cbc's cbdata or nil
74 };
75 
76 template <class Cbc>
77 inline
78 std::ostream &operator <<(std::ostream &os, const CbcPointer<Cbc> &p)
79 {
80     return p.print(os);
81 }
82 
83 // inlined methods
84 
85 template<class Cbc>
CbcPointer()86 CbcPointer<Cbc>::CbcPointer(): cbc(NULL), lock(NULL)
87 {
88 }
89 
90 template<class Cbc>
CbcPointer(Cbc * aCbc)91 CbcPointer<Cbc>::CbcPointer(Cbc *aCbc): cbc(aCbc), lock(NULL)
92 {
93     if (cbc)
94         lock = cbdataReference(cbc->toCbdata());
95 }
96 
97 template<class Cbc>
CbcPointer(const CbcPointer & d)98 CbcPointer<Cbc>::CbcPointer(const CbcPointer &d): cbc(d.cbc), lock(NULL)
99 {
100     if (d.lock && cbdataReferenceValid(d.lock))
101         lock = cbdataReference(d.lock);
102 }
103 
104 template<class Cbc>
CbcPointer(CbcPointer && d)105 CbcPointer<Cbc>::CbcPointer(CbcPointer &&d): cbc(d.cbc), lock(d.lock)
106 {
107     d.cbc = nullptr;
108     d.lock = nullptr;
109 }
110 
111 template<class Cbc>
~CbcPointer()112 CbcPointer<Cbc>::~CbcPointer()
113 {
114     clear();
115 }
116 
117 template<class Cbc>
118 CbcPointer<Cbc> &CbcPointer<Cbc>::operator =(const CbcPointer &d)
119 {
120     if (this != &d) { // assignment to self
121         clear();
122         cbc = d.cbc;
123         if (d.lock && cbdataReferenceValid(d.lock))
124             lock = cbdataReference(d.lock);
125     }
126     return *this;
127 }
128 
129 template<class Cbc>
130 CbcPointer<Cbc> &CbcPointer<Cbc>::operator =(CbcPointer &&d)
131 {
132     if (this != &d) { // assignment to self
133         clear();
134         cbc = d.cbc;
135         d.cbc = nullptr;
136         lock = d.lock;
137         d.lock = nullptr;
138     }
139     return *this;
140 }
141 
142 template<class Cbc>
143 void
clear()144 CbcPointer<Cbc>::clear()
145 {
146 #if USE_CBDATA_DEBUG
147     debugs(45, 3, "cbc=" << (void*)cbc << ", lock=" << (void*)lock);
148 #endif
149     cbdataReferenceDone(lock); // lock may be nil before and will be nil after
150     cbc = NULL;
151 }
152 
153 template<class Cbc>
154 Cbc *
raw()155 CbcPointer<Cbc>::raw() const
156 {
157     return cbc;
158 }
159 
160 template<class Cbc>
161 Cbc *
get()162 CbcPointer<Cbc>::get() const
163 {
164     return (lock && cbdataReferenceValid(lock)) ? cbc : NULL;
165 }
166 
167 template<class Cbc>
168 Cbc &
169 CbcPointer<Cbc>::operator *() const
170 {
171     Cbc *c = get();
172     assert(c);
173     return *c;
174 }
175 
176 template<class Cbc>
177 Cbc *
178 CbcPointer<Cbc>::operator ->() const
179 {
180     Cbc *c = get();
181     assert(c);
182     return c;
183 }
184 
185 template <class Cbc>
print(std::ostream & os)186 std::ostream &CbcPointer<Cbc>::print(std::ostream &os) const
187 {
188     return os << cbc << '/' << lock;
189 }
190 
191 #endif /* SQUID_CBC_POINTER_H */
192 
193