Merge ~johill-lanl/epics-base/+git/epics-base:timer-queue-fix into ~epics-core/epics-base/+git/epics-base:7.0

Proposed by Jeff Hill
Status: Needs review
Proposed branch: ~johill-lanl/epics-base/+git/epics-base:timer-queue-fix
Merge into: ~epics-core/epics-base/+git/epics-base:7.0
Diff against target: 7004 lines (+3832/-1151) (has conflicts)
47 files modified
configure/CONFIG.gnuCommon (+2/-2)
dev/null (+0/-1)
modules/libcom/src/Makefile (+2/-0)
modules/libcom/src/misc/AllocatorArena.h (+944/-0)
modules/libcom/src/misc/AllocatorArenaUntyped.cpp (+199/-0)
modules/libcom/src/misc/Makefile (+3/-0)
modules/libcom/src/osi/Makefile (+10/-0)
modules/libcom/src/osi/compiler/clang/compilerSpecific.h (+6/-0)
modules/libcom/src/osi/compiler/clang/epicsAtomicCD.h (+2/-2)
modules/libcom/src/osi/compiler/default/compilerDependentDemangle.cpp (+28/-0)
modules/libcom/src/osi/compiler/default/compilerSpecific.h (+7/-2)
modules/libcom/src/osi/compiler/default/epicsAtomicCD.h (+2/-2)
modules/libcom/src/osi/compiler/default/epicsStaticInstanceCD.h (+20/-0)
modules/libcom/src/osi/compiler/gcc/compilerDependentDemangle.cpp (+168/-0)
modules/libcom/src/osi/compiler/gcc/compilerSpecific.h (+10/-0)
modules/libcom/src/osi/compiler/gcc/epicsAtomicCD.h (+2/-2)
modules/libcom/src/osi/compiler/gcc/epicsStaticInstanceCD.h (+26/-0)
modules/libcom/src/osi/compiler/msvc/compilerSpecific.h (+6/-2)
modules/libcom/src/osi/compiler/msvc/epicsAtomicCD.h (+2/-2)
modules/libcom/src/osi/compiler/msvc/epicsStaticInstanceCD.h (+32/-0)
modules/libcom/src/osi/compiler/solStudio/compilerSpecific.h (+2/-2)
modules/libcom/src/osi/compiler/solStudio/epicsAtomicCD.h (+2/-2)
modules/libcom/src/osi/compilerDependencies.h (+42/-0)
modules/libcom/src/osi/epicsDemangle.h (+26/-0)
modules/libcom/src/osi/epicsStaticInstance.h (+52/-0)
modules/libcom/src/osi/epicsStaticInstanceSaneCmplr.h (+45/-0)
modules/libcom/src/osi/epicsStaticInstanceSketchyCmplr.cpp (+88/-0)
modules/libcom/src/osi/epicsStaticInstanceSketchyCmplr.h (+53/-0)
modules/libcom/src/timer/epicsTimer.cpp (+107/-102)
modules/libcom/src/timer/epicsTimer.h (+61/-34)
modules/libcom/src/timer/timer.cpp (+160/-160)
modules/libcom/src/timer/timerPrivate.h (+228/-134)
modules/libcom/src/timer/timerQueue.cpp (+179/-131)
modules/libcom/src/timer/timerQueueActive.cpp (+53/-95)
modules/libcom/src/timer/timerQueueActiveMgr.cpp (+17/-17)
modules/libcom/src/timer/timerQueuePassive.cpp (+21/-17)
modules/libcom/src/valgrind/epicsMemChk.h (+42/-0)
modules/libcom/src/valgrind/memcheck.h (+303/-0)
modules/libcom/src/valgrind/valgrind.h (+324/-239)
modules/libcom/test/AllocatorArenaTest.cpp (+98/-0)
modules/libcom/test/Makefile (+17/-0)
modules/libcom/test/epicsDemangleTest.cpp (+75/-0)
modules/libcom/test/epicsStaticInstanceTest.cpp (+66/-0)
modules/libcom/test/epicsTimerTest.cpp (+297/-200)
modules/pvAccess (+1/-1)
modules/pvDatabase (+1/-1)
modules/pva2pva (+1/-1)
Conflict in modules/libcom/test/Makefile
Reviewer Review Type Date Requested Status
EPICS Core Developers Pending
Review via email: mp+382887@code.launchpad.net

Commit message

o changed timer library to use heap algorithm
o merged thread private C++ allocator - AllocatorArena
o merged compiler, and compiler version, independent thread safe static C++ object library
o merged compiler independent C++ symbol demangler
o added C++ 11 compatibility keywords to compiler dependent library
o upgraded and or added tests
o updated valgrind header versions to newer version, added missing valgrind header files
o added mechanism to turn off valgrind macros, which have runtime penalty in optimized builds

Description of the change

Changed timer queue library to use heap algorithm.

Also upgraded the timer test coverage, and accuracy statistics emitted as diagnostics during the tests.

In order to simplify the merge I moved the timer library to a modernized thread private C++ STL compliant allocation library - AllocatorArena. This avoids (personal) difficulties with maintaining two different versions {EPICS 7.0, LANSCE DAR} using the original cxx free list library interface, and an enhanced newer template interface version of that original library. If you prefer I could change the timer library to just use new and delete as the timer objects themselves may not be created and destroyed periodically by users (difficult to speculate). I could also rebase on the older version of the cxx free list library, but again I would have more maintenance labor to attend to over time.

The AllocatorArena also pulls in the (small) static instance library and the C++ demangle libraries. There are also some tests for these layered components.

I have also added some c++ 11 compatibility macros to the compiler dependencies library. I also removed the throw compatibility macro because no code uses it, and no one should be using the C++ throw specification on new code (according to C++ standards committee, Meyers, and many others).

Updated valgrind header versions to newer version, and added missing valgrind header files. Added mechanism to turn off valgrind macros, which have runtime penalty in optimized builds.

BTW: On a similar note, I would also prefer to see assert tests removed from optimized builds. Otherwise developers may leave out assert calls for fear of runtime penalty. I have not made that change here, however.

To post a comment you must log in.
Revision history for this message
Martin Konrad (info-martin-konrad) wrote :

I haven't looked at the code, yet, but it builds fine on Ubuntu 19.10 with GCC 9.2: no warnings, all tests pass :-) A few compiler/OS combinations fail to build on Travis (https://travis-ci.com/github/mark0n/epics-base/builds/161843145) and AppVeyor (https://ci.appveyor.com/project/MartinKonrad/epics-base/builds/32416944), though.

Before digging into the code, I benchmarked the old and the proposed timer queue implementation. You can find the results here:

https://www.martin-konrad.net/nextcloud/index.php/s/mYHXWQxbJFz4LkL

The old implementation takes more than 100 us to create and start a new timer if there are already 30,000 timers in the queue (this number is based on a real-world scenario with Asyn/Stream at FRIB) and the new timer needs to be inserted at the beginning of the list (30,000 existing timers with 60 s, the new timer has 30 s duration). In this case the old code has to walk a linked list from the back all the way to the front (the code was optimized for inserting timers with the same duration). The new implementation performs two orders of magnitude better in this scenario. Not bad! None of the cases I benchmarked is performing significantly worse than with the old implementation. For comparison I also benchmarked boost::asio's timers - its performance is in the same order of magnitude.

See https://github.com/mark0n/benchmark_timerqueue for my benchmark code.

Revision history for this message
Jeff Hill (johill-lanl) wrote :

Martin,

I will hopefully attend to to the build errors tomorrow. Suspect that MSVC will never work with valgrind? If so we can simply ifdef the valgrind macros out? Need to take closer look.

Also need to look at your performance metrics.

Jeff

________________________________
From: <email address hidden> <email address hidden> on behalf of Martin Konrad <email address hidden>
Sent: Friday, April 24, 2020 1:27 PM
To: Hill, Jeff
Subject: [EXTERNAL] Re: [Merge] ~johill-lanl/epics-base/+git/epics-base:timer-queue-fix into epics-base:7.0

I haven't looked at the code, yet, but it builds fine on Ubuntu 19.10 with GCC 9.2: no warnings, all tests pass :-) A few compiler/OS combinations fail to build on Travis (https://travis-ci.com/github/mark0n/epics-base/builds/161843145) and AppVeyor (https://ci.appveyor.com/project/MartinKonrad/epics-base/builds/32416944), though.

Before digging into the code, I benchmarked the old and the proposed timer queue implementation. You can find the results here:

https://www.martin-konrad.net/nextcloud/index.php/s/mYHXWQxbJFz4LkL

The old implementation takes more than 100 us to create and start a new timer if there are already 30,000 timers in the queue (this number is based on a real-world scenario with Asyn/Stream at FRIB) and the new timer needs to be inserted at the beginning of the list (30,000 existing timers with 60 s, the new timer has 30 s duration). In this case the old code has to walk a linked list from the back all the way to the front (the code was optimized for inserting timers with the same duration). The new implementation performs two orders of magnitude better in this scenario. Not bad! None of the cases I benchmarked is performing significantly worse than with the old implementation. For comparison I also benchmarked boost::asio's timers - its performance is in the same order of magnitude.

See https://github.com/mark0n/benchmark_timerqueue for my benchmark code.
--
https://code.launchpad.net/~johill-lanl/epics-base/+git/epics-base/+merge/382887
You are the owner of ~johill-lanl/epics-base/+git/epics-base:timer-queue-fix.

Revision history for this message
Martin Konrad (info-martin-konrad) wrote :

I have pushed a few suggestions to https://github.com/mark0n/epics-base/tree/timer-queue-fix-mk that among other things fix the failing builds with clang. I'll keep adding to this branch as I review the code.

9b266f7... by Jeff Hill

fixed bug occuring when timer restarted from within timer callback

1eee997... by Jeff Hill

merged from 7.0

85b70eb... by Jeff Hill

Merge branch 'timer-queue-fix' of git+ssh://git.launchpad.net/~johill-lanl/epics-base/+git/epics-base into timer-queue-fix

437efa7... by Jeff Hill

improved comments

854b08a... by Jeff Hill

test timer callback restarts timer path

78b49c4... by Jeff Hill

cosmetics

Revision history for this message
Jeff Hill (johill-lanl) wrote :

Hi Martin,

Sorry about delayed response; I have been focusing on another project.

I had a quick look at your branch, and all of it looks in principal good. My spelling is unfortunately egregious and of course the doc is a needed upgrade. Some of the macros I use in other codes, to ease into C++ 11, but if some of them are already in 7.0 under different names then I will need to switch to those names of course. I don't recall seeing these duplications under different names; I will need to look closer.

The API on the gnu demangler function is unfortunately tricky to use, and I had to make some adjustments in the demangler support early on, but haven't touched that code for a year or so. I haven't looked at support for other compilers such as clang, but perhaps it (clang) will be compatible to gcc. As I recall the MSVC provides names from type_info::name already in human readable form.

I have another merge request in progress which actually uses some of the c++ 11 compatibility macros you are removing. They could be added back in for that proposal of course.

I could merge, probably all of, your changes into my branch. Is that how you want to proceed?

Jeff

________________________________
From: <email address hidden> <email address hidden> on behalf of Martin Konrad <email address hidden>
Sent: Monday, April 27, 2020 11:30 AM
To: Hill, Jeff
Subject: [EXTERNAL] Re: [Merge] ~johill-lanl/epics-base/+git/epics-base:timer-queue-fix into epics-base:7.0

I have pushed a few suggestions to https://github.com/mark0n/epics-base/tree/timer-queue-fix-mk that among other things fix the failing builds with clang. I'll keep adding to this branch as I review the code.
--
https://code.launchpad.net/~johill-lanl/epics-base/+git/epics-base/+merge/382887
You are the owner of ~johill-lanl/epics-base/+git/epics-base:timer-queue-fix.

Unmerged commits

78b49c4... by Jeff Hill

cosmetics

854b08a... by Jeff Hill

test timer callback restarts timer path

437efa7... by Jeff Hill

improved comments

85b70eb... by Jeff Hill

Merge branch 'timer-queue-fix' of git+ssh://git.launchpad.net/~johill-lanl/epics-base/+git/epics-base into timer-queue-fix

1eee997... by Jeff Hill

merged from 7.0

9b266f7... by Jeff Hill

fixed bug occuring when timer restarted from within timer callback

c112d69... by Jeff Hill

Merge branch '7.0' into timer-queue-fix

099c0ea... by Jeff Hill

fixed spelling in comment

eb4fa08... by Jeff Hill

o switched from epicsTime :: getCurrent to epicsTime :: getMonotonic as per EPICS 7 convention

Nevertheless, personally I have some concerns
---------------------------------------------

I do understand that general time can cause time discontinuities, and that discontinuities are
bad for a timer queue. However, I also worry about this being a backward incompatible API change,
and about users subtracting monotonic epicsTime time from ordinary epicsTime to produce a garbage
difference amount. Perhaps a different user defined type should have been used for monotonic
time. Also, does monotonic epicsTime convert to a date the same as ordinary epicsTime?

9dafde4... by Jeff Hill

resrve heap space during timer instantiation

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/.ci b/.ci
2deleted file mode 160000
3index e91a588..0000000
4--- a/.ci
5+++ /dev/null
6@@ -1 +0,0 @@
7-Subproject commit e91a5883704e9fa57792953436eb7020baf37063
8diff --git a/configure/CONFIG.gnuCommon b/configure/CONFIG.gnuCommon
9index c4fd8ce..96eab65 100644
10--- a/configure/CONFIG.gnuCommon
11+++ b/configure/CONFIG.gnuCommon
12@@ -35,7 +35,7 @@ CODE_CFLAGS += $(ASAN_FLAGS_$(ENABLE_ASAN))
13 WARN_CFLAGS_YES = -Wall
14 WARN_CFLAGS_NO = -w
15 OPT_CFLAGS_YES = -O3
16-OPT_CFLAGS_NO = -g
17+OPT_CFLAGS_NO = -g -DMEMCHECK
18
19 PROF_CXXFLAGS_YES = -p
20 GPROF_CXXFLAGS_YES = -pg
21@@ -44,7 +44,7 @@ CODE_CXXFLAGS += $(ASAN_FLAGS_$(ENABLE_ASAN))
22 WARN_CXXFLAGS_YES = -Wall
23 WARN_CXXFLAGS_NO = -w
24 OPT_CXXFLAGS_YES = -O3
25-OPT_CXXFLAGS_NO = -g
26+OPT_CXXFLAGS_NO = -g -DMEMCHECK
27
28 CODE_LDFLAGS = $(PROF_CXXFLAGS_$(PROFILE)) $(GPROF_CXXFLAGS_$(GPROF))
29 CODE_LDFLAGS += $(ASAN_LDFLAGS_$(ENABLE_ASAN))
30diff --git a/modules/libcom/src/Makefile b/modules/libcom/src/Makefile
31index 57533ba..c966e2c 100644
32--- a/modules/libcom/src/Makefile
33+++ b/modules/libcom/src/Makefile
34@@ -15,6 +15,8 @@ include $(TOP)/configure/CONFIG
35 #USR_CFLAGS += -DNVALGRIND
36
37 INC += valgrind/valgrind.h
38+INC += valgrind/memcheck.h
39+INC += valgrind/epicsMemChk.h
40
41 INC += libComVersion.h
42 INC += libComVersionNum.h
43diff --git a/modules/libcom/src/misc/AllocatorArena.h b/modules/libcom/src/misc/AllocatorArena.h
44new file mode 100644
45index 0000000..33a46c5
46--- /dev/null
47+++ b/modules/libcom/src/misc/AllocatorArena.h
48@@ -0,0 +1,944 @@
49+
50+/*************************************************************************\
51+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
52+* National Laboratory
53+* EPICS BASE is distributed subject to a Software License Agreement found
54+* in file LICENSE that is included with this distribution.
55+\*************************************************************************/
56+
57+/*
58+ * Author Jeffrey O. Hill
59+ */
60+
61+//
62+// Arena Allocator
63+//
64+// A thread private allocator for N of type T allocated in-mass, and
65+// deallocated in-mass. The individual calls to allocate run very
66+// efficiently because they simply return a pointer to preallocated
67+// space for a type T, and advance the index identifying the space for
68+// the next allocation, using thread private storage sans mutex
69+// protection overhead. The in-bulk deallocation is postponed until
70+// the last active T, residing within a bulk allocated block, is
71+// deallocated.
72+//
73+// The allocator falls back to ordinary global new/delete if the user
74+// requests more than one element for allocation using the vector
75+// form of new.
76+//
77+// This facility is fully safe for use in a multi-threaded environment.
78+// A thread private variable, and a thread private cleanup, are used to
79+// maintain a thread private context so that the overhead associated
80+// with a mutual exclusion locking can be avoided.
81+//
82+// Be aware that the storage overhead for any type T is sizeof ( T ) plus
83+// sizeof ( void * ), a substantial consideration probably only if small
84+// objects are stored, and storage efficency is more important than
85+// performance considerations. Furthermore, storage overhead increases
86+// for C++ compilers predating C++ 11.
87+//
88+// In this code a contiguous bulk block of storage for N of type T
89+// is template type Rack<S,A,N> where S is the size of T, and A is the
90+// required alignment. The thread-private allocaton occurs when peeling
91+// off storage for an individual T from the thread's private Rack. When
92+// the thread's private Rack is exausted, then a new Rack is allocated
93+// from the specified Rack allocator type. Currently two global Rack
94+// allocator implementations are provided. One that uses ordinary global
95+// new/delete, and one that uses a mutex protected global free list
96+// (the default) designated by rack allocator policies rap_pool and
97+// rap_freeList respectively.
98+//
99+// Define ALLOCATOR_ARENA_MEMORY_ACCESS_INSPECTION_ACTIVE in order to
100+// temporarily bypass bulk allocation and return to ordinary global
101+// operator new and delete, so that memory access inspectors such as
102+// purify or valgrind might be more effective. Furthermore, when the
103+// allocator _is_ active, and it is a debug build, specialized
104+// valgrind macros document with valgrind memory regions owned by this
105+// allocater for which ownership has not yet passed to an end application
106+// so that they do not appear as undesireable noise in valgrind leak
107+// reports.
108+//
109+
110+#ifndef epicsAllocatorArena_h
111+#define epicsAllocatorArena_h
112+
113+// see comment above
114+#if 0
115+#define ALLOCATOR_ARENA_MEMORY_ACCESS_INSPECTION_ACTIVE
116+#endif
117+
118+#if __cplusplus >= 201103L
119+# include <cstdint>
120+#endif
121+
122+#include <new>
123+#include <cstdlib>
124+#include <string>
125+#include <cstdio>
126+#include <typeinfo>
127+
128+#include "epicsAtomic.h"
129+#include "epicsMutex.h"
130+#include "epicsThread.h"
131+#include "epicsStaticInstance.h"
132+#include "compilerDependencies.h"
133+#include "valgrind/epicsMemChk.h"
134+#include "shareLib.h"
135+
136+
137+#if __cplusplus >= 201103L
138+# if defined ( __GNUC__ )
139+# define GCC_VERSION_AA \
140+ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
141+ // perhaps the nios2 cross compiler doesnt properly implement
142+ // alignment even at gcc 4.8, based on experimental evidence
143+# define ALIGNAS_CMPLR_OK ( GCC_VERSION_AA >= 50000 )
144+# else
145+# define ALIGNAS_CMPLR_OK 1
146+# endif
147+#else
148+# define ALIGNAS_CMPLR_OK 0
149+#endif
150+
151+#ifndef SIZE_MAX
152+# define SIZE_MAX ( static_cast < size_t > ( -1L ) )
153+#endif
154+
155+namespace epics {
156+namespace _impl {
157+
158+using std :: size_t;
159+using std :: type_info;
160+using std :: ptrdiff_t;
161+using std :: allocator;
162+using std :: bad_alloc;
163+
164+//
165+// S - the allocation size (the size of T)
166+// A - the required alignment
167+// N - the block size for pool allocation
168+// (pool allocation size will be approximately S * N)
169+//
170+template < size_t S, size_t A, size_t N = 256 > class Rack;
171+
172+//
173+// R - the rack type
174+// P - the allocation policy type
175+// TRACE - if true, print a message each time that a new racks allocated
176+// counter power of two is exceeded for a particular allocation type
177+//
178+enum RackAllocPolicy { rap_pool, rap_freeList };
179+template < typename R, RackAllocPolicy P, bool TRACE > class RackAlloc;
180+
181+//
182+// T - the allocation type
183+// G - the discriminator for the thread private variable group
184+// (proper scaling requires an independent thread private variable
185+// group for each library) any type is allowed and appropriate for
186+// identifying an independent thread private context
187+// N - the block size for pool allocation
188+// A - the rack allocator
189+//
190+// on old compilers prior to ALIGNAS_CMPLR_OK all blocks are aligned
191+// for worst case alignment requirements
192+//
193+template < typename T, typename G, size_t N = 256,
194+ RackAllocPolicy P = rap_freeList, bool TRACE = false >
195+class AllocatorArena {
196+public:
197+ typedef T value_type;
198+ typedef value_type * pointer;
199+ typedef const value_type * const_pointer;
200+ typedef value_type & reference;
201+ typedef const value_type & const_reference;
202+ typedef size_t size_type;
203+ typedef ptrdiff_t difference_type;
204+ typedef typename allocator < void > :: const_pointer void_const_pointer;
205+ typedef typename allocator < void > :: pointer void_pointer;
206+
207+ template < typename T0 >
208+ struct rebind {
209+ typedef AllocatorArena < T0, G, N, P, TRACE > other;
210+ };
211+
212+ AllocatorArena ();
213+
214+ template < typename Y >
215+ AllocatorArena ( const Y & );
216+
217+ // address
218+ static pointer address ( reference r );
219+ static const_pointer address ( const_reference r );
220+
221+ // memory allocation
222+ static pointer allocate ( size_type nAlloc,
223+ void_const_pointer pNearbyHint = 0 );
224+ static void deallocate ( const pointer p, size_type nAlloc );
225+
226+ // helpers, for creating class specific operator new and delete
227+ static void * allocateOctets ( size_type size );
228+ static void * allocateOctets ( size_type size, const std :: nothrow_t & );
229+ static void deallocateOctets ( void * p, size_type size );
230+
231+ // remove the allocator's thread private reference to any partially
232+ // consumed block so that it can be released back into system pool
233+ // (this action is automated at thread exit)
234+ static void cleanup ();
235+
236+ // size
237+ static size_type max_size ();
238+
239+ // construction / destruction of target
240+#if __cplusplus >= 201103L
241+ template < typename T0, typename ... Args >
242+ static void construct ( T0 *, Args && ... ); // depricated in c++ 17
243+#else
244+ template < typename T0, typename A0 >
245+ static void construct ( T0 *, A0 );
246+ template < typename T0, typename A0, typename A1 >
247+ static void construct ( T0 *, A0, A1 );
248+ template < typename T0, typename A0, typename A1, typename A2 >
249+ static void construct ( T0 *, A0, A1, A2 );
250+ template < typename T0, typename A0, typename A1, typename A2,
251+ typename A3 >
252+ static void construct ( T0 *, A0, A1, A2, A3 );
253+ template < typename T0, typename A0, typename A1, typename A2,
254+ typename A3, typename A4 >
255+ static void construct ( T0 *, A0, A1, A2, A3, A4 );
256+#endif
257+ template < class U >
258+ static void destroy ( U * ); // depricated in c++ 17
259+
260+ bool operator == ( AllocatorArena const & );
261+ bool operator != ( AllocatorArena const & );
262+
263+ static size_t rackCount ();
264+ static size_t byteCount ();
265+private:
266+#if ALIGNAS_CMPLR_OK
267+ typedef Rack < sizeof ( T ), alignof ( T ), N > M_Rack;
268+#else
269+ /* worst case alignment is used */
270+ typedef Rack < sizeof ( T ), 0u, N > M_Rack;
271+#endif
272+ typedef RackAlloc < M_Rack, P, TRACE > M_RackAlloc;
273+ static pointer m_threadPrivateAlloc ();
274+ static void m_rackCleanup ( void * );
275+}; // end of class AllocatorArena
276+
277+class epicsShareClass ThreadPrivateIdBadAlloc : public bad_alloc
278+{
279+ const char * what () const throw ();
280+};
281+
282+class epicsShareClass AtThreadExitBadAlloc : public bad_alloc
283+{
284+ const char * what () const throw ();
285+};
286+
287+#if __cplusplus >= 201103L
288+ typedef std :: uint8_t Octet;
289+#else
290+ typedef unsigned char Octet;
291+#endif
292+
293+typedef Octet * POctet;
294+
295+// align for all possible types, similar to malloc
296+union MaxAlign {
297+ struct SomeStruct {};
298+ long double m_ld;
299+ long long m_ll;
300+ long double * m_pd;
301+ SomeStruct * m_pss;
302+ void (* m_pf) ();
303+ long double SomeStruct :: * m_pmd;
304+ void ( SomeStruct :: * m_pmf ) ();
305+ /*
306+ * eye of newt ...
307+ */
308+};
309+
310+template < size_t S, size_t A, size_t N >
311+class Rack {
312+public:
313+ typedef size_t size_type;
314+ typedef ptrdiff_t difference_type;
315+
316+ Rack ();
317+ ~Rack ();
318+ bool empty () const;
319+ void * alloc ();
320+ size_t removeReference ();
321+ void addReference ();
322+
323+ static const size_t number;
324+ static const size_t alignment;
325+ static Rack * dealloc ( void * );
326+private:
327+ struct M_Wrapper {
328+ VALGRIND_RED_ZONE ( m_redZoneBefore )
329+# if ALIGNAS_CMPLR_OK
330+ alignas ( A ) Octet m_bufForObj [ S ];
331+# else
332+ union {
333+ Octet m_bufForObj [ S ];
334+ MaxAlign m_maxAlign;
335+ };
336+# endif
337+ VALGRIND_RED_ZONE ( m_redZoneAfter )
338+ void * m_pRack;
339+ };
340+ typedef M_Wrapper * PWrapper;
341+ M_Wrapper m_wrapped[N];
342+ size_t m_nAlloc;
343+ size_t m_refCount;
344+#if __cplusplus >= 201103L
345+ Rack ( const Rack & ) = delete;
346+ Rack & operator = ( const Rack & ) = delete;
347+#endif
348+};
349+
350+struct RackManager {
351+ void * m_pRack;
352+ void ( *m_pThreadExitFunc )( void * pRack );
353+};
354+
355+class epicsShareClass AllocCtxCom {
356+public:
357+ AllocCtxCom ();
358+ RackManager * getRackHandlerPtr ( size_t idx );
359+ void cleanup ( size_t idx );
360+ size_t allocIdx ();
361+private:
362+ epicsThreadPrivateId m_threadPrivateId;
363+ size_t m_curIdx;
364+ static void m_threadExitFunc ( void * const pPriv );
365+ static const size_t m_initialCapacity;
366+};
367+
368+//
369+// G - the discriminator for the thread private variable group
370+// (proper scaling requires an indepent thread private variable
371+// group for each library) any type is allowed and appropriate
372+// for identifying an independent thread private context
373+//
374+template < typename G > class AllocCtxGrouped : public AllocCtxCom {};
375+
376+//
377+// G - the discriminator for the thread private variable group
378+// (proper scaling requires an indepent thread private variable
379+// group for each library) any type is allowed and appropriate
380+// for identifying an independent thread private context
381+//
382+template < typename G >
383+class AllocCtx {
384+public:
385+ AllocCtx ();
386+ void cleanup ();
387+ RackManager * getRackHandlerPtr ();
388+private:
389+ size_t m_idx;
390+};
391+
392+//
393+// T - the allocation type
394+// G - the discriminator for the thread private variable group
395+// (proper scaling requires an indepent thread private variable
396+// group for each library) any type is allowed and appropriate
397+// for identifying an independent thread private context
398+//
399+template < typename T, typename G >
400+class AllocCtxTyped : public AllocCtx < G > {};
401+
402+template < bool TRACE >
403+class epicsShareClass AllocCounter;
404+
405+template <>
406+class epicsShareClass AllocCounter < true > {
407+public:
408+ AllocCounter ();
409+ void increment ( size_t nBytesThisTime, const type_info & );
410+ void decrement ( size_t nBytesThisTime );
411+ size_t rackCount () const { return m_nRacks; }
412+ size_t byteCount () const { return m_bytes; }
413+ void show ( const type_info & ) const;
414+private:
415+ size_t m_nRacksTrace;
416+ size_t m_nRacks;
417+ size_t m_bytes;
418+};
419+
420+template <>
421+class epicsShareClass AllocCounter < false > {
422+public:
423+ void increment ( size_t nBytesThisTime,
424+ const type_info & ) {}
425+ void decrement ( size_t nBytesThisTime ) {}
426+ size_t rackCount () const { return 0u; }
427+ size_t byteCount () const { return 0u; }
428+ void show ( const char * pContext ) const {}
429+};
430+
431+template < typename R, bool TRACE >
432+class RackAlloc < R, rap_pool, TRACE > {
433+public:
434+ typedef R Rack;
435+ template < typename R0 >
436+ struct rebind {
437+ typedef RackAlloc < R0, rap_pool, TRACE > other;
438+ };
439+ static R * create ( const type_info & ti );
440+ static void destroy ( R * p );
441+ static size_t rackCount ();
442+ static size_t byteCount ();
443+private:
444+ static AllocCounter < TRACE > m_counter;
445+};
446+
447+template < typename R, bool TRACE >
448+class RackAlloc < R, rap_freeList, TRACE > {
449+public:
450+ template < typename R0 >
451+ struct rebind {
452+ typedef RackAlloc < R0, rap_freeList, TRACE > other;
453+ };
454+ typedef R Rack;
455+ RackAlloc ();
456+ ~RackAlloc ();
457+ R * create ( const type_info & );
458+ void destroy ( R * p );
459+ size_t rackCount () const;
460+ size_t byteCount () const;
461+private:
462+ typedef epicsMutex Mutex;
463+ typedef epicsGuard < epicsMutex > Guard;
464+ struct M_Alias {
465+ VALGRIND_RED_ZONE ( m_redZoneBefore )
466+ union {
467+# if ALIGNAS_CMPLR_OK
468+ alignas ( R :: alignment )
469+ Octet m_rackBuf [ sizeof ( R ) ];
470+# else
471+ union {
472+ Octet m_rackBuf [ sizeof ( R ) ];
473+ MaxAlign m_maxAlign;
474+ };
475+# endif
476+ struct M_Alias * m_pNext;
477+ };
478+ VALGRIND_RED_ZONE ( m_redZoneAfter )
479+ };
480+ M_Alias * m_pAlias;
481+ Mutex m_mutex;
482+ AllocCounter < TRACE > m_counter;
483+ RackAlloc ( const RackAlloc & ) epicsDeleteMethod;
484+ RackAlloc operator = ( const RackAlloc & ) epicsDeleteMethod;
485+};
486+
487+template < typename G >
488+inline AllocCtx < G > :: AllocCtx () :
489+ m_idx ( staticInstance < AllocCtxGrouped < G > > ().allocIdx () )
490+{
491+}
492+
493+template < typename G >
494+inline RackManager * AllocCtx < G > :: getRackHandlerPtr ()
495+{
496+ AllocCtxCom & grp = staticInstance < AllocCtxGrouped < G > > ();
497+ return grp.getRackHandlerPtr ( m_idx );
498+}
499+
500+template < typename G >
501+void AllocCtx < G > :: cleanup ()
502+{
503+ AllocCtxCom & grp = staticInstance < AllocCtxGrouped < G > > ();
504+ grp.cleanup ( m_idx );
505+}
506+
507+template < typename R, bool TRACE >
508+inline R * RackAlloc < R, rap_pool, TRACE > :: create ( const type_info & ti )
509+{
510+ R * const p = new R ();
511+ m_counter.increment ( sizeof ( R ), ti );
512+ return p;
513+}
514+
515+template < typename R, bool TRACE >
516+inline void RackAlloc < R, rap_pool, TRACE > :: destroy ( R * p )
517+{
518+ m_counter.decrement ( sizeof ( R ) );
519+ delete p;
520+}
521+
522+template < typename R, bool TRACE >
523+inline size_t RackAlloc < R, rap_pool, TRACE > :: rackCount ()
524+{
525+ return m_counter.rackCount ();
526+}
527+
528+template < typename R, bool TRACE >
529+inline size_t RackAlloc < R, rap_pool, TRACE > :: byteCount ()
530+{
531+ return m_counter.byteCount ();
532+}
533+
534+template < typename R, bool TRACE >
535+inline RackAlloc < R, rap_freeList, TRACE > :: RackAlloc () :
536+ m_pAlias ( 0 )
537+{
538+ VALGRIND_CREATE_MEMPOOL_EXT ( this, sizeof (epicsMemChkRedZone),
539+ false, VALGRIND_MEMPOOL_METAPOOL );
540+}
541+
542+template < typename R, bool TRACE >
543+RackAlloc < R, rap_freeList, TRACE > :: ~RackAlloc ()
544+{
545+ Guard guard ( m_mutex );
546+ M_Alias * p = m_pAlias;
547+ while ( p ) {
548+ M_Alias * pNext = p->m_pNext;
549+ {
550+ delete p;
551+ }
552+ p = pNext;
553+ };
554+ VALGRIND_DESTROY_MEMPOOL ( this );
555+}
556+
557+template < typename R, bool TRACE >
558+R * RackAlloc < R, rap_freeList, TRACE > :: create (
559+ const type_info & ti )
560+{
561+ M_Alias * pA = 0;
562+ {
563+ Guard guard ( m_mutex );
564+ if ( m_pAlias ) {
565+ pA = m_pAlias;
566+ m_pAlias = m_pAlias->m_pNext;
567+ }
568+ }
569+ if ( ! pA ) {
570+ pA = new M_Alias;
571+ VALGRIND_MAKE_MEM_NOACCESS ( pA, sizeof ( *pA ) );
572+ }
573+ VALGRIND_MEMPOOL_ALLOC ( this, pA->m_rackBuf,
574+ sizeof ( pA->m_rackBuf ) );
575+ m_counter.increment ( sizeof ( R ), ti );
576+
577+ return new ( pA->m_rackBuf ) R ();
578+}
579+
580+template < typename R, bool TRACE >
581+void RackAlloc < R, rap_freeList, TRACE > :: destroy ( R * const pR )
582+{
583+ if ( pR ) {
584+ pR->~R ();
585+ static const size_t bufOffset = offsetof ( M_Alias, m_rackBuf );
586+ const POctet pOctets = reinterpret_cast < POctet > ( pR ) - bufOffset;
587+ M_Alias * const pA = reinterpret_cast < M_Alias * > ( pOctets );
588+ VALGRIND_MEMPOOL_FREE ( this, pA->m_rackBuf );
589+ VALGRIND_MAKE_MEM_UNDEFINED ( &pA->m_pNext, sizeof ( pA->m_pNext ) );
590+ {
591+ Guard guard ( m_mutex );
592+ pA->m_pNext = m_pAlias;
593+ m_pAlias = pA;
594+ }
595+ VALGRIND_MAKE_MEM_DEFINED ( &pA->m_pNext, sizeof ( pA->m_pNext ) );
596+ m_counter.decrement ( sizeof ( R ) );
597+ }
598+}
599+
600+template < typename R, bool TRACE >
601+inline size_t RackAlloc < R, rap_freeList, TRACE > :: rackCount () const
602+{
603+ return m_counter.rackCount ();
604+}
605+
606+template < typename R, bool TRACE >
607+inline size_t RackAlloc < R, rap_freeList, TRACE > :: byteCount () const
608+{
609+ return m_counter.byteCount ();
610+}
611+
612+template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
613+inline AllocatorArena < T, G, N, P, TRACE > :: AllocatorArena ()
614+{
615+}
616+
617+template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
618+template < typename Y >
619+inline AllocatorArena < T, G, N, P, TRACE > :: AllocatorArena ( const Y & )
620+{
621+}
622+
623+// address
624+template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
625+inline typename AllocatorArena < T, G, N, P, TRACE > :: pointer
626+ AllocatorArena < T, G, N, P, TRACE > :: address ( reference r )
627+{
628+ return & r;
629+}
630+
631+template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
632+inline typename AllocatorArena < T, G, N, P, TRACE > :: const_pointer
633+ AllocatorArena < T, G, N, P, TRACE > :: address ( const_reference r )
634+{
635+ return & r;
636+}
637+
638+//
639+// memory allocation
640+// (inline arranges for pNearbyHint to be eliminated
641+// at compile time)
642+template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
643+inline typename AllocatorArena < T, G, N, P, TRACE > :: pointer
644+ AllocatorArena < T, G, N, P, TRACE > :: allocate ( size_type nAlloc,
645+ void_const_pointer pNearbyHint )
646+{
647+ pointer p;
648+ if ( nAlloc == 1u ) {
649+#if defined ( ALLOCATOR_ARENA_MEMORY_ACCESS_INSPECTION_ACTIVE )
650+# if __cplusplus >= 201703L
651+ void * const pVoid = :: operator new ( sizeof (T),
652+ alignof ( T ) );
653+# else
654+ // This function is required to return a pointer suitably
655+ // aligned to hold an object of any fundamental alignment.
656+ void * const pVoid = :: operator new ( sizeof (T) );
657+# endif
658+ p = static_cast < pointer > ( pVoid );
659+#else
660+ p = m_threadPrivateAlloc ();
661+#endif
662+ }
663+ else {
664+# if __cplusplus >= 201703L
665+ void * const pVoid = :: operator new ( sizeof (T) * nAlloc,
666+ alignof ( T ) );
667+# else
668+ // This function is required to return a pointer suitably
669+ // aligned to hold an object of any fundamental alignment.
670+ void * const pVoid = :: operator new ( sizeof (T) * nAlloc );
671+# endif
672+ p = static_cast < pointer > ( pVoid );
673+ }
674+ return p;
675+}
676+
677+template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
678+inline void AllocatorArena < T, G, N, P, TRACE > :: deallocate ( const pointer p,
679+ size_type nAlloc )
680+{
681+ if ( nAlloc == 1u ) {
682+#if defined ( ALLOCATOR_ARENA_MEMORY_ACCESS_INSPECTION_ACTIVE )
683+ :: operator delete ( p );
684+#else
685+ M_Rack * const pRack = M_Rack :: dealloc ( p );
686+ if ( pRack ) {
687+ staticInstance < M_RackAlloc > ().destroy ( pRack );
688+ }
689+#endif
690+ }
691+ else {
692+ :: operator delete ( p );
693+ }
694+}
695+
696+template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
697+inline void * AllocatorArena < T, G, N, P, TRACE > ::
698+ allocateOctets ( size_type sz )
699+{
700+ if ( sz == sizeof ( T ) ) {
701+ return AllocatorArena :: allocate ( 1u );
702+ }
703+ else {
704+ // This function is required to return a pointer suitably
705+ // aligned to hold an object of any fundamental alignment.
706+ return :: operator new ( sz );
707+ }
708+}
709+
710+template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
711+inline void * AllocatorArena < T, G, N, P, TRACE > ::
712+ allocateOctets ( size_type sz,
713+ const std :: nothrow_t & )
714+{
715+ if ( sz == sizeof ( T ) ) {
716+ try {
717+ return AllocatorArena :: allocate ( 1u );
718+ }
719+ catch ( const std :: bad_alloc & ) {
720+ return static_cast < void * > ( 0 );
721+ }
722+ }
723+ else {
724+ // This function is required to return a pointer suitably
725+ // aligned to hold an object of any fundamental alignment.
726+ return :: operator new ( sz, std :: nothrow );
727+ }
728+}
729+
730+template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
731+inline void AllocatorArena < T, G, N, P, TRACE > ::
732+ deallocateOctets ( void * const p, size_type sz )
733+{
734+ if ( sz == sizeof ( T ) ) {
735+ T * const pT = static_cast < T * > ( p );
736+ AllocatorArena :: deallocate ( pT, 1u );
737+ }
738+ else {
739+#if __cplusplus >= 201400L
740+ :: operator delete ( p, sz );
741+#else
742+ :: operator delete ( p );
743+#endif
744+ }
745+}
746+
747+template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
748+inline typename AllocatorArena < T, G, N, P, TRACE > :: size_type
749+ AllocatorArena < T, G, N, P, TRACE > :: max_size ()
750+{
751+ // This class is intended only for use with an allocation size of one;
752+ // if requests for more than one object occur it falls back to ordinary
753+ // new and delete based allocation.
754+ return 1u;
755+}
756+
757+template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
758+typename AllocatorArena < T, G, N, P, TRACE > :: pointer
759+ AllocatorArena < T, G, N, P, TRACE > :: m_threadPrivateAlloc ()
760+{
761+ AllocCtx < G > & ctx = staticInstance < AllocCtxTyped < T, G > > ();
762+ RackManager * const pRM = ctx.getRackHandlerPtr ();
763+ M_Rack * pRack = static_cast < M_Rack * > ( pRM->m_pRack );
764+ if ( pRack ) {
765+ pointer p = static_cast < T * > ( pRack->alloc () );
766+ if ( p ) {
767+ if ( pRack->empty () ) {
768+ assert ( pRM->m_pThreadExitFunc );
769+ ( *pRM->m_pThreadExitFunc ) ( pRack );
770+ pRM->m_pThreadExitFunc = 0;
771+ pRM->m_pRack = 0;
772+ }
773+ return p;
774+ }
775+ assert ( pRM->m_pThreadExitFunc );
776+ ( *pRM->m_pThreadExitFunc ) ( pRack );
777+ pRM->m_pThreadExitFunc = 0;
778+ pRM->m_pRack = 0;
779+ }
780+ pRack = staticInstance < M_RackAlloc > ().create ( typeid ( T ) );
781+ assert ( pRack );
782+ pRack->addReference ();
783+ pRM->m_pThreadExitFunc = m_rackCleanup;
784+ pRM->m_pRack = pRack;
785+ pointer p = static_cast < pointer > ( pRack->alloc () );
786+ assert ( p );
787+ return p;
788+}
789+
790+template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
791+void AllocatorArena < T, G, N, P, TRACE > :: m_rackCleanup ( void * const pPriv )
792+{
793+ assert ( pPriv );
794+ M_Rack * pRack = static_cast < M_Rack * > ( pPriv );
795+ if ( pRack->removeReference () == 0u ) {
796+ staticInstance < M_RackAlloc > ().destroy ( pRack );
797+ }
798+}
799+
800+#if __cplusplus >= 201103L
801+template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
802+template < typename T0, typename ... Args >
803+inline void AllocatorArena < T, G, N, P, TRACE > :: construct ( T0 * p,
804+ Args && ... args )
805+{
806+ void * const pvoid = p;
807+ :: new ( pvoid ) T0 ( std :: forward <Args> ( args ) ... );
808+}
809+#else
810+
811+template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
812+template < typename T0, typename A0 >
813+inline void AllocatorArena < T, G, N, P, TRACE > :: construct (
814+ T0 * p, A0 a0 )
815+{
816+ new ( p ) T ( a0 );
817+}
818+
819+template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
820+template < typename T0, typename A0, typename A1 >
821+inline void AllocatorArena < T, G, N, P, TRACE > :: construct (
822+ T0 * p, A0 a0, A1 a1 )
823+{
824+ new ( p ) T ( a0, a1 );
825+}
826+
827+template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
828+template < typename T0, typename A0, typename A1, typename A2 >
829+inline void AllocatorArena < T, G, N, P, TRACE > :: construct (
830+ T0 * p, A0 a0, A1 a1, A2 a2 )
831+{
832+ new ( p ) T ( a0, a1, a2 );
833+}
834+
835+template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
836+template < typename T0, typename A0, typename A1, typename A2,
837+ typename A3 >
838+inline void AllocatorArena < T, G, N, P, TRACE > :: construct (
839+ T0 * p, A0 a0, A1 a1, A2 a2, A3 a3 )
840+{
841+ new ( p ) T ( a0, a1, a2, a3 );
842+}
843+
844+template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
845+template < typename T0, typename A0, typename A1, typename A2,
846+ typename A3, typename A4 >
847+inline void AllocatorArena < T, G, N, P, TRACE > :: construct (
848+ T0 * p, A0 a0, A1 a1, A2 a2, A3 a3,
849+ A4 a4 )
850+{
851+ new ( p ) T ( a0, a1, a2, a3, a4 );
852+}
853+
854+#endif
855+
856+template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
857+template < class U >
858+inline void AllocatorArena < T, G, N, P, TRACE > :: destroy ( U * p )
859+{
860+ p->~U();
861+}
862+
863+template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
864+inline bool AllocatorArena < T, G, N, P, TRACE > :: operator == (
865+ AllocatorArena const & ao )
866+{
867+ return true;
868+}
869+
870+template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
871+inline bool AllocatorArena < T, G, N, P, TRACE > :: operator != (
872+ AllocatorArena const & a )
873+{
874+ return ! operator == ( a );
875+}
876+
877+template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
878+inline void AllocatorArena < T, G, N, P, TRACE > :: cleanup ()
879+{
880+ AllocCtx < G > & ctx = staticInstance < AllocCtxTyped < T, G > > ();
881+ ctx.cleanup ();
882+}
883+
884+template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
885+inline size_t AllocatorArena < T, G, N, P, TRACE > :: rackCount ()
886+{
887+ return staticInstance < M_RackAlloc > ().rackCount();
888+}
889+
890+template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
891+inline size_t AllocatorArena < T, G, N, P, TRACE > :: byteCount ()
892+{
893+ return staticInstance < M_RackAlloc > ().byteCount();
894+}
895+
896+template < size_t S, size_t A, size_t N >
897+const size_t Rack < S, A, N > :: number = N;
898+
899+template < size_t S, size_t A, size_t N >
900+const size_t Rack < S, A, N > :: alignment = A;
901+
902+template < size_t S, size_t A, size_t N >
903+inline Rack < S, A, N > :: Rack () :
904+ m_nAlloc ( 0u ),
905+ m_refCount ( 0u )
906+{
907+ VALGRIND_MAKE_MEM_NOACCESS ( m_wrapped, sizeof ( m_wrapped ) );
908+}
909+
910+template < size_t S, size_t A, size_t N >
911+inline Rack < S, A, N > :: ~Rack ()
912+{
913+ // if a Rack allocating free list is destroyed, and it destroys
914+ // a rack with outstanding references remaining then problems
915+ // will ensue
916+ assert ( m_refCount == 0u );
917+ VALGRIND_MAKE_MEM_NOACCESS ( m_wrapped, sizeof ( m_wrapped ) );
918+}
919+
920+template < size_t S, size_t A, size_t N >
921+inline bool Rack < S, A, N > :: empty () const
922+{
923+ return m_nAlloc >= N;
924+}
925+
926+template < size_t S, size_t A, size_t N >
927+void * Rack < S, A, N > :: alloc ()
928+{
929+ void * p = 0;
930+ if ( m_nAlloc < N ) {
931+ M_Wrapper * const pAlloc = & m_wrapped[m_nAlloc];
932+ m_nAlloc++;
933+ this->addReference ();
934+ VALGRIND_MAKE_MEM_UNDEFINED ( &pAlloc->m_pRack,
935+ sizeof ( pAlloc->m_pRack ) );
936+ atomic :: set ( pAlloc->m_pRack, this );
937+ VALGRIND_MAKE_MEM_DEFINED ( &pAlloc->m_pRack,
938+ sizeof ( pAlloc->m_pRack ) );
939+ p = static_cast < void * > ( pAlloc->m_bufForObj );
940+ VALGRIND_MALLOCLIKE_BLOCK ( pAlloc->m_bufForObj,
941+ sizeof ( pAlloc->m_bufForObj ),
942+ sizeof ( epicsMemChkRedZone ),
943+ false );
944+ }
945+ return p;
946+}
947+
948+template < size_t S, size_t A, size_t N >
949+Rack < S, A , N > * Rack < S, A, N > :: dealloc ( void * const p )
950+{
951+ static const size_t bufOffset = offsetof ( M_Wrapper, m_bufForObj );
952+ const POctet pOctets = static_cast < POctet > ( p ) - bufOffset;
953+ const PWrapper pDealloc = reinterpret_cast < PWrapper > ( pOctets );
954+ VALGRIND_FREELIKE_BLOCK ( pDealloc->m_bufForObj,
955+ sizeof ( epicsMemChkRedZone ) );
956+ Rack * const pRack = static_cast < Rack * >
957+ ( atomic :: get ( pDealloc->m_pRack ) );
958+ pDealloc->m_pRack = 0; // for imperfect error detection purposes
959+ assert ( pRack );
960+ if ( pRack->removeReference () == 0u ) {
961+ return pRack;
962+ }
963+ return 0;
964+}
965+
966+template < size_t S, size_t A, size_t N >
967+inline void Rack < S, A, N > :: addReference ()
968+{
969+ assert ( m_refCount < SIZE_MAX );
970+ atomic :: increment ( m_refCount );
971+}
972+
973+template < size_t S, size_t A, size_t N >
974+inline size_t Rack < S, A, N > :: removeReference ()
975+{
976+ assert ( m_refCount > 0u );
977+ return atomic :: decrement ( m_refCount );
978+}
979+
980+} // end of name space _impl
981+
982+using _impl :: Rack;
983+using _impl :: RackAlloc;
984+using _impl :: RackAllocPolicy;
985+using _impl :: rap_pool;
986+using _impl :: rap_freeList;
987+using _impl :: AllocatorArena;
988+
989+} // end of name space epics
990+
991+#endif // if not defined epicsAllocatorArena_h
992+
993diff --git a/modules/libcom/src/misc/AllocatorArenaUntyped.cpp b/modules/libcom/src/misc/AllocatorArenaUntyped.cpp
994new file mode 100644
995index 0000000..91693a2
996--- /dev/null
997+++ b/modules/libcom/src/misc/AllocatorArenaUntyped.cpp
998@@ -0,0 +1,199 @@
999+
1000+/*************************************************************************\
1001+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
1002+* National Laboratory
1003+* EPICS BASE is distributed subject to a Software License Agreement found
1004+* in file LICENSE that is included with this distribution.
1005+\*************************************************************************/
1006+
1007+/*
1008+ * Author Jeffrey O. Hill
1009+ */
1010+
1011+#include <cstdio>
1012+#include <memory>
1013+
1014+#define epicsExportSharedSymbols
1015+#include "AllocatorArena.h"
1016+#include "errlog.h"
1017+#include "epicsTypes.h"
1018+#include "epicsExit.h"
1019+#include "epicsDemangle.h"
1020+
1021+namespace epics {
1022+namespace _impl {
1023+
1024+const char * ThreadPrivateIdBadAlloc :: what () const throw ()
1025+{
1026+ return "epicsThreadPrivateCreate returned nill";
1027+}
1028+
1029+const char * AtThreadExitBadAlloc :: what () const throw ()
1030+{
1031+ return "epicsAtThreadExit was unsuccessful";
1032+}
1033+
1034+const size_t AllocCtxCom :: m_initialCapacity = 16u;
1035+
1036+AllocCtxCom :: AllocCtxCom () :
1037+ m_threadPrivateId ( epicsThreadPrivateCreate () ),
1038+ m_curIdx ( 0 )
1039+{
1040+}
1041+
1042+union RackManagerUnion {
1043+ RackManager m_entry;
1044+ size_t m_capacity;
1045+};
1046+
1047+size_t AllocCtxCom :: allocIdx ()
1048+{
1049+ return atomic :: increment ( m_curIdx );
1050+}
1051+
1052+/*
1053+ * from the bit twiddling hacks web site
1054+ */
1055+static inline epicsUInt32 nextPwrOf2 ( epicsUInt32 v )
1056+{
1057+ v--;
1058+ v |= v >> 1u;
1059+ v |= v >> 2u;
1060+ v |= v >> 4u;
1061+ v |= v >> 8u;
1062+ v |= v >> 16u;
1063+ v++;
1064+ return v;
1065+}
1066+
1067+RackManager * AllocCtxCom :: getRackHandlerPtr ( const size_t idx )
1068+{
1069+ void * const pPriv = epicsThreadPrivateGet ( m_threadPrivateId );
1070+ RackManagerUnion * pThrPriv;
1071+ if ( pPriv ) {
1072+ pThrPriv = static_cast < RackManagerUnion * > ( pPriv );
1073+ if ( idx >= pThrPriv->m_capacity ) {
1074+ const size_t newCapacity = nextPwrOf2 ( idx + 1u );
1075+ RackManagerUnion * const pThrPrivNew =
1076+ new RackManagerUnion [newCapacity];
1077+ assert ( newCapacity > idx );
1078+ size_t i;
1079+ for ( i = 1u; i < pThrPriv->m_capacity; i++ ) {
1080+ pThrPrivNew[i] = pThrPriv[i];
1081+ }
1082+ for ( i = pThrPriv->m_capacity; i < newCapacity; i++ ) {
1083+ pThrPrivNew[i].m_entry.m_pRack = 0;
1084+ pThrPrivNew[i].m_entry.m_pThreadExitFunc = 0;
1085+ }
1086+ pThrPrivNew->m_capacity = newCapacity;
1087+ delete [] pThrPriv;
1088+ epicsThreadPrivateSet ( m_threadPrivateId, pThrPrivNew );
1089+ pThrPriv = pThrPrivNew;
1090+ }
1091+ }
1092+ else {
1093+ size_t capacity;
1094+ if ( idx >= m_initialCapacity ) {
1095+ capacity = nextPwrOf2 ( idx + 1u );
1096+ }
1097+ else {
1098+ capacity = m_initialCapacity;
1099+ }
1100+ pThrPriv = new RackManagerUnion [capacity];
1101+ pThrPriv->m_capacity = capacity;
1102+ for ( size_t i = 1u; i < capacity; i++ ) {
1103+ pThrPriv[i].m_entry.m_pRack = 0;
1104+ pThrPriv[i].m_entry.m_pThreadExitFunc = 0;
1105+ }
1106+ int status = epicsAtThreadExit ( m_threadExitFunc, this );
1107+ if ( status != 0 ) {
1108+ delete [] pThrPriv;
1109+ throw AtThreadExitBadAlloc ();
1110+ }
1111+ epicsThreadPrivateSet ( m_threadPrivateId, pThrPriv );
1112+ }
1113+ return & pThrPriv[idx].m_entry;
1114+}
1115+
1116+void AllocCtxCom :: cleanup ( const size_t idx )
1117+{
1118+ void * const pPriv = epicsThreadPrivateGet ( m_threadPrivateId );
1119+ if ( pPriv ) {
1120+ RackManagerUnion * pThrPriv =
1121+ static_cast < RackManagerUnion * > ( pPriv );
1122+ if ( idx < pThrPriv->m_capacity ) {
1123+ if ( pThrPriv[idx].m_entry.m_pThreadExitFunc &&
1124+ pThrPriv[idx].m_entry.m_pRack ) {
1125+ ( *pThrPriv[idx].m_entry.m_pThreadExitFunc )
1126+ ( pThrPriv[idx].m_entry.m_pRack );
1127+ pThrPriv[idx].m_entry.m_pRack = 0;
1128+ pThrPriv[idx].m_entry.m_pThreadExitFunc = 0;
1129+ }
1130+ }
1131+ }
1132+}
1133+
1134+void AllocCtxCom :: m_threadExitFunc ( void * const pPriv )
1135+{
1136+ AllocCtxCom * const pCtx = static_cast < AllocCtxCom * > ( pPriv );
1137+ void * const pThrPrivVoid = epicsThreadPrivateGet ( pCtx->m_threadPrivateId );
1138+ if ( pThrPrivVoid ) {
1139+ RackManagerUnion * const pThrPriv =
1140+ static_cast < RackManagerUnion * > ( pThrPrivVoid );
1141+ for ( size_t i = 1u; i < pThrPriv->m_capacity; i++ ) {
1142+ if ( pThrPriv[i].m_entry.m_pThreadExitFunc &&
1143+ pThrPriv[i].m_entry.m_pRack ) {
1144+ ( *pThrPriv[i].m_entry.m_pThreadExitFunc )
1145+ ( pThrPriv[i].m_entry.m_pRack );
1146+ }
1147+ }
1148+ delete [] pThrPriv;
1149+ epicsThreadPrivateSet ( pCtx->m_threadPrivateId, 0 );
1150+ }
1151+}
1152+
1153+AllocCounter < true > :: AllocCounter ()
1154+{
1155+ atomic :: set ( m_nRacks, 0u );
1156+ atomic :: set ( m_bytes, 0u );
1157+ atomic :: set ( m_nRacksTrace, 8 );
1158+}
1159+
1160+static size_t m_nRacksTotal = 0u;
1161+static size_t m_bytesTotal = 0u;
1162+
1163+void AllocCounter < true > :: increment ( size_t nBytesThisTime,
1164+ const type_info & ti )
1165+{
1166+ const size_t newNRacksVal = atomic :: increment ( m_nRacks );
1167+ atomic :: increment ( m_nRacksTotal );
1168+ atomic :: add ( m_bytes, nBytesThisTime );
1169+ atomic :: add ( m_bytesTotal, nBytesThisTime );
1170+ if ( newNRacksVal >= m_nRacksTrace ) {
1171+ atomic :: add ( m_nRacksTrace, m_nRacksTrace );
1172+ this->show ( ti );
1173+ }
1174+}
1175+
1176+void AllocCounter < true > :: decrement ( size_t nBytesThisTime )
1177+{
1178+ atomic :: decrement ( m_nRacks );
1179+ atomic :: decrement ( m_nRacksTotal );
1180+ atomic :: subtract ( m_bytes, nBytesThisTime );
1181+ atomic :: subtract ( m_bytesTotal, nBytesThisTime );
1182+}
1183+
1184+void AllocCounter < true > :: show ( const type_info & ti ) const
1185+{
1186+ const std :: string name = epicsDemangleTypeName ( ti );
1187+ errlogPrintf (
1188+ "AA C=%08lu SZ=%08lu CT=%08lu SZT=%08lu \"%s\"\n",
1189+ ( unsigned long ) m_nRacks,
1190+ ( unsigned long ) m_bytes,
1191+ ( unsigned long ) m_nRacksTotal,
1192+ ( unsigned long ) m_bytesTotal,
1193+ name.c_str () );
1194+}
1195+
1196+} // end of name space _impl
1197+} // end of name space epics
1198diff --git a/modules/libcom/src/misc/Makefile b/modules/libcom/src/misc/Makefile
1199index 3d5412d..fb94ec9 100644
1200--- a/modules/libcom/src/misc/Makefile
1201+++ b/modules/libcom/src/misc/Makefile
1202@@ -27,6 +27,7 @@ INC += ipAddrToAsciiAsynchronous.h
1203 INC += compilerDependencies.h
1204 INC += epicsUnitTest.h
1205 INC += testMain.h
1206+INC += AllocatorArena.h
1207
1208 # epicsVersion.h is created by this Makefile
1209 INC += epicsVersion.h
1210@@ -42,3 +43,5 @@ Com_SRCS += epicsString.c
1211 Com_SRCS += truncateFile.c
1212 Com_SRCS += ipAddrToAsciiAsynchronous.cpp
1213 Com_SRCS += epicsUnitTest.c
1214+Com_SRCS += AllocatorArenaUntyped.cpp
1215+
1216diff --git a/modules/libcom/src/osi/Makefile b/modules/libcom/src/osi/Makefile
1217index f0108e6..9e1dcee 100644
1218--- a/modules/libcom/src/osi/Makefile
1219+++ b/modules/libcom/src/osi/Makefile
1220@@ -9,8 +9,16 @@
1221
1222 SRC_DIRS += $(LIBCOM)/osi
1223
1224+# compiler specific
1225 INC += compilerDependencies.h
1226 INC += compilerSpecific.h
1227+INC += epicsStaticInstance.h
1228+INC += epicsStaticInstanceCD.h
1229+INC += epicsStaticInstanceSaneCmplr.h
1230+INC += epicsStaticInstanceSketchyCmplr.h
1231+
1232+Com_SRCS += epicsStaticInstanceSketchyCmplr.cpp
1233+Com_SRCS += compilerDependentDemangle.cpp
1234
1235 INC += osiFileName.h
1236 INC += osiSock.h
1237@@ -57,6 +65,7 @@ INC += epicsStdioRedirect.h
1238 INC += epicsTempFile.h
1239 INC += epicsGetopt.h
1240 INC += epicsStackTrace.h
1241+INC += epicsDemangle.h
1242
1243 INC += devLib.h
1244 INC += devLibVME.h
1245@@ -157,3 +166,4 @@ Com_SRCS_WIN32 += forceBadAllocException.cpp
1246 Com_SRCS += epicsStackTrace.c
1247 Com_SRCS += osdBackTrace.cpp
1248 Com_SRCS += osdFindAddr.c
1249+
1250diff --git a/modules/libcom/src/osi/compiler/clang/compilerSpecific.h b/modules/libcom/src/osi/compiler/clang/compilerSpecific.h
1251index 0498f6e..c06272f 100644
1252--- a/modules/libcom/src/osi/compiler/clang/compilerSpecific.h
1253+++ b/modules/libcom/src/osi/compiler/clang/compilerSpecific.h
1254@@ -1,4 +1,6 @@
1255 /*************************************************************************\
1256+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
1257+* National Laboratory
1258 * Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
1259 * National Laboratory.
1260 * Copyright (c) 2002 The Regents of the University of California, as
1261@@ -29,6 +31,8 @@
1262 /* Expands to a 'const char*' which describes the name of the current function scope */
1263 #define EPICS_FUNCTION __PRETTY_FUNCTION__
1264
1265+#define NO_RETURN __attribute__((noreturn))
1266+
1267 #ifdef __cplusplus
1268
1269 /*
1270@@ -36,6 +40,8 @@
1271 */
1272 #define CXX_PLACEMENT_DELETE
1273
1274+#define USING_BASE_TYPE(B,T) using typename B :: T;
1275+
1276 #endif /* __cplusplus */
1277
1278 /*
1279diff --git a/modules/libcom/src/osi/compiler/clang/epicsAtomicCD.h b/modules/libcom/src/osi/compiler/clang/epicsAtomicCD.h
1280index 763cb05..515129b 100644
1281--- a/modules/libcom/src/osi/compiler/clang/epicsAtomicCD.h
1282+++ b/modules/libcom/src/osi/compiler/clang/epicsAtomicCD.h
1283@@ -1,7 +1,7 @@
1284
1285 /*************************************************************************\
1286-* Copyright (c) 2011 LANS LLC, as Operator of
1287-* Los Alamos National Laboratory.
1288+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
1289+* National Laboratory
1290 * Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
1291 * National Laboratory.
1292 * EPICS BASE is distributed subject to a Software License Agreement found
1293diff --git a/modules/libcom/src/osi/compiler/default/compilerDependentDemangle.cpp b/modules/libcom/src/osi/compiler/default/compilerDependentDemangle.cpp
1294new file mode 100644
1295index 0000000..4a1f404
1296--- /dev/null
1297+++ b/modules/libcom/src/osi/compiler/default/compilerDependentDemangle.cpp
1298@@ -0,0 +1,28 @@
1299+
1300+/*************************************************************************\
1301+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
1302+* National Laboratory
1303+* EPICS BASE is distributed subject to a Software License Agreement found
1304+* in file LICENSE that is included with this distribution.
1305+\*************************************************************************/
1306+
1307+/*
1308+ * Author: Jeffrey O. Hill
1309+ */
1310+#include <exception>
1311+#include <cstdlib>
1312+
1313+#define epicsExportSharedSymbols
1314+#include "epicsDemangle.h"
1315+
1316+using std :: string;
1317+
1318+std :: string epicsDemangle ( const char * const pMangledName )
1319+{
1320+ return std :: string ( pMangledName );
1321+}
1322+
1323+std :: string epicsDemangleTypeName ( const std :: type_info & ti )
1324+{
1325+ return epicsDemangle ( ti.name () );
1326+}
1327diff --git a/modules/libcom/src/osi/compiler/default/compilerSpecific.h b/modules/libcom/src/osi/compiler/default/compilerSpecific.h
1328index 8af1727..3c64c39 100644
1329--- a/modules/libcom/src/osi/compiler/default/compilerSpecific.h
1330+++ b/modules/libcom/src/osi/compiler/default/compilerSpecific.h
1331@@ -1,4 +1,6 @@
1332 /*************************************************************************\
1333+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
1334+* National Laboratory
1335 * Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
1336 * National Laboratory.
1337 * Copyright (c) 2002 The Regents of the University of California, as
1338@@ -26,15 +28,18 @@
1339
1340 #ifdef __cplusplus
1341
1342+#define NO_RETURN
1343+
1344+
1345 /*
1346 * CXX_PLACEMENT_DELETE - defined if compiler supports placement delete
1347- * CXX_THROW_SPECIFICATION - defined if compiler supports throw specification
1348 *
1349 * (our default guess is that the compiler implements the C++ 97 standard)
1350 */
1351-#define CXX_THROW_SPECIFICATION
1352 #define CXX_PLACEMENT_DELETE
1353
1354+#define USING_BASE_TYPE(B,T) using typename B :: T;
1355+
1356 #endif /* __cplusplus */
1357
1358
1359diff --git a/modules/libcom/src/osi/compiler/default/epicsAtomicCD.h b/modules/libcom/src/osi/compiler/default/epicsAtomicCD.h
1360index 585a39c..55e4ab7 100644
1361--- a/modules/libcom/src/osi/compiler/default/epicsAtomicCD.h
1362+++ b/modules/libcom/src/osi/compiler/default/epicsAtomicCD.h
1363@@ -1,7 +1,7 @@
1364
1365 /*************************************************************************\
1366-* Copyright (c) 2011 LANS LLC, as Operator of
1367-* Los Alamos National Laboratory.
1368+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
1369+* National Laboratory
1370 * Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
1371 * National Laboratory.
1372 * EPICS BASE is distributed subject to a Software License Agreement found
1373diff --git a/modules/libcom/src/osi/compiler/default/epicsStaticInstanceCD.h b/modules/libcom/src/osi/compiler/default/epicsStaticInstanceCD.h
1374new file mode 100644
1375index 0000000..094e7a9
1376--- /dev/null
1377+++ b/modules/libcom/src/osi/compiler/default/epicsStaticInstanceCD.h
1378@@ -0,0 +1,20 @@
1379+
1380+/*************************************************************************\
1381+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
1382+* National Laboratory
1383+* EPICS BASE is distributed subject to a Software License Agreement found
1384+* in file LICENSE that is included with this distribution.
1385+\*************************************************************************/
1386+
1387+/*
1388+ * Author Jeffrey O. Hill
1389+ * johill@lanl.gov
1390+ */
1391+
1392+#ifndef epicsStaticInstanceCD_h
1393+#define epicsStaticInstanceCD_h
1394+
1395+// we dont trust compilers we dont know
1396+# include "epicsStaticInstanceSketchyCmplr.h"
1397+
1398+#endif /* epicsStaticInstanceCD_h */
1399diff --git a/modules/libcom/src/osi/compiler/gcc/compilerDependentDemangle.cpp b/modules/libcom/src/osi/compiler/gcc/compilerDependentDemangle.cpp
1400new file mode 100644
1401index 0000000..a0f0429
1402--- /dev/null
1403+++ b/modules/libcom/src/osi/compiler/gcc/compilerDependentDemangle.cpp
1404@@ -0,0 +1,168 @@
1405+
1406+/*************************************************************************\
1407+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
1408+* National Laboratory
1409+* EPICS BASE is distributed subject to a Software License Agreement found
1410+* in file LICENSE that is included with this distribution.
1411+\*************************************************************************/
1412+
1413+/*
1414+ * Author: Jeffrey O. Hill
1415+ */
1416+#include <exception>
1417+#include <cstdlib>
1418+
1419+#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 300
1420+# include <cxxabi.h>
1421+#endif
1422+
1423+#include "epicsThread.h"
1424+#include "epicsAtomic.h"
1425+#include "epicsExit.h"
1426+#include "epicsAssert.h"
1427+
1428+#include "epicsDemangle.h"
1429+
1430+using std :: string;
1431+
1432+union ThreadPrivateId {
1433+ ThreadPrivateId () : m_epics ( 0 ) {}
1434+ epicsThreadPrivateId m_epics;
1435+ void * m_cmpAndSwap;
1436+};
1437+
1438+class ThreadPrivate {
1439+public:
1440+ ThreadPrivate ();
1441+ ~ThreadPrivate ();
1442+ string demangle ( const char * pMangledName );
1443+ static ThreadPrivate * get ();
1444+ static void epicsExit ( void * /* arg */ );
1445+private:
1446+ char * m_pBuf;
1447+ size_t m_bufSize;
1448+ static const size_t m_bufSizeInit;
1449+ static ThreadPrivateId m_privateId;
1450+};
1451+
1452+const size_t ThreadPrivate :: m_bufSizeInit = 256u;
1453+ThreadPrivateId ThreadPrivate :: m_privateId;
1454+
1455+//
1456+// __cxa_demangle doc indicates that buffer passed must be allocated
1457+// with malloc
1458+//
1459+ThreadPrivate :: ThreadPrivate () :
1460+ m_pBuf ( static_cast < char * > ( malloc ( m_bufSizeInit ) ) ),
1461+ m_bufSize ( m_pBuf ? m_bufSizeInit : 0u )
1462+{
1463+}
1464+
1465+ThreadPrivate :: ~ThreadPrivate ()
1466+{
1467+ //
1468+ // __cxa_demangle doc indicates that buffer passed must be allocated
1469+ // with malloc
1470+ //
1471+ free ( m_pBuf );
1472+}
1473+
1474+string ThreadPrivate :: demangle ( const char * const pMangledName )
1475+{
1476+ if ( ! m_pBuf ) {
1477+ //
1478+ // __cxa_demangle doc indicates that buffer passed must be
1479+ // allocated with malloc
1480+ //
1481+ m_pBuf = static_cast < char * > ( malloc ( m_bufSizeInit ) );
1482+ if ( m_pBuf ) {
1483+ m_bufSize = m_bufSizeInit;
1484+ }
1485+ else {
1486+ m_bufSize = 0u;
1487+ return pMangledName;
1488+ }
1489+ }
1490+ int status = -1000;
1491+ size_t sz = m_bufSize;
1492+ char * const pBufResult =
1493+ abi :: __cxa_demangle ( pMangledName, m_pBuf,
1494+ & sz, & status );
1495+ if ( pBufResult ) {
1496+ m_pBuf = pBufResult;
1497+ m_bufSize = sz;
1498+ if ( status == 0 ) {
1499+ return string ( pBufResult );
1500+ }
1501+ else {
1502+ return string ( pMangledName );
1503+ }
1504+ }
1505+ return string ( pMangledName );
1506+}
1507+
1508+void ThreadPrivate :: epicsExit ( void * p )
1509+{
1510+ if ( m_privateId.m_epics ) {
1511+ epicsThreadPrivateSet ( m_privateId.m_epics, 0 );
1512+ }
1513+ ThreadPrivate * const pPriv = static_cast < ThreadPrivate * > ( p );
1514+ delete pPriv;
1515+}
1516+
1517+inline ThreadPrivate * ThreadPrivate :: get ()
1518+{
1519+ STATIC_ASSERT ( sizeof ( m_privateId.m_cmpAndSwap ) ==
1520+ sizeof ( m_privateId.m_epics ) );
1521+ if ( ! m_privateId.m_epics ) {
1522+ ThreadPrivateId newId;
1523+ newId.m_epics = epicsThreadPrivateCreate ();
1524+ if ( ! newId.m_epics ) {
1525+ return 0;
1526+ }
1527+ const EpicsAtomicPtrT pBefore =
1528+ epicsAtomicCmpAndSwapPtrT ( & m_privateId.m_cmpAndSwap,
1529+ 0, newId.m_cmpAndSwap );
1530+ if ( pBefore ) {
1531+ epicsThreadPrivateDelete ( newId.m_epics );
1532+ }
1533+ }
1534+ void * const p = epicsThreadPrivateGet ( m_privateId.m_epics );
1535+ ThreadPrivate * pPriv = static_cast < ThreadPrivate * > ( p );
1536+ if ( ! pPriv ) {
1537+ pPriv = new ( std :: nothrow ) ThreadPrivate ();
1538+ if ( pPriv ) {
1539+ const int status =
1540+ epicsAtThreadExit ( ThreadPrivate :: epicsExit, pPriv );
1541+ if ( status < 0 ) {
1542+ delete pPriv;
1543+ pPriv = 0;
1544+ }
1545+ epicsThreadPrivateSet ( m_privateId.m_epics, pPriv );
1546+ }
1547+ }
1548+ return pPriv;
1549+}
1550+
1551+std :: string epicsDemangle ( const char * const pMangledName )
1552+{
1553+ if ( pMangledName ) {
1554+# if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 300
1555+ ThreadPrivate * const pPriv = ThreadPrivate :: get ();
1556+ if ( ! pPriv ) {
1557+ return pMangledName;
1558+ }
1559+ return pPriv->demangle ( pMangledName );
1560+# else
1561+ return pMangledName;
1562+# endif
1563+ }
1564+ else {
1565+ return "<nil type name>";
1566+ }
1567+}
1568+
1569+std :: string epicsDemangleTypeName ( const std :: type_info & ti )
1570+{
1571+ return epicsDemangle ( ti.name () );
1572+}
1573diff --git a/modules/libcom/src/osi/compiler/gcc/compilerSpecific.h b/modules/libcom/src/osi/compiler/gcc/compilerSpecific.h
1574index 3342308..3a75150 100644
1575--- a/modules/libcom/src/osi/compiler/gcc/compilerSpecific.h
1576+++ b/modules/libcom/src/osi/compiler/gcc/compilerSpecific.h
1577@@ -1,4 +1,6 @@
1578 /*************************************************************************\
1579+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
1580+* National Laboratory
1581 * Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
1582 * National Laboratory.
1583 * Copyright (c) 2002 The Regents of the University of California, as
1584@@ -29,6 +31,8 @@
1585 /* Expands to a 'const char*' which describes the name of the current function scope */
1586 #define EPICS_FUNCTION __PRETTY_FUNCTION__
1587
1588+#define NO_RETURN __attribute__((noreturn))
1589+
1590 #ifdef __cplusplus
1591
1592 /*
1593@@ -50,6 +54,12 @@
1594 */
1595 #define EPICS_PRINTF_STYLE(f,a) __attribute__((format(__printf__,f,a)))
1596
1597+#if __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 8 )
1598+# define USING_BASE_TYPE(B,T) using typename B :: T;
1599+#else
1600+# define USING_BASE_TYPE(B,T) typedef typename B :: T T;
1601+#endif
1602+
1603 /*
1604 * Deprecation marker
1605 */
1606diff --git a/modules/libcom/src/osi/compiler/gcc/epicsAtomicCD.h b/modules/libcom/src/osi/compiler/gcc/epicsAtomicCD.h
1607index 15b9a6c..d268803 100644
1608--- a/modules/libcom/src/osi/compiler/gcc/epicsAtomicCD.h
1609+++ b/modules/libcom/src/osi/compiler/gcc/epicsAtomicCD.h
1610@@ -1,7 +1,7 @@
1611
1612 /*************************************************************************\
1613-* Copyright (c) 2011 LANS LLC, as Operator of
1614-* Los Alamos National Laboratory.
1615+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
1616+* National Laboratory
1617 * Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
1618 * National Laboratory.
1619 * EPICS BASE is distributed subject to a Software License Agreement found
1620diff --git a/modules/libcom/src/osi/compiler/gcc/epicsStaticInstanceCD.h b/modules/libcom/src/osi/compiler/gcc/epicsStaticInstanceCD.h
1621new file mode 100644
1622index 0000000..d7d974e
1623--- /dev/null
1624+++ b/modules/libcom/src/osi/compiler/gcc/epicsStaticInstanceCD.h
1625@@ -0,0 +1,26 @@
1626+
1627+/*************************************************************************\
1628+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
1629+* National Laboratory
1630+* EPICS BASE is distributed subject to a Software License Agreement found
1631+* in file LICENSE that is included with this distribution.
1632+\*************************************************************************/
1633+
1634+/*
1635+ * Author Jeffrey O. Hill
1636+ * johill@lanl.gov
1637+ */
1638+
1639+#ifndef epicsStaticInstanceCD_h
1640+#define epicsStaticInstanceCD_h
1641+
1642+#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 401
1643+ // any gcc version that has -fno-threadsafe-statics
1644+ // should be ok
1645+# include "epicsStaticInstanceSaneCmplr.h"
1646+#else // ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 401
1647+ // other gcc maybe cant be trusted without more testing
1648+# include "epicsStaticInstanceSketchyCmplr.h"
1649+#endif // ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 401
1650+
1651+#endif // epicsStaticInstanceCD_h
1652diff --git a/modules/libcom/src/osi/compiler/msvc/compilerSpecific.h b/modules/libcom/src/osi/compiler/msvc/compilerSpecific.h
1653index 4e282db..ab4e134 100644
1654--- a/modules/libcom/src/osi/compiler/msvc/compilerSpecific.h
1655+++ b/modules/libcom/src/osi/compiler/msvc/compilerSpecific.h
1656@@ -1,4 +1,6 @@
1657 /*************************************************************************\
1658+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
1659+* National Laboratory
1660 * Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
1661 * National Laboratory.
1662 * Copyright (c) 2002 The Regents of the University of California, as
1663@@ -21,6 +23,8 @@
1664 #endif
1665
1666 #define EPICS_ALWAYS_INLINE __forceinline
1667+#define NO_RETURN __declspec(noreturn)
1668+
1669
1670 /* Expands to a 'const char*' which describes the name of the current function scope */
1671 #define EPICS_FUNCTION __FUNCTION__
1672@@ -36,10 +40,10 @@
1673
1674 /*
1675 * CXX_PLACEMENT_DELETE - defined if compiler supports placement delete
1676- * CXX_THROW_SPECIFICATION - defined if compiler supports throw specification
1677 */
1678 #define CXX_PLACEMENT_DELETE
1679-#define CXX_THROW_SPECIFICATION
1680+
1681+#define USING_BASE_TYPE(B,T) using typename B :: T;
1682
1683 #endif /* __cplusplus */
1684
1685diff --git a/modules/libcom/src/osi/compiler/msvc/epicsAtomicCD.h b/modules/libcom/src/osi/compiler/msvc/epicsAtomicCD.h
1686index e7d1c4b..f9ddc79 100644
1687--- a/modules/libcom/src/osi/compiler/msvc/epicsAtomicCD.h
1688+++ b/modules/libcom/src/osi/compiler/msvc/epicsAtomicCD.h
1689@@ -1,7 +1,7 @@
1690
1691 /*************************************************************************\
1692-* Copyright (c) 2011 LANS LLC, as Operator of
1693-* Los Alamos National Laboratory.
1694+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
1695+* National Laboratory
1696 * Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
1697 * National Laboratory.
1698 * EPICS BASE is distributed subject to a Software License Agreement found
1699diff --git a/modules/libcom/src/osi/compiler/msvc/epicsStaticInstanceCD.h b/modules/libcom/src/osi/compiler/msvc/epicsStaticInstanceCD.h
1700new file mode 100644
1701index 0000000..1859595
1702--- /dev/null
1703+++ b/modules/libcom/src/osi/compiler/msvc/epicsStaticInstanceCD.h
1704@@ -0,0 +1,32 @@
1705+
1706+/*************************************************************************\
1707+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
1708+* National Laboratory
1709+* EPICS BASE is distributed subject to a Software License Agreement found
1710+* in file LICENSE that is included with this distribution.
1711+\*************************************************************************/
1712+
1713+/*
1714+ * Author Jeffrey O. Hill
1715+ * johill@lanl.gov
1716+ */
1717+
1718+#ifndef epicsStaticInstanceCD_h
1719+#define epicsStaticInstanceCD_h
1720+
1721+// visual c++ has some issues
1722+// --------------------------
1723+//
1724+// 1) it lacks mutual exclusion protecting concurrent on demand
1725+// initialization of block scope static variables
1726+//
1727+// 2) it silently adds the path to the .cpp file to the very beginning
1728+// of the include search list so if a msvc specific version of this
1729+// file does not exist and we use the default version then it will
1730+// also use compiler/default/ version, despite the existence
1731+// of a more specialized version, and even if not told to do so on
1732+// the command line
1733+//
1734+# include "epicsStaticInstanceSketchyCmplr.h"
1735+
1736+#endif epicsStaticInstanceCD_h
1737diff --git a/modules/libcom/src/osi/compiler/solStudio/compilerSpecific.h b/modules/libcom/src/osi/compiler/solStudio/compilerSpecific.h
1738index a9d59a5..20065e2 100644
1739--- a/modules/libcom/src/osi/compiler/solStudio/compilerSpecific.h
1740+++ b/modules/libcom/src/osi/compiler/solStudio/compilerSpecific.h
1741@@ -1,4 +1,6 @@
1742 /*************************************************************************\
1743+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
1744+* National Laboratory
1745 * Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
1746 * National Laboratory.
1747 * Copyright (c) 2002 The Regents of the University of California, as
1748@@ -31,11 +33,9 @@
1749
1750 /*
1751 * CXX_PLACEMENT_DELETE - defined if compiler supports placement delete
1752- * CXX_THROW_SPECIFICATION - defined if compiler supports throw specification
1753 *
1754 * (our default guess is that the compiler implements the C++ 97 standard)
1755 */
1756-#define CXX_THROW_SPECIFICATION
1757 #define CXX_PLACEMENT_DELETE
1758
1759 #endif /* __cplusplus */
1760diff --git a/modules/libcom/src/osi/compiler/solStudio/epicsAtomicCD.h b/modules/libcom/src/osi/compiler/solStudio/epicsAtomicCD.h
1761index 8a733a5..b92e36a 100644
1762--- a/modules/libcom/src/osi/compiler/solStudio/epicsAtomicCD.h
1763+++ b/modules/libcom/src/osi/compiler/solStudio/epicsAtomicCD.h
1764@@ -1,7 +1,7 @@
1765
1766 /*************************************************************************\
1767-* Copyright (c) 2011 LANS LLC, as Operator of
1768-* Los Alamos National Laboratory.
1769+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
1770+* National Laboratory
1771 * Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
1772 * National Laboratory.
1773 * EPICS BASE is distributed subject to a Software License Agreement found
1774diff --git a/modules/libcom/src/osi/compilerDependencies.h b/modules/libcom/src/osi/compilerDependencies.h
1775index 0b333d7..509687a 100644
1776--- a/modules/libcom/src/osi/compilerDependencies.h
1777+++ b/modules/libcom/src/osi/compilerDependencies.h
1778@@ -1,4 +1,6 @@
1779 /*************************************************************************\
1780+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
1781+* National Laboratory
1782 * Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
1783 * National Laboratory.
1784 * Copyright (c) 2002 The Regents of the University of California, as
1785@@ -20,6 +22,46 @@
1786
1787 #ifdef __cplusplus
1788
1789+#if __cplusplus >= 201103L
1790+#define epicsOverride override
1791+#else
1792+#define epicsOverride
1793+#endif
1794+
1795+#if __cplusplus >= 201103L
1796+#define epicsFinal final
1797+#else
1798+#define epicsFinal
1799+#endif
1800+
1801+#if __cplusplus >= 201103L
1802+#define epicsNoexcept noexcept
1803+#else
1804+#define epicsNoexcept throw()
1805+#endif
1806+
1807+#if __cplusplus >= 201103L
1808+#define epicsConstexpr constexpr
1809+#else
1810+#define epicsConstexpr
1811+#endif
1812+
1813+#if __cplusplus >= 201103L
1814+#define epicsMove(A) std::move(A)
1815+#else
1816+#define epicsMove(A) (A)
1817+#endif
1818+
1819+/*
1820+ * deleted method should also be declared private as per convention
1821+ * with old compilers
1822+ */
1823+#if __cplusplus >= 201103L
1824+#define epicsDeleteMethod =delete
1825+#else
1826+#define epicsDeleteMethod
1827+#endif
1828+
1829 /*
1830 * usage: epicsPlacementDeleteOperator (( void *, myMemoryManager & ))
1831 */
1832diff --git a/modules/libcom/src/osi/epicsDemangle.h b/modules/libcom/src/osi/epicsDemangle.h
1833new file mode 100644
1834index 0000000..07bd299
1835--- /dev/null
1836+++ b/modules/libcom/src/osi/epicsDemangle.h
1837@@ -0,0 +1,26 @@
1838+
1839+/*************************************************************************\
1840+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
1841+* National Laboratory
1842+* EPICS BASE is distributed subject to a Software License Agreement found
1843+* in file LICENSE that is included with this distribution.
1844+\*************************************************************************/
1845+
1846+/*
1847+ * Author: Jeffrey O. Hill
1848+ */
1849+
1850+#ifndef epicsDemangleh
1851+#define epicsDemangleh
1852+
1853+#include <string>
1854+#include <typeinfo>
1855+
1856+#include "shareLib.h"
1857+
1858+epicsShareFunc std :: string
1859+ epicsDemangle ( const char * const pMangledName );
1860+epicsShareFunc std :: string
1861+ epicsDemangleTypeName ( const std :: type_info & );
1862+
1863+#endif /* epicsDemangleh */
1864diff --git a/modules/libcom/src/osi/epicsStaticInstance.h b/modules/libcom/src/osi/epicsStaticInstance.h
1865new file mode 100644
1866index 0000000..8e8d469
1867--- /dev/null
1868+++ b/modules/libcom/src/osi/epicsStaticInstance.h
1869@@ -0,0 +1,52 @@
1870+/*************************************************************************\
1871+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
1872+* National Laboratory
1873+* EPICS BASE is distributed subject to a Software License Agreement found
1874+* in file LICENSE that is included with this distribution.
1875+\*************************************************************************/
1876+
1877+/*
1878+ * Author Jeffrey O. Hill
1879+ * johill@lanl.gov
1880+ */
1881+
1882+#ifndef epicsStaticInstance_h
1883+#define epicsStaticInstance_h
1884+
1885+namespace epics {
1886+
1887+//
1888+// c++ 11 specifies the behavior for concurrent
1889+// access to block scope statics but some compiler
1890+// writers, lacking clear guidance in the earlier
1891+// c++ standards, curiously implement thread unsafe
1892+// block static variables despite ensuring for
1893+// proper multi-threaded behavior for many other
1894+// aspects of the compiler runtime infrastructure
1895+// such as runtime support for exception handling
1896+//
1897+// T - the type of the initialized once only static
1898+//
1899+template < typename T > T & staticInstance ();
1900+
1901+//
1902+// !!!! perhaps we need versions here that pass parameters
1903+// !!!! to the constructor using templates also
1904+//
1905+
1906+} // end of name space epics
1907+
1908+//
1909+// if the compiler claims its c++ 11 then we are optimistic, ref:
1910+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf
1911+// (see section 6.7)
1912+//
1913+#if __cplusplus >= 201103L
1914+# include "epicsStaticInstanceSaneCmplr.h"
1915+#else
1916+ // otherwise we can implement compiler specific behavior
1917+# include "epicsStaticInstanceCD.h"
1918+#endif
1919+
1920+#endif // ifndef epicsStaticInstance_h
1921+
1922diff --git a/modules/libcom/src/osi/epicsStaticInstanceSaneCmplr.h b/modules/libcom/src/osi/epicsStaticInstanceSaneCmplr.h
1923new file mode 100644
1924index 0000000..523e509
1925--- /dev/null
1926+++ b/modules/libcom/src/osi/epicsStaticInstanceSaneCmplr.h
1927@@ -0,0 +1,45 @@
1928+
1929+/*************************************************************************\
1930+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
1931+* National Laboratory
1932+* EPICS BASE is distributed subject to a Software License Agreement found
1933+* in file LICENSE that is included with this distribution.
1934+\*************************************************************************/
1935+
1936+/*
1937+ * Author Jeffrey O. Hill
1938+ * johill@lanl.gov
1939+ */
1940+
1941+#ifndef epicsStaticInstanceSaneCmplr_h
1942+#define epicsStaticInstanceSaneCmplr_h
1943+
1944+namespace epics {
1945+
1946+// c++ 11 specifies the behavior for concurrent
1947+// access to block scope statics but some compiler
1948+// writers, lacking clear guidance in the earlier
1949+// c++ standards, curiously implement thread unsafe
1950+// block static variables despite ensuring for
1951+// proper multi-threaded behavior for many other
1952+// aspects of the compiler infrastructure such as
1953+// runtime support for exception handling
1954+//
1955+// if the compiler claims its c++ 11 then we are optimistic, ref:
1956+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf
1957+// (see section 6.7)
1958+// "If control enters the (block-scope variable with static storage duration)
1959+// declaration concurrently while the variable is being initialized, the
1960+// concurrent execution shall wait for completion of the initialization."
1961+//
1962+// also see c++ FAQ, how do I prevent the
1963+// "static initialization order fiasco"?
1964+template < typename T > T & staticInstance ()
1965+{
1966+ static T * const m_pInstance = new T;
1967+ return * m_pInstance;
1968+}
1969+
1970+} // end of name space epics
1971+
1972+#endif // ifndef epicsStaticInstanceSaneCmplr_h
1973diff --git a/modules/libcom/src/osi/epicsStaticInstanceSketchyCmplr.cpp b/modules/libcom/src/osi/epicsStaticInstanceSketchyCmplr.cpp
1974new file mode 100644
1975index 0000000..9581618
1976--- /dev/null
1977+++ b/modules/libcom/src/osi/epicsStaticInstanceSketchyCmplr.cpp
1978@@ -0,0 +1,88 @@
1979+
1980+/*************************************************************************\
1981+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
1982+* National Laboratory
1983+* EPICS BASE is distributed subject to a Software License Agreement found
1984+* in file LICENSE that is included with this distribution.
1985+\*************************************************************************/
1986+
1987+/*
1988+ * Author Jeffrey O. Hill
1989+ * johill@lanl.gov
1990+ */
1991+
1992+#include <cstddef>
1993+
1994+#define epicsExportSharedSymbols
1995+#include "errlog.h"
1996+#include "epicsThread.h"
1997+#include "epicsAssert.h"
1998+#include "epicsStaticInstanceSketchyCmplr.h"
1999+
2000+namespace epics {
2001+
2002+epicsShareDef char staticInstanceBusy;
2003+
2004+//
2005+// c++ 0x specifies the behavior for concurrent
2006+// access to block scope statics but some compiler
2007+// writers, lacking clear guidance in the earlier
2008+// c++ standards, curiously implement thread unsafe
2009+// block static variables despite ensuring for
2010+// proper multi-threaded behavior for many other
2011+// aspects of the compiler infrastructure such as
2012+// runtime support for exception handling
2013+//
2014+// see also c++ faq, static initialization order fiasco
2015+//
2016+// This implementation is active if we don't
2017+// know for certain that we can trust the compiler.
2018+// This implementation is substantially more efficient
2019+// at runtime than epicsThreadOnce
2020+//
2021+// we are careful to create T no more than once here
2022+//
2023+EpicsAtomicPtrT staticInstanceInit ( EpicsAtomicPtrT & target,
2024+ const PStaticInstanceFactory pFactory )
2025+{
2026+ static const std :: size_t spinDownInit = 1000u;
2027+ static const std :: size_t spinCount = 10u;
2028+ STATIC_ASSERT ( spinDownInit > spinCount );
2029+ static const std :: size_t spinThresh = spinDownInit - spinCount;
2030+ std :: size_t spinDown = spinDownInit;
2031+ EpicsAtomicPtrT pCur = 0;
2032+ while ( true ) {
2033+ pCur = epics :: atomic :: compareAndSwap ( target,
2034+ pStaticInstanceInit,
2035+ & staticInstanceBusy );
2036+ if ( pCur == pStaticInstanceInit ) {
2037+ try {
2038+ pCur = ( * pFactory ) ();
2039+ epics :: atomic :: set ( target, pCur );
2040+ break;
2041+ }
2042+ catch ( ... ) {
2043+ epics :: atomic :: set ( target,
2044+ pStaticInstanceInit );
2045+ throw;
2046+ }
2047+ }
2048+ else if ( pCur != & staticInstanceBusy ) {
2049+ break;
2050+ }
2051+ if ( spinDown <= spinThresh ) {
2052+ epicsThreadSleep ( epicsThreadSleepQuantum () );
2053+ }
2054+ if ( spinDown > 0u ) {
2055+ spinDown--;
2056+ }
2057+ else {
2058+ errlogPrintf ( "staticInstanceInit: waiting for another "
2059+ "thread to finish creating the static instance\n" );
2060+ spinDown = spinThresh;
2061+ }
2062+ }
2063+ return pCur;
2064+}
2065+
2066+} // end of name space epics
2067diff --git a/modules/libcom/src/osi/epicsStaticInstanceSketchyCmplr.h b/modules/libcom/src/osi/epicsStaticInstanceSketchyCmplr.h
2068new file mode 100644
2069index 0000000..33765d9
2070--- /dev/null
2071+++ b/modules/libcom/src/osi/epicsStaticInstanceSketchyCmplr.h
2072@@ -0,0 +1,53 @@
2073+/*************************************************************************\
2074+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
2075+* National Laboratory
2076+* EPICS BASE is distributed subject to a Software License Agreement found
2077+* in file LICENSE that is included with this distribution.
2078+\*************************************************************************/
2079+
2080+/*
2081+ * Author Jeffrey O. Hill
2082+ * johill@lanl.gov
2083+ */
2084+
2085+#ifndef epicsStaticInstanceSketchyCmplr_h
2086+#define epicsStaticInstanceSketchyCmplr_h
2087+
2088+#include "epicsAtomic.h"
2089+
2090+#include "shareLib.h"
2091+
2092+namespace epics {
2093+
2094+typedef EpicsAtomicPtrT ( * PStaticInstanceFactory ) ();
2095+
2096+epicsShareFunc EpicsAtomicPtrT staticInstanceInit ( EpicsAtomicPtrT & target,
2097+ const PStaticInstanceFactory pFactory );
2098+
2099+epicsShareExtern char staticInstanceBusy;
2100+
2101+namespace {
2102+ template < typename T >
2103+ EpicsAtomicPtrT staticInstanceFactory ()
2104+ {
2105+ return new T ();
2106+ }
2107+ static const EpicsAtomicPtrT pStaticInstanceInit = 0;
2108+}
2109+
2110+// this should _not_ be an in line function so that
2111+// we guarantee that only one instance of type T per
2112+// executable is created
2113+template < typename T > T & staticInstance ()
2114+{
2115+ static EpicsAtomicPtrT pInstance = pStaticInstanceInit;
2116+ EpicsAtomicPtrT pCur = epics :: atomic :: get ( pInstance );
2117+ if ( pCur == pStaticInstanceInit || pCur == & staticInstanceBusy ) {
2118+ pCur = staticInstanceInit ( pInstance, staticInstanceFactory < T > );
2119+ }
2120+ return * reinterpret_cast < T * > ( pCur );
2121+}
2122+
2123+} // end of name space epics
2124+
2125+#endif // ifndef epicsStaticInstanceSketchyCmplr_h
2126diff --git a/modules/libcom/src/timer/epicsTimer.cpp b/modules/libcom/src/timer/epicsTimer.cpp
2127index e55280e..96bfa31 100644
2128--- a/modules/libcom/src/timer/epicsTimer.cpp
2129+++ b/modules/libcom/src/timer/epicsTimer.cpp
2130@@ -1,4 +1,6 @@
2131 /*************************************************************************\
2132+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
2133+* National Laboratory
2134 * Copyright (c) 2015 UChicago Argonne LLC, as Operator of Argonne
2135 * National Laboratory.
2136 * Copyright (c) 2002 The Regents of the University of California, as
2137@@ -12,151 +14,144 @@
2138 * 505 665 1831
2139 */
2140
2141+#include <cstdio>
2142 #include <string>
2143 #include <stdexcept>
2144
2145 #define epicsExportSharedSymbols
2146 #include "epicsMath.h"
2147 #include "epicsTimer.h"
2148-#include "epicsGuard.h"
2149 #include "timerPrivate.h"
2150
2151-#ifdef _MSC_VER
2152-# pragma warning ( push )
2153-# pragma warning ( disable:4660 )
2154-#endif
2155-
2156-#ifdef _MSC_VER
2157-# pragma warning ( pop )
2158-#endif
2159-
2160-template class tsFreeList < epicsTimerForC, 0x20 >;
2161-
2162 epicsTimer::~epicsTimer () {}
2163
2164-epicsTimerQueueNotify::~epicsTimerQueueNotify () {}
2165+void epicsTimerNotify :: show ( unsigned /* level */ ) const {}
2166
2167-epicsTimerNotify::~epicsTimerNotify () {}
2168-
2169-void epicsTimerNotify::show ( unsigned /* level */ ) const {}
2170-
2171-epicsTimerForC::epicsTimerForC ( timerQueue &queue, epicsTimerCallback pCBIn, void *pPrivateIn ) :
2172- timer ( queue ), pCallBack ( pCBIn ), pPrivate ( pPrivateIn )
2173+TimerForC :: TimerForC ( timerQueue & queue, epicsTimerCallback const pCB,
2174+ void * const pPrivate ) :
2175+ m_pTimer ( & queue.createTimerImpl () ),
2176+ m_pCallBack ( pCB ),
2177+ m_pPrivate ( pPrivate )
2178 {
2179 }
2180
2181-epicsTimerForC::~epicsTimerForC ()
2182+TimerForC :: ~TimerForC ()
2183 {
2184+ m_pTimer->destroy ();
2185 }
2186
2187-void epicsTimerForC::destroy ()
2188+void TimerForC :: show ( unsigned level ) const
2189 {
2190- timerQueue & queueTmp = this->queue;
2191- this->~epicsTimerForC ();
2192- queueTmp.timerForCFreeList.release ( this );
2193+ printf ( "TimerForC: callback ptr %p private ptr %p\n",
2194+ m_pCallBack, m_pPrivate );
2195+ if ( level > 1 && m_pTimer ) {
2196+ m_pTimer->show ( level - 1 );
2197+ }
2198 }
2199
2200-epicsTimerNotify::expireStatus epicsTimerForC::expire ( const epicsTime & )
2201+epicsTimerNotify :: expireStatus
2202+ TimerForC :: expire ( const epicsTime & )
2203 {
2204- ( *this->pCallBack ) ( this->pPrivate );
2205+ ( *m_pCallBack ) ( m_pPrivate );
2206 return noRestart;
2207 }
2208
2209 epicsTimerQueueActiveForC ::
2210- epicsTimerQueueActiveForC ( RefMgr & refMgr,
2211- bool okToShare, unsigned priority ) :
2212- timerQueueActive ( refMgr, okToShare, priority )
2213+ epicsTimerQueueActiveForC ( bool okToShare, unsigned priority ) :
2214+ timerQueueActive ( okToShare, priority )
2215 {
2216- timerQueueActive::start();
2217 }
2218
2219-epicsTimerQueueActiveForC::~epicsTimerQueueActiveForC ()
2220+epicsTimerQueueActiveForC :: ~epicsTimerQueueActiveForC ()
2221 {
2222 }
2223
2224-void epicsTimerQueueActiveForC::release ()
2225+void epicsTimerQueueActiveForC :: release ()
2226 {
2227- _refMgr->release ( *this );
2228+ timerQueueActiveMgr :: master ().release ( *this );
2229 }
2230
2231-epicsTimerQueuePassiveForC::epicsTimerQueuePassiveForC (
2232- epicsTimerQueueNotifyReschedule pRescheduleCallbackIn,
2233- epicsTimerQueueNotifyQuantum pSleepQuantumCallbackIn,
2234- void * pPrivateIn ) :
2235- timerQueuePassive ( * static_cast < epicsTimerQueueNotify * > ( this ) ),
2236- pRescheduleCallback ( pRescheduleCallbackIn ),
2237- pSleepQuantumCallback ( pSleepQuantumCallbackIn ),
2238- pPrivate ( pPrivateIn )
2239+epicsTimerQueuePassiveForC :: epicsTimerQueuePassiveForC (
2240+ epicsTimerQueueNotifyReschedule pRescheduleCallback,
2241+ epicsTimerQueueNotifyQuantum pSleepQuantumCallback,
2242+ void * pPrivate ) :
2243+ timerQueuePassive (
2244+ * static_cast < epicsTimerQueueNotify * > ( this ) ),
2245+ m_pRescheduleCallback ( pRescheduleCallback ),
2246+ m_pSleepQuantumCallback ( pSleepQuantumCallback ),
2247+ m_pPrivate ( pPrivate )
2248 {
2249 }
2250
2251-epicsTimerQueuePassiveForC::~epicsTimerQueuePassiveForC ()
2252+epicsTimerQueuePassiveForC :: ~epicsTimerQueuePassiveForC ()
2253 {
2254 }
2255
2256-void epicsTimerQueuePassiveForC::reschedule ()
2257+void epicsTimerQueuePassiveForC :: reschedule ()
2258 {
2259- (*this->pRescheduleCallback) ( this->pPrivate );
2260+ ( *m_pRescheduleCallback ) ( m_pPrivate );
2261 }
2262
2263-double epicsTimerQueuePassiveForC::quantum ()
2264-{
2265- return (*this->pSleepQuantumCallback) ( this->pPrivate );
2266-}
2267-
2268-void epicsTimerQueuePassiveForC::destroy ()
2269+void epicsTimerQueuePassiveForC :: destroy ()
2270 {
2271 delete this;
2272 }
2273
2274-epicsShareFunc epicsTimerNotify::expireStatus::expireStatus ( restart_t restart ) :
2275- delay ( - DBL_MAX )
2276+epicsShareFunc epicsTimerNotify :: expireStatus ::
2277+ expireStatus ( restart_t restart ) :
2278+ m_delay ( -DBL_MAX )
2279 {
2280 if ( restart != noRestart ) {
2281 throw std::logic_error
2282- ( "timer restart was requested without specifying a delay?" );
2283+ ( "timer restart was requested "
2284+ "without specifying a delay?" );
2285 }
2286 }
2287
2288-epicsShareFunc epicsTimerNotify::expireStatus::expireStatus
2289- ( restart_t restartIn, const double & expireDelaySec ) :
2290- delay ( expireDelaySec )
2291+epicsShareFunc epicsTimerNotify :: expireStatus :: expireStatus
2292+ ( restart_t restartIn, const double & expireDelaySec ) :
2293+ m_delay ( expireDelaySec )
2294 {
2295- if ( restartIn != epicsTimerNotify::restart ) {
2296+ if ( restartIn != epicsTimerNotify :: restart ) {
2297 throw std::logic_error
2298- ( "no timer restart was requested, but a delay was specified?" );
2299+ ( "no timer restart was requested, "
2300+ "but a delay was specified?" );
2301 }
2302- if ( this->delay < 0.0 || !finite(this->delay) ) {
2303+ if ( m_delay < 0.0 || ! finite ( m_delay ) ) {
2304 throw std::logic_error
2305- ( "timer restart was requested, but a negative delay was specified?" );
2306+ ( "timer restart was requested, but a "
2307+ "negative delay was specified?" );
2308 }
2309 }
2310
2311-epicsShareFunc bool epicsTimerNotify::expireStatus::restart () const
2312+epicsShareFunc bool
2313+ epicsTimerNotify :: expireStatus :: restart () const
2314 {
2315- return this->delay >= 0.0 && finite(this->delay);
2316+ return m_delay >= 0.0 && finite ( m_delay );
2317 }
2318
2319-epicsShareFunc double epicsTimerNotify::expireStatus::expirationDelay () const
2320+epicsShareFunc double
2321+ epicsTimerNotify :: expireStatus :: expirationDelay () const
2322 {
2323- if ( this->delay < 0.0 || !finite(this->delay) ) {
2324+ if ( m_delay < 0.0 || ! finite ( m_delay ) ) {
2325 throw std::logic_error
2326- ( "no timer restart was requested, but you are asking for a restart delay?" );
2327+ ( "no timer restart was requested, "
2328+ "but you are asking for a restart delay?" );
2329 }
2330- return this->delay;
2331+ return m_delay;
2332 }
2333
2334 extern "C" epicsTimerQueuePassiveId epicsShareAPI
2335 epicsTimerQueuePassiveCreate (
2336- epicsTimerQueueNotifyReschedule pRescheduleCallbackIn,
2337- epicsTimerQueueNotifyQuantum pSleepQuantumCallbackIn,
2338- void * pPrivateIn )
2339+ const epicsTimerQueueNotifyReschedule pRescheduleCallback,
2340+ const epicsTimerQueueNotifyQuantum pSleepQuantumCallback,
2341+ void * const pPrivate )
2342 {
2343 try {
2344 return new epicsTimerQueuePassiveForC (
2345- pRescheduleCallbackIn,
2346- pSleepQuantumCallbackIn,
2347- pPrivateIn );
2348+ pRescheduleCallback,
2349+ pSleepQuantumCallback,
2350+ pPrivate );
2351 }
2352 catch ( ... ) {
2353 return 0;
2354@@ -173,28 +168,31 @@ extern "C" double epicsShareAPI
2355 epicsTimerQueuePassiveProcess ( epicsTimerQueuePassiveId pQueue )
2356 {
2357 try {
2358- return pQueue->process ( epicsTime::getCurrent() );
2359+ return pQueue->process ( epicsTime :: getCurrent () );
2360 }
2361 catch ( ... ) {
2362 return 1.0;
2363 }
2364 }
2365
2366-extern "C" epicsTimerId epicsShareAPI epicsTimerQueuePassiveCreateTimer (
2367- epicsTimerQueuePassiveId pQueue, epicsTimerCallback pCallback, void *pArg )
2368+extern "C" epicsTimerId epicsShareAPI
2369+ epicsTimerQueuePassiveCreateTimer (
2370+ epicsTimerQueuePassiveId pQueue,
2371+ epicsTimerCallback pCallback, void *pArg )
2372 {
2373 try {
2374- return & pQueue->createTimerForC ( pCallback, pArg );
2375+ return & pQueue->createTimerForC ( pCallback, pArg );
2376 }
2377 catch ( ... ) {
2378 return 0;
2379 }
2380 }
2381
2382-extern "C" epicsShareFunc void epicsShareAPI epicsTimerQueuePassiveDestroyTimer (
2383- epicsTimerQueuePassiveId /* pQueue */, epicsTimerId pTmr )
2384+extern "C" epicsShareFunc void epicsShareAPI
2385+ epicsTimerQueuePassiveDestroyTimer (
2386+ epicsTimerQueuePassiveId pQueue, epicsTimerId pTmr )
2387 {
2388- pTmr->destroy ();
2389+ delete pTmr;
2390 }
2391
2392 extern "C" void epicsShareAPI epicsTimerQueuePassiveShow (
2393@@ -207,11 +205,10 @@ extern "C" epicsTimerQueueId epicsShareAPI
2394 epicsTimerQueueAllocate ( int okToShare, unsigned int threadPriority )
2395 {
2396 try {
2397- epicsSingleton < timerQueueActiveMgr > :: reference ref =
2398- timerQueueMgrEPICS.getReference ();
2399 epicsTimerQueueActiveForC & tmr =
2400- ref->allocate ( ref, okToShare ? true : false, threadPriority );
2401- return &tmr;
2402+ timerQueueActiveMgr :: master ().
2403+ allocate ( okToShare ? true : false, threadPriority );
2404+ return & tmr;
2405 }
2406 catch ( ... ) {
2407 return 0;
2408@@ -223,8 +220,10 @@ extern "C" void epicsShareAPI epicsTimerQueueRelease ( epicsTimerQueueId pQueue
2409 pQueue->release ();
2410 }
2411
2412-extern "C" epicsTimerId epicsShareAPI epicsTimerQueueCreateTimer (
2413- epicsTimerQueueId pQueue, epicsTimerCallback pCallback, void *pArg )
2414+extern "C" epicsTimerId epicsShareAPI
2415+ epicsTimerQueueCreateTimer (
2416+ epicsTimerQueueId pQueue,
2417+ epicsTimerCallback pCallback, void *pArg )
2418 {
2419 try {
2420 return & pQueue->createTimerForC ( pCallback, pArg );
2421@@ -234,43 +233,49 @@ extern "C" epicsTimerId epicsShareAPI epicsTimerQueueCreateTimer (
2422 }
2423 }
2424
2425-extern "C" void epicsShareAPI epicsTimerQueueShow (
2426- epicsTimerQueueId pQueue, unsigned int level )
2427+extern "C" void epicsShareAPI
2428+ epicsTimerQueueShow (
2429+ epicsTimerQueueId pQueue, unsigned int level )
2430 {
2431 pQueue->show ( level );
2432 }
2433
2434-extern "C" void epicsShareAPI epicsTimerQueueDestroyTimer (
2435- epicsTimerQueueId /* pQueue */, epicsTimerId pTmr )
2436+extern "C" void epicsShareAPI
2437+ epicsTimerQueueDestroyTimer (
2438+ epicsTimerQueueId pQueue, epicsTimerId pTmr )
2439 {
2440- pTmr->destroy ();
2441+ delete pTmr;
2442 }
2443
2444-extern "C" void epicsShareAPI epicsTimerStartTime (
2445- epicsTimerId pTmr, const epicsTimeStamp *pTime )
2446+extern "C" unsigned epicsShareAPI
2447+ epicsTimerStartTime (
2448+ epicsTimerId pTmr, const epicsTimeStamp *pTime )
2449 {
2450- pTmr->start ( *pTmr, *pTime );
2451+ return pTmr->start ( *pTime );
2452 }
2453
2454-extern "C" void epicsShareAPI epicsTimerStartDelay (
2455- epicsTimerId pTmr, double delaySeconds )
2456+extern "C" unsigned epicsShareAPI
2457+ epicsTimerStartDelay (
2458+ epicsTimerId pTmr, double delaySeconds )
2459 {
2460- pTmr->start ( *pTmr, delaySeconds );
2461+ return pTmr->start ( delaySeconds );
2462 }
2463
2464-extern "C" void epicsShareAPI epicsTimerCancel ( epicsTimerId pTmr )
2465+extern "C" int epicsShareAPI
2466+ epicsTimerCancel ( epicsTimerId pTmr )
2467 {
2468- pTmr->cancel ();
2469+ return pTmr->cancel ();
2470 }
2471
2472-extern "C" double epicsShareAPI epicsTimerGetExpireDelay ( epicsTimerId pTmr )
2473+extern "C" double epicsShareAPI
2474+ epicsTimerGetExpireDelay ( epicsTimerId pTmr )
2475 {
2476 return pTmr->getExpireDelay ();
2477 }
2478
2479-extern "C" void epicsShareAPI epicsTimerShow (
2480- epicsTimerId pTmr, unsigned int level )
2481+extern "C" void epicsShareAPI
2482+ epicsTimerShow ( epicsTimerId pTmr, unsigned int level )
2483 {
2484- pTmr->timer::show ( level );
2485+ pTmr->show ( level );
2486 }
2487
2488diff --git a/modules/libcom/src/timer/epicsTimer.h b/modules/libcom/src/timer/epicsTimer.h
2489index 72270f2..45c6b29 100644
2490--- a/modules/libcom/src/timer/epicsTimer.h
2491+++ b/modules/libcom/src/timer/epicsTimer.h
2492@@ -1,11 +1,12 @@
2493 /*************************************************************************\
2494+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
2495+* National Laboratory
2496 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
2497 * National Laboratory.
2498 * Copyright (c) 2002 The Regents of the University of California, as
2499 * Operator of Los Alamos National Laboratory.
2500-* EPICS BASE Versions 3.13.7
2501-* and higher are distributed subject to a Software License Agreement found
2502-* in file LICENSE that is included with this distribution.
2503+* EPICS BASE is distributed subject to a Software License Agreement found
2504+* in file LICENSE that is included with this distribution.
2505 \*************************************************************************/
2506 /* epicsTimer.h */
2507
2508@@ -14,50 +15,80 @@
2509 #ifndef epicsTimerH
2510 #define epicsTimerH
2511
2512-#include <float.h>
2513-
2514-#include "shareLib.h"
2515 #include "epicsTime.h"
2516 #include "epicsThread.h"
2517+#include "shareLib.h"
2518
2519 #ifdef __cplusplus
2520
2521+#include <cfloat>
2522+
2523 /*
2524 * Notes:
2525- * 1) epicsTimer does not hold its lock when calling callbacks.
2526+ * 1) The timer queue process method does not hold the timer
2527+ * queue lock when calling callbacks, to avoid deadlocks.
2528+ *
2529+ * 2) The timer start method has three different possible outcomes
2530+ *
2531+ * 2a) If start is called and the timer isnt pending in the timer
2532+ * queue, and the timer callback isnt currently being orchestrated,
2533+ * then the timer is schedualed in the queue and start returns
2534+ * 1u, indicating that the timer callback will run once as a
2535+ * direct consequence of this invocation of start.
2536+ *
2537+ * 2b) If start is called and the timer is already pending in
2538+ * the timer queue, then the timer is reschedualed back into
2539+ * a new positon in the queue and start returns 0u. The
2540+ * timer callback will run once as a reschedualed (postponed)
2541+ * consequence of a previous invocation of start, but zero
2542+ * times as a direct consequence of this call to start.
2543+ *
2544+ * 2c) If start is called and the timer isnt pending in the timer
2545+ * queue, but the timer callback _is_ currently being orchestrated
2546+ * then it is reschedualed in the queue for a new expiration
2547+ * time, and start returns 1u. The timer callback will run twice.
2548+ * Once as a consequence of this invocation of start, and once
2549+ * as a consequence of a previous call to start.
2550+ *
2551+ * 3) Cancel returns true if the timer was pending in the queue
2552+ * when cancel was called, and false otherwise.
2553 */
2554
2555 /* code using a timer must implement epicsTimerNotify */
2556 class epicsShareClass epicsTimerNotify {
2557 public:
2558 enum restart_t { noRestart, restart };
2559- class expireStatus {
2560+ class epicsShareClass expireStatus {
2561 public:
2562- epicsShareFunc expireStatus ( restart_t );
2563- epicsShareFunc expireStatus ( restart_t, const double & expireDelaySec );
2564- epicsShareFunc bool restart () const;
2565- epicsShareFunc double expirationDelay () const;
2566+ expireStatus ( restart_t );
2567+ expireStatus ( restart_t, const double & expireDelaySec );
2568+ bool restart () const;
2569+ double expirationDelay () const;
2570 private:
2571- double delay;
2572+ double m_delay;
2573 };
2574
2575- virtual ~epicsTimerNotify () = 0;
2576 /* return "noRestart" or "expireStatus ( restart, 30.0 )" */
2577 virtual expireStatus expire ( const epicsTime & currentTime ) = 0;
2578 virtual void show ( unsigned int level ) const;
2579+protected:
2580+ virtual ~epicsTimerNotify () {} // protected disables delete through intf
2581 };
2582
2583 class epicsShareClass epicsTimer {
2584 public:
2585 /* calls cancel (see warning below) and then destroys the timer */
2586 virtual void destroy () = 0;
2587- virtual void start ( epicsTimerNotify &, const epicsTime & ) = 0;
2588- virtual void start ( epicsTimerNotify &, double delaySeconds ) = 0;
2589- /* WARNING: A deadlock will occur if you hold a lock while
2590+ /* see note 2 above for the significance of the return value */
2591+ virtual unsigned start ( epicsTimerNotify &, const epicsTime & ) = 0;
2592+ virtual unsigned start ( epicsTimerNotify &, double delaySeconds ) = 0;
2593+ /* see note 3 for the significance of the return value
2594+ *
2595+ * WARNING: A deadlock will occur if you hold a lock while
2596 * calling this function that you also take within the timer
2597 * expiration callback.
2598 */
2599- virtual void cancel () = 0;
2600+ virtual bool cancel () = 0;
2601 struct expireInfo {
2602 expireInfo ( bool active, const epicsTime & expireTime );
2603 bool active;
2604@@ -67,7 +98,7 @@ public:
2605 double getExpireDelay ();
2606 virtual void show ( unsigned int level ) const = 0;
2607 protected:
2608- virtual ~epicsTimer () = 0; /* protected => delete() must not be called */
2609+ virtual ~epicsTimer () = 0; /* disable delete */
2610 };
2611
2612 class epicsTimerQueue {
2613@@ -75,7 +106,7 @@ public:
2614 virtual epicsTimer & createTimer () = 0;
2615 virtual void show ( unsigned int level ) const = 0;
2616 protected:
2617- epicsShareFunc virtual ~epicsTimerQueue () = 0;
2618+ virtual ~epicsTimerQueue () {} /* disable delete */
2619 };
2620
2621 class epicsTimerQueueActive
2622@@ -85,7 +116,7 @@ public:
2623 bool okToShare, unsigned threadPriority = epicsThreadPriorityMin + 10 );
2624 virtual void release () = 0;
2625 protected:
2626- epicsShareFunc virtual ~epicsTimerQueueActive () = 0;
2627+ virtual ~epicsTimerQueueActive () {} /* disable delete */
2628 };
2629
2630 class epicsTimerQueueNotify {
2631@@ -93,18 +124,14 @@ public:
2632 /* called when a new timer is inserted into the queue and the */
2633 /* delay to the next expire has changed */
2634 virtual void reschedule () = 0;
2635- /* if there is a quantum in the scheduling of timer intervals */
2636- /* return this quantum in seconds. If unknown then return zero. */
2637- virtual double quantum () = 0;
2638 protected:
2639- epicsShareFunc virtual ~epicsTimerQueueNotify () = 0;
2640+ virtual ~epicsTimerQueueNotify () {} /* disable delete */
2641 };
2642
2643-class epicsTimerQueuePassive
2644- : public epicsTimerQueue {
2645+class epicsTimerQueuePassive : public epicsTimerQueue {
2646 public:
2647 static epicsShareFunc epicsTimerQueuePassive & create ( epicsTimerQueueNotify & );
2648- epicsShareFunc virtual ~epicsTimerQueuePassive () = 0; /* ok to call delete */
2649+ virtual ~epicsTimerQueuePassive () {} /* ok to call delete */
2650 virtual double process ( const epicsTime & currentTime ) = 0; /* returns delay to next expire */
2651 };
2652
2653@@ -114,11 +141,11 @@ inline epicsTimer::expireInfo::expireInfo ( bool activeIn,
2654 {
2655 }
2656
2657-inline double epicsTimer::getExpireDelay ()
2658+inline double epicsTimer :: getExpireDelay ()
2659 {
2660 epicsTimer::expireInfo info = this->getExpireInfo ();
2661 if ( info.active ) {
2662- double delay = info.expireTime - epicsTime::getCurrent ();
2663+ double delay = info.expireTime - epicsTime :: getCurrent ();
2664 if ( delay < 0.0 ) {
2665 delay = 0.0;
2666 }
2667@@ -130,7 +157,7 @@ inline double epicsTimer::getExpireDelay ()
2668 extern "C" {
2669 #endif /* __cplusplus */
2670
2671-typedef struct epicsTimerForC * epicsTimerId;
2672+typedef struct TimerForC * epicsTimerId;
2673 typedef void ( *epicsTimerCallback ) ( void *pPrivate );
2674
2675 /* thread managed timer queue */
2676@@ -167,11 +194,11 @@ epicsShareFunc void epicsShareAPI
2677 epicsTimerQueuePassiveShow ( epicsTimerQueuePassiveId id, unsigned int level );
2678
2679 /* timer */
2680-epicsShareFunc void epicsShareAPI
2681+epicsShareFunc unsigned epicsShareAPI
2682 epicsTimerStartTime ( epicsTimerId id, const epicsTimeStamp *pTime );
2683-epicsShareFunc void epicsShareAPI
2684+epicsShareFunc unsigned epicsShareAPI
2685 epicsTimerStartDelay ( epicsTimerId id, double delaySeconds );
2686-epicsShareFunc void epicsShareAPI
2687+epicsShareFunc int epicsShareAPI
2688 epicsTimerCancel ( epicsTimerId id );
2689 epicsShareFunc double epicsShareAPI
2690 epicsTimerGetExpireDelay ( epicsTimerId id );
2691diff --git a/modules/libcom/src/timer/timer.cpp b/modules/libcom/src/timer/timer.cpp
2692index 35d6e47..2c49f7e 100644
2693--- a/modules/libcom/src/timer/timer.cpp
2694+++ b/modules/libcom/src/timer/timer.cpp
2695@@ -1,11 +1,12 @@
2696 /*************************************************************************\
2697+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
2698+* National Laboratory
2699 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
2700 * National Laboratory.
2701 * Copyright (c) 2002 The Regents of the University of California, as
2702 * Operator of Los Alamos National Laboratory.
2703-* EPICS BASE Versions 3.13.7
2704-* and higher are distributed subject to a Software License Agreement found
2705-* in file LICENSE that is included with this distribution.
2706+* EPICS BASE is distributed subject to a Software License Agreement found
2707+* in file LICENSE that is included with this distribution.
2708 \*************************************************************************/
2709
2710 /*
2711@@ -17,227 +18,226 @@
2712 #include <typeinfo>
2713 #include <string>
2714 #include <stdexcept>
2715-#include <stdio.h>
2716+#include <cstdio>
2717
2718 #define epicsExportSharedSymbols
2719-#include "epicsGuard.h"
2720 #include "timerPrivate.h"
2721 #include "errlog.h"
2722
2723-#ifdef _MSC_VER
2724-# pragma warning ( push )
2725-# pragma warning ( disable:4660 )
2726-#endif
2727-
2728-template class tsFreeList < timer, 0x20 >;
2729-
2730-#ifdef _MSC_VER
2731-# pragma warning ( pop )
2732-#endif
2733-
2734-timer::timer ( timerQueue & queueIn ) :
2735- queue ( queueIn ), curState ( stateLimbo ), pNotify ( 0 )
2736+Timer :: Timer ( timerQueue & queueIn ) :
2737+ m_queue ( queueIn ),
2738+ m_curState ( stateLimbo ),
2739+ m_pNotify ( 0 ),
2740+ m_index ( m_invalidIndex )
2741 {
2742 }
2743
2744-timer::~timer ()
2745+Timer :: ~Timer ()
2746 {
2747- this->cancel ();
2748+ M_CancelStatus cs = { false, false };
2749+ {
2750+ Guard guard ( m_queue );
2751+ cs = m_cancelPvt ( guard );
2752+ m_queue.m_numTimers--;
2753+ }
2754+ // we are careful to wakeup the timer queue thread after
2755+ // we nolonger hold the lock
2756+ if ( cs.reschedule ) {
2757+ m_queue.m_notify.reschedule ();
2758+ }
2759 }
2760
2761-void timer::destroy ()
2762+void Timer :: destroy ()
2763 {
2764- timerQueue & queueTmp = this->queue;
2765- this->~timer ();
2766- queueTmp.timerFreeList.release ( this );
2767+ delete this;
2768 }
2769
2770-void timer::start ( epicsTimerNotify & notify, double delaySeconds )
2771+unsigned Timer :: start ( epicsTimerNotify & notify, double delaySeconds )
2772 {
2773- this->start ( notify, epicsTime::getCurrent () + delaySeconds );
2774+ const epicsTime current = epicsTime :: getCurrent ();
2775+ const epicsTime exp = current + delaySeconds;
2776+ const Timer :: M_StartReturn sr = m_privateStart ( notify, exp );
2777+ // we are careful to wakeup the timer queue thread after
2778+ // we nolonger hold the lock
2779+ if ( sr.resched ) {
2780+ m_queue.m_notify.reschedule ();
2781+ }
2782+ return sr.numNew;
2783 }
2784
2785-void timer::start ( epicsTimerNotify & notify, const epicsTime & expire )
2786+unsigned Timer :: start ( epicsTimerNotify & notify,
2787+ const epicsTime & expire )
2788 {
2789- epicsGuard < epicsMutex > locker ( this->queue.mutex );
2790- this->privateStart ( notify, expire );
2791+ Timer :: M_StartReturn sr = m_privateStart ( notify, expire );
2792+ // we are careful to wakeup the timer queue thread after
2793+ // we nolonger hold the lock
2794+ if ( sr.resched ) {
2795+ m_queue.m_notify.reschedule ();
2796+ }
2797+ return sr.numNew;
2798 }
2799
2800-void timer::privateStart ( epicsTimerNotify & notify, const epicsTime & expire )
2801+Timer :: M_StartReturn
2802+ Timer :: m_privateStart ( epicsTimerNotify & notify,
2803+ const epicsTime & expire )
2804 {
2805- this->pNotify = & notify;
2806- this->exp = expire - ( this->queue.notify.quantum () / 2.0 );
2807-
2808- bool reschedualNeeded = false;
2809- if ( this->curState == stateActive ) {
2810- // above expire time and notify will override any restart parameters
2811- // that may be returned from the timer expire callback
2812- return;
2813- }
2814- else if ( this->curState == statePending ) {
2815- this->queue.timerList.remove ( *this );
2816- if ( this->queue.timerList.first() == this &&
2817- this->queue.timerList.count() > 0 ) {
2818- reschedualNeeded = true;
2819+ Timer :: M_StartReturn sr;
2820+ Guard locker ( m_queue );
2821+ m_pNotify = & notify;
2822+ if ( m_curState == statePending ) {
2823+ const epicsTime oldExp = m_queue.m_heap.front ()->m_exp;
2824+ m_exp = expire;
2825+ if ( ! m_queue.m_fixParent ( m_index ) ) {
2826+ m_queue.m_fixChildren ( m_index );
2827+ }
2828+ if ( m_queue.m_pExpTmr == this ) {
2829+ // new expire time and notify will override
2830+ // any restart parameters that may be returned
2831+ // from the timer expire callback
2832+ sr.numNew = 1u;
2833+ sr.resched = false;
2834+ }
2835+ else {
2836+ sr.numNew = 0u;
2837+ sr.resched = ( oldExp > m_queue.m_heap.front ()->m_exp );
2838 }
2839 }
2840-
2841-# ifdef DEBUG
2842- unsigned preemptCount=0u;
2843-# endif
2844-
2845- //
2846- // insert into the pending queue
2847- //
2848- // Finds proper time sorted location using a linear search.
2849- //
2850- // **** this should use a binary tree ????
2851- //
2852- tsDLIter < timer > pTmr = this->queue.timerList.lastIter ();
2853- while ( true ) {
2854- if ( ! pTmr.valid () ) {
2855- //
2856- // add to the beginning of the list
2857- //
2858- this->queue.timerList.push ( *this );
2859- reschedualNeeded = true;
2860- break;
2861+ else {
2862+ sr.numNew = 1u;
2863+ m_curState = Timer :: statePending;
2864+ m_index = m_queue.m_heap.size ();
2865+ if ( m_index > 0u ) {
2866+ const epicsTime oldExp = m_queue.m_heap.front ()->m_exp;
2867+ m_exp = expire;
2868+ m_queue.m_heap.push_back ( this );
2869+ m_queue.m_fixParent ( m_index );
2870+ sr.resched = ( oldExp > m_queue.m_heap.front ()->m_exp );
2871 }
2872- if ( pTmr->exp <= this->exp ) {
2873- //
2874- // add after the item found that expires earlier
2875- //
2876- this->queue.timerList.insertAfter ( *this, *pTmr );
2877- break;
2878+ else {
2879+ m_exp = expire;
2880+ m_queue.m_heap.push_back ( this );
2881+ sr.resched = true;
2882 }
2883-# ifdef DEBUG
2884- preemptCount++;
2885-# endif
2886- --pTmr;
2887 }
2888+ debugPrintf ( ("Start of \"%s\" with delay %f at %p\n",
2889+ m_pNotify ?
2890+ typeid ( *m_pNotify ).name () :
2891+ typeid ( m_pNotify ).name (),
2892+ m_exp - epicsTime :: getCurrent (),
2893+ this ) );
2894+ return sr;
2895+}
2896
2897- this->curState = timer::statePending;
2898-
2899- if ( reschedualNeeded ) {
2900- this->queue.notify.reschedule ();
2901- }
2902-
2903-# if defined(DEBUG) && 0
2904- this->show ( 10u );
2905- this->queue.show ( 10u );
2906-# endif
2907-
2908- debugPrintf ( ("Start of \"%s\" with delay %f at %p preempting %u\n",
2909- typeid ( this->notify ).name (),
2910- expire - epicsTime::getCurrent (),
2911- this, preemptCount ) );
2912+void Timer :: m_remove ( Guard & guard )
2913+{
2914+ Timer * const pMoved = m_queue.m_heap.back ();
2915+ m_queue.m_heap.pop_back ();
2916+ if ( m_index != m_queue.m_heap.size () ) {
2917+ const size_t oldIndex = m_index;
2918+ m_queue.m_heap[oldIndex] = pMoved;
2919+ pMoved->m_index = oldIndex;
2920+ if ( ! m_queue.m_fixParent ( oldIndex ) ) {
2921+ m_queue.m_fixChildren ( oldIndex );
2922+ }
2923+ }
2924+ m_index = m_invalidIndex;
2925+ m_curState = stateLimbo;
2926 }
2927
2928-void timer::cancel ()
2929+bool Timer :: cancel ()
2930 {
2931- bool reschedual = false;
2932- bool wakeupCancelBlockingThreads = false;
2933+ M_CancelStatus cs = { false, false };
2934 {
2935- epicsGuard < epicsMutex > locker ( this->queue.mutex );
2936- this->pNotify = 0;
2937- if ( this->curState == statePending ) {
2938- this->queue.timerList.remove ( *this );
2939- this->curState = stateLimbo;
2940- if ( this->queue.timerList.first() == this &&
2941- this->queue.timerList.count() > 0 ) {
2942- reschedual = true;
2943- }
2944- }
2945- else if ( this->curState == stateActive ) {
2946- this->queue.cancelPending = true;
2947- this->curState = timer::stateLimbo;
2948- if ( this->queue.processThread != epicsThreadGetIdSelf() ) {
2949- // make certain timer expire() does not run after cancel () returns,
2950- // but dont require that lock is applied while calling expire()
2951- while ( this->queue.cancelPending &&
2952- this->queue.pExpireTmr == this ) {
2953- epicsGuardRelease < epicsMutex > autoRelease ( locker );
2954- this->queue.cancelBlockingEvent.wait ();
2955+ Guard guard ( m_queue );
2956+ cs = m_cancelPvt ( guard );
2957+ }
2958+ // we are careful to wakeup the timer queue thread after
2959+ // we nolonger hold the lock
2960+ if ( cs.reschedule ) {
2961+ m_queue.m_notify.reschedule ();
2962+ }
2963+ return cs.wasPending;
2964+}
2965+
2966+Timer :: M_CancelStatus Timer :: m_cancelPvt ( Guard & gd )
2967+{
2968+ gd.assertIdenticalMutex ( m_queue );
2969+ M_CancelStatus cs = { false, false };
2970+ Guard guard ( m_queue );
2971+ if ( m_curState == statePending ) {
2972+ const epicsTime oldExp = m_queue.m_heap.front ()->m_exp;
2973+ m_remove ( guard );
2974+ m_queue.m_cancelPending = ( m_queue.m_pExpTmr == this );
2975+ if ( m_queue.m_cancelPending ) {
2976+ if ( m_queue.m_processThread != epicsThreadGetIdSelf() ) {
2977+ // 1) make certain timer expire cllback does not run
2978+ // after this cancel method returns
2979+ // 2) dont require that lock is applied while calling
2980+ // expire callback
2981+ // 3) assume that timer could be deleted in its
2982+ // expire callback so we dont touch this after lock
2983+ // is released
2984+ timerQueue & queue = m_queue;
2985+ while ( queue.m_cancelPending &&
2986+ queue.m_pExpTmr == this ) {
2987+ GuardRelease unguard ( guard );
2988+ queue.m_cancelBlockingEvent.wait ();
2989 }
2990 // in case other threads are waiting
2991- wakeupCancelBlockingThreads = true;
2992+ queue.m_cancelBlockingEvent.signal ();
2993+ }
2994+ }
2995+ else {
2996+ cs.wasPending = true;
2997+ if ( oldExp > m_queue.m_heap.front ()->m_exp ) {
2998+ cs.reschedule = true;
2999 }
3000 }
3001 }
3002- if ( reschedual ) {
3003- this->queue.notify.reschedule ();
3004- }
3005- if ( wakeupCancelBlockingThreads ) {
3006- this->queue.cancelBlockingEvent.signal ();
3007- }
3008+ return cs;
3009 }
3010
3011-epicsTimer::expireInfo timer::getExpireInfo () const
3012+epicsTimer :: expireInfo Timer :: getExpireInfo () const
3013 {
3014 // taking a lock here guarantees that users will not
3015 // see brief intervals when a timer isnt active because
3016 // it is is canceled when start is called
3017- epicsGuard < epicsMutex > locker ( this->queue.mutex );
3018- if ( this->curState == statePending || this->curState == stateActive ) {
3019- return expireInfo ( true, this->exp );
3020+ Guard locker ( m_queue );
3021+ if ( m_curState == statePending ) {
3022+ return expireInfo ( true, m_exp );
3023 }
3024 return expireInfo ( false, epicsTime() );
3025 }
3026
3027-void timer::show ( unsigned int level ) const
3028+void Timer :: show ( unsigned int level ) const
3029 {
3030- epicsGuard < epicsMutex > locker ( this->queue.mutex );
3031+ Guard locker ( m_queue );
3032 double delay;
3033- if ( this->curState == statePending || this->curState == stateActive ) {
3034+ if ( m_curState == statePending ) {
3035 try {
3036- delay = this->exp - epicsTime::getCurrent();
3037+ delay = m_exp - epicsTime :: getCurrent ();
3038 }
3039 catch ( ... ) {
3040- delay = - DBL_MAX;
3041+ delay = -DBL_MAX;
3042 }
3043 }
3044 else {
3045 delay = -DBL_MAX;
3046 }
3047 const char *pStateName;
3048- if ( this->curState == statePending ) {
3049+ if ( m_curState == statePending ) {
3050 pStateName = "pending";
3051 }
3052- else if ( this->curState == stateActive ) {
3053- pStateName = "active";
3054- }
3055- else if ( this->curState == stateLimbo ) {
3056+ else if ( m_curState == stateLimbo ) {
3057 pStateName = "limbo";
3058 }
3059 else {
3060 pStateName = "corrupt";
3061 }
3062- printf ( "timer, state = %s, delay = %f\n",
3063- pStateName, delay );
3064- if ( level >= 1u && this->pNotify ) {
3065- this->pNotify->show ( level - 1u );
3066+ printf ( "Timer, state = %s, index = %lu, delay = %f\n",
3067+ pStateName, (unsigned long ) m_index, delay );
3068+ if ( level >= 1u && m_pNotify ) {
3069+ m_pNotify->show ( level - 1u );
3070 }
3071 }
3072
3073-void timer::operator delete ( void * )
3074-{
3075- // Visual C++ .net appears to require operator delete if
3076- // placement operator delete is defined? I smell a ms rat
3077- // because if I declare placement new and delete, but
3078- // comment out the placement delete definition there are
3079- // no undefined symbols.
3080- errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
3081- __FILE__, __LINE__ );
3082-}
3083-
3084-void epicsTimerForC::operator delete ( void * )
3085-{
3086- // Visual C++ .net appears to require operator delete if
3087- // placement operator delete is defined? I smell a ms rat
3088- // because if I declare placement new and delete, but
3089- // comment out the placement delete definition there are
3090- // no undefined symbols.
3091- errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
3092- __FILE__, __LINE__ );
3093-}
3094-
3095diff --git a/modules/libcom/src/timer/timerPrivate.h b/modules/libcom/src/timer/timerPrivate.h
3096index 259afae..8ca0e67 100644
3097--- a/modules/libcom/src/timer/timerPrivate.h
3098+++ b/modules/libcom/src/timer/timerPrivate.h
3099@@ -1,5 +1,7 @@
3100 /*************************************************************************\
3101-* Copyright (c) 2015 UChicago Argonne LLC, as Operator of Argonne
3102+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
3103+* National Laboratory
3104+* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3105 * National Laboratory.
3106 * Copyright (c) 2002 The Regents of the University of California, as
3107 * Operator of Los Alamos National Laboratory.
3108@@ -7,6 +9,7 @@
3109 * in file LICENSE that is included with this distribution.
3110 \*************************************************************************/
3111 /*
3112+ *
3113 * Author Jeffrey O. Hill
3114 * johill@lanl.gov
3115 * 505 665 1831
3116@@ -16,12 +19,15 @@
3117 #define epicsTimerPrivate_h
3118
3119 #include <typeinfo>
3120+#include <vector>
3121
3122-#include "tsFreeList.h"
3123-#include "epicsSingleton.h"
3124 #include "tsDLList.h"
3125 #include "epicsTimer.h"
3126+#include "epicsMutex.h"
3127+#include "epicsGuard.h"
3128 #include "compilerDependencies.h"
3129+#include "epicsStaticInstance.h"
3130+#include "AllocatorArena.h"
3131
3132 #ifdef DEBUG
3133 # define debugPrintf(ARGSINPAREN) printf ARGSINPAREN
3134@@ -29,90 +35,130 @@
3135 # define debugPrintf(ARGSINPAREN)
3136 #endif
3137
3138-template < class T > class epicsGuard;
3139+using std :: type_info;
3140+
3141+class Timer;
3142+class timerQueue;
3143
3144-class timer : public epicsTimer, public tsDLNode < timer > {
3145+bool operator < ( const Timer &, const Timer & );
3146+bool operator > ( const Timer &, const Timer & );
3147+bool operator <= ( const Timer &, const Timer & );
3148+bool operator >= ( const Timer &, const Timer & );
3149+
3150+class Timer : public epicsTimer {
3151 public:
3152+ typedef epicsMutex Mutex;
3153+ typedef epicsGuard < Mutex > Guard;
3154+ typedef epicsGuardRelease < Mutex > GuardRelease;
3155+ Timer ( timerQueue & );
3156+ ~Timer ();
3157 void destroy ();
3158- void start ( class epicsTimerNotify &, const epicsTime & );
3159- void start ( class epicsTimerNotify &, double delaySeconds );
3160- void cancel ();
3161+ unsigned start ( class epicsTimerNotify &, const epicsTime & );
3162+ unsigned start ( class epicsTimerNotify &, double delaySeconds );
3163+ bool cancel ();
3164 expireInfo getExpireInfo () const;
3165+ double getExpireDelay ( const epicsTime & currentTime );
3166 void show ( unsigned int level ) const;
3167- void * operator new ( size_t size, tsFreeList < timer, 0x20 > & );
3168- epicsPlacementDeleteOperator (( void *, tsFreeList < timer, 0x20 > & ))
3169+ static void * operator new ( size_t sz );
3170+ static void operator delete ( void * ptr, size_t sz );
3171 protected:
3172- timer ( class timerQueue & );
3173- ~timer ();
3174- timerQueue & queue;
3175+ timerQueue & m_queue;
3176 private:
3177- enum state { statePending = 45, stateActive = 56, stateLimbo = 78 };
3178- epicsTime exp; // experation time
3179- state curState; // current state
3180- epicsTimerNotify * pNotify; // callback
3181- void privateStart ( epicsTimerNotify & notify, const epicsTime & );
3182- timer & operator = ( const timer & );
3183- // Visual C++ .net appears to require operator delete if
3184- // placement operator delete is defined? I smell a ms rat
3185- // because if I declare placement new and delete, but
3186- // comment out the placement delete definition there are
3187- // no undefined symbols.
3188- void operator delete ( void * );
3189+ typedef epics :: AllocatorArena < Timer, timerQueue, 16u > M_Allocator;
3190+ enum state {
3191+ statePending = 45,
3192+ stateLimbo = 78 };
3193+ epicsTime m_exp; // experation time
3194+ state m_curState; // current state
3195+ epicsTimerNotify * m_pNotify; // callback
3196+ size_t m_index;
3197+ static const size_t m_invalidIndex =
3198+ ~ static_cast < size_t > ( 0u );
3199+ struct M_StartReturn {
3200+ unsigned numNew;
3201+ bool resched;
3202+ };
3203+ M_StartReturn m_privateStart ( epicsTimerNotify & notify,
3204+ const epicsTime & expire );
3205+ struct M_CancelStatus {
3206+ bool reschedule;
3207+ bool wasPending;
3208+ };
3209+ M_CancelStatus m_cancelPvt ( Guard & );
3210+ void m_remove ( Guard & guard );
3211+ Timer & operator = ( const Timer & );
3212 friend class timerQueue;
3213+ friend bool operator < ( const Timer &, const Timer & );
3214+ friend bool operator > ( const Timer &, const Timer & );
3215+ friend bool operator <= ( const Timer &, const Timer & );
3216+ friend bool operator >= ( const Timer &, const Timer & );
3217 };
3218
3219-struct epicsTimerForC : public epicsTimerNotify, public timer {
3220+struct TimerForC : public epicsTimerNotify {
3221 public:
3222- void destroy ();
3223-protected:
3224- epicsTimerForC ( timerQueue &, epicsTimerCallback, void *pPrivateIn );
3225- ~epicsTimerForC ();
3226- void * operator new ( size_t size, tsFreeList < epicsTimerForC, 0x20 > & );
3227- epicsPlacementDeleteOperator (( void *, tsFreeList < epicsTimerForC, 0x20 > & ))
3228-private:
3229- epicsTimerCallback pCallBack;
3230- void * pPrivate;
3231+ typedef epicsMutex Mutex;
3232+ typedef epicsGuard < Mutex > Guard;
3233+ TimerForC ( class timerQueue &, epicsTimerCallback, void * pPrivateIn );
3234+ ~TimerForC ();
3235+ unsigned start ( const epicsTime & );
3236+ unsigned start ( double delaySeconds );
3237+ bool cancel ();
3238+ void show ( unsigned level ) const;
3239 expireStatus expire ( const epicsTime & currentTime );
3240- epicsTimerForC & operator = ( const epicsTimerForC & );
3241- // Visual C++ .net appears to require operator delete if
3242- // placement operator delete is defined? I smell a ms rat
3243- // because if I declare placement new and delete, but
3244- // comment out the placement delete definition there are
3245- // no undefined symbols.
3246- void operator delete ( void * );
3247- friend class timerQueue;
3248-};
3249-
3250-using std :: type_info;
3251+ double getExpireDelay ();
3252+ static void * operator new ( size_t sz );
3253+ static void operator delete ( void * ptr, size_t sz );
3254+private:
3255+ typedef epics :: AllocatorArena < TimerForC, timerQueue, 16u > M_Allocator;
3256+ Timer * m_pTimer;
3257+ epicsTimerCallback m_pCallBack;
3258+ void * m_pPrivate;
3259+ TimerForC & operator = ( const TimerForC & );
3260+};
3261
3262-class timerQueue : public epicsTimerQueue {
3263+class timerQueue :
3264+ public epicsTimerQueue,
3265+ public epicsMutex {
3266 public:
3267+ typedef epicsMutex Mutex;
3268+ typedef epicsGuard < Mutex > Guard;
3269+ typedef epicsGuardRelease < Mutex > GuardRelease;
3270 timerQueue ( epicsTimerQueueNotify &notify );
3271 virtual ~timerQueue ();
3272 epicsTimer & createTimer ();
3273- epicsTimerForC & createTimerForC ( epicsTimerCallback pCallback, void *pArg );
3274+ Timer & createTimerImpl ();
3275+ TimerForC & createTimerForC (
3276+ epicsTimerCallback pCallback, void *pArg );
3277 double process ( const epicsTime & currentTime );
3278+ double process ( Guard &, const epicsTime & currentTime );
3279 void show ( unsigned int level ) const;
3280+ void show ( Guard &, unsigned int level ) const;
3281 private:
3282- tsFreeList < timer, 0x20 > timerFreeList;
3283- tsFreeList < epicsTimerForC, 0x20 > timerForCFreeList;
3284- mutable epicsMutex mutex;
3285- epicsEvent cancelBlockingEvent;
3286- tsDLList < timer > timerList;
3287- epicsTimerQueueNotify & notify;
3288- timer * pExpireTmr;
3289- epicsThreadId processThread;
3290- epicsTime exceptMsgTimeStamp;
3291- bool cancelPending;
3292- static const double exceptMsgMinPeriod;
3293- void printExceptMsg ( const char * pName,
3294- const type_info & type );
3295+ epicsEvent m_cancelBlockingEvent;
3296+ std :: vector < Timer * > m_heap;
3297+ epicsTime m_exceptMsgTimeStamp;
3298+ epicsTimerQueueNotify & m_notify;
3299+ Timer * m_pExpTmr;
3300+ epicsThreadId m_processThread;
3301+ size_t m_numTimers;
3302+ bool m_cancelPending;
3303+ static const double m_exceptMsgMinPeriod;
3304 timerQueue ( const timerQueue & );
3305 timerQueue & operator = ( const timerQueue & );
3306- friend class timer;
3307- friend struct epicsTimerForC;
3308+ void m_printExceptMsg ( const char * pName, const type_info & type );
3309+ bool m_fixParent ( size_t childIdx );
3310+ void m_fixChildren ( size_t parentIdx );
3311+ void m_swapEntries ( size_t idx0, size_t idx1 );
3312+ double m_expDelay ( const epicsTime & currentTime );
3313+ static size_t m_parent ( size_t childIdx );
3314+ static size_t m_leftChild ( size_t parentIdx );
3315+ static size_t m_rightChild ( size_t parentIdx );
3316+ friend class Timer;
3317+ friend struct TimerForC;
3318 };
3319
3320+class timerQueueActiveMgr;
3321+
3322 class timerQueueActiveMgrPrivate {
3323 public:
3324 timerQueueActiveMgrPrivate ();
3325@@ -123,101 +169,95 @@ private:
3326 friend class timerQueueActiveMgr;
3327 };
3328
3329-class timerQueueActiveMgr;
3330-
3331-class timerQueueActive : public epicsTimerQueueActive,
3332- public epicsThreadRunable, public epicsTimerQueueNotify,
3333+class timerQueueActive :
3334+ public epicsTimerQueueActive,
3335+ public epicsThreadRunable,
3336+ public epicsTimerQueueNotify,
3337 public timerQueueActiveMgrPrivate {
3338 public:
3339- typedef epicsSingleton < timerQueueActiveMgr > :: reference RefMgr;
3340- timerQueueActive ( RefMgr &, bool okToShare, unsigned priority );
3341- void start ();
3342+ timerQueueActive ( bool okToShare, unsigned priority );
3343 epicsTimer & createTimer ();
3344- epicsTimerForC & createTimerForC ( epicsTimerCallback pCallback, void *pArg );
3345+ TimerForC & createTimerForC (
3346+ epicsTimerCallback pCallback, void *pArg );
3347+ void run ();
3348+ void reschedule ();
3349+ epicsTimerQueue & getEpicsTimerQueue ();
3350 void show ( unsigned int level ) const;
3351 bool sharingOK () const;
3352 unsigned threadPriority () const;
3353 protected:
3354 ~timerQueueActive ();
3355- RefMgr _refMgr;
3356 private:
3357- timerQueue queue;
3358- epicsEvent rescheduleEvent;
3359- epicsEvent exitEvent;
3360- epicsThread thread;
3361- const double sleepQuantum;
3362- bool okToShare;
3363- int exitFlag; // use atomic ops
3364- bool terminateFlag;
3365- void run ();
3366- void reschedule ();
3367- double quantum ();
3368- void _printLastChanceExceptionMessage (
3369- const char * pExceptionTypeName,
3370- const char * pExceptionContext );
3371- epicsTimerQueue & getEpicsTimerQueue ();
3372+ typedef epicsMutex Mutex;
3373+ typedef epicsGuard < Mutex > Guard;
3374+ typedef epicsGuardRelease < Mutex > GuardRelease;
3375+ timerQueue m_queue;
3376+ epicsEvent m_rescheduleEvent;
3377+ epicsEvent m_exitEvent;
3378+ epicsThread m_thread;
3379+ bool m_okToShare;
3380+ bool m_exitFlag;
3381+ bool m_terminateFlag;
3382 timerQueueActive ( const timerQueueActive & );
3383 timerQueueActive & operator = ( const timerQueueActive & );
3384 };
3385
3386 class timerQueueActiveMgr {
3387 public:
3388- typedef epicsSingleton < timerQueueActiveMgr > :: reference RefThis;
3389+ static timerQueueActiveMgr & master ();
3390 timerQueueActiveMgr ();
3391 ~timerQueueActiveMgr ();
3392- epicsTimerQueueActiveForC & allocate ( RefThis &, bool okToShare,
3393+ epicsTimerQueueActiveForC & allocate ( bool okToShare,
3394 unsigned threadPriority = epicsThreadPriorityMin + 10 );
3395 void release ( epicsTimerQueueActiveForC & );
3396 private:
3397- epicsMutex mutex;
3398- tsDLList < epicsTimerQueueActiveForC > sharedQueueList;
3399+ typedef epicsMutex Mutex;
3400+ typedef epicsGuard < Mutex > Guard;
3401+ Mutex m_mutex;
3402+ tsDLList < epicsTimerQueueActiveForC > m_sharedQueueList;
3403 timerQueueActiveMgr ( const timerQueueActiveMgr & );
3404 timerQueueActiveMgr & operator = ( const timerQueueActiveMgr & );
3405 };
3406
3407-extern epicsSingleton < timerQueueActiveMgr > timerQueueMgrEPICS;
3408-
3409 class timerQueuePassive : public epicsTimerQueuePassive {
3410 public:
3411 timerQueuePassive ( epicsTimerQueueNotify & );
3412 epicsTimer & createTimer ();
3413- epicsTimerForC & createTimerForC ( epicsTimerCallback pCallback, void *pArg );
3414+ TimerForC & createTimerForC (
3415+ epicsTimerCallback pCallback, void *pArg );
3416 void show ( unsigned int level ) const;
3417 double process ( const epicsTime & currentTime );
3418+ epicsTimerQueue & getEpicsTimerQueue ();
3419 protected:
3420- timerQueue queue;
3421+ timerQueue m_queue;
3422 ~timerQueuePassive ();
3423- epicsTimerQueue & getEpicsTimerQueue ();
3424 timerQueuePassive ( const timerQueuePassive & );
3425 timerQueuePassive & operator = ( const timerQueuePassive & );
3426 };
3427
3428-struct epicsTimerQueuePassiveForC :
3429- public epicsTimerQueueNotify, public timerQueuePassive {
3430+struct epicsTimerQueuePassiveForC :
3431+ public epicsTimerQueueNotify,
3432+ public timerQueuePassive {
3433 public:
3434- epicsTimerQueuePassiveForC (
3435- epicsTimerQueueNotifyReschedule,
3436+ epicsTimerQueuePassiveForC (
3437+ epicsTimerQueueNotifyReschedule,
3438 epicsTimerQueueNotifyQuantum,
3439 void * pPrivate );
3440 void destroy ();
3441+ void reschedule ();
3442 protected:
3443 ~epicsTimerQueuePassiveForC ();
3444 private:
3445- epicsTimerQueueNotifyReschedule pRescheduleCallback;
3446- epicsTimerQueueNotifyQuantum pSleepQuantumCallback;
3447- void * pPrivate;
3448- static epicsSingleton < tsFreeList < epicsTimerQueuePassiveForC, 0x10 > > pFreeList;
3449- void reschedule ();
3450- double quantum ();
3451+ epicsTimerQueueNotifyReschedule m_pRescheduleCallback;
3452+ epicsTimerQueueNotifyQuantum m_pSleepQuantumCallback;
3453+ void * m_pPrivate;
3454 };
3455
3456-struct epicsTimerQueueActiveForC : public timerQueueActive,
3457+struct epicsTimerQueueActiveForC : public timerQueueActive,
3458 public tsDLNode < epicsTimerQueueActiveForC > {
3459 public:
3460- epicsTimerQueueActiveForC ( RefMgr &, bool okToShare, unsigned priority );
3461+ epicsTimerQueueActiveForC ( bool okToShare, unsigned priority );
3462 void release ();
3463- void * operator new ( size_t );
3464- void operator delete ( void * );
3465 protected:
3466 virtual ~epicsTimerQueueActiveForC ();
3467 private:
3468@@ -225,52 +265,106 @@ private:
3469 epicsTimerQueueActiveForC & operator = ( const epicsTimerQueueActiveForC & );
3470 };
3471
3472-inline bool timerQueueActive::sharingOK () const
3473+inline double Timer :: getExpireDelay ( const epicsTime & currentTime )
3474+{
3475+ return m_exp - currentTime;
3476+}
3477+
3478+inline void * Timer :: operator new ( size_t sz )
3479+{
3480+ return M_Allocator :: allocateOctets ( sz );
3481+}
3482+
3483+inline void Timer :: operator delete ( void * p, size_t sz )
3484 {
3485- return this->okToShare;
3486+ M_Allocator :: deallocateOctets ( p, sz );
3487+}
3488+
3489+inline bool operator < ( const Timer & lhs, const Timer & rhs )
3490+{
3491+ return lhs.m_exp < rhs.m_exp;
3492+}
3493+
3494+inline bool operator > ( const Timer & lhs, const Timer & rhs )
3495+{
3496+ return rhs < lhs;
3497+}
3498+
3499+inline bool operator <= ( const Timer & lhs, const Timer & rhs )
3500+{
3501+ return ! ( lhs > rhs );
3502 }
3503
3504-inline unsigned timerQueueActive::threadPriority () const
3505+inline bool operator >= ( const Timer & lhs, const Timer & rhs )
3506+{
3507+ return ! ( lhs < rhs );
3508+}
3509+
3510+inline size_t timerQueue :: m_parent ( const size_t childIdx )
3511 {
3512- return thread.getPriority ();
3513+ return ( childIdx + ( childIdx & 1u ) ) / 2u - 1u;
3514 }
3515
3516-inline void * timer::operator new ( size_t size,
3517- tsFreeList < timer, 0x20 > & freeList )
3518+inline size_t timerQueue :: m_leftChild ( const size_t parentIdx )
3519 {
3520- return freeList.allocate ( size );
3521+ return ( parentIdx + 1u ) * 2u - 1u;
3522 }
3523
3524-#ifdef CXX_PLACEMENT_DELETE
3525-inline void timer::operator delete ( void * pCadaver,
3526- tsFreeList < timer, 0x20 > & freeList )
3527+inline size_t timerQueue :: m_rightChild ( const size_t parentIdx )
3528 {
3529- freeList.release ( pCadaver );
3530+ return ( parentIdx + 1u ) * 2u;
3531 }
3532-#endif
3533
3534-inline void * epicsTimerForC::operator new ( size_t size,
3535- tsFreeList < epicsTimerForC, 0x20 > & freeList )
3536+inline void timerQueue :: m_swapEntries ( size_t idx0, size_t idx1 )
3537 {
3538- return freeList.allocate ( size );
3539+ std :: swap ( m_heap[idx0], m_heap[idx1] );
3540+ m_heap[idx0]->m_index = idx0;
3541+ m_heap[idx1]->m_index = idx1;
3542 }
3543
3544-#ifdef CXX_PLACEMENT_DELETE
3545-inline void epicsTimerForC::operator delete ( void * pCadaver,
3546- tsFreeList < epicsTimerForC, 0x20 > & freeList )
3547+inline bool timerQueueActive :: sharingOK () const
3548 {
3549- freeList.release ( pCadaver );
3550+ return m_okToShare;
3551+}
3552+
3553+inline unsigned timerQueueActive :: threadPriority () const
3554+{
3555+ return m_thread.getPriority ();
3556+}
3557+
3558+inline unsigned TimerForC :: start ( const epicsTime & expTime )
3559+{
3560+ return m_pTimer->start ( *this, expTime );
3561+}
3562+
3563+inline unsigned TimerForC :: start ( double delaySeconds )
3564+{
3565+ return m_pTimer->start ( *this, delaySeconds );
3566+}
3567+
3568+inline bool TimerForC :: cancel ()
3569+{
3570+ return m_pTimer->cancel ();
3571+}
3572+
3573+inline double TimerForC :: getExpireDelay ()
3574+{
3575+ return m_pTimer->getExpireDelay ( epicsTime :: getCurrent () );
3576+}
3577+
3578+inline void * TimerForC :: operator new ( size_t sz )
3579+{
3580+ return M_Allocator :: allocateOctets ( sz );
3581 }
3582-#endif
3583
3584-inline void * epicsTimerQueueActiveForC::operator new ( size_t size )
3585+inline void TimerForC :: operator delete ( void * p, size_t sz )
3586 {
3587- return ::operator new ( size );
3588+ M_Allocator :: deallocateOctets ( p, sz );
3589 }
3590
3591-inline void epicsTimerQueueActiveForC::operator delete ( void * pCadaver )
3592+inline timerQueueActiveMgr & timerQueueActiveMgr :: master ()
3593 {
3594- ::operator delete ( pCadaver );
3595+ return epics :: staticInstance < timerQueueActiveMgr > ();
3596 }
3597
3598 #endif // epicsTimerPrivate_h
3599diff --git a/modules/libcom/src/timer/timerQueue.cpp b/modules/libcom/src/timer/timerQueue.cpp
3600index 8f7f98e..5948941 100644
3601--- a/modules/libcom/src/timer/timerQueue.cpp
3602+++ b/modules/libcom/src/timer/timerQueue.cpp
3603@@ -1,4 +1,6 @@
3604 /*************************************************************************\
3605+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
3606+* National Laboratory
3607 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3608 * National Laboratory.
3609 * Copyright (c) 2002 The Regents of the University of California, as
3610@@ -12,56 +14,45 @@
3611 * 505 665 1831
3612 */
3613
3614-#include <stdio.h>
3615-#include <float.h>
3616+#include <cstdio>
3617
3618 #define epicsExportSharedSymbols
3619-#include "epicsGuard.h"
3620-#include "timerPrivate.h"
3621 #include "errlog.h"
3622+#include "timerPrivate.h"
3623
3624-const double timerQueue :: exceptMsgMinPeriod = 60.0 * 5.0; // seconds
3625-
3626-epicsTimerQueue::~epicsTimerQueue () {}
3627+const double timerQueue :: m_exceptMsgMinPeriod = 60.0 * 5.0; // seconds
3628
3629-timerQueue::timerQueue ( epicsTimerQueueNotify & notifyIn ) :
3630- mutex(__FILE__, __LINE__),
3631- notify ( notifyIn ),
3632- pExpireTmr ( 0 ),
3633- processThread ( 0 ),
3634- exceptMsgTimeStamp (
3635- epicsTime :: getCurrent () - exceptMsgMinPeriod ),
3636- cancelPending ( false )
3637+timerQueue :: timerQueue ( epicsTimerQueueNotify & notifyIn ) :
3638+ Mutex ( __FILE__, __LINE__ ),
3639+ m_exceptMsgTimeStamp ( epicsTime :: getCurrent ()
3640+ - m_exceptMsgMinPeriod ),
3641+ m_notify ( notifyIn ),
3642+ m_pExpTmr ( 0 ),
3643+ m_processThread ( 0 ),
3644+ m_numTimers ( 0u ),
3645+ m_cancelPending ( false )
3646 {
3647 }
3648
3649-timerQueue::~timerQueue ()
3650+timerQueue :: ~timerQueue ()
3651 {
3652- timer *pTmr;
3653- while ( ( pTmr = this->timerList.get () ) ) {
3654- pTmr->curState = timer::stateLimbo;
3655+ if ( m_heap.size () ) {
3656+ while ( Timer * const pTmr = m_heap.back () ) {
3657+ pTmr->m_curState = Timer :: stateLimbo;
3658+ m_heap.pop_back ();
3659+ }
3660 }
3661 }
3662
3663 void timerQueue ::
3664- printExceptMsg ( const char * pName, const type_info & type )
3665+ m_printExceptMsg ( const char * pName, const type_info & type )
3666 {
3667- char date[64];
3668- double delay;
3669- try {
3670- epicsTime cur = epicsTime :: getCurrent ();
3671- delay = cur - this->exceptMsgTimeStamp;
3672- cur.strftime ( date, sizeof ( date ),
3673- "%a %b %d %Y %H:%M:%S.%f" );
3674- if ( delay >= exceptMsgMinPeriod ) {
3675- this->exceptMsgTimeStamp = cur;
3676- }
3677- }
3678- catch ( ... ) {
3679- delay = DBL_MAX;
3680- strcpy ( date, "UKN DATE" );
3681- }
3682- if ( delay >= exceptMsgMinPeriod ) {
3683+ const epicsTime cur = epicsTime :: getCurrent ();
3684+ const double delay = cur - m_exceptMsgTimeStamp;
3685+ if ( delay >= m_exceptMsgMinPeriod ) {
3686+ m_exceptMsgTimeStamp = cur;
3687+ char date[64];
3688+ cur.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S.%f" );
3689 // we dont touch the typeid for the timer expiration
3690 // notify interface here because they might have
3691 // destroyed the timer during its callback
3692@@ -72,155 +63,212 @@ void timerQueue ::
3693 pName,
3694 type.name (),
3695 date );
3696+ errlogPrintf ( "!!!! WARNING - PERIODIC TIMER MAY NOT RESTART !!!!\n" );
3697 errlogFlush ();
3698 }
3699 }
3700
3701-double timerQueue::process ( const epicsTime & currentTime )
3702-{
3703- epicsGuard < epicsMutex > guard ( this->mutex );
3704+inline double timerQueue :: m_expDelay ( const epicsTime & currentTime )
3705+{
3706+ double delay = DBL_MAX;
3707+ if ( m_heap.size () > 0u ) {
3708+ delay = m_heap.front ()->m_exp - currentTime;
3709+ }
3710+ return delay;
3711+}
3712+
3713+double timerQueue :: process ( const epicsTime & currentTime )
3714+{
3715+ Guard guard ( *this );
3716+ return this->process ( guard, currentTime );
3717+}
3718
3719- if ( this->pExpireTmr ) {
3720+double timerQueue :: process ( Guard & guard,
3721+ const epicsTime & currentTime )
3722+{
3723+ guard.assertIdenticalMutex ( *this );
3724+ if ( m_processThread ) {
3725 // if some other thread is processing the queue
3726 // (or if this is a recursive call)
3727- timer * pTmr = this->timerList.first ();
3728- if ( pTmr ) {
3729- double delay = pTmr->exp - currentTime;
3730- if ( delay < 0.0 ) {
3731- delay = 0.0;
3732- }
3733- return delay;
3734- }
3735- else {
3736- return DBL_MAX;
3737+ double delay = m_expDelay ( currentTime );
3738+ if ( delay <= 0.0 ) {
3739+ delay = 0.0;
3740 }
3741- }
3742-
3743- //
3744- // Tag current epired tmr so that we can detect if call back
3745- // is in progress when canceling the timer.
3746- //
3747- if ( this->timerList.first () ) {
3748- if ( currentTime >= this->timerList.first ()->exp ) {
3749- this->pExpireTmr = this->timerList.first ();
3750- this->timerList.remove ( *this->pExpireTmr );
3751- this->pExpireTmr->curState = timer::stateActive;
3752- this->processThread = epicsThreadGetIdSelf ();
3753-# ifdef DEBUG
3754- this->pExpireTmr->show ( 0u );
3755-# endif
3756- }
3757- else {
3758- double delay = this->timerList.first ()->exp - currentTime;
3759- debugPrintf ( ( "no activity process %f to next\n", delay ) );
3760- return delay;
3761- }
3762- }
3763- else {
3764- return DBL_MAX;
3765+ return delay;
3766 }
3767
3768 # ifdef DEBUG
3769 unsigned N = 0u;
3770 # endif
3771
3772- double delay = DBL_MAX;
3773- while ( true ) {
3774- epicsTimerNotify *pTmpNotify = this->pExpireTmr->pNotify;
3775- this->pExpireTmr->pNotify = 0;
3776- epicsTimerNotify::expireStatus expStat ( epicsTimerNotify::noRestart );
3777-
3778- {
3779- epicsGuardRelease < epicsMutex > unguard ( guard );
3780-
3781+ m_processThread = epicsThreadGetIdSelf ();
3782+ double delay = m_expDelay ( currentTime );
3783+ while ( delay <= 0.0 ) {
3784+ //
3785+ // if delay is zero or less we know at least one timer is on
3786+ // the queue
3787+ //
3788+ // tag current expired tmr so that we can detect if call back
3789+ // is in progress when canceling the timer
3790+ //
3791+ delay = 0.0;
3792+ m_pExpTmr = m_heap.front ();
3793+ epicsTimerNotify * const pTmpNotify = m_pExpTmr->m_pNotify;
3794+ m_pExpTmr->m_pNotify = 0;
3795+ epicsTimerNotify :: expireStatus
3796+ expStat ( epicsTimerNotify :: noRestart );
3797+ if ( pTmpNotify ) {
3798+ GuardRelease unguard ( guard );
3799 debugPrintf ( ( "%5u expired \"%s\" with error %f sec\n",
3800- N++, typeid ( this->pExpireTmr->notify ).name (),
3801- currentTime - this->pExpireTmr->exp ) );
3802+ N++,
3803+ typeid ( *pTmpNotify ).name (),
3804+ currentTime - m_pExpTmr->m_exp ) );
3805 try {
3806 expStat = pTmpNotify->expire ( currentTime );
3807 }
3808 catch ( std::exception & except ) {
3809- printExceptMsg ( except.what (), typeid ( except ) );
3810+ m_printExceptMsg ( except.what (), typeid ( except ) );
3811 }
3812 catch ( ... ) {
3813- printExceptMsg ( "non-standard exception", typeid ( void ) );
3814+ m_printExceptMsg ( "non-standard exception", typeid ( void ) );
3815 }
3816 }
3817
3818 //
3819- // only restart if they didnt cancel() the timer
3820- // while the call back was running
3821+ // !! The position of a timer in the queue is allowed to change
3822+ // !! while its timer callback is running. This happens
3823+ // !! potentially when they reschedule a timer or cancel a
3824+ // !! timer. A small amount of additional labor is expended
3825+ // !! to properly handle this type of change below (we
3826+ // !! test the return from fix_parent and conditionally
3827+ // !! call fix_child, instead of calling only fix_child).
3828 //
3829- if ( this->cancelPending ) {
3830+ if ( m_cancelPending ) {
3831+ //
3832+ // only restart if they didnt cancel() the currently
3833+ // expiring timer while its call-back is running
3834+ //
3835 // 1) if another thread is canceling then cancel() waits for
3836 // the event below
3837 // 2) if this thread is canceling in the timer callback then
3838 // dont touch timer or notify here because the cancel might
3839 // have occurred because they destroyed the timer in the
3840 // callback
3841- this->cancelPending = false;
3842- this->cancelBlockingEvent.signal ();
3843+ // 3) timer::cancel sets timer state to limbo and timer index
3844+ // to invalid
3845+ //
3846+ m_cancelPending = false;
3847+ m_cancelBlockingEvent.signal ();
3848 }
3849 else {
3850- this->pExpireTmr->curState = timer::stateLimbo;
3851- if ( this->pExpireTmr->pNotify ) {
3852- // pNotify was cleared above so if it is valid now we know that
3853- // someone has started the timer from another thread and that
3854- // predominates over the restart parameters from expire.
3855- this->pExpireTmr->privateStart (
3856- *this->pExpireTmr->pNotify, this->pExpireTmr->exp );
3857+ if ( m_pExpTmr->m_pNotify ) {
3858+ // pNotify was cleared above; if its valid now we
3859+ // know that someone has restarted the timer when
3860+ // its callback is currently running either
3861+ // asynchronously from another thread or from
3862+ // within the currently running expire callback,
3863+ // possibly moving its position in the heap. As
3864+ // a defined policy either of these situations
3865+ // overrides any restart request parameters
3866+ // returned from expire
3867 }
3868 else if ( expStat.restart() ) {
3869 // restart as nec
3870- this->pExpireTmr->privateStart (
3871- *pTmpNotify, currentTime + expStat.expirationDelay() );
3872- }
3873- }
3874- this->pExpireTmr = 0;
3875-
3876- if ( this->timerList.first () ) {
3877- if ( currentTime >= this->timerList.first ()->exp ) {
3878- this->pExpireTmr = this->timerList.first ();
3879- this->timerList.remove ( *this->pExpireTmr );
3880- this->pExpireTmr->curState = timer::stateActive;
3881-# ifdef DEBUG
3882- this->pExpireTmr->show ( 0u );
3883-# endif
3884+ m_pExpTmr->m_pNotify = pTmpNotify;
3885+ m_pExpTmr->m_exp = currentTime + expStat.expirationDelay ();
3886+ if ( ! m_fixParent ( m_pExpTmr->m_index ) ) {
3887+ m_fixChildren ( m_pExpTmr->m_index );
3888+ }
3889 }
3890 else {
3891- delay = this->timerList.first ()->exp - currentTime;
3892- this->processThread = 0;
3893- break;
3894+ m_pExpTmr->m_remove ( guard );
3895 }
3896 }
3897- else {
3898- this->processThread = 0;
3899- delay = DBL_MAX;
3900+ delay = m_expDelay ( currentTime );
3901+ }
3902+ m_pExpTmr = 0;
3903+ m_processThread = 0;
3904+ return delay;
3905+}
3906+
3907+bool timerQueue :: m_fixParent ( size_t childIdx )
3908+{
3909+ bool itMoved = false;
3910+ while ( childIdx != 0u ) {
3911+ const size_t parentIdx = m_parent ( childIdx );
3912+ if ( *m_heap[parentIdx] <= *m_heap[childIdx] ) {
3913 break;
3914 }
3915+ m_swapEntries ( parentIdx, childIdx );
3916+ childIdx = parentIdx;
3917+ itMoved = true;
3918 }
3919- return delay;
3920+ return itMoved;
3921 }
3922
3923-epicsTimer & timerQueue::createTimer ()
3924+void timerQueue :: m_fixChildren ( size_t parentIdx )
3925 {
3926- return * new ( this->timerFreeList ) timer ( * this );
3927+ const size_t hpsz = m_heap.size ();
3928+ while ( true ) {
3929+ const size_t leftChildIdx = m_leftChild ( parentIdx );
3930+ const size_t rightChildIdx = m_rightChild ( parentIdx );
3931+ size_t smallestIdx = parentIdx;
3932+ if ( leftChildIdx < hpsz ) {
3933+ if ( *m_heap[parentIdx] > *m_heap[leftChildIdx] ) {
3934+ smallestIdx = leftChildIdx;
3935+ }
3936+ }
3937+ if ( rightChildIdx < hpsz ) {
3938+ if ( *m_heap[smallestIdx] > *m_heap[rightChildIdx] ) {
3939+ smallestIdx = rightChildIdx;
3940+ }
3941+ }
3942+ if ( smallestIdx == parentIdx ) {
3943+ break;
3944+ }
3945+ m_swapEntries ( parentIdx, smallestIdx );
3946+ parentIdx = smallestIdx;
3947+ }
3948+}
3949+
3950+Timer & timerQueue :: createTimerImpl ()
3951+{
3952+ // better to throw now in contrast with later during start
3953+ Guard guard ( *this );
3954+ m_numTimers++;
3955+ m_heap.reserve ( m_numTimers );
3956+ return * new Timer ( * this );
3957 }
3958
3959-epicsTimerForC & timerQueue::createTimerForC ( epicsTimerCallback pCallback, void *pArg )
3960+epicsTimer & timerQueue :: createTimer ()
3961 {
3962- return * new ( this->timerForCFreeList ) epicsTimerForC ( *this, pCallback, pArg );
3963+ return createTimerImpl ();
3964 }
3965
3966-void timerQueue::show ( unsigned level ) const
3967+TimerForC & timerQueue :: createTimerForC (
3968+ epicsTimerCallback pCallback, void *pArg )
3969 {
3970- epicsGuard < epicsMutex > locker ( this->mutex );
3971- printf ( "epicsTimerQueue with %u items pending\n", this->timerList.count () );
3972+ return * new TimerForC ( *this, pCallback, pArg );
3973+}
3974+
3975+void timerQueue :: show ( unsigned level ) const
3976+{
3977+ Guard guard ( const_cast < timerQueue & > ( *this ) );
3978+ this->show ( guard, level );
3979+}
3980+
3981+void timerQueue :: show ( Guard & guard, unsigned level ) const
3982+{
3983+ guard.assertIdenticalMutex ( *this );
3984+ printf ( "epicsTimerQueue with %lu items pending\n",
3985+ (unsigned long) m_heap.size () );
3986 if ( level >= 1u ) {
3987- tsDLIterConst < timer > iter = this->timerList.firstIter ();
3988- while ( iter.valid () ) {
3989- iter->show ( level - 1u );
3990- ++iter;
3991+ std :: vector < Timer * > :: const_iterator
3992+ ppTimer = m_heap.begin ();
3993+ while ( ppTimer != m_heap.end () && *ppTimer ) {
3994+ (*ppTimer)->show ( level - 1u );
3995+ ++ppTimer;
3996 }
3997 }
3998 }
3999+
4000diff --git a/modules/libcom/src/timer/timerQueueActive.cpp b/modules/libcom/src/timer/timerQueueActive.cpp
4001index 4db68c0..3efedee 100644
4002--- a/modules/libcom/src/timer/timerQueueActive.cpp
4003+++ b/modules/libcom/src/timer/timerQueueActive.cpp
4004@@ -1,5 +1,7 @@
4005 /*************************************************************************\
4006-* Copyright (c) 2015 UChicago Argonne LLC, as Operator of Argonne
4007+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
4008+* National Laboratory
4009+* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
4010 * National Laboratory.
4011 * Copyright (c) 2002 The Regents of the University of California, as
4012 * Operator of Los Alamos National Laboratory.
4013@@ -12,144 +14,100 @@
4014 * 505 665 1831
4015 */
4016
4017-#include <stdio.h>
4018+#include <cstdio>
4019
4020 #define epicsExportSharedSymbols
4021-#include "epicsAtomic.h"
4022+#include "epicsGuard.h"
4023 #include "timerPrivate.h"
4024-#include "errlog.h"
4025
4026-#ifdef _MSC_VER
4027-# pragma warning ( push )
4028-# pragma warning ( disable:4660 )
4029-#endif
4030-
4031-template class epicsSingleton < timerQueueActiveMgr >;
4032-
4033-#ifdef _MSC_VER
4034-# pragma warning ( pop )
4035-#endif
4036-
4037-epicsSingleton < timerQueueActiveMgr > timerQueueMgrEPICS;
4038-
4039-epicsTimerQueueActive::~epicsTimerQueueActive () {}
4040-
4041-epicsTimerQueueActive & epicsTimerQueueActive::allocate ( bool okToShare, unsigned threadPriority )
4042+epicsTimerQueueActive & epicsTimerQueueActive :: allocate ( bool okToShare,
4043+ unsigned threadPriority )
4044 {
4045- epicsSingleton < timerQueueActiveMgr >::reference pMgr =
4046- timerQueueMgrEPICS.getReference ();
4047- return pMgr->allocate ( pMgr, okToShare, threadPriority );
4048+ return timerQueueActiveMgr :: master ().
4049+ allocate ( okToShare, threadPriority );
4050 }
4051
4052 timerQueueActive ::
4053- timerQueueActive ( RefMgr & refMgr,
4054- bool okToShareIn, unsigned priority ) :
4055- _refMgr ( refMgr ), queue ( *this ), thread ( *this, "timerQueue",
4056+ timerQueueActive ( bool okToShareIn, unsigned priority ) :
4057+ m_queue ( *this ),
4058+ m_thread ( *this, "timerQueue",
4059 epicsThreadGetStackSize ( epicsThreadStackMedium ), priority ),
4060- sleepQuantum ( epicsThreadSleepQuantum() ), okToShare ( okToShareIn ),
4061- exitFlag ( 0 ), terminateFlag ( false )
4062+ m_okToShare ( okToShareIn ),
4063+ m_exitFlag ( false ),
4064+ m_terminateFlag ( false )
4065 {
4066+ epicsGuard < epicsMutex > guard ( m_queue );
4067+ m_thread.start ();
4068 }
4069
4070-void timerQueueActive::start ()
4071+timerQueueActive :: ~timerQueueActive ()
4072 {
4073- this->thread.start ();
4074-}
4075-
4076-timerQueueActive::~timerQueueActive ()
4077-{
4078- this->terminateFlag = true;
4079- this->rescheduleEvent.signal ();
4080- while ( ! epics::atomic::get(this->exitFlag) ) {
4081- this->exitEvent.wait ( 1.0 );
4082+ Guard guard ( m_queue );
4083+ m_terminateFlag = true;
4084+ m_rescheduleEvent.signal ();
4085+ while ( ! m_exitFlag ) {
4086+ GuardRelease release ( guard );
4087+ m_exitEvent.wait ( 1.0 );
4088 }
4089 // in case other threads are waiting here also
4090- this->exitEvent.signal ();
4091-}
4092-
4093-void timerQueueActive :: _printLastChanceExceptionMessage (
4094- const char * pExceptionTypeName,
4095- const char * pExceptionContext )
4096-{
4097- char date[64];
4098- try {
4099- epicsTime cur = epicsTime :: getCurrent ();
4100- cur.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S.%f");
4101- }
4102- catch ( ... ) {
4103- strcpy ( date, "<UKN DATE>" );
4104- }
4105- errlogPrintf (
4106- "timerQueueActive: Unexpected C++ exception \"%s\" with type \"%s\" "
4107- "while processing timer queue, at %s\n",
4108- pExceptionContext, pExceptionTypeName, date );
4109+ m_exitEvent.signal ();
4110 }
4111
4112-
4113 void timerQueueActive :: run ()
4114 {
4115- epics::atomic::set(this->exitFlag, 0);
4116- while ( ! this->terminateFlag ) {
4117- try {
4118- double delay = this->queue.process ( epicsTime::getCurrent() );
4119- debugPrintf ( ( "timer thread sleeping for %g sec (max)\n", delay ) );
4120- this->rescheduleEvent.wait ( delay );
4121- }
4122- catch ( std :: exception & except ) {
4123- _printLastChanceExceptionMessage (
4124- typeid ( except ).name (), except.what () );
4125- epicsThreadSleep ( 10.0 );
4126- }
4127- catch ( ... ) {
4128- _printLastChanceExceptionMessage (
4129- "catch ( ... )", "Non-standard C++ exception" );
4130- epicsThreadSleep ( 10.0 );
4131+ Guard guard ( m_queue );
4132+ m_exitFlag = false;
4133+ while ( ! m_terminateFlag ) {
4134+ const epicsTime curr = epicsTime :: getCurrent ();
4135+ double delay = m_queue.process ( guard, curr );
4136+ {
4137+ GuardRelease release ( guard );
4138+ debugPrintf ( ( "timer thread sleeping for %g sec (max)\n",
4139+ delay ) );
4140+ m_rescheduleEvent.wait ( delay );
4141 }
4142 }
4143- epics::atomic::set(this->exitFlag, 1);
4144- this->exitEvent.signal (); // no access to queue after exitEvent signal
4145-}
4146-
4147-epicsTimer & timerQueueActive::createTimer ()
4148-{
4149- return this->queue.createTimer();
4150+ m_exitFlag = true;
4151+ m_exitEvent.signal (); // no access to queue after exitEvent signal
4152 }
4153
4154-epicsTimerForC & timerQueueActive::createTimerForC ( epicsTimerCallback pCallback, void * pArg )
4155+epicsTimer & timerQueueActive :: createTimer ()
4156 {
4157- return this->queue.createTimerForC ( pCallback, pArg );
4158+ return m_queue.createTimer();
4159 }
4160
4161-void timerQueueActive::reschedule ()
4162+TimerForC & timerQueueActive :: createTimerForC (
4163+ epicsTimerCallback pCallback, void * pArg )
4164 {
4165- this->rescheduleEvent.signal ();
4166+ return m_queue.createTimerForC ( pCallback, pArg );
4167 }
4168
4169-double timerQueueActive::quantum ()
4170+void timerQueueActive :: reschedule ()
4171 {
4172- return this->sleepQuantum;
4173+ m_rescheduleEvent.signal ();
4174 }
4175
4176-void timerQueueActive::show ( unsigned int level ) const
4177+void timerQueueActive :: show ( unsigned int level ) const
4178 {
4179+ Guard guard ( const_cast < timerQueue & > ( m_queue ) );
4180 printf ( "EPICS threaded timer queue at %p\n",
4181 static_cast <const void *> ( this ) );
4182 if ( level > 0u ) {
4183 // specifying level one here avoids recursive
4184 // show callback
4185- this->thread.show ( 1u );
4186- this->queue.show ( level - 1u );
4187+ m_thread.show ( 1u );
4188+ m_queue.show ( guard, level - 1u );
4189 printf ( "reschedule event\n" );
4190- this->rescheduleEvent.show ( level - 1u );
4191+ m_rescheduleEvent.show ( level - 1u );
4192 printf ( "exit event\n" );
4193- this->exitEvent.show ( level - 1u );
4194+ m_exitEvent.show ( level - 1u );
4195 printf ( "exitFlag = %c, terminateFlag = %c\n",
4196- epics::atomic::get(this->exitFlag) ? 'T' : 'F',
4197- this->terminateFlag ? 'T' : 'F' );
4198+ m_exitFlag ? 'T' : 'F',
4199+ m_terminateFlag ? 'T' : 'F' );
4200 }
4201 }
4202
4203-epicsTimerQueue & timerQueueActive::getEpicsTimerQueue ()
4204+epicsTimerQueue & timerQueueActive :: getEpicsTimerQueue ()
4205 {
4206 return static_cast < epicsTimerQueue &> ( * this );
4207 }
4208diff --git a/modules/libcom/src/timer/timerQueueActiveMgr.cpp b/modules/libcom/src/timer/timerQueueActiveMgr.cpp
4209index eff2e0c..af122a8 100644
4210--- a/modules/libcom/src/timer/timerQueueActiveMgr.cpp
4211+++ b/modules/libcom/src/timer/timerQueueActiveMgr.cpp
4212@@ -1,11 +1,12 @@
4213 /*************************************************************************\
4214+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
4215+* National Laboratory
4216 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
4217 * National Laboratory.
4218 * Copyright (c) 2002 The Regents of the University of California, as
4219 * Operator of Los Alamos National Laboratory.
4220-* EPICS BASE Versions 3.13.7
4221-* and higher are distributed subject to a Software License Agreement found
4222-* in file LICENSE that is included with this distribution.
4223+* EPICS BASE is distributed subject to a Software License Agreement found
4224+* in file LICENSE that is included with this distribution.
4225 \*************************************************************************/
4226 /*
4227 * Author Jeffrey O. Hill
4228@@ -13,28 +14,27 @@
4229 * 505 665 1831
4230 */
4231
4232-#include <limits.h>
4233+#include <climits>
4234
4235 #define epicsExportSharedSymbols
4236-#include "epicsGuard.h"
4237 #include "timerPrivate.h"
4238
4239-timerQueueActiveMgr::timerQueueActiveMgr ()
4240- :mutex(__FILE__, __LINE__)
4241+timerQueueActiveMgr::timerQueueActiveMgr () :
4242+ m_mutex ( __FILE__, __LINE__ )
4243 {
4244 }
4245
4246 timerQueueActiveMgr::~timerQueueActiveMgr ()
4247 {
4248- epicsGuard < epicsMutex > locker ( this->mutex );
4249+ Guard locker ( m_mutex );
4250 }
4251
4252 epicsTimerQueueActiveForC & timerQueueActiveMgr ::
4253- allocate ( RefThis & refThis, bool okToShare, unsigned threadPriority )
4254+ allocate ( bool okToShare, unsigned threadPriority )
4255 {
4256- epicsGuard < epicsMutex > locker ( this->mutex );
4257+ Guard locker ( m_mutex );
4258 if ( okToShare ) {
4259- tsDLIter < epicsTimerQueueActiveForC > iter = this->sharedQueueList.firstIter ();
4260+ tsDLIter < epicsTimerQueueActiveForC > iter = m_sharedQueueList.firstIter ();
4261 while ( iter.valid () ) {
4262 if ( iter->threadPriority () == threadPriority ) {
4263 assert ( iter->timerQueueActiveMgrPrivate::referenceCount < UINT_MAX );
4264@@ -46,10 +46,10 @@ epicsTimerQueueActiveForC & timerQueueActiveMgr ::
4265 }
4266
4267 epicsTimerQueueActiveForC & queue =
4268- * new epicsTimerQueueActiveForC ( refThis, okToShare, threadPriority );
4269+ * new epicsTimerQueueActiveForC ( okToShare, threadPriority );
4270 queue.timerQueueActiveMgrPrivate::referenceCount = 1u;
4271 if ( okToShare ) {
4272- this->sharedQueueList.add ( queue );
4273+ m_sharedQueueList.add ( queue );
4274 }
4275 return queue;
4276 }
4277@@ -58,20 +58,20 @@ void timerQueueActiveMgr ::
4278 release ( epicsTimerQueueActiveForC & queue )
4279 {
4280 {
4281- epicsGuard < epicsMutex > locker ( this->mutex );
4282+ Guard locker ( m_mutex );
4283 assert ( queue.timerQueueActiveMgrPrivate::referenceCount > 0u );
4284 queue.timerQueueActiveMgrPrivate::referenceCount--;
4285 if ( queue.timerQueueActiveMgrPrivate::referenceCount > 0u ) {
4286 return;
4287 }
4288 else if ( queue.sharingOK () ) {
4289- this->sharedQueueList.remove ( queue );
4290+ m_sharedQueueList.remove ( queue );
4291 }
4292 }
4293- // delete only after we release the guard in case the embedded
4294+ // delete only after we release the guard in case the embedded
4295 // reference is the last one and this object is destroyed
4296 // as a side effect
4297- timerQueueActiveMgrPrivate * pPriv = & queue;
4298+ timerQueueActiveMgrPrivate * const pPriv = & queue;
4299 delete pPriv;
4300 }
4301
4302diff --git a/modules/libcom/src/timer/timerQueuePassive.cpp b/modules/libcom/src/timer/timerQueuePassive.cpp
4303index a352c56..5ac3186 100644
4304--- a/modules/libcom/src/timer/timerQueuePassive.cpp
4305+++ b/modules/libcom/src/timer/timerQueuePassive.cpp
4306@@ -1,11 +1,12 @@
4307 /*************************************************************************\
4308+* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
4309+* National Laboratory
4310 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
4311 * National Laboratory.
4312 * Copyright (c) 2002 The Regents of the University of California, as
4313 * Operator of Los Alamos National Laboratory.
4314-* EPICS BASE Versions 3.13.7
4315-* and higher are distributed subject to a Software License Agreement found
4316-* in file LICENSE that is included with this distribution.
4317+* EPICS BASE is distributed subject to a Software License Agreement found
4318+* in file LICENSE that is included with this distribution.
4319 \*************************************************************************/
4320 /*
4321 * Author Jeffrey O. Hill
4322@@ -21,48 +22,51 @@
4323 // in pool.
4324 //
4325
4326-#include <stdio.h>
4327+#include <cstdio>
4328
4329 #define epicsExportSharedSymbols
4330 #include "timerPrivate.h"
4331
4332-epicsTimerQueuePassive::~epicsTimerQueuePassive () {}
4333-
4334-epicsTimerQueuePassive & epicsTimerQueuePassive::create ( epicsTimerQueueNotify &notify )
4335+epicsTimerQueuePassive &
4336+ epicsTimerQueuePassive :: create (
4337+ epicsTimerQueueNotify &notify )
4338 {
4339 return * new timerQueuePassive ( notify );
4340 }
4341
4342-timerQueuePassive::timerQueuePassive ( epicsTimerQueueNotify &notifyIn ) :
4343- queue ( notifyIn ) {}
4344+timerQueuePassive :: timerQueuePassive ( epicsTimerQueueNotify &notifyIn ) :
4345+ m_queue ( notifyIn ) {}
4346
4347 timerQueuePassive::~timerQueuePassive () {}
4348
4349 epicsTimer & timerQueuePassive::createTimer ()
4350 {
4351- return this->queue.createTimer ();
4352+ return m_queue.createTimer ();
4353 }
4354
4355-epicsTimerForC & timerQueuePassive::createTimerForC ( epicsTimerCallback pCallback, void * pArg )
4356+TimerForC & timerQueuePassive :: createTimerForC (
4357+ epicsTimerCallback pCallback, void * pArg )
4358 {
4359- return this->queue.createTimerForC ( pCallback, pArg );
4360+ return m_queue.createTimerForC ( pCallback, pArg );
4361 }
4362
4363-double timerQueuePassive::process ( const epicsTime & currentTime )
4364+double timerQueuePassive :: process (
4365+ const epicsTime & currentTime )
4366 {
4367- return this->queue.process ( currentTime );
4368+ return m_queue.process ( currentTime );
4369 }
4370
4371-void timerQueuePassive::show ( unsigned int level ) const
4372+void timerQueuePassive :: show (
4373+ unsigned int level ) const
4374 {
4375 printf ( "EPICS non-threaded timer queue at %p\n",
4376 static_cast <const void *> ( this ) );
4377 if ( level >=1u ) {
4378- this->queue.show ( level - 1u );
4379+ m_queue.show ( level - 1u );
4380 }
4381 }
4382
4383-epicsTimerQueue & timerQueuePassive::getEpicsTimerQueue ()
4384+epicsTimerQueue & timerQueuePassive :: getEpicsTimerQueue ()
4385 {
4386 return static_cast < epicsTimerQueue &> ( * this );
4387 }
4388diff --git a/modules/libcom/src/valgrind/epicsMemChk.h b/modules/libcom/src/valgrind/epicsMemChk.h
4389new file mode 100644
4390index 0000000..a190605
4391--- /dev/null
4392+++ b/modules/libcom/src/valgrind/epicsMemChk.h
4393@@ -0,0 +1,42 @@
4394+/*************************************************************************\
4395+ * Copyright (c) 2020 Triad National Security, as operator of Los Alamos
4396+ * National Laboratory
4397+ * EPICS BASE is distributed subject to a Software License Agreement found
4398+ * in file LICENSE that is included with this distribution.
4399+\*************************************************************************/
4400+
4401+#ifndef epicsMemChk_h
4402+#define epicsMemChk_h
4403+
4404+
4405+#if defined ( __cplusplus )
4406+extern "C" {
4407+#endif
4408+
4409+#ifdef MEMCHECK
4410+# include "valgrind/memcheck.h"
4411+ typedef struct epicsMemChkRedZone { volatile char m_redZone[32]; } epicsMemChkRedZone;
4412+# define VALGRIND_RED_ZONE(memberName) epicsMemChkRedZone memberName;
4413+# define VALGRIND_RED_ZONE_SIZE ( sizeof ( epicsMemChkRedZone ) )
4414+#else
4415+# define VALGRIND_RED_ZONE(memberName)
4416+# define VALGRIND_RED_ZONE_SIZE 0
4417+# define VALGRIND_MAKE_MEM_NOACCESS(_qzz_addr, _qzz_len)
4418+# define VALGRIND_MAKE_MEM_UNDEFINED(_qzz_addr, _qzz_len)
4419+# define VALGRIND_MAKE_MEM_DEFINED(_qzz_addr, _qzz_len)
4420+# define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed)
4421+# define VALGRIND_CREATE_MEMPOOL_EXT(pool, rzB, is_zeroed, flags)
4422+# define VALGRIND_DESTROY_MEMPOOL(pool)
4423+# define VALGRIND_MEMPOOL_ALLOC(pool, addr, sz)
4424+# define VALGRIND_MEMPOOL_FREE(pool, addr)
4425+# define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed)
4426+# define VALGRIND_FREELIKE_BLOCK(addr, rzB)
4427+# define VALGRIND_MEMPOOL_METAPOOL 0
4428+#endif
4429+
4430+#if defined ( __cplusplus )
4431+} // end of extern C
4432+#endif
4433+
4434+#endif // ifdef epicsMemChk_h
4435+
4436diff --git a/modules/libcom/src/valgrind/memcheck.h b/modules/libcom/src/valgrind/memcheck.h
4437new file mode 100644
4438index 0000000..bca7323
4439--- /dev/null
4440+++ b/modules/libcom/src/valgrind/memcheck.h
4441@@ -0,0 +1,303 @@
4442+
4443+/*
4444+ ----------------------------------------------------------------
4445+
4446+ Notice that the following BSD-style license applies to this one
4447+ file (memcheck.h) only. The rest of Valgrind is licensed under the
4448+ terms of the GNU General Public License, version 2, unless
4449+ otherwise indicated. See the COPYING file in the source
4450+ distribution for details.
4451+
4452+ ----------------------------------------------------------------
4453+
4454+ This file is part of MemCheck, a heavyweight Valgrind tool for
4455+ detecting memory errors.
4456+
4457+ Copyright (C) 2000-2017 Julian Seward. All rights reserved.
4458+
4459+ Redistribution and use in source and binary forms, with or without
4460+ modification, are permitted provided that the following conditions
4461+ are met:
4462+
4463+ 1. Redistributions of source code must retain the above copyright
4464+ notice, this list of conditions and the following disclaimer.
4465+
4466+ 2. The origin of this software must not be misrepresented; you must
4467+ not claim that you wrote the original software. If you use this
4468+ software in a product, an acknowledgment in the product
4469+ documentation would be appreciated but is not required.
4470+
4471+ 3. Altered source versions must be plainly marked as such, and must
4472+ not be misrepresented as being the original software.
4473+
4474+ 4. The name of the author may not be used to endorse or promote
4475+ products derived from this software without specific prior written
4476+ permission.
4477+
4478+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
4479+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
4480+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4481+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
4482+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4483+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
4484+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
4485+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
4486+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
4487+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
4488+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4489+
4490+ ----------------------------------------------------------------
4491+
4492+ Notice that the above BSD-style license applies to this one file
4493+ (memcheck.h) only. The entire rest of Valgrind is licensed under
4494+ the terms of the GNU General Public License, version 2. See the
4495+ COPYING file in the source distribution for details.
4496+
4497+ ----------------------------------------------------------------
4498+*/
4499+
4500+
4501+#ifndef __MEMCHECK_H
4502+#define __MEMCHECK_H
4503+
4504+
4505+/* This file is for inclusion into client (your!) code.
4506+
4507+ You can use these macros to manipulate and query memory permissions
4508+ inside your own programs.
4509+
4510+ See comment near the top of valgrind.h on how to use them.
4511+*/
4512+
4513+#include "valgrind.h"
4514+
4515+/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !!
4516+ This enum comprises an ABI exported by Valgrind to programs
4517+ which use client requests. DO NOT CHANGE THE ORDER OF THESE
4518+ ENTRIES, NOR DELETE ANY -- add new ones at the end. */
4519+typedef
4520+ enum {
4521+ VG_USERREQ__MAKE_MEM_NOACCESS = VG_USERREQ_TOOL_BASE('M','C'),
4522+ VG_USERREQ__MAKE_MEM_UNDEFINED,
4523+ VG_USERREQ__MAKE_MEM_DEFINED,
4524+ VG_USERREQ__DISCARD,
4525+ VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE,
4526+ VG_USERREQ__CHECK_MEM_IS_DEFINED,
4527+ VG_USERREQ__DO_LEAK_CHECK,
4528+ VG_USERREQ__COUNT_LEAKS,
4529+
4530+ VG_USERREQ__GET_VBITS,
4531+ VG_USERREQ__SET_VBITS,
4532+
4533+ VG_USERREQ__CREATE_BLOCK,
4534+
4535+ VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE,
4536+
4537+ /* Not next to VG_USERREQ__COUNT_LEAKS because it was added later. */
4538+ VG_USERREQ__COUNT_LEAK_BLOCKS,
4539+
4540+ VG_USERREQ__ENABLE_ADDR_ERROR_REPORTING_IN_RANGE,
4541+ VG_USERREQ__DISABLE_ADDR_ERROR_REPORTING_IN_RANGE,
4542+
4543+ /* This is just for memcheck's internal use - don't use it */
4544+ _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR
4545+ = VG_USERREQ_TOOL_BASE('M','C') + 256
4546+ } Vg_MemCheckClientRequest;
4547+
4548+
4549+
4550+/* Client-code macros to manipulate the state of memory. */
4551+
4552+/* Mark memory at _qzz_addr as unaddressable for _qzz_len bytes. */
4553+#define VALGRIND_MAKE_MEM_NOACCESS(_qzz_addr,_qzz_len) \
4554+ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \
4555+ VG_USERREQ__MAKE_MEM_NOACCESS, \
4556+ (_qzz_addr), (_qzz_len), 0, 0, 0)
4557+
4558+/* Similarly, mark memory at _qzz_addr as addressable but undefined
4559+ for _qzz_len bytes. */
4560+#define VALGRIND_MAKE_MEM_UNDEFINED(_qzz_addr,_qzz_len) \
4561+ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \
4562+ VG_USERREQ__MAKE_MEM_UNDEFINED, \
4563+ (_qzz_addr), (_qzz_len), 0, 0, 0)
4564+
4565+/* Similarly, mark memory at _qzz_addr as addressable and defined
4566+ for _qzz_len bytes. */
4567+#define VALGRIND_MAKE_MEM_DEFINED(_qzz_addr,_qzz_len) \
4568+ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \
4569+ VG_USERREQ__MAKE_MEM_DEFINED, \
4570+ (_qzz_addr), (_qzz_len), 0, 0, 0)
4571+
4572+/* Similar to VALGRIND_MAKE_MEM_DEFINED except that addressability is
4573+ not altered: bytes which are addressable are marked as defined,
4574+ but those which are not addressable are left unchanged. */
4575+#define VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(_qzz_addr,_qzz_len) \
4576+ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \
4577+ VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE, \
4578+ (_qzz_addr), (_qzz_len), 0, 0, 0)
4579+
4580+/* Create a block-description handle. The description is an ascii
4581+ string which is included in any messages pertaining to addresses
4582+ within the specified memory range. Has no other effect on the
4583+ properties of the memory range. */
4584+#define VALGRIND_CREATE_BLOCK(_qzz_addr,_qzz_len, _qzz_desc) \
4585+ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \
4586+ VG_USERREQ__CREATE_BLOCK, \
4587+ (_qzz_addr), (_qzz_len), (_qzz_desc), \
4588+ 0, 0)
4589+
4590+/* Discard a block-description-handle. Returns 1 for an
4591+ invalid handle, 0 for a valid handle. */
4592+#define VALGRIND_DISCARD(_qzz_blkindex) \
4593+ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \
4594+ VG_USERREQ__DISCARD, \
4595+ 0, (_qzz_blkindex), 0, 0, 0)
4596+
4597+
4598+/* Client-code macros to check the state of memory. */
4599+
4600+/* Check that memory at _qzz_addr is addressable for _qzz_len bytes.
4601+ If suitable addressibility is not established, Valgrind prints an
4602+ error message and returns the address of the first offending byte.
4603+ Otherwise it returns zero. */
4604+#define VALGRIND_CHECK_MEM_IS_ADDRESSABLE(_qzz_addr,_qzz_len) \
4605+ VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
4606+ VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE, \
4607+ (_qzz_addr), (_qzz_len), 0, 0, 0)
4608+
4609+/* Check that memory at _qzz_addr is addressable and defined for
4610+ _qzz_len bytes. If suitable addressibility and definedness are not
4611+ established, Valgrind prints an error message and returns the
4612+ address of the first offending byte. Otherwise it returns zero. */
4613+#define VALGRIND_CHECK_MEM_IS_DEFINED(_qzz_addr,_qzz_len) \
4614+ VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
4615+ VG_USERREQ__CHECK_MEM_IS_DEFINED, \
4616+ (_qzz_addr), (_qzz_len), 0, 0, 0)
4617+
4618+/* Use this macro to force the definedness and addressibility of an
4619+ lvalue to be checked. If suitable addressibility and definedness
4620+ are not established, Valgrind prints an error message and returns
4621+ the address of the first offending byte. Otherwise it returns
4622+ zero. */
4623+#define VALGRIND_CHECK_VALUE_IS_DEFINED(__lvalue) \
4624+ VALGRIND_CHECK_MEM_IS_DEFINED( \
4625+ (volatile unsigned char *)&(__lvalue), \
4626+ (unsigned long)(sizeof (__lvalue)))
4627+
4628+
4629+/* Do a full memory leak check (like --leak-check=full) mid-execution. */
4630+#define VALGRIND_DO_LEAK_CHECK \
4631+ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \
4632+ 0, 0, 0, 0, 0)
4633+
4634+/* Same as VALGRIND_DO_LEAK_CHECK but only showing the entries for
4635+ which there was an increase in leaked bytes or leaked nr of blocks
4636+ since the previous leak search. */
4637+#define VALGRIND_DO_ADDED_LEAK_CHECK \
4638+ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \
4639+ 0, 1, 0, 0, 0)
4640+
4641+/* Same as VALGRIND_DO_ADDED_LEAK_CHECK but showing entries with
4642+ increased or decreased leaked bytes/blocks since previous leak
4643+ search. */
4644+#define VALGRIND_DO_CHANGED_LEAK_CHECK \
4645+ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \
4646+ 0, 2, 0, 0, 0)
4647+
4648+/* Do a summary memory leak check (like --leak-check=summary) mid-execution. */
4649+#define VALGRIND_DO_QUICK_LEAK_CHECK \
4650+ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \
4651+ 1, 0, 0, 0, 0)
4652+
4653+/* Return number of leaked, dubious, reachable and suppressed bytes found by
4654+ all previous leak checks. They must be lvalues. */
4655+#define VALGRIND_COUNT_LEAKS(leaked, dubious, reachable, suppressed) \
4656+ /* For safety on 64-bit platforms we assign the results to private
4657+ unsigned long variables, then assign these to the lvalues the user
4658+ specified, which works no matter what type 'leaked', 'dubious', etc
4659+ are. We also initialise '_qzz_leaked', etc because
4660+ VG_USERREQ__COUNT_LEAKS doesn't mark the values returned as
4661+ defined. */ \
4662+ { \
4663+ unsigned long _qzz_leaked = 0, _qzz_dubious = 0; \
4664+ unsigned long _qzz_reachable = 0, _qzz_suppressed = 0; \
4665+ VALGRIND_DO_CLIENT_REQUEST_STMT( \
4666+ VG_USERREQ__COUNT_LEAKS, \
4667+ &_qzz_leaked, &_qzz_dubious, \
4668+ &_qzz_reachable, &_qzz_suppressed, 0); \
4669+ leaked = _qzz_leaked; \
4670+ dubious = _qzz_dubious; \
4671+ reachable = _qzz_reachable; \
4672+ suppressed = _qzz_suppressed; \
4673+ }
4674+
4675+/* Return number of leaked, dubious, reachable and suppressed bytes found by
4676+ all previous leak checks. They must be lvalues. */
4677+#define VALGRIND_COUNT_LEAK_BLOCKS(leaked, dubious, reachable, suppressed) \
4678+ /* For safety on 64-bit platforms we assign the results to private
4679+ unsigned long variables, then assign these to the lvalues the user
4680+ specified, which works no matter what type 'leaked', 'dubious', etc
4681+ are. We also initialise '_qzz_leaked', etc because
4682+ VG_USERREQ__COUNT_LEAKS doesn't mark the values returned as
4683+ defined. */ \
4684+ { \
4685+ unsigned long _qzz_leaked = 0, _qzz_dubious = 0; \
4686+ unsigned long _qzz_reachable = 0, _qzz_suppressed = 0; \
4687+ VALGRIND_DO_CLIENT_REQUEST_STMT( \
4688+ VG_USERREQ__COUNT_LEAK_BLOCKS, \
4689+ &_qzz_leaked, &_qzz_dubious, \
4690+ &_qzz_reachable, &_qzz_suppressed, 0); \
4691+ leaked = _qzz_leaked; \
4692+ dubious = _qzz_dubious; \
4693+ reachable = _qzz_reachable; \
4694+ suppressed = _qzz_suppressed; \
4695+ }
4696+
4697+
4698+/* Get the validity data for addresses [zza..zza+zznbytes-1] and copy it
4699+ into the provided zzvbits array. Return values:
4700+ 0 if not running on valgrind
4701+ 1 success
4702+ 2 [previously indicated unaligned arrays; these are now allowed]
4703+ 3 if any parts of zzsrc/zzvbits are not addressable.
4704+ The metadata is not copied in cases 0, 2 or 3 so it should be
4705+ impossible to segfault your system by using this call.
4706+*/
4707+#define VALGRIND_GET_VBITS(zza,zzvbits,zznbytes) \
4708+ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
4709+ VG_USERREQ__GET_VBITS, \
4710+ (const char*)(zza), \
4711+ (char*)(zzvbits), \
4712+ (zznbytes), 0, 0)
4713+
4714+/* Set the validity data for addresses [zza..zza+zznbytes-1], copying it
4715+ from the provided zzvbits array. Return values:
4716+ 0 if not running on valgrind
4717+ 1 success
4718+ 2 [previously indicated unaligned arrays; these are now allowed]
4719+ 3 if any parts of zza/zzvbits are not addressable.
4720+ The metadata is not copied in cases 0, 2 or 3 so it should be
4721+ impossible to segfault your system by using this call.
4722+*/
4723+#define VALGRIND_SET_VBITS(zza,zzvbits,zznbytes) \
4724+ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
4725+ VG_USERREQ__SET_VBITS, \
4726+ (const char*)(zza), \
4727+ (const char*)(zzvbits), \
4728+ (zznbytes), 0, 0 )
4729+
4730+/* Disable and re-enable reporting of addressing errors in the
4731+ specified address range. */
4732+#define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(_qzz_addr,_qzz_len) \
4733+ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \
4734+ VG_USERREQ__DISABLE_ADDR_ERROR_REPORTING_IN_RANGE, \
4735+ (_qzz_addr), (_qzz_len), 0, 0, 0)
4736+
4737+#define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(_qzz_addr,_qzz_len) \
4738+ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \
4739+ VG_USERREQ__ENABLE_ADDR_ERROR_REPORTING_IN_RANGE, \
4740+ (_qzz_addr), (_qzz_len), 0, 0, 0)
4741+
4742+#endif
4743+
4744+
4745diff --git a/modules/libcom/src/valgrind/valgrind.h b/modules/libcom/src/valgrind/valgrind.h
4746old mode 100755
4747new mode 100644
4748index c503172..5b26c98
4749--- a/modules/libcom/src/valgrind/valgrind.h
4750+++ b/modules/libcom/src/valgrind/valgrind.h
4751@@ -12,7 +12,7 @@
4752 This file is part of Valgrind, a dynamic binary instrumentation
4753 framework.
4754
4755- Copyright (C) 2000-2013 Julian Seward. All rights reserved.
4756+ Copyright (C) 2000-2017 Julian Seward. All rights reserved.
4757
4758 Redistribution and use in source and binary forms, with or without
4759 modification, are permitted provided that the following conditions
4760@@ -89,10 +89,14 @@
4761 || (__VALGRIND_MAJOR__ == 3 && __VALGRIND_MINOR__ >= 6))
4762 */
4763 #define __VALGRIND_MAJOR__ 3
4764-#define __VALGRIND_MINOR__ 10
4765+#define __VALGRIND_MINOR__ 16
4766
4767
4768-#include <stdarg.h>
4769+#if defined ( __cplusplus )
4770+# include <cstdarg>
4771+#else
4772+# include <stdarg.h>
4773+#endif
4774
4775 /* Nb: this file might be included in a file compiled with -ansi. So
4776 we can't use C++ style "//" comments nor the "asm" keyword (instead
4777@@ -122,6 +126,8 @@
4778 #undef PLAT_s390x_linux
4779 #undef PLAT_mips32_linux
4780 #undef PLAT_mips64_linux
4781+#undef PLAT_x86_solaris
4782+#undef PLAT_amd64_solaris
4783
4784
4785 #if defined(__APPLE__) && defined(__i386__)
4786@@ -130,14 +136,14 @@
4787 # define PLAT_amd64_darwin 1
4788 #elif (defined(__MINGW32__) && !defined(__MINGW64__)) \
4789 || defined(__CYGWIN32__) \
4790- || (defined(_WIN32) && defined(_M_IX86) && defined(__GNUC__))
4791+ || (defined(_WIN32) && defined(_M_IX86))
4792 # define PLAT_x86_win32 1
4793 #elif defined(__MINGW64__) \
4794- || (defined(_WIN64) && defined(_M_X64) && defined(__GNUC__))
4795+ || (defined(_WIN64) && defined(_M_X64))
4796 # define PLAT_amd64_win64 1
4797 #elif defined(__linux__) && defined(__i386__)
4798 # define PLAT_x86_linux 1
4799-#elif defined(__linux__) && defined(__x86_64__)
4800+#elif defined(__linux__) && defined(__x86_64__) && !defined(__ILP32__)
4801 # define PLAT_amd64_linux 1
4802 #elif defined(__linux__) && defined(__powerpc__) && !defined(__powerpc64__)
4803 # define PLAT_ppc32_linux 1
4804@@ -157,6 +163,10 @@
4805 # define PLAT_mips64_linux 1
4806 #elif defined(__linux__) && defined(__mips__) && (__mips!=64)
4807 # define PLAT_mips32_linux 1
4808+#elif defined(__sun) && defined(__i386__)
4809+# define PLAT_x86_solaris 1
4810+#elif defined(__sun) && defined(__x86_64__)
4811+# define PLAT_amd64_solaris 1
4812 #else
4813 /* If we're not compiling for our target platform, don't generate
4814 any inline asms. */
4815@@ -244,10 +254,11 @@
4816 inline asm stuff to be useful.
4817 */
4818
4819-/* ------------------------- x86-{linux,darwin} ---------------- */
4820+/* ----------------- x86-{linux,darwin,solaris} ---------------- */
4821
4822 #if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) \
4823- || (defined(PLAT_x86_win32) && defined(__GNUC__))
4824+ || (defined(PLAT_x86_win32) && defined(__GNUC__)) \
4825+ || defined(PLAT_x86_solaris)
4826
4827 typedef
4828 struct {
4829@@ -307,7 +318,8 @@ typedef
4830 ); \
4831 } while (0)
4832
4833-#endif /* PLAT_x86_linux || PLAT_x86_darwin || (PLAT_x86_win32 && __GNUC__) */
4834+#endif /* PLAT_x86_linux || PLAT_x86_darwin || (PLAT_x86_win32 && __GNUC__)
4835+ || PLAT_x86_solaris */
4836
4837 /* ------------------------- x86-Win32 ------------------------- */
4838
4839@@ -382,14 +394,15 @@ valgrind_do_client_request_expr(uintptr_t _zzq_default, uintptr_t _zzq_request,
4840
4841 #endif /* PLAT_x86_win32 */
4842
4843-/* ------------------------ amd64-{linux,darwin} --------------- */
4844+/* ----------------- amd64-{linux,darwin,solaris} --------------- */
4845
4846 #if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) \
4847+ || defined(PLAT_amd64_solaris) \
4848 || (defined(PLAT_amd64_win64) && defined(__GNUC__))
4849
4850 typedef
4851 struct {
4852- unsigned long long int nraddr; /* where's the code? */
4853+ unsigned long int nraddr; /* where's the code? */
4854 }
4855 OrigFn;
4856
4857@@ -401,14 +414,14 @@ typedef
4858 _zzq_default, _zzq_request, \
4859 _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
4860 __extension__ \
4861- ({ volatile unsigned long long int _zzq_args[6]; \
4862- volatile unsigned long long int _zzq_result; \
4863- _zzq_args[0] = (unsigned long long int)(_zzq_request); \
4864- _zzq_args[1] = (unsigned long long int)(_zzq_arg1); \
4865- _zzq_args[2] = (unsigned long long int)(_zzq_arg2); \
4866- _zzq_args[3] = (unsigned long long int)(_zzq_arg3); \
4867- _zzq_args[4] = (unsigned long long int)(_zzq_arg4); \
4868- _zzq_args[5] = (unsigned long long int)(_zzq_arg5); \
4869+ ({ volatile unsigned long int _zzq_args[6]; \
4870+ volatile unsigned long int _zzq_result; \
4871+ _zzq_args[0] = (unsigned long int)(_zzq_request); \
4872+ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \
4873+ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \
4874+ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \
4875+ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \
4876+ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \
4877 __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
4878 /* %RDX = client_request ( %RAX ) */ \
4879 "xchgq %%rbx,%%rbx" \
4880@@ -421,7 +434,7 @@ typedef
4881
4882 #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
4883 { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
4884- volatile unsigned long long int __addr; \
4885+ volatile unsigned long int __addr; \
4886 __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
4887 /* %RAX = guest_NRADDR */ \
4888 "xchgq %%rcx,%%rcx" \
4889@@ -445,7 +458,7 @@ typedef
4890 ); \
4891 } while (0)
4892
4893-#endif /* PLAT_amd64_linux || PLAT_amd64_darwin */
4894+#endif /* PLAT_amd64_linux || PLAT_amd64_darwin || PLAT_amd64_solaris */
4895
4896 /* ------------------------- amd64-Win64 ------------------------- */
4897
4898@@ -530,8 +543,8 @@ typedef
4899
4900 typedef
4901 struct {
4902- unsigned long long int nraddr; /* where's the code? */
4903- unsigned long long int r2; /* what tocptr do we need? */
4904+ unsigned long int nraddr; /* where's the code? */
4905+ unsigned long int r2; /* what tocptr do we need? */
4906 }
4907 OrigFn;
4908
4909@@ -544,15 +557,15 @@ typedef
4910 _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
4911 \
4912 __extension__ \
4913- ({ unsigned long long int _zzq_args[6]; \
4914- unsigned long long int _zzq_result; \
4915- unsigned long long int* _zzq_ptr; \
4916- _zzq_args[0] = (unsigned long long int)(_zzq_request); \
4917- _zzq_args[1] = (unsigned long long int)(_zzq_arg1); \
4918- _zzq_args[2] = (unsigned long long int)(_zzq_arg2); \
4919- _zzq_args[3] = (unsigned long long int)(_zzq_arg3); \
4920- _zzq_args[4] = (unsigned long long int)(_zzq_arg4); \
4921- _zzq_args[5] = (unsigned long long int)(_zzq_arg5); \
4922+ ({ unsigned long int _zzq_args[6]; \
4923+ unsigned long int _zzq_result; \
4924+ unsigned long int* _zzq_ptr; \
4925+ _zzq_args[0] = (unsigned long int)(_zzq_request); \
4926+ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \
4927+ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \
4928+ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \
4929+ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \
4930+ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \
4931 _zzq_ptr = _zzq_args; \
4932 __asm__ volatile("mr 3,%1\n\t" /*default*/ \
4933 "mr 4,%2\n\t" /*ptr*/ \
4934@@ -568,7 +581,7 @@ typedef
4935
4936 #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
4937 { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
4938- unsigned long long int __addr; \
4939+ unsigned long int __addr; \
4940 __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
4941 /* %R3 = guest_NRADDR */ \
4942 "or 2,2,2\n\t" \
4943@@ -607,8 +620,8 @@ typedef
4944
4945 typedef
4946 struct {
4947- unsigned long long int nraddr; /* where's the code? */
4948- unsigned long long int r2; /* what tocptr do we need? */
4949+ unsigned long int nraddr; /* where's the code? */
4950+ unsigned long int r2; /* what tocptr do we need? */
4951 }
4952 OrigFn;
4953
4954@@ -621,15 +634,15 @@ typedef
4955 _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
4956 \
4957 __extension__ \
4958- ({ unsigned long long int _zzq_args[6]; \
4959- unsigned long long int _zzq_result; \
4960- unsigned long long int* _zzq_ptr; \
4961- _zzq_args[0] = (unsigned long long int)(_zzq_request); \
4962- _zzq_args[1] = (unsigned long long int)(_zzq_arg1); \
4963- _zzq_args[2] = (unsigned long long int)(_zzq_arg2); \
4964- _zzq_args[3] = (unsigned long long int)(_zzq_arg3); \
4965- _zzq_args[4] = (unsigned long long int)(_zzq_arg4); \
4966- _zzq_args[5] = (unsigned long long int)(_zzq_arg5); \
4967+ ({ unsigned long int _zzq_args[6]; \
4968+ unsigned long int _zzq_result; \
4969+ unsigned long int* _zzq_ptr; \
4970+ _zzq_args[0] = (unsigned long int)(_zzq_request); \
4971+ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \
4972+ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \
4973+ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \
4974+ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \
4975+ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \
4976 _zzq_ptr = _zzq_args; \
4977 __asm__ volatile("mr 3,%1\n\t" /*default*/ \
4978 "mr 4,%2\n\t" /*ptr*/ \
4979@@ -645,7 +658,7 @@ typedef
4980
4981 #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
4982 { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
4983- unsigned long long int __addr; \
4984+ unsigned long int __addr; \
4985 __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
4986 /* %R3 = guest_NRADDR */ \
4987 "or 2,2,2\n\t" \
4988@@ -754,7 +767,7 @@ typedef
4989
4990 typedef
4991 struct {
4992- unsigned long long int nraddr; /* where's the code? */
4993+ unsigned long int nraddr; /* where's the code? */
4994 }
4995 OrigFn;
4996
4997@@ -767,14 +780,14 @@ typedef
4998 _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
4999 \
5000 __extension__ \
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches