pvxslibs 1.5.0__cp310-cp310-manylinux2014_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. pvxslibs/__init__.py +0 -0
  2. pvxslibs/dbd/pvxsIoc.dbd +8 -0
  3. pvxslibs/include/pvxs/client.h +1094 -0
  4. pvxslibs/include/pvxs/data.h +948 -0
  5. pvxslibs/include/pvxs/iochooks.h +170 -0
  6. pvxslibs/include/pvxs/log.h +148 -0
  7. pvxslibs/include/pvxs/netcommon.h +82 -0
  8. pvxslibs/include/pvxs/nt.h +208 -0
  9. pvxslibs/include/pvxs/server.h +238 -0
  10. pvxslibs/include/pvxs/sharedArray.h +748 -0
  11. pvxslibs/include/pvxs/sharedpv.h +121 -0
  12. pvxslibs/include/pvxs/source.h +290 -0
  13. pvxslibs/include/pvxs/srvcommon.h +148 -0
  14. pvxslibs/include/pvxs/unittest.h +327 -0
  15. pvxslibs/include/pvxs/util.h +354 -0
  16. pvxslibs/include/pvxs/version.h +97 -0
  17. pvxslibs/include/pvxs/versionNum.h +6 -0
  18. pvxslibs/ioc.py +10 -0
  19. pvxslibs/lib/__init__.py +0 -0
  20. pvxslibs/lib/event_core_dsoinfo.py +14 -0
  21. pvxslibs/lib/event_pthread_dsoinfo.py +14 -0
  22. pvxslibs/lib/libevent_core.so +0 -0
  23. pvxslibs/lib/libevent_core.so.2.2.0 +0 -0
  24. pvxslibs/lib/libevent_pthread.so +0 -0
  25. pvxslibs/lib/libevent_pthread.so.2.2.0 +0 -0
  26. pvxslibs/lib/libpvxs.so +0 -0
  27. pvxslibs/lib/libpvxs.so.1.5 +0 -0
  28. pvxslibs/lib/libpvxsIoc.so +0 -0
  29. pvxslibs/lib/libpvxsIoc.so.1.5 +0 -0
  30. pvxslibs/lib/pvxsIoc_dsoinfo.py +14 -0
  31. pvxslibs/lib/pvxs_dsoinfo.py +14 -0
  32. pvxslibs/path.py +12 -0
  33. pvxslibs/test/__init__.py +0 -0
  34. pvxslibs/test/test_load.py +30 -0
  35. pvxslibs/version.py +32 -0
  36. pvxslibs-1.5.0.dist-info/METADATA +44 -0
  37. pvxslibs-1.5.0.dist-info/RECORD +40 -0
  38. pvxslibs-1.5.0.dist-info/WHEEL +5 -0
  39. pvxslibs-1.5.0.dist-info/licenses/LICENSE +26 -0
  40. pvxslibs-1.5.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,327 @@
1
+ /**
2
+ * Copyright - See the COPYRIGHT that is included with this distribution.
3
+ * pvxs is distributed subject to a Software License Agreement found
4
+ * in file LICENSE that is included with this distribution.
5
+ */
6
+
7
+ #ifndef PVXS_UNITTEST_H
8
+ #define PVXS_UNITTEST_H
9
+
10
+ /** @file pvxs/unittest.h
11
+ *
12
+ * C++ helpers for use with epicsUnitTest.h
13
+ */
14
+
15
+ #include <sstream>
16
+ #include <vector>
17
+ #include <functional>
18
+ #include <type_traits>
19
+
20
+ #include <pvxs/version.h>
21
+ #include <pvxs/util.h>
22
+
23
+ namespace pvxs {
24
+
25
+ /** Prepare for testing. Call after testPlan()
26
+ * @since 1.2.0 If linked with pvxsIoc library, PVA server started
27
+ * by ``iocInit()`` will use "isolated" configuration.
28
+ */
29
+ PVXS_API
30
+ void testSetup();
31
+
32
+ /** Free some internal global allocations to avoid false positives in
33
+ * valgrind (or similar) tools looking for memory leaks.
34
+ *
35
+ * Calls libevent_global_shutdown() when available (libevent >=2.1).
36
+ *
37
+ * @warning This function is optional.
38
+ * If you don't understand the intended use case, then do not call it!
39
+ *
40
+ * @pre Caller must release all resources explicitly allocated through PVXS (on all threads).
41
+ * @post Invalidates internal state.
42
+ * Use of __any__ API functions afterwards is undefined!
43
+ */
44
+ PVXS_API
45
+ void cleanup_for_valgrind();
46
+
47
+ /** A single test case (or diagnostic line).
48
+ *
49
+ * Acts as an output string to accumulate test comment.
50
+ * Multi-line output results in one test line, and subsequent diagnostic lines.
51
+ *
52
+ * Test line is printed when an active (non-moved) testCase is destroyed.
53
+ */
54
+ class PVXS_API testCase
55
+ {
56
+ enum {
57
+ Nothing, // after move()'d
58
+ Diag, // no test, just print
59
+ Pass,
60
+ Fail,
61
+ } result;
62
+ std::ostringstream msg;
63
+ public:
64
+ //! new diag message
65
+ testCase();
66
+ //! new test case
67
+ explicit testCase(bool result);
68
+ testCase(const testCase&) = delete;
69
+ testCase& operator=(const testCase&) = delete;
70
+ testCase(testCase&&) noexcept;
71
+ testCase& operator=(testCase&&) noexcept;
72
+ ~testCase();
73
+
74
+ //! true when passing
75
+ explicit operator bool() const { return result==Pass; }
76
+
77
+ //! Override current pass/fail result
78
+ testCase& setPass(bool v) {
79
+ result = v ? Pass : Fail;
80
+ return *this;
81
+ }
82
+
83
+ //! Override current pass/fail result if input matches a regular expression
84
+ //! @since 0.2.1 Expression syntax is POSIX extended.
85
+ //! @since 0.1.1 Added
86
+ testCase& setPassMatch(const std::string& expr, const std::string& inp);
87
+
88
+ //! Append to message
89
+ template<typename T>
90
+ inline testCase& operator<<(const T& v) {
91
+ msg<<v;
92
+ return *this;
93
+ }
94
+
95
+ /** Access to underlying std::ostream used to accumulate notes.
96
+ * When our operator<< isn't enough.
97
+ * @since 1.1.4
98
+ */
99
+ inline
100
+ std::ostream& stream() { return msg; }
101
+ };
102
+
103
+ namespace detail {
104
+
105
+ // control how testEq() and testNotEq() print things
106
+ template<typename T, typename Enable=void>
107
+ struct test_print {
108
+ template<class C>
109
+ static inline void op(C& strm, const T& v) {
110
+ strm<<v;
111
+ }
112
+ };
113
+ template <>
114
+ struct test_print<std::string> {
115
+ template<class C>
116
+ static inline void op(C& strm, const std::string& v) {
117
+ strm<<'"'<<escape(v)<<'"';
118
+ }
119
+ };
120
+ template <>
121
+ struct test_print<const char*> {
122
+ template<class C>
123
+ static inline void op(C& strm, const char* v) {
124
+ strm<<'"'<<escape(v)<<'"';
125
+ }
126
+ };
127
+ template<typename E>
128
+ struct test_print<std::vector<E>, typename std::enable_if<sizeof(E)==1>::type> {
129
+ template<class C>
130
+ static inline void op(C& strm, const std::vector<E>& v) {
131
+ strm<<'"'<<escape((const char*)v.data(), v.size())<<'"';
132
+ }
133
+ };
134
+ template <typename E>
135
+ struct test_print<E, typename std::enable_if<std::is_same<E, char>::value||std::is_same<E, signed char>::value||std::is_same<E, unsigned char>::value>::type> {
136
+ template<class C>
137
+ static inline void op(C& strm, char v) {
138
+ strm<<int(v);
139
+ }
140
+ };
141
+
142
+ template<typename LHS, typename RHS>
143
+ testCase testEq(const char *sLHS, const LHS& lhs, const char *sRHS, const RHS& rhs)
144
+ {
145
+ testCase ret(lhs==rhs);
146
+ ret<<sLHS<<" (";
147
+ test_print<LHS>::op(ret, lhs);
148
+ ret<<") == "<<sRHS<<" (";
149
+ test_print<RHS>::op(ret, rhs);
150
+ ret<<") ";
151
+ return ret;
152
+ }
153
+
154
+ template<typename LHS, typename RHS>
155
+ testCase testNotEq(const char *sLHS, const LHS& lhs, const char *sRHS, const RHS& rhs)
156
+ {
157
+ testCase ret(lhs!=rhs);
158
+ ret<<sLHS<<" (";
159
+ test_print<LHS>::op(ret, lhs);
160
+ ret<<") != "<<sRHS<<" (";
161
+ test_print<RHS>::op(ret, rhs);
162
+ ret<<") ";
163
+ return ret;
164
+ }
165
+
166
+ template<typename T>
167
+ struct as_str {
168
+ static const char* op(const T& v) { return v; }
169
+ };
170
+ template<> struct as_str<std::string> {
171
+ static const char* op(const std::string& v) { return v.c_str(); }
172
+ };
173
+ template<> struct as_str<const std::string> {
174
+ static const char* op(const std::string& v) { return v.c_str(); }
175
+ };
176
+
177
+ template<typename T>
178
+ const char* asStr(const T& v) { return as_str<T>::op(v); }
179
+
180
+ PVXS_API
181
+ testCase _testStrTest(unsigned op, const char *sLHS, const char* lhs, const char *sRHS, const char* rhs);
182
+
183
+ PVXS_API
184
+ testCase _testStrMatch(const char *spat, const std::string& pat, const char *sstr, const std::string& str);
185
+
186
+ template<typename LHS, typename RHS>
187
+ testCase testArrEq(const char *sLHS, const LHS& lhs, const char *sRHS, const RHS& rhs)
188
+ {
189
+ bool eq = lhs.size()==rhs.size();
190
+ testCase ret;
191
+ ret<<sLHS<<" (";
192
+ test_print<LHS>::op(ret, lhs);
193
+ ret<<") == "<<sRHS<<" (";
194
+ test_print<RHS>::op(ret, rhs);
195
+ ret<<")\n";
196
+ for(size_t i=0; i<lhs.size() && i<rhs.size(); i++) {
197
+ if(lhs[i]!=rhs[i]) {
198
+ eq = false;
199
+ ret<<" ["<<i<<"] -> ";
200
+ test_print<typename std::decay<decltype (lhs[i])>::type>::op(ret, lhs[i]);
201
+ ret<<" != ";
202
+ test_print<typename std::decay<decltype (rhs[i])>::type>::op(ret, rhs[i]);
203
+ ret<<"\n";
204
+ }
205
+ }
206
+ ret.setPass(eq);
207
+ return ret;
208
+ }
209
+
210
+ } // namespace detail
211
+
212
+ /** Assert that an exception is thrown.
213
+ *
214
+ * @tparam Exception The exception type which should be thrown
215
+ * @param fn A callable
216
+ *
217
+ * @returns A testCase which passes if an Exception instance was caught,
218
+ * and false otherwise (wrong type, or no exception).
219
+ *
220
+ * @code
221
+ * testThrows<std::runtime_error>([]() {
222
+ * testShow()<<"Now you see me";
223
+ * throw std::runtime_error("I happened");
224
+ * testShow()<<"Now you don't";
225
+ * })<<"some message";
226
+ * @endcode
227
+ */
228
+ template<class Exception, typename FN>
229
+ testCase testThrows(FN fn)
230
+ {
231
+ testCase ret(false);
232
+ try {
233
+ fn();
234
+ ret<<"Unexpected success - ";
235
+ }catch(Exception& e){
236
+ ret.setPass(true)<<"Expected exception \""<<e.what()<<"\" - ";
237
+ }catch(std::exception& e){
238
+ ret<<"Unexpected exception "<<typeid(e).name()<<" \""<<e.what()<<"\" - ";
239
+ }
240
+ return ret;
241
+ }
242
+
243
+ /** Assert that an exception is throw with a certain message.
244
+ *
245
+ * @tparam Exception The exception type which should be thrown
246
+ * @param expr A regular expression
247
+ * @param fn A callable
248
+ *
249
+ * @returns A testCase which passes if an Exception instance was caught
250
+ * and std::exception::what() matched the provided regular expression.
251
+ *
252
+ * @code
253
+ * testThrowsMatch<std::runtime_error>("happened", []() {
254
+ * testShow()<<"Now you see me";
255
+ * throw std::runtime_error("I happened");
256
+ * testShow()<<"Now you don't";
257
+ * })<<"some message";
258
+ * @endcode
259
+ *
260
+ * @since 0.1.1
261
+ */
262
+ template<class Exception, typename FN>
263
+ testCase testThrowsMatch(const std::string& expr, FN fn)
264
+ {
265
+ testCase ret(false);
266
+ try {
267
+ fn();
268
+ ret<<"Unexpected success - ";
269
+ }catch(Exception& e){
270
+ ret.setPassMatch(expr, e.what())<<"Expected matching (\""<<expr<<"\") exception \""<<e.what()<<"\" - ";
271
+ }catch(std::exception& e){
272
+ ret<<"Unexpected exception "<<typeid(e).name()<<" \""<<e.what()<<"\" - ";
273
+ }
274
+ return ret;
275
+ }
276
+
277
+ } // namespace pvxs
278
+
279
+ //! Macro which assert that an expression evaluate to 'true'.
280
+ //! Evaluates to a pvxs::testCase
281
+ #define testTrue(EXPR) ::pvxs::testCase(EXPR)<<(" " #EXPR)
282
+
283
+ //! Macro which assert that an expression evaluate to 'true'.
284
+ //! Evaluates to a pvxs::testCase
285
+ #define testFalse(EXPR) ::pvxs::testCase(!(EXPR))<<(" !" #EXPR)
286
+
287
+ //! Macro which asserts equality between LHS and RHS.
288
+ //! Evaluates to a pvxs::testCase
289
+ //! Roughly equivalent to @code testOk((LHS)==(RHS), "..."); @endcode
290
+ #define testEq(LHS, RHS) ::pvxs::detail::testEq(#LHS, LHS, #RHS, RHS)
291
+
292
+ //! Macro which asserts in-equality between LHS and RHS.
293
+ //! Evaluates to a pvxs::testCase
294
+ //! Roughly equivalent to @code testOk((LHS)!=(RHS), "..."); @endcode
295
+ #define testNotEq(LHS, RHS) ::pvxs::detail::testNotEq(#LHS, LHS, #RHS, RHS)
296
+
297
+ //! Macro which asserts equality between LHS and RHS.
298
+ //! Evaluates to a pvxs::testCase
299
+ //! Functionally equivalent to testEq() with two std::string instances.
300
+ //! Prints diff-like output which is friendlier to multi-line strings.
301
+ #define testStrEq(LHS, RHS) ::pvxs::detail::_testStrTest(1, #LHS, ::pvxs::detail::asStr(LHS), #RHS, ::pvxs::detail::asStr(RHS))
302
+
303
+ //! Macro which asserts inequality between LHS and RHS.
304
+ //! Evaluates to a pvxs::testCase
305
+ //! Functionally equivalent to testNotEq() with two std::string instances.
306
+ //! Prints diff-like output which is friendlier to multi-line strings.
307
+ //! @since 0.2.0
308
+ #define testStrNotEq(LHS, RHS) ::pvxs::detail::_testStrTest(0, #LHS, ::pvxs::detail::asStr(LHS), #RHS, ::pvxs::detail::asStr(RHS))
309
+
310
+ //! Macro which asserts that STR matches the regular expression EXPR
311
+ //! Evaluates to a pvxs::testCase
312
+ //! @since 0.2.1 Expression syntax is POSIX extended.
313
+ //! @since 0.1.1
314
+ #define testStrMatch(EXPR, STR) ::pvxs::detail::_testStrMatch(#EXPR, EXPR, #STR, STR)
315
+
316
+ //! Macro which asserts equality between LHS and RHS.
317
+ //! Evaluates to a pvxs::testCase
318
+ //! Functionally equivalent to testEq() for objects with .size() and operator[].
319
+ //! Prints element by element differences
320
+ #define testArrEq(LHS, RHS) ::pvxs::detail::testArrEq(#LHS, LHS, #RHS, RHS)
321
+
322
+ //! Macro which prints diagnostic (non-test) lines.
323
+ //! Evaluates to a pvxs::testCase
324
+ //! Roughly equivalent to @code testDiag("..."); @endcode
325
+ #define testShow() ::pvxs::testCase()
326
+
327
+ #endif // PVXS_UNITTEST_H
@@ -0,0 +1,354 @@
1
+ /**
2
+ * Copyright - See the COPYRIGHT that is included with this distribution.
3
+ * pvxs is distributed subject to a Software License Agreement found
4
+ * in file LICENSE that is included with this distribution.
5
+ */
6
+
7
+ #ifndef PVXS_UTIL_H
8
+ #define PVXS_UTIL_H
9
+
10
+ #include <map>
11
+ #include <array>
12
+ #include <deque>
13
+ #include <functional>
14
+ #include <iosfwd>
15
+ #include <type_traits>
16
+ #include <stdexcept>
17
+ #include <memory>
18
+
19
+ #include <osiSock.h>
20
+ #include <epicsEvent.h>
21
+ #include <epicsMutex.h>
22
+ #include <epicsGuard.h>
23
+
24
+ #include <pvxs/version.h>
25
+
26
+ namespace pvxs {
27
+
28
+ namespace detail {
29
+ // ref. wrapper to mark string for escaping
30
+ class Escaper
31
+ {
32
+ const char* val;
33
+ size_t count;
34
+ friend
35
+ PVXS_API
36
+ std::ostream& operator<<(std::ostream& strm, const Escaper& esc);
37
+ public:
38
+ PVXS_API explicit Escaper(const char* v);
39
+ constexpr explicit Escaper(const char* v, size_t l) :val(v),count(l) {}
40
+ };
41
+
42
+ PVXS_API
43
+ std::ostream& operator<<(std::ostream& strm, const Escaper& esc);
44
+
45
+ } // namespace detail
46
+
47
+ //! Print string to output stream with non-printable characters escaped.
48
+ //!
49
+ //! Outputs (almost) C-style escapes.
50
+ //! Prefers short escapes for newline, tab, quote, etc ("\\n").
51
+ //! Falls back to hex escape (eg. "\xab").
52
+ //!
53
+ //! Unlike C, hex escapes are always 2 chars. eg. the output "\xabcase"
54
+ //! would need to be manually changed to "\xab""case" to be used as C source.
55
+ //!
56
+ //! @code
57
+ //! std::string blah("this \"is a test\"");
58
+ //! std::cout<<pvxs::escape(blah);
59
+ //! @endcode
60
+ inline detail::Escaper escape(const std::string& s) {
61
+ return detail::Escaper(s.c_str(), s.size());
62
+ }
63
+ //! Print nil terminated char array to output stream with non-printable characters escaped.
64
+ //! @code
65
+ //! std::cout<<pvxs::escape("this \"is a test\"");
66
+ //! @endcode
67
+ inline detail::Escaper escape(const char* s) {
68
+ return detail::Escaper(s);
69
+ }
70
+ //! Print fixed length char array to output stream with non-printable characters escaped.
71
+ //! @code
72
+ //! std::cout<<pvxs::escape("this \"is a test\"", 6);
73
+ //! // prints 'this \"'
74
+ //! @endcode
75
+ inline detail::Escaper escape(const char* s,size_t n) {
76
+ return detail::Escaper(s,n);
77
+ }
78
+
79
+ struct ServerGUID : public std::array<uint8_t, 12> {};
80
+
81
+ PVXS_API
82
+ std::ostream& operator<<(std::ostream&, const ServerGUID&);
83
+
84
+ #if !defined(__rtems__) && !defined(vxWorks)
85
+
86
+ /** Portable process signal handling in CLI tools.
87
+ *
88
+ * @code
89
+ * epicsEvent evt;
90
+ * SigInt handle([&evt]() {
91
+ * evt.trigger();
92
+ * });
93
+ * ... setup network operations
94
+ * evt.wait();
95
+ * // completion, or SIGINT
96
+ * @endcode
97
+ *
98
+ * Saves existing handler, which are restored by dtor.
99
+ *
100
+ * @since 1.1.0 "handler" action runs in thread context.
101
+ * Safe to take locks etc.
102
+ * Previously handler action ran in signal handler context.
103
+ */
104
+ class PVXS_API SigInt {
105
+ public:
106
+ //! Install signal handler.
107
+ SigInt(const std::function<void()>&& handler);
108
+ SigInt(const SigInt&) = delete;
109
+ ~SigInt();
110
+ struct Pvt;
111
+ private:
112
+ std::shared_ptr<Pvt> pvt;
113
+ };
114
+
115
+ #else // !defined(__rtems__) && !defined(vxWorks)
116
+
117
+ class SigInt {
118
+ const std::function<void()> handler;
119
+ public:
120
+ SigInt(std::function<void()>&& handler) :handler(std::move(handler)) {}
121
+ };
122
+
123
+ #endif // !defined(__rtems__) && !defined(vxWorks)
124
+
125
+ //! return a snapshot of internal instance counters
126
+ PVXS_API
127
+ std::map<std::string, size_t> instanceSnapshot();
128
+
129
+ //! See Indented
130
+ struct indent {};
131
+
132
+ PVXS_API
133
+ std::ostream& operator<<(std::ostream& strm, const indent&);
134
+
135
+ //! Scoped indentation for std::ostream
136
+ struct PVXS_API Indented {
137
+ explicit Indented(std::ostream& strm, int depth=1);
138
+ Indented(const Indented&) = delete;
139
+ Indented(Indented&& o) noexcept
140
+ :strm(o.strm)
141
+ ,depth(o.depth)
142
+ {
143
+ o.strm = nullptr;
144
+ o.depth = 0;
145
+ }
146
+ ~Indented();
147
+ private:
148
+ std::ostream *strm;
149
+ int depth;
150
+ };
151
+
152
+ struct PVXS_API Detailed {
153
+ explicit Detailed(std::ostream& strm, int lvl=1);
154
+ Detailed(const Detailed&) = delete;
155
+ Detailed(Detailed&& o) noexcept
156
+ :strm(o.strm)
157
+ ,lvl(o.lvl)
158
+ {
159
+ o.strm = nullptr;
160
+ o.lvl = 0;
161
+ }
162
+ ~Detailed();
163
+ static
164
+ int level(std::ostream& strm);
165
+ private:
166
+ std::ostream *strm;
167
+ int lvl;
168
+ };
169
+
170
+ /** Describe build and runtime configuration of current system.
171
+ *
172
+ * Print information which may be using for when troubleshooting,
173
+ * or creating a bug report.
174
+ *
175
+ * Printed by CLI "pvxinfo -D" and iocsh "pvxs_target_information".
176
+ *
177
+ * @returns The same ostream passed as argument.
178
+ */
179
+ PVXS_API
180
+ std::ostream& target_information(std::ostream&);
181
+
182
+ /** Print version information for PVXS library and dependencies
183
+ *
184
+ * As shown by eg. ``pvxget -V``
185
+ *
186
+ * @returns The same ostream passed as argument.
187
+ *
188
+ * @since 1.2.3
189
+ */
190
+ PVXS_API
191
+ std::ostream& version_information(std::ostream&);
192
+
193
+ /** Thread-safe, bounded, multi-producer, multi-consumer FIFO queue.
194
+ *
195
+ * Queue value_type must be movable. If T is also copy constructable,
196
+ * then push(const T&) may be used.
197
+ *
198
+ * As an exception, the destructor is not re-entrant. Concurrent calls
199
+ * to methods during destruction will result in undefined behavior.
200
+ *
201
+ * @code
202
+ * MPMCFIFO<std::function<void()>> Q;
203
+ * ...
204
+ * while(auto work = Q.pop()) { // Q.push(nullptr) to break loop
205
+ * work();
206
+ * }
207
+ * @endcode
208
+ *
209
+ * @since 0.2.0
210
+ */
211
+ template<typename T>
212
+ class MPMCFIFO {
213
+ mutable epicsMutex lock;
214
+ epicsEvent notifyW, notifyR;
215
+ std::deque<T> Q;
216
+ const size_t nlimit;
217
+ unsigned nwriters=0u, nreaders=0u;
218
+
219
+ typedef epicsGuard<epicsMutex> Guard;
220
+ typedef epicsGuardRelease<epicsMutex> UnGuard;
221
+ public:
222
+ //! Template parameter
223
+ typedef T value_type;
224
+
225
+ //! Construct a new queue
226
+ //! @param limit If non-zero, then emplace()/push() will block while while
227
+ //! queue size is greater than or equal to this limit.
228
+ explicit MPMCFIFO(size_t limit=0u)
229
+ :nlimit(limit)
230
+ {}
231
+ //! Destructor is not re-entrant
232
+ ~MPMCFIFO() {}
233
+
234
+ //! Poll number of elements in the work queue at this moment.
235
+ size_t size() const {
236
+ Guard G(lock);
237
+ return Q.size();
238
+ }
239
+ size_t max_size() const {
240
+ return nlimit ? nlimit : Q.max_size();
241
+ }
242
+
243
+ /** Construct a new element into the queue.
244
+ *
245
+ * Will block while full.
246
+ */
247
+ template<typename ...Args>
248
+ void emplace(Args&&... args) {
249
+ bool wakeupR, wakeupW;
250
+ {
251
+ Guard G(lock);
252
+ // while full, wait for reader to consume an entry
253
+ while(nlimit && Q.size()>=nlimit) {
254
+ nwriters++;
255
+ {
256
+ UnGuard U(G);
257
+ notifyW.wait();
258
+ }
259
+ nwriters--;
260
+ }
261
+ // notify reader when queue becomes not empty
262
+ wakeupR = Q.empty() && nreaders;
263
+ Q.emplace_back(std::forward<Args>(args)...);
264
+ // wakeup next writer if there is still space
265
+ wakeupW = nwriters && Q.size()<nlimit;
266
+ }
267
+ if(wakeupR)
268
+ notifyR.signal();
269
+ if(wakeupW)
270
+ notifyW.signal();
271
+ }
272
+
273
+ //! Move a new element to the queue
274
+ void push(T&& ent) {
275
+ // delegate to T::T(T&&)
276
+ emplace(std::move(ent));
277
+ }
278
+
279
+ //! Copy a new element to the queue
280
+ void push(const T& ent) {
281
+ // delegate to T::T(const T&)
282
+ emplace(ent);
283
+ }
284
+
285
+ /** Remove an element from the queue.
286
+ *
287
+ * Blocks while queue is empty.
288
+ */
289
+ T pop() {
290
+ bool wakeupW, wakeupR;
291
+ T ret;
292
+ {
293
+ Guard G(lock);
294
+ // wait for queue to become not empty
295
+ while(Q.empty()) {
296
+ nreaders++;
297
+ {
298
+ UnGuard U(G);
299
+ notifyR.wait();
300
+ }
301
+ nreaders--;
302
+ }
303
+ // wakeup a writer since the queue will have an empty entry
304
+ wakeupW = nwriters;
305
+ ret = std::move(Q.front());
306
+ Q.pop_front();
307
+ // wakeup next reader if entries remain
308
+ wakeupR = !Q.empty() && nreaders;
309
+ }
310
+ if(wakeupR)
311
+ notifyR.signal();
312
+ if(wakeupW)
313
+ notifyW.signal();
314
+ return ret;
315
+ }
316
+ };
317
+
318
+ struct Timer;
319
+
320
+ #ifdef PVXS_EXPERT_API_ENABLED
321
+
322
+ //! Timer associated with a client::Context or server::Server
323
+ //! @since 0.2.0
324
+ struct PVXS_API Timer {
325
+ struct Pvt;
326
+
327
+ //! dtor implicitly cancel()s
328
+ ~Timer();
329
+ //! Explicit cancel.
330
+ //! @returns true if the timer was running, and now is not.
331
+ bool cancel();
332
+
333
+ explicit operator bool() const { return pvt.operator bool(); }
334
+
335
+ private:
336
+ std::shared_ptr<Pvt> pvt;
337
+ friend struct Pvt;
338
+ };
339
+
340
+ //! Allocate a pair of connected stream sockets
341
+ //! \since 1.1.4
342
+ PVXS_API
343
+ void compat_socketpair(SOCKET sock[2]);
344
+
345
+ //! Setup socket for non-blocking I/O
346
+ //! \since 1.1.4
347
+ PVXS_API
348
+ void compat_make_socket_nonblocking(SOCKET sock);
349
+
350
+ #endif // PVXS_EXPERT_API_ENABLED
351
+
352
+ } // namespace pvxs
353
+
354
+ #endif // PVXS_UTIL_H