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
diff --git a/.ci b/.ci
0deleted file mode 1600000deleted file mode 160000
index e91a588..0000000
--- a/.ci
+++ /dev/null
@@ -1 +0,0 @@
1Subproject commit e91a5883704e9fa57792953436eb7020baf37063
diff --git a/configure/CONFIG.gnuCommon b/configure/CONFIG.gnuCommon
index c4fd8ce..96eab65 100644
--- a/configure/CONFIG.gnuCommon
+++ b/configure/CONFIG.gnuCommon
@@ -35,7 +35,7 @@ CODE_CFLAGS += $(ASAN_FLAGS_$(ENABLE_ASAN))
35WARN_CFLAGS_YES = -Wall35WARN_CFLAGS_YES = -Wall
36WARN_CFLAGS_NO = -w36WARN_CFLAGS_NO = -w
37OPT_CFLAGS_YES = -O337OPT_CFLAGS_YES = -O3
38OPT_CFLAGS_NO = -g38OPT_CFLAGS_NO = -g -DMEMCHECK
3939
40PROF_CXXFLAGS_YES = -p40PROF_CXXFLAGS_YES = -p
41GPROF_CXXFLAGS_YES = -pg41GPROF_CXXFLAGS_YES = -pg
@@ -44,7 +44,7 @@ CODE_CXXFLAGS += $(ASAN_FLAGS_$(ENABLE_ASAN))
44WARN_CXXFLAGS_YES = -Wall44WARN_CXXFLAGS_YES = -Wall
45WARN_CXXFLAGS_NO = -w45WARN_CXXFLAGS_NO = -w
46OPT_CXXFLAGS_YES = -O346OPT_CXXFLAGS_YES = -O3
47OPT_CXXFLAGS_NO = -g47OPT_CXXFLAGS_NO = -g -DMEMCHECK
4848
49CODE_LDFLAGS = $(PROF_CXXFLAGS_$(PROFILE)) $(GPROF_CXXFLAGS_$(GPROF))49CODE_LDFLAGS = $(PROF_CXXFLAGS_$(PROFILE)) $(GPROF_CXXFLAGS_$(GPROF))
50CODE_LDFLAGS += $(ASAN_LDFLAGS_$(ENABLE_ASAN))50CODE_LDFLAGS += $(ASAN_LDFLAGS_$(ENABLE_ASAN))
diff --git a/modules/libcom/src/Makefile b/modules/libcom/src/Makefile
index 57533ba..c966e2c 100644
--- a/modules/libcom/src/Makefile
+++ b/modules/libcom/src/Makefile
@@ -15,6 +15,8 @@ include $(TOP)/configure/CONFIG
15#USR_CFLAGS += -DNVALGRIND15#USR_CFLAGS += -DNVALGRIND
1616
17INC += valgrind/valgrind.h17INC += valgrind/valgrind.h
18INC += valgrind/memcheck.h
19INC += valgrind/epicsMemChk.h
1820
19INC += libComVersion.h21INC += libComVersion.h
20INC += libComVersionNum.h22INC += libComVersionNum.h
diff --git a/modules/libcom/src/misc/AllocatorArena.h b/modules/libcom/src/misc/AllocatorArena.h
21new file mode 10064423new file mode 100644
index 0000000..33a46c5
--- /dev/null
+++ b/modules/libcom/src/misc/AllocatorArena.h
@@ -0,0 +1,944 @@
1
2/*************************************************************************\
3* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
4* National Laboratory
5* EPICS BASE is distributed subject to a Software License Agreement found
6* in file LICENSE that is included with this distribution.
7\*************************************************************************/
8
9/*
10 * Author Jeffrey O. Hill
11 */
12
13//
14// Arena Allocator
15//
16// A thread private allocator for N of type T allocated in-mass, and
17// deallocated in-mass. The individual calls to allocate run very
18// efficiently because they simply return a pointer to preallocated
19// space for a type T, and advance the index identifying the space for
20// the next allocation, using thread private storage sans mutex
21// protection overhead. The in-bulk deallocation is postponed until
22// the last active T, residing within a bulk allocated block, is
23// deallocated.
24//
25// The allocator falls back to ordinary global new/delete if the user
26// requests more than one element for allocation using the vector
27// form of new.
28//
29// This facility is fully safe for use in a multi-threaded environment.
30// A thread private variable, and a thread private cleanup, are used to
31// maintain a thread private context so that the overhead associated
32// with a mutual exclusion locking can be avoided.
33//
34// Be aware that the storage overhead for any type T is sizeof ( T ) plus
35// sizeof ( void * ), a substantial consideration probably only if small
36// objects are stored, and storage efficency is more important than
37// performance considerations. Furthermore, storage overhead increases
38// for C++ compilers predating C++ 11.
39//
40// In this code a contiguous bulk block of storage for N of type T
41// is template type Rack<S,A,N> where S is the size of T, and A is the
42// required alignment. The thread-private allocaton occurs when peeling
43// off storage for an individual T from the thread's private Rack. When
44// the thread's private Rack is exausted, then a new Rack is allocated
45// from the specified Rack allocator type. Currently two global Rack
46// allocator implementations are provided. One that uses ordinary global
47// new/delete, and one that uses a mutex protected global free list
48// (the default) designated by rack allocator policies rap_pool and
49// rap_freeList respectively.
50//
51// Define ALLOCATOR_ARENA_MEMORY_ACCESS_INSPECTION_ACTIVE in order to
52// temporarily bypass bulk allocation and return to ordinary global
53// operator new and delete, so that memory access inspectors such as
54// purify or valgrind might be more effective. Furthermore, when the
55// allocator _is_ active, and it is a debug build, specialized
56// valgrind macros document with valgrind memory regions owned by this
57// allocater for which ownership has not yet passed to an end application
58// so that they do not appear as undesireable noise in valgrind leak
59// reports.
60//
61
62#ifndef epicsAllocatorArena_h
63#define epicsAllocatorArena_h
64
65// see comment above
66#if 0
67#define ALLOCATOR_ARENA_MEMORY_ACCESS_INSPECTION_ACTIVE
68#endif
69
70#if __cplusplus >= 201103L
71# include <cstdint>
72#endif
73
74#include <new>
75#include <cstdlib>
76#include <string>
77#include <cstdio>
78#include <typeinfo>
79
80#include "epicsAtomic.h"
81#include "epicsMutex.h"
82#include "epicsThread.h"
83#include "epicsStaticInstance.h"
84#include "compilerDependencies.h"
85#include "valgrind/epicsMemChk.h"
86#include "shareLib.h"
87
88
89#if __cplusplus >= 201103L
90# if defined ( __GNUC__ )
91# define GCC_VERSION_AA \
92 (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
93 // perhaps the nios2 cross compiler doesnt properly implement
94 // alignment even at gcc 4.8, based on experimental evidence
95# define ALIGNAS_CMPLR_OK ( GCC_VERSION_AA >= 50000 )
96# else
97# define ALIGNAS_CMPLR_OK 1
98# endif
99#else
100# define ALIGNAS_CMPLR_OK 0
101#endif
102
103#ifndef SIZE_MAX
104# define SIZE_MAX ( static_cast < size_t > ( -1L ) )
105#endif
106
107namespace epics {
108namespace _impl {
109
110using std :: size_t;
111using std :: type_info;
112using std :: ptrdiff_t;
113using std :: allocator;
114using std :: bad_alloc;
115
116//
117// S - the allocation size (the size of T)
118// A - the required alignment
119// N - the block size for pool allocation
120// (pool allocation size will be approximately S * N)
121//
122template < size_t S, size_t A, size_t N = 256 > class Rack;
123
124//
125// R - the rack type
126// P - the allocation policy type
127// TRACE - if true, print a message each time that a new racks allocated
128// counter power of two is exceeded for a particular allocation type
129//
130enum RackAllocPolicy { rap_pool, rap_freeList };
131template < typename R, RackAllocPolicy P, bool TRACE > class RackAlloc;
132
133//
134// T - the allocation type
135// G - the discriminator for the thread private variable group
136// (proper scaling requires an independent thread private variable
137// group for each library) any type is allowed and appropriate for
138// identifying an independent thread private context
139// N - the block size for pool allocation
140// A - the rack allocator
141//
142// on old compilers prior to ALIGNAS_CMPLR_OK all blocks are aligned
143// for worst case alignment requirements
144//
145template < typename T, typename G, size_t N = 256,
146 RackAllocPolicy P = rap_freeList, bool TRACE = false >
147class AllocatorArena {
148public:
149 typedef T value_type;
150 typedef value_type * pointer;
151 typedef const value_type * const_pointer;
152 typedef value_type & reference;
153 typedef const value_type & const_reference;
154 typedef size_t size_type;
155 typedef ptrdiff_t difference_type;
156 typedef typename allocator < void > :: const_pointer void_const_pointer;
157 typedef typename allocator < void > :: pointer void_pointer;
158
159 template < typename T0 >
160 struct rebind {
161 typedef AllocatorArena < T0, G, N, P, TRACE > other;
162 };
163
164 AllocatorArena ();
165
166 template < typename Y >
167 AllocatorArena ( const Y & );
168
169 // address
170 static pointer address ( reference r );
171 static const_pointer address ( const_reference r );
172
173 // memory allocation
174 static pointer allocate ( size_type nAlloc,
175 void_const_pointer pNearbyHint = 0 );
176 static void deallocate ( const pointer p, size_type nAlloc );
177
178 // helpers, for creating class specific operator new and delete
179 static void * allocateOctets ( size_type size );
180 static void * allocateOctets ( size_type size, const std :: nothrow_t & );
181 static void deallocateOctets ( void * p, size_type size );
182
183 // remove the allocator's thread private reference to any partially
184 // consumed block so that it can be released back into system pool
185 // (this action is automated at thread exit)
186 static void cleanup ();
187
188 // size
189 static size_type max_size ();
190
191 // construction / destruction of target
192#if __cplusplus >= 201103L
193 template < typename T0, typename ... Args >
194 static void construct ( T0 *, Args && ... ); // depricated in c++ 17
195#else
196 template < typename T0, typename A0 >
197 static void construct ( T0 *, A0 );
198 template < typename T0, typename A0, typename A1 >
199 static void construct ( T0 *, A0, A1 );
200 template < typename T0, typename A0, typename A1, typename A2 >
201 static void construct ( T0 *, A0, A1, A2 );
202 template < typename T0, typename A0, typename A1, typename A2,
203 typename A3 >
204 static void construct ( T0 *, A0, A1, A2, A3 );
205 template < typename T0, typename A0, typename A1, typename A2,
206 typename A3, typename A4 >
207 static void construct ( T0 *, A0, A1, A2, A3, A4 );
208#endif
209 template < class U >
210 static void destroy ( U * ); // depricated in c++ 17
211
212 bool operator == ( AllocatorArena const & );
213 bool operator != ( AllocatorArena const & );
214
215 static size_t rackCount ();
216 static size_t byteCount ();
217private:
218#if ALIGNAS_CMPLR_OK
219 typedef Rack < sizeof ( T ), alignof ( T ), N > M_Rack;
220#else
221 /* worst case alignment is used */
222 typedef Rack < sizeof ( T ), 0u, N > M_Rack;
223#endif
224 typedef RackAlloc < M_Rack, P, TRACE > M_RackAlloc;
225 static pointer m_threadPrivateAlloc ();
226 static void m_rackCleanup ( void * );
227}; // end of class AllocatorArena
228
229class epicsShareClass ThreadPrivateIdBadAlloc : public bad_alloc
230{
231 const char * what () const throw ();
232};
233
234class epicsShareClass AtThreadExitBadAlloc : public bad_alloc
235{
236 const char * what () const throw ();
237};
238
239#if __cplusplus >= 201103L
240 typedef std :: uint8_t Octet;
241#else
242 typedef unsigned char Octet;
243#endif
244
245typedef Octet * POctet;
246
247// align for all possible types, similar to malloc
248union MaxAlign {
249 struct SomeStruct {};
250 long double m_ld;
251 long long m_ll;
252 long double * m_pd;
253 SomeStruct * m_pss;
254 void (* m_pf) ();
255 long double SomeStruct :: * m_pmd;
256 void ( SomeStruct :: * m_pmf ) ();
257 /*
258 * eye of newt ...
259 */
260};
261
262template < size_t S, size_t A, size_t N >
263class Rack {
264public:
265 typedef size_t size_type;
266 typedef ptrdiff_t difference_type;
267
268 Rack ();
269 ~Rack ();
270 bool empty () const;
271 void * alloc ();
272 size_t removeReference ();
273 void addReference ();
274
275 static const size_t number;
276 static const size_t alignment;
277 static Rack * dealloc ( void * );
278private:
279 struct M_Wrapper {
280 VALGRIND_RED_ZONE ( m_redZoneBefore )
281# if ALIGNAS_CMPLR_OK
282 alignas ( A ) Octet m_bufForObj [ S ];
283# else
284 union {
285 Octet m_bufForObj [ S ];
286 MaxAlign m_maxAlign;
287 };
288# endif
289 VALGRIND_RED_ZONE ( m_redZoneAfter )
290 void * m_pRack;
291 };
292 typedef M_Wrapper * PWrapper;
293 M_Wrapper m_wrapped[N];
294 size_t m_nAlloc;
295 size_t m_refCount;
296#if __cplusplus >= 201103L
297 Rack ( const Rack & ) = delete;
298 Rack & operator = ( const Rack & ) = delete;
299#endif
300};
301
302struct RackManager {
303 void * m_pRack;
304 void ( *m_pThreadExitFunc )( void * pRack );
305};
306
307class epicsShareClass AllocCtxCom {
308public:
309 AllocCtxCom ();
310 RackManager * getRackHandlerPtr ( size_t idx );
311 void cleanup ( size_t idx );
312 size_t allocIdx ();
313private:
314 epicsThreadPrivateId m_threadPrivateId;
315 size_t m_curIdx;
316 static void m_threadExitFunc ( void * const pPriv );
317 static const size_t m_initialCapacity;
318};
319
320//
321// G - the discriminator for the thread private variable group
322// (proper scaling requires an indepent thread private variable
323// group for each library) any type is allowed and appropriate
324// for identifying an independent thread private context
325//
326template < typename G > class AllocCtxGrouped : public AllocCtxCom {};
327
328//
329// G - the discriminator for the thread private variable group
330// (proper scaling requires an indepent thread private variable
331// group for each library) any type is allowed and appropriate
332// for identifying an independent thread private context
333//
334template < typename G >
335class AllocCtx {
336public:
337 AllocCtx ();
338 void cleanup ();
339 RackManager * getRackHandlerPtr ();
340private:
341 size_t m_idx;
342};
343
344//
345// T - the allocation type
346// G - the discriminator for the thread private variable group
347// (proper scaling requires an indepent thread private variable
348// group for each library) any type is allowed and appropriate
349// for identifying an independent thread private context
350//
351template < typename T, typename G >
352class AllocCtxTyped : public AllocCtx < G > {};
353
354template < bool TRACE >
355class epicsShareClass AllocCounter;
356
357template <>
358class epicsShareClass AllocCounter < true > {
359public:
360 AllocCounter ();
361 void increment ( size_t nBytesThisTime, const type_info & );
362 void decrement ( size_t nBytesThisTime );
363 size_t rackCount () const { return m_nRacks; }
364 size_t byteCount () const { return m_bytes; }
365 void show ( const type_info & ) const;
366private:
367 size_t m_nRacksTrace;
368 size_t m_nRacks;
369 size_t m_bytes;
370};
371
372template <>
373class epicsShareClass AllocCounter < false > {
374public:
375 void increment ( size_t nBytesThisTime,
376 const type_info & ) {}
377 void decrement ( size_t nBytesThisTime ) {}
378 size_t rackCount () const { return 0u; }
379 size_t byteCount () const { return 0u; }
380 void show ( const char * pContext ) const {}
381};
382
383template < typename R, bool TRACE >
384class RackAlloc < R, rap_pool, TRACE > {
385public:
386 typedef R Rack;
387 template < typename R0 >
388 struct rebind {
389 typedef RackAlloc < R0, rap_pool, TRACE > other;
390 };
391 static R * create ( const type_info & ti );
392 static void destroy ( R * p );
393 static size_t rackCount ();
394 static size_t byteCount ();
395private:
396 static AllocCounter < TRACE > m_counter;
397};
398
399template < typename R, bool TRACE >
400class RackAlloc < R, rap_freeList, TRACE > {
401public:
402 template < typename R0 >
403 struct rebind {
404 typedef RackAlloc < R0, rap_freeList, TRACE > other;
405 };
406 typedef R Rack;
407 RackAlloc ();
408 ~RackAlloc ();
409 R * create ( const type_info & );
410 void destroy ( R * p );
411 size_t rackCount () const;
412 size_t byteCount () const;
413private:
414 typedef epicsMutex Mutex;
415 typedef epicsGuard < epicsMutex > Guard;
416 struct M_Alias {
417 VALGRIND_RED_ZONE ( m_redZoneBefore )
418 union {
419# if ALIGNAS_CMPLR_OK
420 alignas ( R :: alignment )
421 Octet m_rackBuf [ sizeof ( R ) ];
422# else
423 union {
424 Octet m_rackBuf [ sizeof ( R ) ];
425 MaxAlign m_maxAlign;
426 };
427# endif
428 struct M_Alias * m_pNext;
429 };
430 VALGRIND_RED_ZONE ( m_redZoneAfter )
431 };
432 M_Alias * m_pAlias;
433 Mutex m_mutex;
434 AllocCounter < TRACE > m_counter;
435 RackAlloc ( const RackAlloc & ) epicsDeleteMethod;
436 RackAlloc operator = ( const RackAlloc & ) epicsDeleteMethod;
437};
438
439template < typename G >
440inline AllocCtx < G > :: AllocCtx () :
441 m_idx ( staticInstance < AllocCtxGrouped < G > > ().allocIdx () )
442{
443}
444
445template < typename G >
446inline RackManager * AllocCtx < G > :: getRackHandlerPtr ()
447{
448 AllocCtxCom & grp = staticInstance < AllocCtxGrouped < G > > ();
449 return grp.getRackHandlerPtr ( m_idx );
450}
451
452template < typename G >
453void AllocCtx < G > :: cleanup ()
454{
455 AllocCtxCom & grp = staticInstance < AllocCtxGrouped < G > > ();
456 grp.cleanup ( m_idx );
457}
458
459template < typename R, bool TRACE >
460inline R * RackAlloc < R, rap_pool, TRACE > :: create ( const type_info & ti )
461{
462 R * const p = new R ();
463 m_counter.increment ( sizeof ( R ), ti );
464 return p;
465}
466
467template < typename R, bool TRACE >
468inline void RackAlloc < R, rap_pool, TRACE > :: destroy ( R * p )
469{
470 m_counter.decrement ( sizeof ( R ) );
471 delete p;
472}
473
474template < typename R, bool TRACE >
475inline size_t RackAlloc < R, rap_pool, TRACE > :: rackCount ()
476{
477 return m_counter.rackCount ();
478}
479
480template < typename R, bool TRACE >
481inline size_t RackAlloc < R, rap_pool, TRACE > :: byteCount ()
482{
483 return m_counter.byteCount ();
484}
485
486template < typename R, bool TRACE >
487inline RackAlloc < R, rap_freeList, TRACE > :: RackAlloc () :
488 m_pAlias ( 0 )
489{
490 VALGRIND_CREATE_MEMPOOL_EXT ( this, sizeof (epicsMemChkRedZone),
491 false, VALGRIND_MEMPOOL_METAPOOL );
492}
493
494template < typename R, bool TRACE >
495RackAlloc < R, rap_freeList, TRACE > :: ~RackAlloc ()
496{
497 Guard guard ( m_mutex );
498 M_Alias * p = m_pAlias;
499 while ( p ) {
500 M_Alias * pNext = p->m_pNext;
501 {
502 delete p;
503 }
504 p = pNext;
505 };
506 VALGRIND_DESTROY_MEMPOOL ( this );
507}
508
509template < typename R, bool TRACE >
510R * RackAlloc < R, rap_freeList, TRACE > :: create (
511 const type_info & ti )
512{
513 M_Alias * pA = 0;
514 {
515 Guard guard ( m_mutex );
516 if ( m_pAlias ) {
517 pA = m_pAlias;
518 m_pAlias = m_pAlias->m_pNext;
519 }
520 }
521 if ( ! pA ) {
522 pA = new M_Alias;
523 VALGRIND_MAKE_MEM_NOACCESS ( pA, sizeof ( *pA ) );
524 }
525 VALGRIND_MEMPOOL_ALLOC ( this, pA->m_rackBuf,
526 sizeof ( pA->m_rackBuf ) );
527 m_counter.increment ( sizeof ( R ), ti );
528
529 return new ( pA->m_rackBuf ) R ();
530}
531
532template < typename R, bool TRACE >
533void RackAlloc < R, rap_freeList, TRACE > :: destroy ( R * const pR )
534{
535 if ( pR ) {
536 pR->~R ();
537 static const size_t bufOffset = offsetof ( M_Alias, m_rackBuf );
538 const POctet pOctets = reinterpret_cast < POctet > ( pR ) - bufOffset;
539 M_Alias * const pA = reinterpret_cast < M_Alias * > ( pOctets );
540 VALGRIND_MEMPOOL_FREE ( this, pA->m_rackBuf );
541 VALGRIND_MAKE_MEM_UNDEFINED ( &pA->m_pNext, sizeof ( pA->m_pNext ) );
542 {
543 Guard guard ( m_mutex );
544 pA->m_pNext = m_pAlias;
545 m_pAlias = pA;
546 }
547 VALGRIND_MAKE_MEM_DEFINED ( &pA->m_pNext, sizeof ( pA->m_pNext ) );
548 m_counter.decrement ( sizeof ( R ) );
549 }
550}
551
552template < typename R, bool TRACE >
553inline size_t RackAlloc < R, rap_freeList, TRACE > :: rackCount () const
554{
555 return m_counter.rackCount ();
556}
557
558template < typename R, bool TRACE >
559inline size_t RackAlloc < R, rap_freeList, TRACE > :: byteCount () const
560{
561 return m_counter.byteCount ();
562}
563
564template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
565inline AllocatorArena < T, G, N, P, TRACE > :: AllocatorArena ()
566{
567}
568
569template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
570template < typename Y >
571inline AllocatorArena < T, G, N, P, TRACE > :: AllocatorArena ( const Y & )
572{
573}
574
575// address
576template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
577inline typename AllocatorArena < T, G, N, P, TRACE > :: pointer
578 AllocatorArena < T, G, N, P, TRACE > :: address ( reference r )
579{
580 return & r;
581}
582
583template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
584inline typename AllocatorArena < T, G, N, P, TRACE > :: const_pointer
585 AllocatorArena < T, G, N, P, TRACE > :: address ( const_reference r )
586{
587 return & r;
588}
589
590//
591// memory allocation
592// (inline arranges for pNearbyHint to be eliminated
593// at compile time)
594template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
595inline typename AllocatorArena < T, G, N, P, TRACE > :: pointer
596 AllocatorArena < T, G, N, P, TRACE > :: allocate ( size_type nAlloc,
597 void_const_pointer pNearbyHint )
598{
599 pointer p;
600 if ( nAlloc == 1u ) {
601#if defined ( ALLOCATOR_ARENA_MEMORY_ACCESS_INSPECTION_ACTIVE )
602# if __cplusplus >= 201703L
603 void * const pVoid = :: operator new ( sizeof (T),
604 alignof ( T ) );
605# else
606 // This function is required to return a pointer suitably
607 // aligned to hold an object of any fundamental alignment.
608 void * const pVoid = :: operator new ( sizeof (T) );
609# endif
610 p = static_cast < pointer > ( pVoid );
611#else
612 p = m_threadPrivateAlloc ();
613#endif
614 }
615 else {
616# if __cplusplus >= 201703L
617 void * const pVoid = :: operator new ( sizeof (T) * nAlloc,
618 alignof ( T ) );
619# else
620 // This function is required to return a pointer suitably
621 // aligned to hold an object of any fundamental alignment.
622 void * const pVoid = :: operator new ( sizeof (T) * nAlloc );
623# endif
624 p = static_cast < pointer > ( pVoid );
625 }
626 return p;
627}
628
629template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
630inline void AllocatorArena < T, G, N, P, TRACE > :: deallocate ( const pointer p,
631 size_type nAlloc )
632{
633 if ( nAlloc == 1u ) {
634#if defined ( ALLOCATOR_ARENA_MEMORY_ACCESS_INSPECTION_ACTIVE )
635 :: operator delete ( p );
636#else
637 M_Rack * const pRack = M_Rack :: dealloc ( p );
638 if ( pRack ) {
639 staticInstance < M_RackAlloc > ().destroy ( pRack );
640 }
641#endif
642 }
643 else {
644 :: operator delete ( p );
645 }
646}
647
648template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
649inline void * AllocatorArena < T, G, N, P, TRACE > ::
650 allocateOctets ( size_type sz )
651{
652 if ( sz == sizeof ( T ) ) {
653 return AllocatorArena :: allocate ( 1u );
654 }
655 else {
656 // This function is required to return a pointer suitably
657 // aligned to hold an object of any fundamental alignment.
658 return :: operator new ( sz );
659 }
660}
661
662template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
663inline void * AllocatorArena < T, G, N, P, TRACE > ::
664 allocateOctets ( size_type sz,
665 const std :: nothrow_t & )
666{
667 if ( sz == sizeof ( T ) ) {
668 try {
669 return AllocatorArena :: allocate ( 1u );
670 }
671 catch ( const std :: bad_alloc & ) {
672 return static_cast < void * > ( 0 );
673 }
674 }
675 else {
676 // This function is required to return a pointer suitably
677 // aligned to hold an object of any fundamental alignment.
678 return :: operator new ( sz, std :: nothrow );
679 }
680}
681
682template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
683inline void AllocatorArena < T, G, N, P, TRACE > ::
684 deallocateOctets ( void * const p, size_type sz )
685{
686 if ( sz == sizeof ( T ) ) {
687 T * const pT = static_cast < T * > ( p );
688 AllocatorArena :: deallocate ( pT, 1u );
689 }
690 else {
691#if __cplusplus >= 201400L
692 :: operator delete ( p, sz );
693#else
694 :: operator delete ( p );
695#endif
696 }
697}
698
699template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
700inline typename AllocatorArena < T, G, N, P, TRACE > :: size_type
701 AllocatorArena < T, G, N, P, TRACE > :: max_size ()
702{
703 // This class is intended only for use with an allocation size of one;
704 // if requests for more than one object occur it falls back to ordinary
705 // new and delete based allocation.
706 return 1u;
707}
708
709template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
710typename AllocatorArena < T, G, N, P, TRACE > :: pointer
711 AllocatorArena < T, G, N, P, TRACE > :: m_threadPrivateAlloc ()
712{
713 AllocCtx < G > & ctx = staticInstance < AllocCtxTyped < T, G > > ();
714 RackManager * const pRM = ctx.getRackHandlerPtr ();
715 M_Rack * pRack = static_cast < M_Rack * > ( pRM->m_pRack );
716 if ( pRack ) {
717 pointer p = static_cast < T * > ( pRack->alloc () );
718 if ( p ) {
719 if ( pRack->empty () ) {
720 assert ( pRM->m_pThreadExitFunc );
721 ( *pRM->m_pThreadExitFunc ) ( pRack );
722 pRM->m_pThreadExitFunc = 0;
723 pRM->m_pRack = 0;
724 }
725 return p;
726 }
727 assert ( pRM->m_pThreadExitFunc );
728 ( *pRM->m_pThreadExitFunc ) ( pRack );
729 pRM->m_pThreadExitFunc = 0;
730 pRM->m_pRack = 0;
731 }
732 pRack = staticInstance < M_RackAlloc > ().create ( typeid ( T ) );
733 assert ( pRack );
734 pRack->addReference ();
735 pRM->m_pThreadExitFunc = m_rackCleanup;
736 pRM->m_pRack = pRack;
737 pointer p = static_cast < pointer > ( pRack->alloc () );
738 assert ( p );
739 return p;
740}
741
742template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
743void AllocatorArena < T, G, N, P, TRACE > :: m_rackCleanup ( void * const pPriv )
744{
745 assert ( pPriv );
746 M_Rack * pRack = static_cast < M_Rack * > ( pPriv );
747 if ( pRack->removeReference () == 0u ) {
748 staticInstance < M_RackAlloc > ().destroy ( pRack );
749 }
750}
751
752#if __cplusplus >= 201103L
753template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
754template < typename T0, typename ... Args >
755inline void AllocatorArena < T, G, N, P, TRACE > :: construct ( T0 * p,
756 Args && ... args )
757{
758 void * const pvoid = p;
759 :: new ( pvoid ) T0 ( std :: forward <Args> ( args ) ... );
760}
761#else
762
763template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
764template < typename T0, typename A0 >
765inline void AllocatorArena < T, G, N, P, TRACE > :: construct (
766 T0 * p, A0 a0 )
767{
768 new ( p ) T ( a0 );
769}
770
771template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
772template < typename T0, typename A0, typename A1 >
773inline void AllocatorArena < T, G, N, P, TRACE > :: construct (
774 T0 * p, A0 a0, A1 a1 )
775{
776 new ( p ) T ( a0, a1 );
777}
778
779template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
780template < typename T0, typename A0, typename A1, typename A2 >
781inline void AllocatorArena < T, G, N, P, TRACE > :: construct (
782 T0 * p, A0 a0, A1 a1, A2 a2 )
783{
784 new ( p ) T ( a0, a1, a2 );
785}
786
787template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
788template < typename T0, typename A0, typename A1, typename A2,
789 typename A3 >
790inline void AllocatorArena < T, G, N, P, TRACE > :: construct (
791 T0 * p, A0 a0, A1 a1, A2 a2, A3 a3 )
792{
793 new ( p ) T ( a0, a1, a2, a3 );
794}
795
796template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
797template < typename T0, typename A0, typename A1, typename A2,
798 typename A3, typename A4 >
799inline void AllocatorArena < T, G, N, P, TRACE > :: construct (
800 T0 * p, A0 a0, A1 a1, A2 a2, A3 a3,
801 A4 a4 )
802{
803 new ( p ) T ( a0, a1, a2, a3, a4 );
804}
805
806#endif
807
808template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
809template < class U >
810inline void AllocatorArena < T, G, N, P, TRACE > :: destroy ( U * p )
811{
812 p->~U();
813}
814
815template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
816inline bool AllocatorArena < T, G, N, P, TRACE > :: operator == (
817 AllocatorArena const & ao )
818{
819 return true;
820}
821
822template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
823inline bool AllocatorArena < T, G, N, P, TRACE > :: operator != (
824 AllocatorArena const & a )
825{
826 return ! operator == ( a );
827}
828
829template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
830inline void AllocatorArena < T, G, N, P, TRACE > :: cleanup ()
831{
832 AllocCtx < G > & ctx = staticInstance < AllocCtxTyped < T, G > > ();
833 ctx.cleanup ();
834}
835
836template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
837inline size_t AllocatorArena < T, G, N, P, TRACE > :: rackCount ()
838{
839 return staticInstance < M_RackAlloc > ().rackCount();
840}
841
842template < typename T, typename G, size_t N, RackAllocPolicy P, bool TRACE >
843inline size_t AllocatorArena < T, G, N, P, TRACE > :: byteCount ()
844{
845 return staticInstance < M_RackAlloc > ().byteCount();
846}
847
848template < size_t S, size_t A, size_t N >
849const size_t Rack < S, A, N > :: number = N;
850
851template < size_t S, size_t A, size_t N >
852const size_t Rack < S, A, N > :: alignment = A;
853
854template < size_t S, size_t A, size_t N >
855inline Rack < S, A, N > :: Rack () :
856 m_nAlloc ( 0u ),
857 m_refCount ( 0u )
858{
859 VALGRIND_MAKE_MEM_NOACCESS ( m_wrapped, sizeof ( m_wrapped ) );
860}
861
862template < size_t S, size_t A, size_t N >
863inline Rack < S, A, N > :: ~Rack ()
864{
865 // if a Rack allocating free list is destroyed, and it destroys
866 // a rack with outstanding references remaining then problems
867 // will ensue
868 assert ( m_refCount == 0u );
869 VALGRIND_MAKE_MEM_NOACCESS ( m_wrapped, sizeof ( m_wrapped ) );
870}
871
872template < size_t S, size_t A, size_t N >
873inline bool Rack < S, A, N > :: empty () const
874{
875 return m_nAlloc >= N;
876}
877
878template < size_t S, size_t A, size_t N >
879void * Rack < S, A, N > :: alloc ()
880{
881 void * p = 0;
882 if ( m_nAlloc < N ) {
883 M_Wrapper * const pAlloc = & m_wrapped[m_nAlloc];
884 m_nAlloc++;
885 this->addReference ();
886 VALGRIND_MAKE_MEM_UNDEFINED ( &pAlloc->m_pRack,
887 sizeof ( pAlloc->m_pRack ) );
888 atomic :: set ( pAlloc->m_pRack, this );
889 VALGRIND_MAKE_MEM_DEFINED ( &pAlloc->m_pRack,
890 sizeof ( pAlloc->m_pRack ) );
891 p = static_cast < void * > ( pAlloc->m_bufForObj );
892 VALGRIND_MALLOCLIKE_BLOCK ( pAlloc->m_bufForObj,
893 sizeof ( pAlloc->m_bufForObj ),
894 sizeof ( epicsMemChkRedZone ),
895 false );
896 }
897 return p;
898}
899
900template < size_t S, size_t A, size_t N >
901Rack < S, A , N > * Rack < S, A, N > :: dealloc ( void * const p )
902{
903 static const size_t bufOffset = offsetof ( M_Wrapper, m_bufForObj );
904 const POctet pOctets = static_cast < POctet > ( p ) - bufOffset;
905 const PWrapper pDealloc = reinterpret_cast < PWrapper > ( pOctets );
906 VALGRIND_FREELIKE_BLOCK ( pDealloc->m_bufForObj,
907 sizeof ( epicsMemChkRedZone ) );
908 Rack * const pRack = static_cast < Rack * >
909 ( atomic :: get ( pDealloc->m_pRack ) );
910 pDealloc->m_pRack = 0; // for imperfect error detection purposes
911 assert ( pRack );
912 if ( pRack->removeReference () == 0u ) {
913 return pRack;
914 }
915 return 0;
916}
917
918template < size_t S, size_t A, size_t N >
919inline void Rack < S, A, N > :: addReference ()
920{
921 assert ( m_refCount < SIZE_MAX );
922 atomic :: increment ( m_refCount );
923}
924
925template < size_t S, size_t A, size_t N >
926inline size_t Rack < S, A, N > :: removeReference ()
927{
928 assert ( m_refCount > 0u );
929 return atomic :: decrement ( m_refCount );
930}
931
932} // end of name space _impl
933
934using _impl :: Rack;
935using _impl :: RackAlloc;
936using _impl :: RackAllocPolicy;
937using _impl :: rap_pool;
938using _impl :: rap_freeList;
939using _impl :: AllocatorArena;
940
941} // end of name space epics
942
943#endif // if not defined epicsAllocatorArena_h
944
diff --git a/modules/libcom/src/misc/AllocatorArenaUntyped.cpp b/modules/libcom/src/misc/AllocatorArenaUntyped.cpp
0new file mode 100644945new file mode 100644
index 0000000..91693a2
--- /dev/null
+++ b/modules/libcom/src/misc/AllocatorArenaUntyped.cpp
@@ -0,0 +1,199 @@
1
2/*************************************************************************\
3* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
4* National Laboratory
5* EPICS BASE is distributed subject to a Software License Agreement found
6* in file LICENSE that is included with this distribution.
7\*************************************************************************/
8
9/*
10 * Author Jeffrey O. Hill
11 */
12
13#include <cstdio>
14#include <memory>
15
16#define epicsExportSharedSymbols
17#include "AllocatorArena.h"
18#include "errlog.h"
19#include "epicsTypes.h"
20#include "epicsExit.h"
21#include "epicsDemangle.h"
22
23namespace epics {
24namespace _impl {
25
26const char * ThreadPrivateIdBadAlloc :: what () const throw ()
27{
28 return "epicsThreadPrivateCreate returned nill";
29}
30
31const char * AtThreadExitBadAlloc :: what () const throw ()
32{
33 return "epicsAtThreadExit was unsuccessful";
34}
35
36const size_t AllocCtxCom :: m_initialCapacity = 16u;
37
38AllocCtxCom :: AllocCtxCom () :
39 m_threadPrivateId ( epicsThreadPrivateCreate () ),
40 m_curIdx ( 0 )
41{
42}
43
44union RackManagerUnion {
45 RackManager m_entry;
46 size_t m_capacity;
47};
48
49size_t AllocCtxCom :: allocIdx ()
50{
51 return atomic :: increment ( m_curIdx );
52}
53
54/*
55 * from the bit twiddling hacks web site
56 */
57static inline epicsUInt32 nextPwrOf2 ( epicsUInt32 v )
58{
59 v--;
60 v |= v >> 1u;
61 v |= v >> 2u;
62 v |= v >> 4u;
63 v |= v >> 8u;
64 v |= v >> 16u;
65 v++;
66 return v;
67}
68
69RackManager * AllocCtxCom :: getRackHandlerPtr ( const size_t idx )
70{
71 void * const pPriv = epicsThreadPrivateGet ( m_threadPrivateId );
72 RackManagerUnion * pThrPriv;
73 if ( pPriv ) {
74 pThrPriv = static_cast < RackManagerUnion * > ( pPriv );
75 if ( idx >= pThrPriv->m_capacity ) {
76 const size_t newCapacity = nextPwrOf2 ( idx + 1u );
77 RackManagerUnion * const pThrPrivNew =
78 new RackManagerUnion [newCapacity];
79 assert ( newCapacity > idx );
80 size_t i;
81 for ( i = 1u; i < pThrPriv->m_capacity; i++ ) {
82 pThrPrivNew[i] = pThrPriv[i];
83 }
84 for ( i = pThrPriv->m_capacity; i < newCapacity; i++ ) {
85 pThrPrivNew[i].m_entry.m_pRack = 0;
86 pThrPrivNew[i].m_entry.m_pThreadExitFunc = 0;
87 }
88 pThrPrivNew->m_capacity = newCapacity;
89 delete [] pThrPriv;
90 epicsThreadPrivateSet ( m_threadPrivateId, pThrPrivNew );
91 pThrPriv = pThrPrivNew;
92 }
93 }
94 else {
95 size_t capacity;
96 if ( idx >= m_initialCapacity ) {
97 capacity = nextPwrOf2 ( idx + 1u );
98 }
99 else {
100 capacity = m_initialCapacity;
101 }
102 pThrPriv = new RackManagerUnion [capacity];
103 pThrPriv->m_capacity = capacity;
104 for ( size_t i = 1u; i < capacity; i++ ) {
105 pThrPriv[i].m_entry.m_pRack = 0;
106 pThrPriv[i].m_entry.m_pThreadExitFunc = 0;
107 }
108 int status = epicsAtThreadExit ( m_threadExitFunc, this );
109 if ( status != 0 ) {
110 delete [] pThrPriv;
111 throw AtThreadExitBadAlloc ();
112 }
113 epicsThreadPrivateSet ( m_threadPrivateId, pThrPriv );
114 }
115 return & pThrPriv[idx].m_entry;
116}
117
118void AllocCtxCom :: cleanup ( const size_t idx )
119{
120 void * const pPriv = epicsThreadPrivateGet ( m_threadPrivateId );
121 if ( pPriv ) {
122 RackManagerUnion * pThrPriv =
123 static_cast < RackManagerUnion * > ( pPriv );
124 if ( idx < pThrPriv->m_capacity ) {
125 if ( pThrPriv[idx].m_entry.m_pThreadExitFunc &&
126 pThrPriv[idx].m_entry.m_pRack ) {
127 ( *pThrPriv[idx].m_entry.m_pThreadExitFunc )
128 ( pThrPriv[idx].m_entry.m_pRack );
129 pThrPriv[idx].m_entry.m_pRack = 0;
130 pThrPriv[idx].m_entry.m_pThreadExitFunc = 0;
131 }
132 }
133 }
134}
135
136void AllocCtxCom :: m_threadExitFunc ( void * const pPriv )
137{
138 AllocCtxCom * const pCtx = static_cast < AllocCtxCom * > ( pPriv );
139 void * const pThrPrivVoid = epicsThreadPrivateGet ( pCtx->m_threadPrivateId );
140 if ( pThrPrivVoid ) {
141 RackManagerUnion * const pThrPriv =
142 static_cast < RackManagerUnion * > ( pThrPrivVoid );
143 for ( size_t i = 1u; i < pThrPriv->m_capacity; i++ ) {
144 if ( pThrPriv[i].m_entry.m_pThreadExitFunc &&
145 pThrPriv[i].m_entry.m_pRack ) {
146 ( *pThrPriv[i].m_entry.m_pThreadExitFunc )
147 ( pThrPriv[i].m_entry.m_pRack );
148 }
149 }
150 delete [] pThrPriv;
151 epicsThreadPrivateSet ( pCtx->m_threadPrivateId, 0 );
152 }
153}
154
155AllocCounter < true > :: AllocCounter ()
156{
157 atomic :: set ( m_nRacks, 0u );
158 atomic :: set ( m_bytes, 0u );
159 atomic :: set ( m_nRacksTrace, 8 );
160}
161
162static size_t m_nRacksTotal = 0u;
163static size_t m_bytesTotal = 0u;
164
165void AllocCounter < true > :: increment ( size_t nBytesThisTime,
166 const type_info & ti )
167{
168 const size_t newNRacksVal = atomic :: increment ( m_nRacks );
169 atomic :: increment ( m_nRacksTotal );
170 atomic :: add ( m_bytes, nBytesThisTime );
171 atomic :: add ( m_bytesTotal, nBytesThisTime );
172 if ( newNRacksVal >= m_nRacksTrace ) {
173 atomic :: add ( m_nRacksTrace, m_nRacksTrace );
174 this->show ( ti );
175 }
176}
177
178void AllocCounter < true > :: decrement ( size_t nBytesThisTime )
179{
180 atomic :: decrement ( m_nRacks );
181 atomic :: decrement ( m_nRacksTotal );
182 atomic :: subtract ( m_bytes, nBytesThisTime );
183 atomic :: subtract ( m_bytesTotal, nBytesThisTime );
184}
185
186void AllocCounter < true > :: show ( const type_info & ti ) const
187{
188 const std :: string name = epicsDemangleTypeName ( ti );
189 errlogPrintf (
190 "AA C=%08lu SZ=%08lu CT=%08lu SZT=%08lu \"%s\"\n",
191 ( unsigned long ) m_nRacks,
192 ( unsigned long ) m_bytes,
193 ( unsigned long ) m_nRacksTotal,
194 ( unsigned long ) m_bytesTotal,
195 name.c_str () );
196}
197
198} // end of name space _impl
199} // end of name space epics
diff --git a/modules/libcom/src/misc/Makefile b/modules/libcom/src/misc/Makefile
index 3d5412d..fb94ec9 100644
--- a/modules/libcom/src/misc/Makefile
+++ b/modules/libcom/src/misc/Makefile
@@ -27,6 +27,7 @@ INC += ipAddrToAsciiAsynchronous.h
27INC += compilerDependencies.h27INC += compilerDependencies.h
28INC += epicsUnitTest.h28INC += epicsUnitTest.h
29INC += testMain.h29INC += testMain.h
30INC += AllocatorArena.h
3031
31# epicsVersion.h is created by this Makefile32# epicsVersion.h is created by this Makefile
32INC += epicsVersion.h33INC += epicsVersion.h
@@ -42,3 +43,5 @@ Com_SRCS += epicsString.c
42Com_SRCS += truncateFile.c43Com_SRCS += truncateFile.c
43Com_SRCS += ipAddrToAsciiAsynchronous.cpp44Com_SRCS += ipAddrToAsciiAsynchronous.cpp
44Com_SRCS += epicsUnitTest.c45Com_SRCS += epicsUnitTest.c
46Com_SRCS += AllocatorArenaUntyped.cpp
47
diff --git a/modules/libcom/src/osi/Makefile b/modules/libcom/src/osi/Makefile
index f0108e6..9e1dcee 100644
--- a/modules/libcom/src/osi/Makefile
+++ b/modules/libcom/src/osi/Makefile
@@ -9,8 +9,16 @@
99
10SRC_DIRS += $(LIBCOM)/osi10SRC_DIRS += $(LIBCOM)/osi
1111
12# compiler specific
12INC += compilerDependencies.h13INC += compilerDependencies.h
13INC += compilerSpecific.h14INC += compilerSpecific.h
15INC += epicsStaticInstance.h
16INC += epicsStaticInstanceCD.h
17INC += epicsStaticInstanceSaneCmplr.h
18INC += epicsStaticInstanceSketchyCmplr.h
19
20Com_SRCS += epicsStaticInstanceSketchyCmplr.cpp
21Com_SRCS += compilerDependentDemangle.cpp
1422
15INC += osiFileName.h23INC += osiFileName.h
16INC += osiSock.h24INC += osiSock.h
@@ -57,6 +65,7 @@ INC += epicsStdioRedirect.h
57INC += epicsTempFile.h65INC += epicsTempFile.h
58INC += epicsGetopt.h66INC += epicsGetopt.h
59INC += epicsStackTrace.h67INC += epicsStackTrace.h
68INC += epicsDemangle.h
6069
61INC += devLib.h70INC += devLib.h
62INC += devLibVME.h71INC += devLibVME.h
@@ -157,3 +166,4 @@ Com_SRCS_WIN32 += forceBadAllocException.cpp
157Com_SRCS += epicsStackTrace.c166Com_SRCS += epicsStackTrace.c
158Com_SRCS += osdBackTrace.cpp167Com_SRCS += osdBackTrace.cpp
159Com_SRCS += osdFindAddr.c168Com_SRCS += osdFindAddr.c
169
diff --git a/modules/libcom/src/osi/compiler/clang/compilerSpecific.h b/modules/libcom/src/osi/compiler/clang/compilerSpecific.h
index 0498f6e..c06272f 100644
--- a/modules/libcom/src/osi/compiler/clang/compilerSpecific.h
+++ b/modules/libcom/src/osi/compiler/clang/compilerSpecific.h
@@ -1,4 +1,6 @@
1/*************************************************************************\1/*************************************************************************\
2* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
3* National Laboratory
2* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne4* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
3* National Laboratory.5* National Laboratory.
4* Copyright (c) 2002 The Regents of the University of California, as6* Copyright (c) 2002 The Regents of the University of California, as
@@ -29,6 +31,8 @@
29/* Expands to a 'const char*' which describes the name of the current function scope */31/* Expands to a 'const char*' which describes the name of the current function scope */
30#define EPICS_FUNCTION __PRETTY_FUNCTION__32#define EPICS_FUNCTION __PRETTY_FUNCTION__
3133
34#define NO_RETURN __attribute__((noreturn))
35
32#ifdef __cplusplus36#ifdef __cplusplus
3337
34/*38/*
@@ -36,6 +40,8 @@
36 */40 */
37#define CXX_PLACEMENT_DELETE41#define CXX_PLACEMENT_DELETE
3842
43#define USING_BASE_TYPE(B,T) using typename B :: T;
44
39#endif /* __cplusplus */45#endif /* __cplusplus */
4046
41/*47/*
diff --git a/modules/libcom/src/osi/compiler/clang/epicsAtomicCD.h b/modules/libcom/src/osi/compiler/clang/epicsAtomicCD.h
index 763cb05..515129b 100644
--- a/modules/libcom/src/osi/compiler/clang/epicsAtomicCD.h
+++ b/modules/libcom/src/osi/compiler/clang/epicsAtomicCD.h
@@ -1,7 +1,7 @@
11
2/*************************************************************************\2/*************************************************************************\
3* Copyright (c) 2011 LANS LLC, as Operator of3* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
4* Los Alamos National Laboratory.4* National Laboratory
5* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne5* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
6* National Laboratory.6* National Laboratory.
7* EPICS BASE is distributed subject to a Software License Agreement found7* EPICS BASE is distributed subject to a Software License Agreement found
diff --git a/modules/libcom/src/osi/compiler/default/compilerDependentDemangle.cpp b/modules/libcom/src/osi/compiler/default/compilerDependentDemangle.cpp
8new file mode 1006448new file mode 100644
index 0000000..4a1f404
--- /dev/null
+++ b/modules/libcom/src/osi/compiler/default/compilerDependentDemangle.cpp
@@ -0,0 +1,28 @@
1
2/*************************************************************************\
3* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
4* National Laboratory
5* EPICS BASE is distributed subject to a Software License Agreement found
6* in file LICENSE that is included with this distribution.
7\*************************************************************************/
8
9/*
10 * Author: Jeffrey O. Hill
11 */
12#include <exception>
13#include <cstdlib>
14
15#define epicsExportSharedSymbols
16#include "epicsDemangle.h"
17
18using std :: string;
19
20std :: string epicsDemangle ( const char * const pMangledName )
21{
22 return std :: string ( pMangledName );
23}
24
25std :: string epicsDemangleTypeName ( const std :: type_info & ti )
26{
27 return epicsDemangle ( ti.name () );
28}
diff --git a/modules/libcom/src/osi/compiler/default/compilerSpecific.h b/modules/libcom/src/osi/compiler/default/compilerSpecific.h
index 8af1727..3c64c39 100644
--- a/modules/libcom/src/osi/compiler/default/compilerSpecific.h
+++ b/modules/libcom/src/osi/compiler/default/compilerSpecific.h
@@ -1,4 +1,6 @@
1/*************************************************************************\1/*************************************************************************\
2* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
3* National Laboratory
2* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne4* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
3* National Laboratory.5* National Laboratory.
4* Copyright (c) 2002 The Regents of the University of California, as6* Copyright (c) 2002 The Regents of the University of California, as
@@ -26,15 +28,18 @@
26 28
27#ifdef __cplusplus29#ifdef __cplusplus
2830
31#define NO_RETURN
32
33
29/*34/*
30 * CXX_PLACEMENT_DELETE - defined if compiler supports placement delete35 * CXX_PLACEMENT_DELETE - defined if compiler supports placement delete
31 * CXX_THROW_SPECIFICATION - defined if compiler supports throw specification
32 *36 *
33 * (our default guess is that the compiler implements the C++ 97 standard)37 * (our default guess is that the compiler implements the C++ 97 standard)
34 */38 */
35#define CXX_THROW_SPECIFICATION
36#define CXX_PLACEMENT_DELETE39#define CXX_PLACEMENT_DELETE
3740
41#define USING_BASE_TYPE(B,T) using typename B :: T;
42
38#endif /* __cplusplus */43#endif /* __cplusplus */
3944
4045
diff --git a/modules/libcom/src/osi/compiler/default/epicsAtomicCD.h b/modules/libcom/src/osi/compiler/default/epicsAtomicCD.h
index 585a39c..55e4ab7 100644
--- a/modules/libcom/src/osi/compiler/default/epicsAtomicCD.h
+++ b/modules/libcom/src/osi/compiler/default/epicsAtomicCD.h
@@ -1,7 +1,7 @@
11
2/*************************************************************************\2/*************************************************************************\
3* Copyright (c) 2011 LANS LLC, as Operator of3* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
4* Los Alamos National Laboratory.4* National Laboratory
5* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne5* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
6* National Laboratory.6* National Laboratory.
7* EPICS BASE is distributed subject to a Software License Agreement found7* EPICS BASE is distributed subject to a Software License Agreement found
diff --git a/modules/libcom/src/osi/compiler/default/epicsStaticInstanceCD.h b/modules/libcom/src/osi/compiler/default/epicsStaticInstanceCD.h
8new file mode 1006448new file mode 100644
index 0000000..094e7a9
--- /dev/null
+++ b/modules/libcom/src/osi/compiler/default/epicsStaticInstanceCD.h
@@ -0,0 +1,20 @@
1
2/*************************************************************************\
3* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
4* National Laboratory
5* EPICS BASE is distributed subject to a Software License Agreement found
6* in file LICENSE that is included with this distribution.
7\*************************************************************************/
8
9/*
10 * Author Jeffrey O. Hill
11 * johill@lanl.gov
12 */
13
14#ifndef epicsStaticInstanceCD_h
15#define epicsStaticInstanceCD_h
16
17// we dont trust compilers we dont know
18# include "epicsStaticInstanceSketchyCmplr.h"
19
20#endif /* epicsStaticInstanceCD_h */
diff --git a/modules/libcom/src/osi/compiler/gcc/compilerDependentDemangle.cpp b/modules/libcom/src/osi/compiler/gcc/compilerDependentDemangle.cpp
0new file mode 10064421new file mode 100644
index 0000000..a0f0429
--- /dev/null
+++ b/modules/libcom/src/osi/compiler/gcc/compilerDependentDemangle.cpp
@@ -0,0 +1,168 @@
1
2/*************************************************************************\
3* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
4* National Laboratory
5* EPICS BASE is distributed subject to a Software License Agreement found
6* in file LICENSE that is included with this distribution.
7\*************************************************************************/
8
9/*
10 * Author: Jeffrey O. Hill
11 */
12#include <exception>
13#include <cstdlib>
14
15#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 300
16# include <cxxabi.h>
17#endif
18
19#include "epicsThread.h"
20#include "epicsAtomic.h"
21#include "epicsExit.h"
22#include "epicsAssert.h"
23
24#include "epicsDemangle.h"
25
26using std :: string;
27
28union ThreadPrivateId {
29 ThreadPrivateId () : m_epics ( 0 ) {}
30 epicsThreadPrivateId m_epics;
31 void * m_cmpAndSwap;
32};
33
34class ThreadPrivate {
35public:
36 ThreadPrivate ();
37 ~ThreadPrivate ();
38 string demangle ( const char * pMangledName );
39 static ThreadPrivate * get ();
40 static void epicsExit ( void * /* arg */ );
41private:
42 char * m_pBuf;
43 size_t m_bufSize;
44 static const size_t m_bufSizeInit;
45 static ThreadPrivateId m_privateId;
46};
47
48const size_t ThreadPrivate :: m_bufSizeInit = 256u;
49ThreadPrivateId ThreadPrivate :: m_privateId;
50
51//
52// __cxa_demangle doc indicates that buffer passed must be allocated
53// with malloc
54//
55ThreadPrivate :: ThreadPrivate () :
56 m_pBuf ( static_cast < char * > ( malloc ( m_bufSizeInit ) ) ),
57 m_bufSize ( m_pBuf ? m_bufSizeInit : 0u )
58{
59}
60
61ThreadPrivate :: ~ThreadPrivate ()
62{
63 //
64 // __cxa_demangle doc indicates that buffer passed must be allocated
65 // with malloc
66 //
67 free ( m_pBuf );
68}
69
70string ThreadPrivate :: demangle ( const char * const pMangledName )
71{
72 if ( ! m_pBuf ) {
73 //
74 // __cxa_demangle doc indicates that buffer passed must be
75 // allocated with malloc
76 //
77 m_pBuf = static_cast < char * > ( malloc ( m_bufSizeInit ) );
78 if ( m_pBuf ) {
79 m_bufSize = m_bufSizeInit;
80 }
81 else {
82 m_bufSize = 0u;
83 return pMangledName;
84 }
85 }
86 int status = -1000;
87 size_t sz = m_bufSize;
88 char * const pBufResult =
89 abi :: __cxa_demangle ( pMangledName, m_pBuf,
90 & sz, & status );
91 if ( pBufResult ) {
92 m_pBuf = pBufResult;
93 m_bufSize = sz;
94 if ( status == 0 ) {
95 return string ( pBufResult );
96 }
97 else {
98 return string ( pMangledName );
99 }
100 }
101 return string ( pMangledName );
102}
103
104void ThreadPrivate :: epicsExit ( void * p )
105{
106 if ( m_privateId.m_epics ) {
107 epicsThreadPrivateSet ( m_privateId.m_epics, 0 );
108 }
109 ThreadPrivate * const pPriv = static_cast < ThreadPrivate * > ( p );
110 delete pPriv;
111}
112
113inline ThreadPrivate * ThreadPrivate :: get ()
114{
115 STATIC_ASSERT ( sizeof ( m_privateId.m_cmpAndSwap ) ==
116 sizeof ( m_privateId.m_epics ) );
117 if ( ! m_privateId.m_epics ) {
118 ThreadPrivateId newId;
119 newId.m_epics = epicsThreadPrivateCreate ();
120 if ( ! newId.m_epics ) {
121 return 0;
122 }
123 const EpicsAtomicPtrT pBefore =
124 epicsAtomicCmpAndSwapPtrT ( & m_privateId.m_cmpAndSwap,
125 0, newId.m_cmpAndSwap );
126 if ( pBefore ) {
127 epicsThreadPrivateDelete ( newId.m_epics );
128 }
129 }
130 void * const p = epicsThreadPrivateGet ( m_privateId.m_epics );
131 ThreadPrivate * pPriv = static_cast < ThreadPrivate * > ( p );
132 if ( ! pPriv ) {
133 pPriv = new ( std :: nothrow ) ThreadPrivate ();
134 if ( pPriv ) {
135 const int status =
136 epicsAtThreadExit ( ThreadPrivate :: epicsExit, pPriv );
137 if ( status < 0 ) {
138 delete pPriv;
139 pPriv = 0;
140 }
141 epicsThreadPrivateSet ( m_privateId.m_epics, pPriv );
142 }
143 }
144 return pPriv;
145}
146
147std :: string epicsDemangle ( const char * const pMangledName )
148{
149 if ( pMangledName ) {
150# if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 300
151 ThreadPrivate * const pPriv = ThreadPrivate :: get ();
152 if ( ! pPriv ) {
153 return pMangledName;
154 }
155 return pPriv->demangle ( pMangledName );
156# else
157 return pMangledName;
158# endif
159 }
160 else {
161 return "<nil type name>";
162 }
163}
164
165std :: string epicsDemangleTypeName ( const std :: type_info & ti )
166{
167 return epicsDemangle ( ti.name () );
168}
diff --git a/modules/libcom/src/osi/compiler/gcc/compilerSpecific.h b/modules/libcom/src/osi/compiler/gcc/compilerSpecific.h
index 3342308..3a75150 100644
--- a/modules/libcom/src/osi/compiler/gcc/compilerSpecific.h
+++ b/modules/libcom/src/osi/compiler/gcc/compilerSpecific.h
@@ -1,4 +1,6 @@
1/*************************************************************************\1/*************************************************************************\
2* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
3* National Laboratory
2* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne4* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
3* National Laboratory.5* National Laboratory.
4* Copyright (c) 2002 The Regents of the University of California, as6* Copyright (c) 2002 The Regents of the University of California, as
@@ -29,6 +31,8 @@
29/* Expands to a 'const char*' which describes the name of the current function scope */31/* Expands to a 'const char*' which describes the name of the current function scope */
30#define EPICS_FUNCTION __PRETTY_FUNCTION__32#define EPICS_FUNCTION __PRETTY_FUNCTION__
31 33
34#define NO_RETURN __attribute__((noreturn))
35
32#ifdef __cplusplus36#ifdef __cplusplus
3337
34/*38/*
@@ -50,6 +54,12 @@
50 */54 */
51#define EPICS_PRINTF_STYLE(f,a) __attribute__((format(__printf__,f,a)))55#define EPICS_PRINTF_STYLE(f,a) __attribute__((format(__printf__,f,a)))
5256
57#if __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 8 )
58# define USING_BASE_TYPE(B,T) using typename B :: T;
59#else
60# define USING_BASE_TYPE(B,T) typedef typename B :: T T;
61#endif
62
53/*63/*
54 * Deprecation marker64 * Deprecation marker
55 */65 */
diff --git a/modules/libcom/src/osi/compiler/gcc/epicsAtomicCD.h b/modules/libcom/src/osi/compiler/gcc/epicsAtomicCD.h
index 15b9a6c..d268803 100644
--- a/modules/libcom/src/osi/compiler/gcc/epicsAtomicCD.h
+++ b/modules/libcom/src/osi/compiler/gcc/epicsAtomicCD.h
@@ -1,7 +1,7 @@
11
2/*************************************************************************\2/*************************************************************************\
3* Copyright (c) 2011 LANS LLC, as Operator of3* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
4* Los Alamos National Laboratory.4* National Laboratory
5* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne5* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
6* National Laboratory.6* National Laboratory.
7* EPICS BASE is distributed subject to a Software License Agreement found7* EPICS BASE is distributed subject to a Software License Agreement found
diff --git a/modules/libcom/src/osi/compiler/gcc/epicsStaticInstanceCD.h b/modules/libcom/src/osi/compiler/gcc/epicsStaticInstanceCD.h
8new file mode 1006448new file mode 100644
index 0000000..d7d974e
--- /dev/null
+++ b/modules/libcom/src/osi/compiler/gcc/epicsStaticInstanceCD.h
@@ -0,0 +1,26 @@
1
2/*************************************************************************\
3* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
4* National Laboratory
5* EPICS BASE is distributed subject to a Software License Agreement found
6* in file LICENSE that is included with this distribution.
7\*************************************************************************/
8
9/*
10 * Author Jeffrey O. Hill
11 * johill@lanl.gov
12 */
13
14#ifndef epicsStaticInstanceCD_h
15#define epicsStaticInstanceCD_h
16
17#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 401
18 // any gcc version that has -fno-threadsafe-statics
19 // should be ok
20# include "epicsStaticInstanceSaneCmplr.h"
21#else // ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 401
22 // other gcc maybe cant be trusted without more testing
23# include "epicsStaticInstanceSketchyCmplr.h"
24#endif // ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 401
25
26#endif // epicsStaticInstanceCD_h
diff --git a/modules/libcom/src/osi/compiler/msvc/compilerSpecific.h b/modules/libcom/src/osi/compiler/msvc/compilerSpecific.h
index 4e282db..ab4e134 100644
--- a/modules/libcom/src/osi/compiler/msvc/compilerSpecific.h
+++ b/modules/libcom/src/osi/compiler/msvc/compilerSpecific.h
@@ -1,4 +1,6 @@
1/*************************************************************************\1/*************************************************************************\
2* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
3* National Laboratory
2* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne4* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
3* National Laboratory.5* National Laboratory.
4* Copyright (c) 2002 The Regents of the University of California, as6* Copyright (c) 2002 The Regents of the University of California, as
@@ -21,6 +23,8 @@
21#endif23#endif
2224
23#define EPICS_ALWAYS_INLINE __forceinline25#define EPICS_ALWAYS_INLINE __forceinline
26#define NO_RETURN __declspec(noreturn)
27
2428
25/* Expands to a 'const char*' which describes the name of the current function scope */29/* Expands to a 'const char*' which describes the name of the current function scope */
26#define EPICS_FUNCTION __FUNCTION__30#define EPICS_FUNCTION __FUNCTION__
@@ -36,10 +40,10 @@
36 40
37/*41/*
38 * CXX_PLACEMENT_DELETE - defined if compiler supports placement delete42 * CXX_PLACEMENT_DELETE - defined if compiler supports placement delete
39 * CXX_THROW_SPECIFICATION - defined if compiler supports throw specification
40 */43 */
41#define CXX_PLACEMENT_DELETE44#define CXX_PLACEMENT_DELETE
42#define CXX_THROW_SPECIFICATION45
46#define USING_BASE_TYPE(B,T) using typename B :: T;
4347
44#endif /* __cplusplus */48#endif /* __cplusplus */
4549
diff --git a/modules/libcom/src/osi/compiler/msvc/epicsAtomicCD.h b/modules/libcom/src/osi/compiler/msvc/epicsAtomicCD.h
index e7d1c4b..f9ddc79 100644
--- a/modules/libcom/src/osi/compiler/msvc/epicsAtomicCD.h
+++ b/modules/libcom/src/osi/compiler/msvc/epicsAtomicCD.h
@@ -1,7 +1,7 @@
11
2/*************************************************************************\2/*************************************************************************\
3* Copyright (c) 2011 LANS LLC, as Operator of3* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
4* Los Alamos National Laboratory.4* National Laboratory
5* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne5* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
6* National Laboratory.6* National Laboratory.
7* EPICS BASE is distributed subject to a Software License Agreement found7* EPICS BASE is distributed subject to a Software License Agreement found
diff --git a/modules/libcom/src/osi/compiler/msvc/epicsStaticInstanceCD.h b/modules/libcom/src/osi/compiler/msvc/epicsStaticInstanceCD.h
8new file mode 1006448new file mode 100644
index 0000000..1859595
--- /dev/null
+++ b/modules/libcom/src/osi/compiler/msvc/epicsStaticInstanceCD.h
@@ -0,0 +1,32 @@
1
2/*************************************************************************\
3* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
4* National Laboratory
5* EPICS BASE is distributed subject to a Software License Agreement found
6* in file LICENSE that is included with this distribution.
7\*************************************************************************/
8
9/*
10 * Author Jeffrey O. Hill
11 * johill@lanl.gov
12 */
13
14#ifndef epicsStaticInstanceCD_h
15#define epicsStaticInstanceCD_h
16
17// visual c++ has some issues
18// --------------------------
19//
20// 1) it lacks mutual exclusion protecting concurrent on demand
21// initialization of block scope static variables
22//
23// 2) it silently adds the path to the .cpp file to the very beginning
24// of the include search list so if a msvc specific version of this
25// file does not exist and we use the default version then it will
26// also use compiler/default/ version, despite the existence
27// of a more specialized version, and even if not told to do so on
28// the command line
29//
30# include "epicsStaticInstanceSketchyCmplr.h"
31
32#endif epicsStaticInstanceCD_h
diff --git a/modules/libcom/src/osi/compiler/solStudio/compilerSpecific.h b/modules/libcom/src/osi/compiler/solStudio/compilerSpecific.h
index a9d59a5..20065e2 100644
--- a/modules/libcom/src/osi/compiler/solStudio/compilerSpecific.h
+++ b/modules/libcom/src/osi/compiler/solStudio/compilerSpecific.h
@@ -1,4 +1,6 @@
1/*************************************************************************\1/*************************************************************************\
2* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
3* National Laboratory
2* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne4* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
3* National Laboratory.5* National Laboratory.
4* Copyright (c) 2002 The Regents of the University of California, as6* Copyright (c) 2002 The Regents of the University of California, as
@@ -31,11 +33,9 @@
3133
32/*34/*
33 * CXX_PLACEMENT_DELETE - defined if compiler supports placement delete35 * CXX_PLACEMENT_DELETE - defined if compiler supports placement delete
34 * CXX_THROW_SPECIFICATION - defined if compiler supports throw specification
35 *36 *
36 * (our default guess is that the compiler implements the C++ 97 standard)37 * (our default guess is that the compiler implements the C++ 97 standard)
37 */38 */
38#define CXX_THROW_SPECIFICATION
39#define CXX_PLACEMENT_DELETE39#define CXX_PLACEMENT_DELETE
4040
41#endif /* __cplusplus */41#endif /* __cplusplus */
diff --git a/modules/libcom/src/osi/compiler/solStudio/epicsAtomicCD.h b/modules/libcom/src/osi/compiler/solStudio/epicsAtomicCD.h
index 8a733a5..b92e36a 100644
--- a/modules/libcom/src/osi/compiler/solStudio/epicsAtomicCD.h
+++ b/modules/libcom/src/osi/compiler/solStudio/epicsAtomicCD.h
@@ -1,7 +1,7 @@
11
2/*************************************************************************\2/*************************************************************************\
3* Copyright (c) 2011 LANS LLC, as Operator of3* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
4* Los Alamos National Laboratory.4* National Laboratory
5* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne5* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
6* National Laboratory.6* National Laboratory.
7* EPICS BASE is distributed subject to a Software License Agreement found7* EPICS BASE is distributed subject to a Software License Agreement found
diff --git a/modules/libcom/src/osi/compilerDependencies.h b/modules/libcom/src/osi/compilerDependencies.h
index 0b333d7..509687a 100644
--- a/modules/libcom/src/osi/compilerDependencies.h
+++ b/modules/libcom/src/osi/compilerDependencies.h
@@ -1,4 +1,6 @@
1/*************************************************************************\1/*************************************************************************\
2* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
3* National Laboratory
2* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne4* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
3* National Laboratory.5* National Laboratory.
4* Copyright (c) 2002 The Regents of the University of California, as6* Copyright (c) 2002 The Regents of the University of California, as
@@ -20,6 +22,46 @@
2022
21#ifdef __cplusplus23#ifdef __cplusplus
2224
25#if __cplusplus >= 201103L
26#define epicsOverride override
27#else
28#define epicsOverride
29#endif
30
31#if __cplusplus >= 201103L
32#define epicsFinal final
33#else
34#define epicsFinal
35#endif
36
37#if __cplusplus >= 201103L
38#define epicsNoexcept noexcept
39#else
40#define epicsNoexcept throw()
41#endif
42
43#if __cplusplus >= 201103L
44#define epicsConstexpr constexpr
45#else
46#define epicsConstexpr
47#endif
48
49#if __cplusplus >= 201103L
50#define epicsMove(A) std::move(A)
51#else
52#define epicsMove(A) (A)
53#endif
54
55/*
56 * deleted method should also be declared private as per convention
57 * with old compilers
58 */
59#if __cplusplus >= 201103L
60#define epicsDeleteMethod =delete
61#else
62#define epicsDeleteMethod
63#endif
64
23/*65/*
24 * usage: epicsPlacementDeleteOperator (( void *, myMemoryManager & ))66 * usage: epicsPlacementDeleteOperator (( void *, myMemoryManager & ))
25 */67 */
diff --git a/modules/libcom/src/osi/epicsDemangle.h b/modules/libcom/src/osi/epicsDemangle.h
26new file mode 10064468new file mode 100644
index 0000000..07bd299
--- /dev/null
+++ b/modules/libcom/src/osi/epicsDemangle.h
@@ -0,0 +1,26 @@
1
2/*************************************************************************\
3* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
4* National Laboratory
5* EPICS BASE is distributed subject to a Software License Agreement found
6* in file LICENSE that is included with this distribution.
7\*************************************************************************/
8
9/*
10 * Author: Jeffrey O. Hill
11 */
12
13#ifndef epicsDemangleh
14#define epicsDemangleh
15
16#include <string>
17#include <typeinfo>
18
19#include "shareLib.h"
20
21epicsShareFunc std :: string
22 epicsDemangle ( const char * const pMangledName );
23epicsShareFunc std :: string
24 epicsDemangleTypeName ( const std :: type_info & );
25
26#endif /* epicsDemangleh */
diff --git a/modules/libcom/src/osi/epicsStaticInstance.h b/modules/libcom/src/osi/epicsStaticInstance.h
0new file mode 10064427new file mode 100644
index 0000000..8e8d469
--- /dev/null
+++ b/modules/libcom/src/osi/epicsStaticInstance.h
@@ -0,0 +1,52 @@
1/*************************************************************************\
2* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
3* National Laboratory
4* EPICS BASE is distributed subject to a Software License Agreement found
5* in file LICENSE that is included with this distribution.
6\*************************************************************************/
7
8/*
9 * Author Jeffrey O. Hill
10 * johill@lanl.gov
11 */
12
13#ifndef epicsStaticInstance_h
14#define epicsStaticInstance_h
15
16namespace epics {
17
18//
19// c++ 11 specifies the behavior for concurrent
20// access to block scope statics but some compiler
21// writers, lacking clear guidance in the earlier
22// c++ standards, curiously implement thread unsafe
23// block static variables despite ensuring for
24// proper multi-threaded behavior for many other
25// aspects of the compiler runtime infrastructure
26// such as runtime support for exception handling
27//
28// T - the type of the initialized once only static
29//
30template < typename T > T & staticInstance ();
31
32//
33// !!!! perhaps we need versions here that pass parameters
34// !!!! to the constructor using templates also
35//
36
37} // end of name space epics
38
39//
40// if the compiler claims its c++ 11 then we are optimistic, ref:
41// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf
42// (see section 6.7)
43//
44#if __cplusplus >= 201103L
45# include "epicsStaticInstanceSaneCmplr.h"
46#else
47 // otherwise we can implement compiler specific behavior
48# include "epicsStaticInstanceCD.h"
49#endif
50
51#endif // ifndef epicsStaticInstance_h
52
diff --git a/modules/libcom/src/osi/epicsStaticInstanceSaneCmplr.h b/modules/libcom/src/osi/epicsStaticInstanceSaneCmplr.h
0new file mode 10064453new file mode 100644
index 0000000..523e509
--- /dev/null
+++ b/modules/libcom/src/osi/epicsStaticInstanceSaneCmplr.h
@@ -0,0 +1,45 @@
1
2/*************************************************************************\
3* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
4* National Laboratory
5* EPICS BASE is distributed subject to a Software License Agreement found
6* in file LICENSE that is included with this distribution.
7\*************************************************************************/
8
9/*
10 * Author Jeffrey O. Hill
11 * johill@lanl.gov
12 */
13
14#ifndef epicsStaticInstanceSaneCmplr_h
15#define epicsStaticInstanceSaneCmplr_h
16
17namespace epics {
18
19// c++ 11 specifies the behavior for concurrent
20// access to block scope statics but some compiler
21// writers, lacking clear guidance in the earlier
22// c++ standards, curiously implement thread unsafe
23// block static variables despite ensuring for
24// proper multi-threaded behavior for many other
25// aspects of the compiler infrastructure such as
26// runtime support for exception handling
27//
28// if the compiler claims its c++ 11 then we are optimistic, ref:
29// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf
30// (see section 6.7)
31// "If control enters the (block-scope variable with static storage duration)
32// declaration concurrently while the variable is being initialized, the
33// concurrent execution shall wait for completion of the initialization."
34//
35// also see c++ FAQ, how do I prevent the
36// "static initialization order fiasco"?
37template < typename T > T & staticInstance ()
38{
39 static T * const m_pInstance = new T;
40 return * m_pInstance;
41}
42
43} // end of name space epics
44
45#endif // ifndef epicsStaticInstanceSaneCmplr_h
diff --git a/modules/libcom/src/osi/epicsStaticInstanceSketchyCmplr.cpp b/modules/libcom/src/osi/epicsStaticInstanceSketchyCmplr.cpp
0new file mode 10064446new file mode 100644
index 0000000..9581618
--- /dev/null
+++ b/modules/libcom/src/osi/epicsStaticInstanceSketchyCmplr.cpp
@@ -0,0 +1,88 @@
1
2/*************************************************************************\
3* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
4* National Laboratory
5* EPICS BASE is distributed subject to a Software License Agreement found
6* in file LICENSE that is included with this distribution.
7\*************************************************************************/
8
9/*
10 * Author Jeffrey O. Hill
11 * johill@lanl.gov
12 */
13
14#include <cstddef>
15
16#define epicsExportSharedSymbols
17#include "errlog.h"
18#include "epicsThread.h"
19#include "epicsAssert.h"
20#include "epicsStaticInstanceSketchyCmplr.h"
21
22namespace epics {
23
24epicsShareDef char staticInstanceBusy;
25
26//
27// c++ 0x specifies the behavior for concurrent
28// access to block scope statics but some compiler
29// writers, lacking clear guidance in the earlier
30// c++ standards, curiously implement thread unsafe
31// block static variables despite ensuring for
32// proper multi-threaded behavior for many other
33// aspects of the compiler infrastructure such as
34// runtime support for exception handling
35//
36// see also c++ faq, static initialization order fiasco
37//
38// This implementation is active if we don't
39// know for certain that we can trust the compiler.
40// This implementation is substantially more efficient
41// at runtime than epicsThreadOnce
42//
43// we are careful to create T no more than once here
44//
45EpicsAtomicPtrT staticInstanceInit ( EpicsAtomicPtrT & target,
46 const PStaticInstanceFactory pFactory )
47{
48 static const std :: size_t spinDownInit = 1000u;
49 static const std :: size_t spinCount = 10u;
50 STATIC_ASSERT ( spinDownInit > spinCount );
51 static const std :: size_t spinThresh = spinDownInit - spinCount;
52 std :: size_t spinDown = spinDownInit;
53 EpicsAtomicPtrT pCur = 0;
54 while ( true ) {
55 pCur = epics :: atomic :: compareAndSwap ( target,
56 pStaticInstanceInit,
57 & staticInstanceBusy );
58 if ( pCur == pStaticInstanceInit ) {
59 try {
60 pCur = ( * pFactory ) ();
61 epics :: atomic :: set ( target, pCur );
62 break;
63 }
64 catch ( ... ) {
65 epics :: atomic :: set ( target,
66 pStaticInstanceInit );
67 throw;
68 }
69 }
70 else if ( pCur != & staticInstanceBusy ) {
71 break;
72 }
73 if ( spinDown <= spinThresh ) {
74 epicsThreadSleep ( epicsThreadSleepQuantum () );
75 }
76 if ( spinDown > 0u ) {
77 spinDown--;
78 }
79 else {
80 errlogPrintf ( "staticInstanceInit: waiting for another "
81 "thread to finish creating the static instance\n" );
82 spinDown = spinThresh;
83 }
84 }
85 return pCur;
86}
87
88} // end of name space epics
diff --git a/modules/libcom/src/osi/epicsStaticInstanceSketchyCmplr.h b/modules/libcom/src/osi/epicsStaticInstanceSketchyCmplr.h
0new file mode 10064489new file mode 100644
index 0000000..33765d9
--- /dev/null
+++ b/modules/libcom/src/osi/epicsStaticInstanceSketchyCmplr.h
@@ -0,0 +1,53 @@
1/*************************************************************************\
2* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
3* National Laboratory
4* EPICS BASE is distributed subject to a Software License Agreement found
5* in file LICENSE that is included with this distribution.
6\*************************************************************************/
7
8/*
9 * Author Jeffrey O. Hill
10 * johill@lanl.gov
11 */
12
13#ifndef epicsStaticInstanceSketchyCmplr_h
14#define epicsStaticInstanceSketchyCmplr_h
15
16#include "epicsAtomic.h"
17
18#include "shareLib.h"
19
20namespace epics {
21
22typedef EpicsAtomicPtrT ( * PStaticInstanceFactory ) ();
23
24epicsShareFunc EpicsAtomicPtrT staticInstanceInit ( EpicsAtomicPtrT & target,
25 const PStaticInstanceFactory pFactory );
26
27epicsShareExtern char staticInstanceBusy;
28
29namespace {
30 template < typename T >
31 EpicsAtomicPtrT staticInstanceFactory ()
32 {
33 return new T ();
34 }
35 static const EpicsAtomicPtrT pStaticInstanceInit = 0;
36}
37
38// this should _not_ be an in line function so that
39// we guarantee that only one instance of type T per
40// executable is created
41template < typename T > T & staticInstance ()
42{
43 static EpicsAtomicPtrT pInstance = pStaticInstanceInit;
44 EpicsAtomicPtrT pCur = epics :: atomic :: get ( pInstance );
45 if ( pCur == pStaticInstanceInit || pCur == & staticInstanceBusy ) {
46 pCur = staticInstanceInit ( pInstance, staticInstanceFactory < T > );
47 }
48 return * reinterpret_cast < T * > ( pCur );
49}
50
51} // end of name space epics
52
53#endif // ifndef epicsStaticInstanceSketchyCmplr_h
diff --git a/modules/libcom/src/timer/epicsTimer.cpp b/modules/libcom/src/timer/epicsTimer.cpp
index e55280e..96bfa31 100644
--- a/modules/libcom/src/timer/epicsTimer.cpp
+++ b/modules/libcom/src/timer/epicsTimer.cpp
@@ -1,4 +1,6 @@
1/*************************************************************************\1/*************************************************************************\
2* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
3* National Laboratory
2* Copyright (c) 2015 UChicago Argonne LLC, as Operator of Argonne4* Copyright (c) 2015 UChicago Argonne LLC, as Operator of Argonne
3* National Laboratory.5* National Laboratory.
4* Copyright (c) 2002 The Regents of the University of California, as6* Copyright (c) 2002 The Regents of the University of California, as
@@ -12,151 +14,144 @@
12 * 505 665 183114 * 505 665 1831
13 */15 */
1416
17#include <cstdio>
15#include <string>18#include <string>
16#include <stdexcept>19#include <stdexcept>
1720
18#define epicsExportSharedSymbols21#define epicsExportSharedSymbols
19#include "epicsMath.h"22#include "epicsMath.h"
20#include "epicsTimer.h"23#include "epicsTimer.h"
21#include "epicsGuard.h"
22#include "timerPrivate.h"24#include "timerPrivate.h"
2325
24#ifdef _MSC_VER
25# pragma warning ( push )
26# pragma warning ( disable:4660 )
27#endif
28
29#ifdef _MSC_VER
30# pragma warning ( pop )
31#endif
32
33template class tsFreeList < epicsTimerForC, 0x20 >;
34
35epicsTimer::~epicsTimer () {}26epicsTimer::~epicsTimer () {}
3627
37epicsTimerQueueNotify::~epicsTimerQueueNotify () {}28void epicsTimerNotify :: show ( unsigned /* level */ ) const {}
3829
39epicsTimerNotify::~epicsTimerNotify () {}30TimerForC :: TimerForC ( timerQueue & queue, epicsTimerCallback const pCB,
4031 void * const pPrivate ) :
41void epicsTimerNotify::show ( unsigned /* level */ ) const {}32 m_pTimer ( & queue.createTimerImpl () ),
4233 m_pCallBack ( pCB ),
43epicsTimerForC::epicsTimerForC ( timerQueue &queue, epicsTimerCallback pCBIn, void *pPrivateIn ) :34 m_pPrivate ( pPrivate )
44 timer ( queue ), pCallBack ( pCBIn ), pPrivate ( pPrivateIn )
45{35{
46}36}
4737
48epicsTimerForC::~epicsTimerForC ()38TimerForC :: ~TimerForC ()
49{39{
40 m_pTimer->destroy ();
50}41}
5142
52void epicsTimerForC::destroy ()43void TimerForC :: show ( unsigned level ) const
53{44{
54 timerQueue & queueTmp = this->queue;45 printf ( "TimerForC: callback ptr %p private ptr %p\n",
55 this->~epicsTimerForC ();46 m_pCallBack, m_pPrivate );
56 queueTmp.timerForCFreeList.release ( this );47 if ( level > 1 && m_pTimer ) {
48 m_pTimer->show ( level - 1 );
49 }
57}50}
5851
59epicsTimerNotify::expireStatus epicsTimerForC::expire ( const epicsTime & )52epicsTimerNotify :: expireStatus
53 TimerForC :: expire ( const epicsTime & )
60{54{
61 ( *this->pCallBack ) ( this->pPrivate );55 ( *m_pCallBack ) ( m_pPrivate );
62 return noRestart;56 return noRestart;
63}57}
6458
65epicsTimerQueueActiveForC ::59epicsTimerQueueActiveForC ::
66 epicsTimerQueueActiveForC ( RefMgr & refMgr, 60 epicsTimerQueueActiveForC ( bool okToShare, unsigned priority ) :
67 bool okToShare, unsigned priority ) :61 timerQueueActive ( okToShare, priority )
68 timerQueueActive ( refMgr, okToShare, priority )
69{62{
70 timerQueueActive::start();
71}63}
7264
73epicsTimerQueueActiveForC::~epicsTimerQueueActiveForC ()65epicsTimerQueueActiveForC :: ~epicsTimerQueueActiveForC ()
74{66{
75}67}
7668
77void epicsTimerQueueActiveForC::release ()69void epicsTimerQueueActiveForC :: release ()
78{70{
79 _refMgr->release ( *this );71 timerQueueActiveMgr :: master ().release ( *this );
80}72}
8173
82epicsTimerQueuePassiveForC::epicsTimerQueuePassiveForC ( 74epicsTimerQueuePassiveForC :: epicsTimerQueuePassiveForC (
83 epicsTimerQueueNotifyReschedule pRescheduleCallbackIn, 75 epicsTimerQueueNotifyReschedule pRescheduleCallback,
84 epicsTimerQueueNotifyQuantum pSleepQuantumCallbackIn,76 epicsTimerQueueNotifyQuantum pSleepQuantumCallback,
85 void * pPrivateIn ) :77 void * pPrivate ) :
86 timerQueuePassive ( * static_cast < epicsTimerQueueNotify * > ( this ) ), 78 timerQueuePassive (
87 pRescheduleCallback ( pRescheduleCallbackIn ), 79 * static_cast < epicsTimerQueueNotify * > ( this ) ),
88 pSleepQuantumCallback ( pSleepQuantumCallbackIn ),80 m_pRescheduleCallback ( pRescheduleCallback ),
89 pPrivate ( pPrivateIn )81 m_pSleepQuantumCallback ( pSleepQuantumCallback ),
82 m_pPrivate ( pPrivate )
90{83{
91}84}
9285
93epicsTimerQueuePassiveForC::~epicsTimerQueuePassiveForC () 86epicsTimerQueuePassiveForC :: ~epicsTimerQueuePassiveForC ()
94{87{
95}88}
9689
97void epicsTimerQueuePassiveForC::reschedule ()90void epicsTimerQueuePassiveForC :: reschedule ()
98{91{
99 (*this->pRescheduleCallback) ( this->pPrivate );92 ( *m_pRescheduleCallback ) ( m_pPrivate );
100}93}
10194
102double epicsTimerQueuePassiveForC::quantum ()95void epicsTimerQueuePassiveForC :: destroy ()
103{
104 return (*this->pSleepQuantumCallback) ( this->pPrivate );
105}
106
107void epicsTimerQueuePassiveForC::destroy ()
108{96{
109 delete this;97 delete this;
110}98}
11199
112epicsShareFunc epicsTimerNotify::expireStatus::expireStatus ( restart_t restart ) : 100epicsShareFunc epicsTimerNotify :: expireStatus ::
113 delay ( - DBL_MAX )101 expireStatus ( restart_t restart ) :
102 m_delay ( -DBL_MAX )
114{103{
115 if ( restart != noRestart ) {104 if ( restart != noRestart ) {
116 throw std::logic_error 105 throw std::logic_error
117 ( "timer restart was requested without specifying a delay?" );106 ( "timer restart was requested "
107 "without specifying a delay?" );
118 }108 }
119}109}
120110
121epicsShareFunc epicsTimerNotify::expireStatus::expireStatus 111epicsShareFunc epicsTimerNotify :: expireStatus :: expireStatus
122 ( restart_t restartIn, const double & expireDelaySec ) :112 ( restart_t restartIn, const double & expireDelaySec ) :
123 delay ( expireDelaySec )113 m_delay ( expireDelaySec )
124{114{
125 if ( restartIn != epicsTimerNotify::restart ) {115 if ( restartIn != epicsTimerNotify :: restart ) {
126 throw std::logic_error 116 throw std::logic_error
127 ( "no timer restart was requested, but a delay was specified?" );117 ( "no timer restart was requested, "
118 "but a delay was specified?" );
128 }119 }
129 if ( this->delay < 0.0 || !finite(this->delay) ) {120 if ( m_delay < 0.0 || ! finite ( m_delay ) ) {
130 throw std::logic_error 121 throw std::logic_error
131 ( "timer restart was requested, but a negative delay was specified?" );122 ( "timer restart was requested, but a "
123 "negative delay was specified?" );
132 }124 }
133}125}
134126
135epicsShareFunc bool epicsTimerNotify::expireStatus::restart () const127epicsShareFunc bool
128 epicsTimerNotify :: expireStatus :: restart () const
136{129{
137 return this->delay >= 0.0 && finite(this->delay);130 return m_delay >= 0.0 && finite ( m_delay );
138}131}
139132
140epicsShareFunc double epicsTimerNotify::expireStatus::expirationDelay () const133epicsShareFunc double
134 epicsTimerNotify :: expireStatus :: expirationDelay () const
141{135{
142 if ( this->delay < 0.0 || !finite(this->delay) ) {136 if ( m_delay < 0.0 || ! finite ( m_delay ) ) {
143 throw std::logic_error 137 throw std::logic_error
144 ( "no timer restart was requested, but you are asking for a restart delay?" );138 ( "no timer restart was requested, "
139 "but you are asking for a restart delay?" );
145 }140 }
146 return this->delay;141 return m_delay;
147}142}
148143
149extern "C" epicsTimerQueuePassiveId epicsShareAPI144extern "C" epicsTimerQueuePassiveId epicsShareAPI
150 epicsTimerQueuePassiveCreate ( 145 epicsTimerQueuePassiveCreate (
151 epicsTimerQueueNotifyReschedule pRescheduleCallbackIn, 146 const epicsTimerQueueNotifyReschedule pRescheduleCallback,
152 epicsTimerQueueNotifyQuantum pSleepQuantumCallbackIn,147 const epicsTimerQueueNotifyQuantum pSleepQuantumCallback,
153 void * pPrivateIn )148 void * const pPrivate )
154{149{
155 try {150 try {
156 return new epicsTimerQueuePassiveForC ( 151 return new epicsTimerQueuePassiveForC (
157 pRescheduleCallbackIn, 152 pRescheduleCallback,
158 pSleepQuantumCallbackIn,153 pSleepQuantumCallback,
159 pPrivateIn );154 pPrivate );
160 }155 }
161 catch ( ... ) {156 catch ( ... ) {
162 return 0;157 return 0;
@@ -173,28 +168,31 @@ extern "C" double epicsShareAPI
173 epicsTimerQueuePassiveProcess ( epicsTimerQueuePassiveId pQueue )168 epicsTimerQueuePassiveProcess ( epicsTimerQueuePassiveId pQueue )
174{169{
175 try {170 try {
176 return pQueue->process ( epicsTime::getCurrent() );171 return pQueue->process ( epicsTime :: getCurrent () );
177 }172 }
178 catch ( ... ) {173 catch ( ... ) {
179 return 1.0;174 return 1.0;
180 }175 }
181}176}
182177
183extern "C" epicsTimerId epicsShareAPI epicsTimerQueuePassiveCreateTimer (178extern "C" epicsTimerId epicsShareAPI
184 epicsTimerQueuePassiveId pQueue, epicsTimerCallback pCallback, void *pArg )179 epicsTimerQueuePassiveCreateTimer (
180 epicsTimerQueuePassiveId pQueue,
181 epicsTimerCallback pCallback, void *pArg )
185{182{
186 try {183 try {
187 return & pQueue->createTimerForC ( pCallback, pArg );184 return & pQueue->createTimerForC ( pCallback, pArg );
188 }185 }
189 catch ( ... ) {186 catch ( ... ) {
190 return 0;187 return 0;
191 }188 }
192}189}
193190
194extern "C" epicsShareFunc void epicsShareAPI epicsTimerQueuePassiveDestroyTimer ( 191extern "C" epicsShareFunc void epicsShareAPI
195 epicsTimerQueuePassiveId /* pQueue */, epicsTimerId pTmr )192 epicsTimerQueuePassiveDestroyTimer (
193 epicsTimerQueuePassiveId pQueue, epicsTimerId pTmr )
196{194{
197 pTmr->destroy ();195 delete pTmr;
198}196}
199197
200extern "C" void epicsShareAPI epicsTimerQueuePassiveShow (198extern "C" void epicsShareAPI epicsTimerQueuePassiveShow (
@@ -207,11 +205,10 @@ extern "C" epicsTimerQueueId epicsShareAPI
207 epicsTimerQueueAllocate ( int okToShare, unsigned int threadPriority )205 epicsTimerQueueAllocate ( int okToShare, unsigned int threadPriority )
208{206{
209 try {207 try {
210 epicsSingleton < timerQueueActiveMgr > :: reference ref =
211 timerQueueMgrEPICS.getReference ();
212 epicsTimerQueueActiveForC & tmr = 208 epicsTimerQueueActiveForC & tmr =
213 ref->allocate ( ref, okToShare ? true : false, threadPriority );209 timerQueueActiveMgr :: master ().
214 return &tmr;210 allocate ( okToShare ? true : false, threadPriority );
211 return & tmr;
215 }212 }
216 catch ( ... ) {213 catch ( ... ) {
217 return 0;214 return 0;
@@ -223,8 +220,10 @@ extern "C" void epicsShareAPI epicsTimerQueueRelease ( epicsTimerQueueId pQueue
223 pQueue->release ();220 pQueue->release ();
224}221}
225222
226extern "C" epicsTimerId epicsShareAPI epicsTimerQueueCreateTimer (223extern "C" epicsTimerId epicsShareAPI
227 epicsTimerQueueId pQueue, epicsTimerCallback pCallback, void *pArg )224 epicsTimerQueueCreateTimer (
225 epicsTimerQueueId pQueue,
226 epicsTimerCallback pCallback, void *pArg )
228{227{
229 try {228 try {
230 return & pQueue->createTimerForC ( pCallback, pArg );229 return & pQueue->createTimerForC ( pCallback, pArg );
@@ -234,43 +233,49 @@ extern "C" epicsTimerId epicsShareAPI epicsTimerQueueCreateTimer (
234 }233 }
235}234}
236235
237extern "C" void epicsShareAPI epicsTimerQueueShow (236extern "C" void epicsShareAPI
238 epicsTimerQueueId pQueue, unsigned int level )237 epicsTimerQueueShow (
238 epicsTimerQueueId pQueue, unsigned int level )
239{239{
240 pQueue->show ( level );240 pQueue->show ( level );
241}241}
242242
243extern "C" void epicsShareAPI epicsTimerQueueDestroyTimer ( 243extern "C" void epicsShareAPI
244 epicsTimerQueueId /* pQueue */, epicsTimerId pTmr )244 epicsTimerQueueDestroyTimer (
245 epicsTimerQueueId pQueue, epicsTimerId pTmr )
245{246{
246 pTmr->destroy ();247 delete pTmr;
247}248}
248249
249extern "C" void epicsShareAPI epicsTimerStartTime (250extern "C" unsigned epicsShareAPI
250 epicsTimerId pTmr, const epicsTimeStamp *pTime )251 epicsTimerStartTime (
252 epicsTimerId pTmr, const epicsTimeStamp *pTime )
251{253{
252 pTmr->start ( *pTmr, *pTime );254 return pTmr->start ( *pTime );
253}255}
254256
255extern "C" void epicsShareAPI epicsTimerStartDelay (257extern "C" unsigned epicsShareAPI
256 epicsTimerId pTmr, double delaySeconds )258 epicsTimerStartDelay (
259 epicsTimerId pTmr, double delaySeconds )
257{260{
258 pTmr->start ( *pTmr, delaySeconds );261 return pTmr->start ( delaySeconds );
259}262}
260263
261extern "C" void epicsShareAPI epicsTimerCancel ( epicsTimerId pTmr )264extern "C" int epicsShareAPI
265 epicsTimerCancel ( epicsTimerId pTmr )
262{266{
263 pTmr->cancel ();267 return pTmr->cancel ();
264}268}
265269
266extern "C" double epicsShareAPI epicsTimerGetExpireDelay ( epicsTimerId pTmr )270extern "C" double epicsShareAPI
271 epicsTimerGetExpireDelay ( epicsTimerId pTmr )
267{272{
268 return pTmr->getExpireDelay ();273 return pTmr->getExpireDelay ();
269}274}
270275
271extern "C" void epicsShareAPI epicsTimerShow (276extern "C" void epicsShareAPI
272 epicsTimerId pTmr, unsigned int level )277 epicsTimerShow ( epicsTimerId pTmr, unsigned int level )
273{278{
274 pTmr->timer::show ( level );279 pTmr->show ( level );
275}280}
276281
diff --git a/modules/libcom/src/timer/epicsTimer.h b/modules/libcom/src/timer/epicsTimer.h
index 72270f2..45c6b29 100644
--- a/modules/libcom/src/timer/epicsTimer.h
+++ b/modules/libcom/src/timer/epicsTimer.h
@@ -1,11 +1,12 @@
1/*************************************************************************\1/*************************************************************************\
2* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
3* National Laboratory
2* Copyright (c) 2002 The University of Chicago, as Operator of Argonne4* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3* National Laboratory.5* National Laboratory.
4* Copyright (c) 2002 The Regents of the University of California, as6* Copyright (c) 2002 The Regents of the University of California, as
5* Operator of Los Alamos National Laboratory.7* Operator of Los Alamos National Laboratory.
6* EPICS BASE Versions 3.13.78* EPICS BASE is distributed subject to a Software License Agreement found
7* and higher are distributed subject to a Software License Agreement found9* in file LICENSE that is included with this distribution.
8* in file LICENSE that is included with this distribution.
9\*************************************************************************/10\*************************************************************************/
10/* epicsTimer.h */11/* epicsTimer.h */
1112
@@ -14,50 +15,80 @@
14#ifndef epicsTimerH15#ifndef epicsTimerH
15#define epicsTimerH16#define epicsTimerH
1617
17#include <float.h>
18
19#include "shareLib.h"
20#include "epicsTime.h"18#include "epicsTime.h"
21#include "epicsThread.h"19#include "epicsThread.h"
20#include "shareLib.h"
2221
23#ifdef __cplusplus22#ifdef __cplusplus
2423
24#include <cfloat>
25
25/*26/*
26 * Notes:27 * Notes:
27 * 1) epicsTimer does not hold its lock when calling callbacks.28 * 1) The timer queue process method does not hold the timer
29 * queue lock when calling callbacks, to avoid deadlocks.
30 *
31 * 2) The timer start method has three different possible outcomes
32 *
33 * 2a) If start is called and the timer isnt pending in the timer
34 * queue, and the timer callback isnt currently being orchestrated,
35 * then the timer is schedualed in the queue and start returns
36 * 1u, indicating that the timer callback will run once as a
37 * direct consequence of this invocation of start.
38 *
39 * 2b) If start is called and the timer is already pending in
40 * the timer queue, then the timer is reschedualed back into
41 * a new positon in the queue and start returns 0u. The
42 * timer callback will run once as a reschedualed (postponed)
43 * consequence of a previous invocation of start, but zero
44 * times as a direct consequence of this call to start.
45 *
46 * 2c) If start is called and the timer isnt pending in the timer
47 * queue, but the timer callback _is_ currently being orchestrated
48 * then it is reschedualed in the queue for a new expiration
49 * time, and start returns 1u. The timer callback will run twice.
50 * Once as a consequence of this invocation of start, and once
51 * as a consequence of a previous call to start.
52 *
53 * 3) Cancel returns true if the timer was pending in the queue
54 * when cancel was called, and false otherwise.
28 */55 */
2956
30/* code using a timer must implement epicsTimerNotify */57/* code using a timer must implement epicsTimerNotify */
31class epicsShareClass epicsTimerNotify {58class epicsShareClass epicsTimerNotify {
32public:59public:
33 enum restart_t { noRestart, restart };60 enum restart_t { noRestart, restart };
34 class expireStatus {61 class epicsShareClass expireStatus {
35 public:62 public:
36 epicsShareFunc expireStatus ( restart_t );63 expireStatus ( restart_t );
37 epicsShareFunc expireStatus ( restart_t, const double & expireDelaySec );64 expireStatus ( restart_t, const double & expireDelaySec );
38 epicsShareFunc bool restart () const;65 bool restart () const;
39 epicsShareFunc double expirationDelay () const;66 double expirationDelay () const;
40 private:67 private:
41 double delay;68 double m_delay;
42 };69 };
4370
44 virtual ~epicsTimerNotify () = 0;
45 /* return "noRestart" or "expireStatus ( restart, 30.0 )" */71 /* return "noRestart" or "expireStatus ( restart, 30.0 )" */
46 virtual expireStatus expire ( const epicsTime & currentTime ) = 0;72 virtual expireStatus expire ( const epicsTime & currentTime ) = 0;
47 virtual void show ( unsigned int level ) const;73 virtual void show ( unsigned int level ) const;
74protected:
75 virtual ~epicsTimerNotify () {} // protected disables delete through intf
48};76};
4977
50class epicsShareClass epicsTimer {78class epicsShareClass epicsTimer {
51public:79public:
52 /* calls cancel (see warning below) and then destroys the timer */80 /* calls cancel (see warning below) and then destroys the timer */
53 virtual void destroy () = 0;81 virtual void destroy () = 0;
54 virtual void start ( epicsTimerNotify &, const epicsTime & ) = 0;82 /* see note 2 above for the significance of the return value */
55 virtual void start ( epicsTimerNotify &, double delaySeconds ) = 0;83 virtual unsigned start ( epicsTimerNotify &, const epicsTime & ) = 0;
56 /* WARNING: A deadlock will occur if you hold a lock while84 virtual unsigned start ( epicsTimerNotify &, double delaySeconds ) = 0;
85 /* see note 3 for the significance of the return value
86 *
87 * WARNING: A deadlock will occur if you hold a lock while
57 * calling this function that you also take within the timer 88 * calling this function that you also take within the timer
58 * expiration callback.89 * expiration callback.
59 */90 */
60 virtual void cancel () = 0;91 virtual bool cancel () = 0;
61 struct expireInfo {92 struct expireInfo {
62 expireInfo ( bool active, const epicsTime & expireTime );93 expireInfo ( bool active, const epicsTime & expireTime );
63 bool active;94 bool active;
@@ -67,7 +98,7 @@ public:
67 double getExpireDelay ();98 double getExpireDelay ();
68 virtual void show ( unsigned int level ) const = 0;99 virtual void show ( unsigned int level ) const = 0;
69protected:100protected:
70 virtual ~epicsTimer () = 0; /* protected => delete() must not be called */101 virtual ~epicsTimer () = 0; /* disable delete */
71};102};
72103
73class epicsTimerQueue {104class epicsTimerQueue {
@@ -75,7 +106,7 @@ public:
75 virtual epicsTimer & createTimer () = 0;106 virtual epicsTimer & createTimer () = 0;
76 virtual void show ( unsigned int level ) const = 0;107 virtual void show ( unsigned int level ) const = 0;
77protected:108protected:
78 epicsShareFunc virtual ~epicsTimerQueue () = 0;109 virtual ~epicsTimerQueue () {} /* disable delete */
79};110};
80111
81class epicsTimerQueueActive112class epicsTimerQueueActive
@@ -85,7 +116,7 @@ public:
85 bool okToShare, unsigned threadPriority = epicsThreadPriorityMin + 10 );116 bool okToShare, unsigned threadPriority = epicsThreadPriorityMin + 10 );
86 virtual void release () = 0; 117 virtual void release () = 0;
87protected:118protected:
88 epicsShareFunc virtual ~epicsTimerQueueActive () = 0;119 virtual ~epicsTimerQueueActive () {} /* disable delete */
89};120};
90121
91class epicsTimerQueueNotify {122class epicsTimerQueueNotify {
@@ -93,18 +124,14 @@ public:
93 /* called when a new timer is inserted into the queue and the */124 /* called when a new timer is inserted into the queue and the */
94 /* delay to the next expire has changed */125 /* delay to the next expire has changed */
95 virtual void reschedule () = 0;126 virtual void reschedule () = 0;
96 /* if there is a quantum in the scheduling of timer intervals */
97 /* return this quantum in seconds. If unknown then return zero. */
98 virtual double quantum () = 0;
99protected:127protected:
100 epicsShareFunc virtual ~epicsTimerQueueNotify () = 0;128 virtual ~epicsTimerQueueNotify () {} /* disable delete */
101};129};
102130
103class epicsTimerQueuePassive131class epicsTimerQueuePassive : public epicsTimerQueue {
104 : public epicsTimerQueue {
105public:132public:
106 static epicsShareFunc epicsTimerQueuePassive & create ( epicsTimerQueueNotify & );133 static epicsShareFunc epicsTimerQueuePassive & create ( epicsTimerQueueNotify & );
107 epicsShareFunc virtual ~epicsTimerQueuePassive () = 0; /* ok to call delete */134 virtual ~epicsTimerQueuePassive () {} /* ok to call delete */
108 virtual double process ( const epicsTime & currentTime ) = 0; /* returns delay to next expire */135 virtual double process ( const epicsTime & currentTime ) = 0; /* returns delay to next expire */
109};136};
110137
@@ -114,11 +141,11 @@ inline epicsTimer::expireInfo::expireInfo ( bool activeIn,
114{141{
115}142}
116143
117inline double epicsTimer::getExpireDelay ()144inline double epicsTimer :: getExpireDelay ()
118{145{
119 epicsTimer::expireInfo info = this->getExpireInfo ();146 epicsTimer::expireInfo info = this->getExpireInfo ();
120 if ( info.active ) {147 if ( info.active ) {
121 double delay = info.expireTime - epicsTime::getCurrent ();148 double delay = info.expireTime - epicsTime :: getCurrent ();
122 if ( delay < 0.0 ) {149 if ( delay < 0.0 ) {
123 delay = 0.0;150 delay = 0.0;
124 }151 }
@@ -130,7 +157,7 @@ inline double epicsTimer::getExpireDelay ()
130extern "C" {157extern "C" {
131#endif /* __cplusplus */158#endif /* __cplusplus */
132159
133typedef struct epicsTimerForC * epicsTimerId;160typedef struct TimerForC * epicsTimerId;
134typedef void ( *epicsTimerCallback ) ( void *pPrivate );161typedef void ( *epicsTimerCallback ) ( void *pPrivate );
135162
136/* thread managed timer queue */163/* thread managed timer queue */
@@ -167,11 +194,11 @@ epicsShareFunc void epicsShareAPI
167 epicsTimerQueuePassiveShow ( epicsTimerQueuePassiveId id, unsigned int level );194 epicsTimerQueuePassiveShow ( epicsTimerQueuePassiveId id, unsigned int level );
168195
169/* timer */196/* timer */
170epicsShareFunc void epicsShareAPI 197epicsShareFunc unsigned epicsShareAPI
171 epicsTimerStartTime ( epicsTimerId id, const epicsTimeStamp *pTime );198 epicsTimerStartTime ( epicsTimerId id, const epicsTimeStamp *pTime );
172epicsShareFunc void epicsShareAPI 199epicsShareFunc unsigned epicsShareAPI
173 epicsTimerStartDelay ( epicsTimerId id, double delaySeconds );200 epicsTimerStartDelay ( epicsTimerId id, double delaySeconds );
174epicsShareFunc void epicsShareAPI 201epicsShareFunc int epicsShareAPI
175 epicsTimerCancel ( epicsTimerId id );202 epicsTimerCancel ( epicsTimerId id );
176epicsShareFunc double epicsShareAPI 203epicsShareFunc double epicsShareAPI
177 epicsTimerGetExpireDelay ( epicsTimerId id );204 epicsTimerGetExpireDelay ( epicsTimerId id );
diff --git a/modules/libcom/src/timer/timer.cpp b/modules/libcom/src/timer/timer.cpp
index 35d6e47..2c49f7e 100644
--- a/modules/libcom/src/timer/timer.cpp
+++ b/modules/libcom/src/timer/timer.cpp
@@ -1,11 +1,12 @@
1/*************************************************************************\1/*************************************************************************\
2* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
3* National Laboratory
2* Copyright (c) 2002 The University of Chicago, as Operator of Argonne4* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3* National Laboratory.5* National Laboratory.
4* Copyright (c) 2002 The Regents of the University of California, as6* Copyright (c) 2002 The Regents of the University of California, as
5* Operator of Los Alamos National Laboratory.7* Operator of Los Alamos National Laboratory.
6* EPICS BASE Versions 3.13.78* EPICS BASE is distributed subject to a Software License Agreement found
7* and higher are distributed subject to a Software License Agreement found9* in file LICENSE that is included with this distribution.
8* in file LICENSE that is included with this distribution.
9\*************************************************************************/10\*************************************************************************/
1011
11/*12/*
@@ -17,227 +18,226 @@
17#include <typeinfo>18#include <typeinfo>
18#include <string>19#include <string>
19#include <stdexcept>20#include <stdexcept>
20#include <stdio.h>21#include <cstdio>
2122
22#define epicsExportSharedSymbols23#define epicsExportSharedSymbols
23#include "epicsGuard.h"
24#include "timerPrivate.h"24#include "timerPrivate.h"
25#include "errlog.h"25#include "errlog.h"
2626
27#ifdef _MSC_VER27Timer :: Timer ( timerQueue & queueIn ) :
28# pragma warning ( push )28 m_queue ( queueIn ),
29# pragma warning ( disable:4660 )29 m_curState ( stateLimbo ),
30#endif30 m_pNotify ( 0 ),
3131 m_index ( m_invalidIndex )
32template class tsFreeList < timer, 0x20 >;
33
34#ifdef _MSC_VER
35# pragma warning ( pop )
36#endif
37
38timer::timer ( timerQueue & queueIn ) :
39 queue ( queueIn ), curState ( stateLimbo ), pNotify ( 0 )
40{32{
41}33}
4234
43timer::~timer ()35Timer :: ~Timer ()
44{36{
45 this->cancel ();37 M_CancelStatus cs = { false, false };
38 {
39 Guard guard ( m_queue );
40 cs = m_cancelPvt ( guard );
41 m_queue.m_numTimers--;
42 }
43 // we are careful to wakeup the timer queue thread after
44 // we nolonger hold the lock
45 if ( cs.reschedule ) {
46 m_queue.m_notify.reschedule ();
47 }
46}48}
4749
48void timer::destroy () 50void Timer :: destroy ()
49{51{
50 timerQueue & queueTmp = this->queue;52 delete this;
51 this->~timer ();
52 queueTmp.timerFreeList.release ( this );
53}53}
5454
55void timer::start ( epicsTimerNotify & notify, double delaySeconds )55unsigned Timer :: start ( epicsTimerNotify & notify, double delaySeconds )
56{56{
57 this->start ( notify, epicsTime::getCurrent () + delaySeconds );57 const epicsTime current = epicsTime :: getCurrent ();
58 const epicsTime exp = current + delaySeconds;
59 const Timer :: M_StartReturn sr = m_privateStart ( notify, exp );
60 // we are careful to wakeup the timer queue thread after
61 // we nolonger hold the lock
62 if ( sr.resched ) {
63 m_queue.m_notify.reschedule ();
64 }
65 return sr.numNew;
58}66}
5967
60void timer::start ( epicsTimerNotify & notify, const epicsTime & expire )68unsigned Timer :: start ( epicsTimerNotify & notify,
69 const epicsTime & expire )
61{70{
62 epicsGuard < epicsMutex > locker ( this->queue.mutex );71 Timer :: M_StartReturn sr = m_privateStart ( notify, expire );
63 this->privateStart ( notify, expire );72 // we are careful to wakeup the timer queue thread after
73 // we nolonger hold the lock
74 if ( sr.resched ) {
75 m_queue.m_notify.reschedule ();
76 }
77 return sr.numNew;
64}78}
6579
66void timer::privateStart ( epicsTimerNotify & notify, const epicsTime & expire )80Timer :: M_StartReturn
81 Timer :: m_privateStart ( epicsTimerNotify & notify,
82 const epicsTime & expire )
67{83{
68 this->pNotify = & notify;84 Timer :: M_StartReturn sr;
69 this->exp = expire - ( this->queue.notify.quantum () / 2.0 );85 Guard locker ( m_queue );
7086 m_pNotify = & notify;
71 bool reschedualNeeded = false;87 if ( m_curState == statePending ) {
72 if ( this->curState == stateActive ) {88 const epicsTime oldExp = m_queue.m_heap.front ()->m_exp;
73 // above expire time and notify will override any restart parameters89 m_exp = expire;
74 // that may be returned from the timer expire callback90 if ( ! m_queue.m_fixParent ( m_index ) ) {
75 return;91 m_queue.m_fixChildren ( m_index );
76 }92 }
77 else if ( this->curState == statePending ) {93 if ( m_queue.m_pExpTmr == this ) {
78 this->queue.timerList.remove ( *this );94 // new expire time and notify will override
79 if ( this->queue.timerList.first() == this && 95 // any restart parameters that may be returned
80 this->queue.timerList.count() > 0 ) {96 // from the timer expire callback
81 reschedualNeeded = true;97 sr.numNew = 1u;
98 sr.resched = false;
99 }
100 else {
101 sr.numNew = 0u;
102 sr.resched = ( oldExp > m_queue.m_heap.front ()->m_exp );
82 }103 }
83 }104 }
84105 else {
85# ifdef DEBUG106 sr.numNew = 1u;
86 unsigned preemptCount=0u;107 m_curState = Timer :: statePending;
87# endif108 m_index = m_queue.m_heap.size ();
88109 if ( m_index > 0u ) {
89 //110 const epicsTime oldExp = m_queue.m_heap.front ()->m_exp;
90 // insert into the pending queue111 m_exp = expire;
91 //112 m_queue.m_heap.push_back ( this );
92 // Finds proper time sorted location using a linear search.113 m_queue.m_fixParent ( m_index );
93 //114 sr.resched = ( oldExp > m_queue.m_heap.front ()->m_exp );
94 // **** this should use a binary tree ????
95 //
96 tsDLIter < timer > pTmr = this->queue.timerList.lastIter ();
97 while ( true ) {
98 if ( ! pTmr.valid () ) {
99 //
100 // add to the beginning of the list
101 //
102 this->queue.timerList.push ( *this );
103 reschedualNeeded = true;
104 break;
105 }115 }
106 if ( pTmr->exp <= this->exp ) {116 else {
107 //117 m_exp = expire;
108 // add after the item found that expires earlier118 m_queue.m_heap.push_back ( this );
109 //119 sr.resched = true;
110 this->queue.timerList.insertAfter ( *this, *pTmr );
111 break;
112 }120 }
113# ifdef DEBUG
114 preemptCount++;
115# endif
116 --pTmr;
117 }121 }
122 debugPrintf ( ("Start of \"%s\" with delay %f at %p\n",
123 m_pNotify ?
124 typeid ( *m_pNotify ).name () :
125 typeid ( m_pNotify ).name (),
126 m_exp - epicsTime :: getCurrent (),
127 this ) );
128 return sr;
129}
118130
119 this->curState = timer::statePending;131void Timer :: m_remove ( Guard & guard )
120132{
121 if ( reschedualNeeded ) {133 Timer * const pMoved = m_queue.m_heap.back ();
122 this->queue.notify.reschedule ();134 m_queue.m_heap.pop_back ();
123 }135 if ( m_index != m_queue.m_heap.size () ) {
124 136 const size_t oldIndex = m_index;
125# if defined(DEBUG) && 0137 m_queue.m_heap[oldIndex] = pMoved;
126 this->show ( 10u );138 pMoved->m_index = oldIndex;
127 this->queue.show ( 10u );139 if ( ! m_queue.m_fixParent ( oldIndex ) ) {
128# endif140 m_queue.m_fixChildren ( oldIndex );
129141 }
130 debugPrintf ( ("Start of \"%s\" with delay %f at %p preempting %u\n", 142 }
131 typeid ( this->notify ).name (), 143 m_index = m_invalidIndex;
132 expire - epicsTime::getCurrent (), 144 m_curState = stateLimbo;
133 this, preemptCount ) );
134}145}
135146
136void timer::cancel ()147bool Timer :: cancel ()
137{148{
138 bool reschedual = false;149 M_CancelStatus cs = { false, false };
139 bool wakeupCancelBlockingThreads = false;
140 {150 {
141 epicsGuard < epicsMutex > locker ( this->queue.mutex );151 Guard guard ( m_queue );
142 this->pNotify = 0;152 cs = m_cancelPvt ( guard );
143 if ( this->curState == statePending ) {153 }
144 this->queue.timerList.remove ( *this );154 // we are careful to wakeup the timer queue thread after
145 this->curState = stateLimbo;155 // we nolonger hold the lock
146 if ( this->queue.timerList.first() == this && 156 if ( cs.reschedule ) {
147 this->queue.timerList.count() > 0 ) {157 m_queue.m_notify.reschedule ();
148 reschedual = true;158 }
149 }159 return cs.wasPending;
150 }160}
151 else if ( this->curState == stateActive ) {161
152 this->queue.cancelPending = true;162Timer :: M_CancelStatus Timer :: m_cancelPvt ( Guard & gd )
153 this->curState = timer::stateLimbo;163{
154 if ( this->queue.processThread != epicsThreadGetIdSelf() ) {164 gd.assertIdenticalMutex ( m_queue );
155 // make certain timer expire() does not run after cancel () returns,165 M_CancelStatus cs = { false, false };
156 // but dont require that lock is applied while calling expire()166 Guard guard ( m_queue );
157 while ( this->queue.cancelPending && 167 if ( m_curState == statePending ) {
158 this->queue.pExpireTmr == this ) {168 const epicsTime oldExp = m_queue.m_heap.front ()->m_exp;
159 epicsGuardRelease < epicsMutex > autoRelease ( locker );169 m_remove ( guard );
160 this->queue.cancelBlockingEvent.wait ();170 m_queue.m_cancelPending = ( m_queue.m_pExpTmr == this );
171 if ( m_queue.m_cancelPending ) {
172 if ( m_queue.m_processThread != epicsThreadGetIdSelf() ) {
173 // 1) make certain timer expire cllback does not run
174 // after this cancel method returns
175 // 2) dont require that lock is applied while calling
176 // expire callback
177 // 3) assume that timer could be deleted in its
178 // expire callback so we dont touch this after lock
179 // is released
180 timerQueue & queue = m_queue;
181 while ( queue.m_cancelPending &&
182 queue.m_pExpTmr == this ) {
183 GuardRelease unguard ( guard );
184 queue.m_cancelBlockingEvent.wait ();
161 }185 }
162 // in case other threads are waiting186 // in case other threads are waiting
163 wakeupCancelBlockingThreads = true;187 queue.m_cancelBlockingEvent.signal ();
188 }
189 }
190 else {
191 cs.wasPending = true;
192 if ( oldExp > m_queue.m_heap.front ()->m_exp ) {
193 cs.reschedule = true;
164 }194 }
165 }195 }
166 }196 }
167 if ( reschedual ) {197 return cs;
168 this->queue.notify.reschedule ();
169 }
170 if ( wakeupCancelBlockingThreads ) {
171 this->queue.cancelBlockingEvent.signal ();
172 }
173}198}
174199
175epicsTimer::expireInfo timer::getExpireInfo () const200epicsTimer :: expireInfo Timer :: getExpireInfo () const
176{201{
177 // taking a lock here guarantees that users will not 202 // taking a lock here guarantees that users will not
178 // see brief intervals when a timer isnt active because203 // see brief intervals when a timer isnt active because
179 // it is is canceled when start is called204 // it is is canceled when start is called
180 epicsGuard < epicsMutex > locker ( this->queue.mutex );205 Guard locker ( m_queue );
181 if ( this->curState == statePending || this->curState == stateActive ) {206 if ( m_curState == statePending ) {
182 return expireInfo ( true, this->exp );207 return expireInfo ( true, m_exp );
183 }208 }
184 return expireInfo ( false, epicsTime() );209 return expireInfo ( false, epicsTime() );
185}210}
186211
187void timer::show ( unsigned int level ) const212void Timer :: show ( unsigned int level ) const
188{213{
189 epicsGuard < epicsMutex > locker ( this->queue.mutex );214 Guard locker ( m_queue );
190 double delay;215 double delay;
191 if ( this->curState == statePending || this->curState == stateActive ) {216 if ( m_curState == statePending ) {
192 try {217 try {
193 delay = this->exp - epicsTime::getCurrent();218 delay = m_exp - epicsTime :: getCurrent ();
194 }219 }
195 catch ( ... ) {220 catch ( ... ) {
196 delay = - DBL_MAX;221 delay = -DBL_MAX;
197 }222 }
198 }223 }
199 else {224 else {
200 delay = -DBL_MAX;225 delay = -DBL_MAX;
201 }226 }
202 const char *pStateName;227 const char *pStateName;
203 if ( this->curState == statePending ) {228 if ( m_curState == statePending ) {
204 pStateName = "pending";229 pStateName = "pending";
205 }230 }
206 else if ( this->curState == stateActive ) {231 else if ( m_curState == stateLimbo ) {
207 pStateName = "active";
208 }
209 else if ( this->curState == stateLimbo ) {
210 pStateName = "limbo";232 pStateName = "limbo";
211 }233 }
212 else {234 else {
213 pStateName = "corrupt";235 pStateName = "corrupt";
214 }236 }
215 printf ( "timer, state = %s, delay = %f\n",237 printf ( "Timer, state = %s, index = %lu, delay = %f\n",
216 pStateName, delay );238 pStateName, (unsigned long ) m_index, delay );
217 if ( level >= 1u && this->pNotify ) {239 if ( level >= 1u && m_pNotify ) {
218 this->pNotify->show ( level - 1u );240 m_pNotify->show ( level - 1u );
219 }241 }
220}242}
221243
222void timer::operator delete ( void * )
223{
224 // Visual C++ .net appears to require operator delete if
225 // placement operator delete is defined? I smell a ms rat
226 // because if I declare placement new and delete, but
227 // comment out the placement delete definition there are
228 // no undefined symbols.
229 errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
230 __FILE__, __LINE__ );
231}
232
233void epicsTimerForC::operator delete ( void * )
234{
235 // Visual C++ .net appears to require operator delete if
236 // placement operator delete is defined? I smell a ms rat
237 // because if I declare placement new and delete, but
238 // comment out the placement delete definition there are
239 // no undefined symbols.
240 errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
241 __FILE__, __LINE__ );
242}
243
diff --git a/modules/libcom/src/timer/timerPrivate.h b/modules/libcom/src/timer/timerPrivate.h
index 259afae..8ca0e67 100644
--- a/modules/libcom/src/timer/timerPrivate.h
+++ b/modules/libcom/src/timer/timerPrivate.h
@@ -1,5 +1,7 @@
1/*************************************************************************\1/*************************************************************************\
2* Copyright (c) 2015 UChicago Argonne LLC, as Operator of Argonne2* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
3* National Laboratory
4* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3* National Laboratory.5* National Laboratory.
4* Copyright (c) 2002 The Regents of the University of California, as6* Copyright (c) 2002 The Regents of the University of California, as
5* Operator of Los Alamos National Laboratory.7* Operator of Los Alamos National Laboratory.
@@ -7,6 +9,7 @@
7* in file LICENSE that is included with this distribution.9* in file LICENSE that is included with this distribution.
8\*************************************************************************/10\*************************************************************************/
9/*11/*
12 *
10 * Author Jeffrey O. Hill13 * Author Jeffrey O. Hill
11 * johill@lanl.gov14 * johill@lanl.gov
12 * 505 665 183115 * 505 665 1831
@@ -16,12 +19,15 @@
16#define epicsTimerPrivate_h19#define epicsTimerPrivate_h
1720
18#include <typeinfo>21#include <typeinfo>
22#include <vector>
1923
20#include "tsFreeList.h"
21#include "epicsSingleton.h"
22#include "tsDLList.h"24#include "tsDLList.h"
23#include "epicsTimer.h"25#include "epicsTimer.h"
26#include "epicsMutex.h"
27#include "epicsGuard.h"
24#include "compilerDependencies.h"28#include "compilerDependencies.h"
29#include "epicsStaticInstance.h"
30#include "AllocatorArena.h"
2531
26#ifdef DEBUG32#ifdef DEBUG
27# define debugPrintf(ARGSINPAREN) printf ARGSINPAREN33# define debugPrintf(ARGSINPAREN) printf ARGSINPAREN
@@ -29,90 +35,130 @@
29# define debugPrintf(ARGSINPAREN)35# define debugPrintf(ARGSINPAREN)
30#endif36#endif
3137
32template < class T > class epicsGuard;38using std :: type_info;
39
40class Timer;
41class timerQueue;
3342
34class timer : public epicsTimer, public tsDLNode < timer > {43bool operator < ( const Timer &, const Timer & );
44bool operator > ( const Timer &, const Timer & );
45bool operator <= ( const Timer &, const Timer & );
46bool operator >= ( const Timer &, const Timer & );
47
48class Timer : public epicsTimer {
35public:49public:
50 typedef epicsMutex Mutex;
51 typedef epicsGuard < Mutex > Guard;
52 typedef epicsGuardRelease < Mutex > GuardRelease;
53 Timer ( timerQueue & );
54 ~Timer ();
36 void destroy ();55 void destroy ();
37 void start ( class epicsTimerNotify &, const epicsTime & );56 unsigned start ( class epicsTimerNotify &, const epicsTime & );
38 void start ( class epicsTimerNotify &, double delaySeconds );57 unsigned start ( class epicsTimerNotify &, double delaySeconds );
39 void cancel ();58 bool cancel ();
40 expireInfo getExpireInfo () const;59 expireInfo getExpireInfo () const;
60 double getExpireDelay ( const epicsTime & currentTime );
41 void show ( unsigned int level ) const;61 void show ( unsigned int level ) const;
42 void * operator new ( size_t size, tsFreeList < timer, 0x20 > & );62 static void * operator new ( size_t sz );
43 epicsPlacementDeleteOperator (( void *, tsFreeList < timer, 0x20 > & ))63 static void operator delete ( void * ptr, size_t sz );
44protected:64protected:
45 timer ( class timerQueue & );65 timerQueue & m_queue;
46 ~timer ();
47 timerQueue & queue;
48private:66private:
49 enum state { statePending = 45, stateActive = 56, stateLimbo = 78 };67 typedef epics :: AllocatorArena < Timer, timerQueue, 16u > M_Allocator;
50 epicsTime exp; // experation time 68 enum state {
51 state curState; // current state 69 statePending = 45,
52 epicsTimerNotify * pNotify; // callback70 stateLimbo = 78 };
53 void privateStart ( epicsTimerNotify & notify, const epicsTime & );71 epicsTime m_exp; // experation time
54 timer & operator = ( const timer & );72 state m_curState; // current state
55 // Visual C++ .net appears to require operator delete if73 epicsTimerNotify * m_pNotify; // callback
56 // placement operator delete is defined? I smell a ms rat74 size_t m_index;
57 // because if I declare placement new and delete, but75 static const size_t m_invalidIndex =
58 // comment out the placement delete definition there are76 ~ static_cast < size_t > ( 0u );
59 // no undefined symbols.77 struct M_StartReturn {
60 void operator delete ( void * ); 78 unsigned numNew;
79 bool resched;
80 };
81 M_StartReturn m_privateStart ( epicsTimerNotify & notify,
82 const epicsTime & expire );
83 struct M_CancelStatus {
84 bool reschedule;
85 bool wasPending;
86 };
87 M_CancelStatus m_cancelPvt ( Guard & );
88 void m_remove ( Guard & guard );
89 Timer & operator = ( const Timer & );
61 friend class timerQueue;90 friend class timerQueue;
91 friend bool operator < ( const Timer &, const Timer & );
92 friend bool operator > ( const Timer &, const Timer & );
93 friend bool operator <= ( const Timer &, const Timer & );
94 friend bool operator >= ( const Timer &, const Timer & );
62};95};
6396
64struct epicsTimerForC : public epicsTimerNotify, public timer {97struct TimerForC : public epicsTimerNotify {
65public:98public:
66 void destroy ();99 typedef epicsMutex Mutex;
67protected:100 typedef epicsGuard < Mutex > Guard;
68 epicsTimerForC ( timerQueue &, epicsTimerCallback, void *pPrivateIn );101 TimerForC ( class timerQueue &, epicsTimerCallback, void * pPrivateIn );
69 ~epicsTimerForC (); 102 ~TimerForC ();
70 void * operator new ( size_t size, tsFreeList < epicsTimerForC, 0x20 > & );103 unsigned start ( const epicsTime & );
71 epicsPlacementDeleteOperator (( void *, tsFreeList < epicsTimerForC, 0x20 > & ))104 unsigned start ( double delaySeconds );
72private:105 bool cancel ();
73 epicsTimerCallback pCallBack;106 void show ( unsigned level ) const;
74 void * pPrivate;
75 expireStatus expire ( const epicsTime & currentTime );107 expireStatus expire ( const epicsTime & currentTime );
76 epicsTimerForC & operator = ( const epicsTimerForC & );108 double getExpireDelay ();
77 // Visual C++ .net appears to require operator delete if109 static void * operator new ( size_t sz );
78 // placement operator delete is defined? I smell a ms rat110 static void operator delete ( void * ptr, size_t sz );
79 // because if I declare placement new and delete, but111private:
80 // comment out the placement delete definition there are112 typedef epics :: AllocatorArena < TimerForC, timerQueue, 16u > M_Allocator;
81 // no undefined symbols.113 Timer * m_pTimer;
82 void operator delete ( void * ); 114 epicsTimerCallback m_pCallBack;
83 friend class timerQueue;115 void * m_pPrivate;
84};116 TimerForC & operator = ( const TimerForC & );
85117};
86using std :: type_info;
87118
88class timerQueue : public epicsTimerQueue {119class timerQueue :
120 public epicsTimerQueue,
121 public epicsMutex {
89public:122public:
123 typedef epicsMutex Mutex;
124 typedef epicsGuard < Mutex > Guard;
125 typedef epicsGuardRelease < Mutex > GuardRelease;
90 timerQueue ( epicsTimerQueueNotify &notify );126 timerQueue ( epicsTimerQueueNotify &notify );
91 virtual ~timerQueue ();127 virtual ~timerQueue ();
92 epicsTimer & createTimer ();128 epicsTimer & createTimer ();
93 epicsTimerForC & createTimerForC ( epicsTimerCallback pCallback, void *pArg );129 Timer & createTimerImpl ();
130 TimerForC & createTimerForC (
131 epicsTimerCallback pCallback, void *pArg );
94 double process ( const epicsTime & currentTime );132 double process ( const epicsTime & currentTime );
133 double process ( Guard &, const epicsTime & currentTime );
95 void show ( unsigned int level ) const;134 void show ( unsigned int level ) const;
135 void show ( Guard &, unsigned int level ) const;
96private:136private:
97 tsFreeList < timer, 0x20 > timerFreeList;137 epicsEvent m_cancelBlockingEvent;
98 tsFreeList < epicsTimerForC, 0x20 > timerForCFreeList;138 std :: vector < Timer * > m_heap;
99 mutable epicsMutex mutex;139 epicsTime m_exceptMsgTimeStamp;
100 epicsEvent cancelBlockingEvent;140 epicsTimerQueueNotify & m_notify;
101 tsDLList < timer > timerList;141 Timer * m_pExpTmr;
102 epicsTimerQueueNotify & notify;142 epicsThreadId m_processThread;
103 timer * pExpireTmr;143 size_t m_numTimers;
104 epicsThreadId processThread;144 bool m_cancelPending;
105 epicsTime exceptMsgTimeStamp;145 static const double m_exceptMsgMinPeriod;
106 bool cancelPending;
107 static const double exceptMsgMinPeriod;
108 void printExceptMsg ( const char * pName,
109 const type_info & type );
110 timerQueue ( const timerQueue & );146 timerQueue ( const timerQueue & );
111 timerQueue & operator = ( const timerQueue & );147 timerQueue & operator = ( const timerQueue & );
112 friend class timer;148 void m_printExceptMsg ( const char * pName, const type_info & type );
113 friend struct epicsTimerForC;149 bool m_fixParent ( size_t childIdx );
150 void m_fixChildren ( size_t parentIdx );
151 void m_swapEntries ( size_t idx0, size_t idx1 );
152 double m_expDelay ( const epicsTime & currentTime );
153 static size_t m_parent ( size_t childIdx );
154 static size_t m_leftChild ( size_t parentIdx );
155 static size_t m_rightChild ( size_t parentIdx );
156 friend class Timer;
157 friend struct TimerForC;
114};158};
115159
160class timerQueueActiveMgr;
161
116class timerQueueActiveMgrPrivate {162class timerQueueActiveMgrPrivate {
117public:163public:
118 timerQueueActiveMgrPrivate ();164 timerQueueActiveMgrPrivate ();
@@ -123,101 +169,95 @@ private:
123 friend class timerQueueActiveMgr;169 friend class timerQueueActiveMgr;
124};170};
125171
126class timerQueueActiveMgr;172class timerQueueActive :
127173 public epicsTimerQueueActive,
128class timerQueueActive : public epicsTimerQueueActive, 174 public epicsThreadRunable,
129 public epicsThreadRunable, public epicsTimerQueueNotify,175 public epicsTimerQueueNotify,
130 public timerQueueActiveMgrPrivate {176 public timerQueueActiveMgrPrivate {
131public:177public:
132 typedef epicsSingleton < timerQueueActiveMgr > :: reference RefMgr;178 timerQueueActive ( bool okToShare, unsigned priority );
133 timerQueueActive ( RefMgr &, bool okToShare, unsigned priority );
134 void start ();
135 epicsTimer & createTimer ();179 epicsTimer & createTimer ();
136 epicsTimerForC & createTimerForC ( epicsTimerCallback pCallback, void *pArg );180 TimerForC & createTimerForC (
181 epicsTimerCallback pCallback, void *pArg );
182 void run ();
183 void reschedule ();
184 epicsTimerQueue & getEpicsTimerQueue ();
137 void show ( unsigned int level ) const;185 void show ( unsigned int level ) const;
138 bool sharingOK () const;186 bool sharingOK () const;
139 unsigned threadPriority () const;187 unsigned threadPriority () const;
140protected:188protected:
141 ~timerQueueActive ();189 ~timerQueueActive ();
142 RefMgr _refMgr;
143private:190private:
144 timerQueue queue;191 typedef epicsMutex Mutex;
145 epicsEvent rescheduleEvent;192 typedef epicsGuard < Mutex > Guard;
146 epicsEvent exitEvent;193 typedef epicsGuardRelease < Mutex > GuardRelease;
147 epicsThread thread;194 timerQueue m_queue;
148 const double sleepQuantum;195 epicsEvent m_rescheduleEvent;
149 bool okToShare;196 epicsEvent m_exitEvent;
150 int exitFlag; // use atomic ops197 epicsThread m_thread;
151 bool terminateFlag;198 bool m_okToShare;
152 void run ();199 bool m_exitFlag;
153 void reschedule ();200 bool m_terminateFlag;
154 double quantum ();
155 void _printLastChanceExceptionMessage (
156 const char * pExceptionTypeName,
157 const char * pExceptionContext );
158 epicsTimerQueue & getEpicsTimerQueue ();
159 timerQueueActive ( const timerQueueActive & );201 timerQueueActive ( const timerQueueActive & );
160 timerQueueActive & operator = ( const timerQueueActive & );202 timerQueueActive & operator = ( const timerQueueActive & );
161};203};
162204
163class timerQueueActiveMgr {205class timerQueueActiveMgr {
164public:206public:
165 typedef epicsSingleton < timerQueueActiveMgr > :: reference RefThis;207 static timerQueueActiveMgr & master ();
166 timerQueueActiveMgr ();208 timerQueueActiveMgr ();
167 ~timerQueueActiveMgr ();209 ~timerQueueActiveMgr ();
168 epicsTimerQueueActiveForC & allocate ( RefThis &, bool okToShare, 210 epicsTimerQueueActiveForC & allocate ( bool okToShare,
169 unsigned threadPriority = epicsThreadPriorityMin + 10 );211 unsigned threadPriority = epicsThreadPriorityMin + 10 );
170 void release ( epicsTimerQueueActiveForC & );212 void release ( epicsTimerQueueActiveForC & );
171private:213private:
172 epicsMutex mutex;214 typedef epicsMutex Mutex;
173 tsDLList < epicsTimerQueueActiveForC > sharedQueueList;215 typedef epicsGuard < Mutex > Guard;
216 Mutex m_mutex;
217 tsDLList < epicsTimerQueueActiveForC > m_sharedQueueList;
174 timerQueueActiveMgr ( const timerQueueActiveMgr & );218 timerQueueActiveMgr ( const timerQueueActiveMgr & );
175 timerQueueActiveMgr & operator = ( const timerQueueActiveMgr & );219 timerQueueActiveMgr & operator = ( const timerQueueActiveMgr & );
176};220};
177221
178extern epicsSingleton < timerQueueActiveMgr > timerQueueMgrEPICS;
179
180class timerQueuePassive : public epicsTimerQueuePassive {222class timerQueuePassive : public epicsTimerQueuePassive {
181public:223public:
182 timerQueuePassive ( epicsTimerQueueNotify & );224 timerQueuePassive ( epicsTimerQueueNotify & );
183 epicsTimer & createTimer ();225 epicsTimer & createTimer ();
184 epicsTimerForC & createTimerForC ( epicsTimerCallback pCallback, void *pArg );226 TimerForC & createTimerForC (
227 epicsTimerCallback pCallback, void *pArg );
185 void show ( unsigned int level ) const;228 void show ( unsigned int level ) const;
186 double process ( const epicsTime & currentTime );229 double process ( const epicsTime & currentTime );
230 epicsTimerQueue & getEpicsTimerQueue ();
187protected:231protected:
188 timerQueue queue;232 timerQueue m_queue;
189 ~timerQueuePassive ();233 ~timerQueuePassive ();
190 epicsTimerQueue & getEpicsTimerQueue ();
191 timerQueuePassive ( const timerQueuePassive & );234 timerQueuePassive ( const timerQueuePassive & );
192 timerQueuePassive & operator = ( const timerQueuePassive & );235 timerQueuePassive & operator = ( const timerQueuePassive & );
193};236};
194237
195struct epicsTimerQueuePassiveForC : 238struct epicsTimerQueuePassiveForC :
196 public epicsTimerQueueNotify, public timerQueuePassive {239 public epicsTimerQueueNotify,
240 public timerQueuePassive {
197public:241public:
198 epicsTimerQueuePassiveForC ( 242 epicsTimerQueuePassiveForC (
199 epicsTimerQueueNotifyReschedule, 243 epicsTimerQueueNotifyReschedule,
200 epicsTimerQueueNotifyQuantum,244 epicsTimerQueueNotifyQuantum,
201 void * pPrivate );245 void * pPrivate );
202 void destroy ();246 void destroy ();
247 void reschedule ();
203protected:248protected:
204 ~epicsTimerQueuePassiveForC ();249 ~epicsTimerQueuePassiveForC ();
205private:250private:
206 epicsTimerQueueNotifyReschedule pRescheduleCallback;251 epicsTimerQueueNotifyReschedule m_pRescheduleCallback;
207 epicsTimerQueueNotifyQuantum pSleepQuantumCallback;252 epicsTimerQueueNotifyQuantum m_pSleepQuantumCallback;
208 void * pPrivate;253 void * m_pPrivate;
209 static epicsSingleton < tsFreeList < epicsTimerQueuePassiveForC, 0x10 > > pFreeList;
210 void reschedule ();
211 double quantum ();
212};254};
213255
214struct epicsTimerQueueActiveForC : public timerQueueActive, 256struct epicsTimerQueueActiveForC : public timerQueueActive,
215 public tsDLNode < epicsTimerQueueActiveForC > {257 public tsDLNode < epicsTimerQueueActiveForC > {
216public:258public:
217 epicsTimerQueueActiveForC ( RefMgr &, bool okToShare, unsigned priority );259 epicsTimerQueueActiveForC ( bool okToShare, unsigned priority );
218 void release ();260 void release ();
219 void * operator new ( size_t );
220 void operator delete ( void * );
221protected:261protected:
222 virtual ~epicsTimerQueueActiveForC ();262 virtual ~epicsTimerQueueActiveForC ();
223private:263private:
@@ -225,52 +265,106 @@ private:
225 epicsTimerQueueActiveForC & operator = ( const epicsTimerQueueActiveForC & );265 epicsTimerQueueActiveForC & operator = ( const epicsTimerQueueActiveForC & );
226};266};
227267
228inline bool timerQueueActive::sharingOK () const268inline double Timer :: getExpireDelay ( const epicsTime & currentTime )
269{
270 return m_exp - currentTime;
271}
272
273inline void * Timer :: operator new ( size_t sz )
274{
275 return M_Allocator :: allocateOctets ( sz );
276}
277
278inline void Timer :: operator delete ( void * p, size_t sz )
229{279{
230 return this->okToShare;280 M_Allocator :: deallocateOctets ( p, sz );
281}
282
283inline bool operator < ( const Timer & lhs, const Timer & rhs )
284{
285 return lhs.m_exp < rhs.m_exp;
286}
287
288inline bool operator > ( const Timer & lhs, const Timer & rhs )
289{
290 return rhs < lhs;
291}
292
293inline bool operator <= ( const Timer & lhs, const Timer & rhs )
294{
295 return ! ( lhs > rhs );
231}296}
232297
233inline unsigned timerQueueActive::threadPriority () const298inline bool operator >= ( const Timer & lhs, const Timer & rhs )
299{
300 return ! ( lhs < rhs );
301}
302
303inline size_t timerQueue :: m_parent ( const size_t childIdx )
234{304{
235 return thread.getPriority ();305 return ( childIdx + ( childIdx & 1u ) ) / 2u - 1u;
236}306}
237307
238inline void * timer::operator new ( size_t size, 308inline size_t timerQueue :: m_leftChild ( const size_t parentIdx )
239 tsFreeList < timer, 0x20 > & freeList )
240{309{
241 return freeList.allocate ( size );310 return ( parentIdx + 1u ) * 2u - 1u;
242}311}
243312
244#ifdef CXX_PLACEMENT_DELETE313inline size_t timerQueue :: m_rightChild ( const size_t parentIdx )
245inline void timer::operator delete ( void * pCadaver,
246 tsFreeList < timer, 0x20 > & freeList )
247{314{
248 freeList.release ( pCadaver );315 return ( parentIdx + 1u ) * 2u;
249}316}
250#endif
251317
252inline void * epicsTimerForC::operator new ( size_t size,318inline void timerQueue :: m_swapEntries ( size_t idx0, size_t idx1 )
253 tsFreeList < epicsTimerForC, 0x20 > & freeList )
254{319{
255 return freeList.allocate ( size );320 std :: swap ( m_heap[idx0], m_heap[idx1] );
321 m_heap[idx0]->m_index = idx0;
322 m_heap[idx1]->m_index = idx1;
256}323}
257324
258#ifdef CXX_PLACEMENT_DELETE325inline bool timerQueueActive :: sharingOK () const
259inline void epicsTimerForC::operator delete ( void * pCadaver,
260 tsFreeList < epicsTimerForC, 0x20 > & freeList )
261{326{
262 freeList.release ( pCadaver );327 return m_okToShare;
328}
329
330inline unsigned timerQueueActive :: threadPriority () const
331{
332 return m_thread.getPriority ();
333}
334
335inline unsigned TimerForC :: start ( const epicsTime & expTime )
336{
337 return m_pTimer->start ( *this, expTime );
338}
339
340inline unsigned TimerForC :: start ( double delaySeconds )
341{
342 return m_pTimer->start ( *this, delaySeconds );
343}
344
345inline bool TimerForC :: cancel ()
346{
347 return m_pTimer->cancel ();
348}
349
350inline double TimerForC :: getExpireDelay ()
351{
352 return m_pTimer->getExpireDelay ( epicsTime :: getCurrent () );
353}
354
355inline void * TimerForC :: operator new ( size_t sz )
356{
357 return M_Allocator :: allocateOctets ( sz );
263}358}
264#endif
265359
266inline void * epicsTimerQueueActiveForC::operator new ( size_t size )360inline void TimerForC :: operator delete ( void * p, size_t sz )
267{361{
268 return ::operator new ( size );362 M_Allocator :: deallocateOctets ( p, sz );
269}363}
270364
271inline void epicsTimerQueueActiveForC::operator delete ( void * pCadaver )365inline timerQueueActiveMgr & timerQueueActiveMgr :: master ()
272{366{
273 ::operator delete ( pCadaver );367 return epics :: staticInstance < timerQueueActiveMgr > ();
274}368}
275369
276#endif // epicsTimerPrivate_h370#endif // epicsTimerPrivate_h
diff --git a/modules/libcom/src/timer/timerQueue.cpp b/modules/libcom/src/timer/timerQueue.cpp
index 8f7f98e..5948941 100644
--- a/modules/libcom/src/timer/timerQueue.cpp
+++ b/modules/libcom/src/timer/timerQueue.cpp
@@ -1,4 +1,6 @@
1/*************************************************************************\1/*************************************************************************\
2* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
3* National Laboratory
2* Copyright (c) 2002 The University of Chicago, as Operator of Argonne4* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3* National Laboratory.5* National Laboratory.
4* Copyright (c) 2002 The Regents of the University of California, as6* Copyright (c) 2002 The Regents of the University of California, as
@@ -12,56 +14,45 @@
12 * 505 665 183114 * 505 665 1831
13 */15 */
1416
15#include <stdio.h>17#include <cstdio>
16#include <float.h>
1718
18#define epicsExportSharedSymbols19#define epicsExportSharedSymbols
19#include "epicsGuard.h"
20#include "timerPrivate.h"
21#include "errlog.h"20#include "errlog.h"
21#include "timerPrivate.h"
2222
23const double timerQueue :: exceptMsgMinPeriod = 60.0 * 5.0; // seconds23const double timerQueue :: m_exceptMsgMinPeriod = 60.0 * 5.0; // seconds
24
25epicsTimerQueue::~epicsTimerQueue () {}
2624
27timerQueue::timerQueue ( epicsTimerQueueNotify & notifyIn ) :25timerQueue :: timerQueue ( epicsTimerQueueNotify & notifyIn ) :
28 mutex(__FILE__, __LINE__),26 Mutex ( __FILE__, __LINE__ ),
29 notify ( notifyIn ), 27 m_exceptMsgTimeStamp ( epicsTime :: getCurrent ()
30 pExpireTmr ( 0 ), 28 - m_exceptMsgMinPeriod ),
31 processThread ( 0 ), 29 m_notify ( notifyIn ),
32 exceptMsgTimeStamp ( 30 m_pExpTmr ( 0 ),
33 epicsTime :: getCurrent () - exceptMsgMinPeriod ),31 m_processThread ( 0 ),
34 cancelPending ( false )32 m_numTimers ( 0u ),
33 m_cancelPending ( false )
35{34{
36}35}
3736
38timerQueue::~timerQueue ()37timerQueue :: ~timerQueue ()
39{38{
40 timer *pTmr;39 if ( m_heap.size () ) {
41 while ( ( pTmr = this->timerList.get () ) ) { 40 while ( Timer * const pTmr = m_heap.back () ) {
42 pTmr->curState = timer::stateLimbo;41 pTmr->m_curState = Timer :: stateLimbo;
42 m_heap.pop_back ();
43 }
43 }44 }
44}45}
4546
46void timerQueue ::47void timerQueue ::
47 printExceptMsg ( const char * pName, const type_info & type )48 m_printExceptMsg ( const char * pName, const type_info & type )
48{49{
49 char date[64];50 const epicsTime cur = epicsTime :: getCurrent ();
50 double delay;51 const double delay = cur - m_exceptMsgTimeStamp;
51 try {52 if ( delay >= m_exceptMsgMinPeriod ) {
52 epicsTime cur = epicsTime :: getCurrent ();53 m_exceptMsgTimeStamp = cur;
53 delay = cur - this->exceptMsgTimeStamp;54 char date[64];
54 cur.strftime ( date, sizeof ( date ), 55 cur.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S.%f" );
55 "%a %b %d %Y %H:%M:%S.%f" );
56 if ( delay >= exceptMsgMinPeriod ) {
57 this->exceptMsgTimeStamp = cur;
58 }
59 }
60 catch ( ... ) {
61 delay = DBL_MAX;
62 strcpy ( date, "UKN DATE" );
63 }
64 if ( delay >= exceptMsgMinPeriod ) {
65 // we dont touch the typeid for the timer expiration56 // we dont touch the typeid for the timer expiration
66 // notify interface here because they might have 57 // notify interface here because they might have
67 // destroyed the timer during its callback58 // destroyed the timer during its callback
@@ -72,155 +63,212 @@ void timerQueue ::
72 pName, 63 pName,
73 type.name (), 64 type.name (),
74 date );65 date );
66 errlogPrintf ( "!!!! WARNING - PERIODIC TIMER MAY NOT RESTART !!!!\n" );
75 errlogFlush ();67 errlogFlush ();
76 }68 }
77}69}
7870
79double timerQueue::process ( const epicsTime & currentTime )71inline double timerQueue :: m_expDelay ( const epicsTime & currentTime )
80{ 72{
81 epicsGuard < epicsMutex > guard ( this->mutex );73 double delay = DBL_MAX;
74 if ( m_heap.size () > 0u ) {
75 delay = m_heap.front ()->m_exp - currentTime;
76 }
77 return delay;
78}
79
80double timerQueue :: process ( const epicsTime & currentTime )
81{
82 Guard guard ( *this );
83 return this->process ( guard, currentTime );
84}
8285
83 if ( this->pExpireTmr ) {86double timerQueue :: process ( Guard & guard,
87 const epicsTime & currentTime )
88{
89 guard.assertIdenticalMutex ( *this );
90 if ( m_processThread ) {
84 // if some other thread is processing the queue91 // if some other thread is processing the queue
85 // (or if this is a recursive call)92 // (or if this is a recursive call)
86 timer * pTmr = this->timerList.first ();93 double delay = m_expDelay ( currentTime );
87 if ( pTmr ) {94 if ( delay <= 0.0 ) {
88 double delay = pTmr->exp - currentTime;95 delay = 0.0;
89 if ( delay < 0.0 ) {
90 delay = 0.0;
91 }
92 return delay;
93 }
94 else {
95 return DBL_MAX;
96 }96 }
97 }97 return delay;
98
99 //
100 // Tag current epired tmr so that we can detect if call back
101 // is in progress when canceling the timer.
102 //
103 if ( this->timerList.first () ) {
104 if ( currentTime >= this->timerList.first ()->exp ) {
105 this->pExpireTmr = this->timerList.first ();
106 this->timerList.remove ( *this->pExpireTmr );
107 this->pExpireTmr->curState = timer::stateActive;
108 this->processThread = epicsThreadGetIdSelf ();
109# ifdef DEBUG
110 this->pExpireTmr->show ( 0u );
111# endif
112 }
113 else {
114 double delay = this->timerList.first ()->exp - currentTime;
115 debugPrintf ( ( "no activity process %f to next\n", delay ) );
116 return delay;
117 }
118 }
119 else {
120 return DBL_MAX;
121 }98 }
12299
123# ifdef DEBUG100# ifdef DEBUG
124 unsigned N = 0u;101 unsigned N = 0u;
125# endif102# endif
126103
127 double delay = DBL_MAX;104 m_processThread = epicsThreadGetIdSelf ();
128 while ( true ) {105 double delay = m_expDelay ( currentTime );
129 epicsTimerNotify *pTmpNotify = this->pExpireTmr->pNotify;106 while ( delay <= 0.0 ) {
130 this->pExpireTmr->pNotify = 0;107 //
131 epicsTimerNotify::expireStatus expStat ( epicsTimerNotify::noRestart );108 // if delay is zero or less we know at least one timer is on
132109 // the queue
133 {110 //
134 epicsGuardRelease < epicsMutex > unguard ( guard );111 // tag current expired tmr so that we can detect if call back
135112 // is in progress when canceling the timer
113 //
114 delay = 0.0;
115 m_pExpTmr = m_heap.front ();
116 epicsTimerNotify * const pTmpNotify = m_pExpTmr->m_pNotify;
117 m_pExpTmr->m_pNotify = 0;
118 epicsTimerNotify :: expireStatus
119 expStat ( epicsTimerNotify :: noRestart );
120 if ( pTmpNotify ) {
121 GuardRelease unguard ( guard );
136 debugPrintf ( ( "%5u expired \"%s\" with error %f sec\n", 122 debugPrintf ( ( "%5u expired \"%s\" with error %f sec\n",
137 N++, typeid ( this->pExpireTmr->notify ).name (), 123 N++,
138 currentTime - this->pExpireTmr->exp ) );124 typeid ( *pTmpNotify ).name (),
125 currentTime - m_pExpTmr->m_exp ) );
139 try {126 try {
140 expStat = pTmpNotify->expire ( currentTime );127 expStat = pTmpNotify->expire ( currentTime );
141 }128 }
142 catch ( std::exception & except ) {129 catch ( std::exception & except ) {
143 printExceptMsg ( except.what (), typeid ( except ) );130 m_printExceptMsg ( except.what (), typeid ( except ) );
144 }131 }
145 catch ( ... ) {132 catch ( ... ) {
146 printExceptMsg ( "non-standard exception", typeid ( void ) );133 m_printExceptMsg ( "non-standard exception", typeid ( void ) );
147 }134 }
148 }135 }
149136
150 //137 //
151 // only restart if they didnt cancel() the timer138 // !! The position of a timer in the queue is allowed to change
152 // while the call back was running139 // !! while its timer callback is running. This happens
140 // !! potentially when they reschedule a timer or cancel a
141 // !! timer. A small amount of additional labor is expended
142 // !! to properly handle this type of change below (we
143 // !! test the return from fix_parent and conditionally
144 // !! call fix_child, instead of calling only fix_child).
153 //145 //
154 if ( this->cancelPending ) {146 if ( m_cancelPending ) {
147 //
148 // only restart if they didnt cancel() the currently
149 // expiring timer while its call-back is running
150 //
155 // 1) if another thread is canceling then cancel() waits for 151 // 1) if another thread is canceling then cancel() waits for
156 // the event below152 // the event below
157 // 2) if this thread is canceling in the timer callback then153 // 2) if this thread is canceling in the timer callback then
158 // dont touch timer or notify here because the cancel might 154 // dont touch timer or notify here because the cancel might
159 // have occurred because they destroyed the timer in the 155 // have occurred because they destroyed the timer in the
160 // callback156 // callback
161 this->cancelPending = false;157 // 3) timer::cancel sets timer state to limbo and timer index
162 this->cancelBlockingEvent.signal ();158 // to invalid
159 //
160 m_cancelPending = false;
161 m_cancelBlockingEvent.signal ();
163 }162 }
164 else {163 else {
165 this->pExpireTmr->curState = timer::stateLimbo;164 if ( m_pExpTmr->m_pNotify ) {
166 if ( this->pExpireTmr->pNotify ) {165 // pNotify was cleared above; if its valid now we
167 // pNotify was cleared above so if it is valid now we know that166 // know that someone has restarted the timer when
168 // someone has started the timer from another thread and that 167 // its callback is currently running either
169 // predominates over the restart parameters from expire.168 // asynchronously from another thread or from
170 this->pExpireTmr->privateStart ( 169 // within the currently running expire callback,
171 *this->pExpireTmr->pNotify, this->pExpireTmr->exp );170 // possibly moving its position in the heap. As
171 // a defined policy either of these situations
172 // overrides any restart request parameters
173 // returned from expire
172 }174 }
173 else if ( expStat.restart() ) {175 else if ( expStat.restart() ) {
174 // restart as nec176 // restart as nec
175 this->pExpireTmr->privateStart ( 177 m_pExpTmr->m_pNotify = pTmpNotify;
176 *pTmpNotify, currentTime + expStat.expirationDelay() );178 m_pExpTmr->m_exp = currentTime + expStat.expirationDelay ();
177 }179 if ( ! m_fixParent ( m_pExpTmr->m_index ) ) {
178 }180 m_fixChildren ( m_pExpTmr->m_index );
179 this->pExpireTmr = 0;181 }
180
181 if ( this->timerList.first () ) {
182 if ( currentTime >= this->timerList.first ()->exp ) {
183 this->pExpireTmr = this->timerList.first ();
184 this->timerList.remove ( *this->pExpireTmr );
185 this->pExpireTmr->curState = timer::stateActive;
186# ifdef DEBUG
187 this->pExpireTmr->show ( 0u );
188# endif
189 }182 }
190 else {183 else {
191 delay = this->timerList.first ()->exp - currentTime;184 m_pExpTmr->m_remove ( guard );
192 this->processThread = 0;
193 break;
194 }185 }
195 }186 }
196 else {187 delay = m_expDelay ( currentTime );
197 this->processThread = 0;188 }
198 delay = DBL_MAX;189 m_pExpTmr = 0;
190 m_processThread = 0;
191 return delay;
192}
193
194bool timerQueue :: m_fixParent ( size_t childIdx )
195{
196 bool itMoved = false;
197 while ( childIdx != 0u ) {
198 const size_t parentIdx = m_parent ( childIdx );
199 if ( *m_heap[parentIdx] <= *m_heap[childIdx] ) {
199 break;200 break;
200 }201 }
202 m_swapEntries ( parentIdx, childIdx );
203 childIdx = parentIdx;
204 itMoved = true;
201 }205 }
202 return delay;206 return itMoved;
203}207}
204208
205epicsTimer & timerQueue::createTimer ()209void timerQueue :: m_fixChildren ( size_t parentIdx )
206{210{
207 return * new ( this->timerFreeList ) timer ( * this );211 const size_t hpsz = m_heap.size ();
212 while ( true ) {
213 const size_t leftChildIdx = m_leftChild ( parentIdx );
214 const size_t rightChildIdx = m_rightChild ( parentIdx );
215 size_t smallestIdx = parentIdx;
216 if ( leftChildIdx < hpsz ) {
217 if ( *m_heap[parentIdx] > *m_heap[leftChildIdx] ) {
218 smallestIdx = leftChildIdx;
219 }
220 }
221 if ( rightChildIdx < hpsz ) {
222 if ( *m_heap[smallestIdx] > *m_heap[rightChildIdx] ) {
223 smallestIdx = rightChildIdx;
224 }
225 }
226 if ( smallestIdx == parentIdx ) {
227 break;
228 }
229 m_swapEntries ( parentIdx, smallestIdx );
230 parentIdx = smallestIdx;
231 }
232}
233
234Timer & timerQueue :: createTimerImpl ()
235{
236 // better to throw now in contrast with later during start
237 Guard guard ( *this );
238 m_numTimers++;
239 m_heap.reserve ( m_numTimers );
240 return * new Timer ( * this );
208}241}
209242
210epicsTimerForC & timerQueue::createTimerForC ( epicsTimerCallback pCallback, void *pArg )243epicsTimer & timerQueue :: createTimer ()
211{244{
212 return * new ( this->timerForCFreeList ) epicsTimerForC ( *this, pCallback, pArg );245 return createTimerImpl ();
213}246}
214247
215void timerQueue::show ( unsigned level ) const248TimerForC & timerQueue :: createTimerForC (
249 epicsTimerCallback pCallback, void *pArg )
216{250{
217 epicsGuard < epicsMutex > locker ( this->mutex );251 return * new TimerForC ( *this, pCallback, pArg );
218 printf ( "epicsTimerQueue with %u items pending\n", this->timerList.count () );252}
253
254void timerQueue :: show ( unsigned level ) const
255{
256 Guard guard ( const_cast < timerQueue & > ( *this ) );
257 this->show ( guard, level );
258}
259
260void timerQueue :: show ( Guard & guard, unsigned level ) const
261{
262 guard.assertIdenticalMutex ( *this );
263 printf ( "epicsTimerQueue with %lu items pending\n",
264 (unsigned long) m_heap.size () );
219 if ( level >= 1u ) {265 if ( level >= 1u ) {
220 tsDLIterConst < timer > iter = this->timerList.firstIter ();266 std :: vector < Timer * > :: const_iterator
221 while ( iter.valid () ) { 267 ppTimer = m_heap.begin ();
222 iter->show ( level - 1u );268 while ( ppTimer != m_heap.end () && *ppTimer ) {
223 ++iter;269 (*ppTimer)->show ( level - 1u );
270 ++ppTimer;
224 }271 }
225 }272 }
226}273}
274
diff --git a/modules/libcom/src/timer/timerQueueActive.cpp b/modules/libcom/src/timer/timerQueueActive.cpp
index 4db68c0..3efedee 100644
--- a/modules/libcom/src/timer/timerQueueActive.cpp
+++ b/modules/libcom/src/timer/timerQueueActive.cpp
@@ -1,5 +1,7 @@
1/*************************************************************************\1/*************************************************************************\
2* Copyright (c) 2015 UChicago Argonne LLC, as Operator of Argonne2* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
3* National Laboratory
4* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3* National Laboratory.5* National Laboratory.
4* Copyright (c) 2002 The Regents of the University of California, as6* Copyright (c) 2002 The Regents of the University of California, as
5* Operator of Los Alamos National Laboratory.7* Operator of Los Alamos National Laboratory.
@@ -12,144 +14,100 @@
12 * 505 665 183114 * 505 665 1831
13 */15 */
1416
15#include <stdio.h>17#include <cstdio>
1618
17#define epicsExportSharedSymbols19#define epicsExportSharedSymbols
18#include "epicsAtomic.h"20#include "epicsGuard.h"
19#include "timerPrivate.h"21#include "timerPrivate.h"
20#include "errlog.h"
2122
22#ifdef _MSC_VER23epicsTimerQueueActive & epicsTimerQueueActive :: allocate ( bool okToShare,
23# pragma warning ( push )24 unsigned threadPriority )
24# pragma warning ( disable:4660 )
25#endif
26
27template class epicsSingleton < timerQueueActiveMgr >;
28
29#ifdef _MSC_VER
30# pragma warning ( pop )
31#endif
32
33epicsSingleton < timerQueueActiveMgr > timerQueueMgrEPICS;
34
35epicsTimerQueueActive::~epicsTimerQueueActive () {}
36
37epicsTimerQueueActive & epicsTimerQueueActive::allocate ( bool okToShare, unsigned threadPriority )
38{25{
39 epicsSingleton < timerQueueActiveMgr >::reference pMgr = 26 return timerQueueActiveMgr :: master ().
40 timerQueueMgrEPICS.getReference ();27 allocate ( okToShare, threadPriority );
41 return pMgr->allocate ( pMgr, okToShare, threadPriority );
42}28}
4329
44timerQueueActive ::30timerQueueActive ::
45 timerQueueActive ( RefMgr & refMgr, 31 timerQueueActive ( bool okToShareIn, unsigned priority ) :
46 bool okToShareIn, unsigned priority ) :32 m_queue ( *this ),
47 _refMgr ( refMgr ), queue ( *this ), thread ( *this, "timerQueue", 33 m_thread ( *this, "timerQueue",
48 epicsThreadGetStackSize ( epicsThreadStackMedium ), priority ),34 epicsThreadGetStackSize ( epicsThreadStackMedium ), priority ),
49 sleepQuantum ( epicsThreadSleepQuantum() ), okToShare ( okToShareIn ), 35 m_okToShare ( okToShareIn ),
50 exitFlag ( 0 ), terminateFlag ( false )36 m_exitFlag ( false ),
37 m_terminateFlag ( false )
51{38{
39 epicsGuard < epicsMutex > guard ( m_queue );
40 m_thread.start ();
52}41}
5342
54void timerQueueActive::start ()43timerQueueActive :: ~timerQueueActive ()
55{44{
56 this->thread.start ();45 Guard guard ( m_queue );
57}46 m_terminateFlag = true;
5847 m_rescheduleEvent.signal ();
59timerQueueActive::~timerQueueActive ()48 while ( ! m_exitFlag ) {
60{49 GuardRelease release ( guard );
61 this->terminateFlag = true;50 m_exitEvent.wait ( 1.0 );
62 this->rescheduleEvent.signal ();
63 while ( ! epics::atomic::get(this->exitFlag) ) {
64 this->exitEvent.wait ( 1.0 );
65 }51 }
66 // in case other threads are waiting here also52 // in case other threads are waiting here also
67 this->exitEvent.signal ();53 m_exitEvent.signal ();
68}
69
70void timerQueueActive :: _printLastChanceExceptionMessage (
71 const char * pExceptionTypeName,
72 const char * pExceptionContext )
73{
74 char date[64];
75 try {
76 epicsTime cur = epicsTime :: getCurrent ();
77 cur.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S.%f");
78 }
79 catch ( ... ) {
80 strcpy ( date, "<UKN DATE>" );
81 }
82 errlogPrintf (
83 "timerQueueActive: Unexpected C++ exception \"%s\" with type \"%s\" "
84 "while processing timer queue, at %s\n",
85 pExceptionContext, pExceptionTypeName, date );
86}54}
8755
88
89void timerQueueActive :: run ()56void timerQueueActive :: run ()
90{57{
91 epics::atomic::set(this->exitFlag, 0);58 Guard guard ( m_queue );
92 while ( ! this->terminateFlag ) {59 m_exitFlag = false;
93 try {60 while ( ! m_terminateFlag ) {
94 double delay = this->queue.process ( epicsTime::getCurrent() );61 const epicsTime curr = epicsTime :: getCurrent ();
95 debugPrintf ( ( "timer thread sleeping for %g sec (max)\n", delay ) );62 double delay = m_queue.process ( guard, curr );
96 this->rescheduleEvent.wait ( delay );63 {
97 }64 GuardRelease release ( guard );
98 catch ( std :: exception & except ) {65 debugPrintf ( ( "timer thread sleeping for %g sec (max)\n",
99 _printLastChanceExceptionMessage (66 delay ) );
100 typeid ( except ).name (), except.what () );67 m_rescheduleEvent.wait ( delay );
101 epicsThreadSleep ( 10.0 );
102 }
103 catch ( ... ) {
104 _printLastChanceExceptionMessage (
105 "catch ( ... )", "Non-standard C++ exception" );
106 epicsThreadSleep ( 10.0 );
107 }68 }
108 }69 }
109 epics::atomic::set(this->exitFlag, 1);70 m_exitFlag = true;
110 this->exitEvent.signal (); // no access to queue after exitEvent signal71 m_exitEvent.signal (); // no access to queue after exitEvent signal
111}
112
113epicsTimer & timerQueueActive::createTimer ()
114{
115 return this->queue.createTimer();
116}72}
11773
118epicsTimerForC & timerQueueActive::createTimerForC ( epicsTimerCallback pCallback, void * pArg )74epicsTimer & timerQueueActive :: createTimer ()
119{75{
120 return this->queue.createTimerForC ( pCallback, pArg );76 return m_queue.createTimer();
121}77}
12278
123void timerQueueActive::reschedule ()79TimerForC & timerQueueActive :: createTimerForC (
80 epicsTimerCallback pCallback, void * pArg )
124{81{
125 this->rescheduleEvent.signal ();82 return m_queue.createTimerForC ( pCallback, pArg );
126}83}
12784
128double timerQueueActive::quantum ()85void timerQueueActive :: reschedule ()
129{86{
130 return this->sleepQuantum;87 m_rescheduleEvent.signal ();
131}88}
13289
133void timerQueueActive::show ( unsigned int level ) const90void timerQueueActive :: show ( unsigned int level ) const
134{91{
92 Guard guard ( const_cast < timerQueue & > ( m_queue ) );
135 printf ( "EPICS threaded timer queue at %p\n", 93 printf ( "EPICS threaded timer queue at %p\n",
136 static_cast <const void *> ( this ) );94 static_cast <const void *> ( this ) );
137 if ( level > 0u ) {95 if ( level > 0u ) {
138 // specifying level one here avoids recursive 96 // specifying level one here avoids recursive
139 // show callback97 // show callback
140 this->thread.show ( 1u );98 m_thread.show ( 1u );
141 this->queue.show ( level - 1u );99 m_queue.show ( guard, level - 1u );
142 printf ( "reschedule event\n" );100 printf ( "reschedule event\n" );
143 this->rescheduleEvent.show ( level - 1u );101 m_rescheduleEvent.show ( level - 1u );
144 printf ( "exit event\n" );102 printf ( "exit event\n" );
145 this->exitEvent.show ( level - 1u );103 m_exitEvent.show ( level - 1u );
146 printf ( "exitFlag = %c, terminateFlag = %c\n",104 printf ( "exitFlag = %c, terminateFlag = %c\n",
147 epics::atomic::get(this->exitFlag) ? 'T' : 'F',105 m_exitFlag ? 'T' : 'F',
148 this->terminateFlag ? 'T' : 'F' );106 m_terminateFlag ? 'T' : 'F' );
149 }107 }
150}108}
151109
152epicsTimerQueue & timerQueueActive::getEpicsTimerQueue () 110epicsTimerQueue & timerQueueActive :: getEpicsTimerQueue ()
153{111{
154 return static_cast < epicsTimerQueue &> ( * this );112 return static_cast < epicsTimerQueue &> ( * this );
155}113}
diff --git a/modules/libcom/src/timer/timerQueueActiveMgr.cpp b/modules/libcom/src/timer/timerQueueActiveMgr.cpp
index eff2e0c..af122a8 100644
--- a/modules/libcom/src/timer/timerQueueActiveMgr.cpp
+++ b/modules/libcom/src/timer/timerQueueActiveMgr.cpp
@@ -1,11 +1,12 @@
1/*************************************************************************\1/*************************************************************************\
2* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
3* National Laboratory
2* Copyright (c) 2002 The University of Chicago, as Operator of Argonne4* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3* National Laboratory.5* National Laboratory.
4* Copyright (c) 2002 The Regents of the University of California, as6* Copyright (c) 2002 The Regents of the University of California, as
5* Operator of Los Alamos National Laboratory.7* Operator of Los Alamos National Laboratory.
6* EPICS BASE Versions 3.13.78* EPICS BASE is distributed subject to a Software License Agreement found
7* and higher are distributed subject to a Software License Agreement found9* in file LICENSE that is included with this distribution.
8* in file LICENSE that is included with this distribution.
9\*************************************************************************/10\*************************************************************************/
10/*11/*
11 * Author Jeffrey O. Hill12 * Author Jeffrey O. Hill
@@ -13,28 +14,27 @@
13 * 505 665 183114 * 505 665 1831
14 */15 */
1516
16#include <limits.h>17#include <climits>
1718
18#define epicsExportSharedSymbols19#define epicsExportSharedSymbols
19#include "epicsGuard.h"
20#include "timerPrivate.h"20#include "timerPrivate.h"
2121
22timerQueueActiveMgr::timerQueueActiveMgr ()22timerQueueActiveMgr::timerQueueActiveMgr () :
23 :mutex(__FILE__, __LINE__)23 m_mutex ( __FILE__, __LINE__ )
24{24{
25}25}
2626
27timerQueueActiveMgr::~timerQueueActiveMgr ()27timerQueueActiveMgr::~timerQueueActiveMgr ()
28{28{
29 epicsGuard < epicsMutex > locker ( this->mutex );29 Guard locker ( m_mutex );
30}30}
31 31
32epicsTimerQueueActiveForC & timerQueueActiveMgr ::32epicsTimerQueueActiveForC & timerQueueActiveMgr ::
33 allocate ( RefThis & refThis, bool okToShare, unsigned threadPriority )33 allocate ( bool okToShare, unsigned threadPriority )
34{34{
35 epicsGuard < epicsMutex > locker ( this->mutex );35 Guard locker ( m_mutex );
36 if ( okToShare ) {36 if ( okToShare ) {
37 tsDLIter < epicsTimerQueueActiveForC > iter = this->sharedQueueList.firstIter ();37 tsDLIter < epicsTimerQueueActiveForC > iter = m_sharedQueueList.firstIter ();
38 while ( iter.valid () ) {38 while ( iter.valid () ) {
39 if ( iter->threadPriority () == threadPriority ) {39 if ( iter->threadPriority () == threadPriority ) {
40 assert ( iter->timerQueueActiveMgrPrivate::referenceCount < UINT_MAX );40 assert ( iter->timerQueueActiveMgrPrivate::referenceCount < UINT_MAX );
@@ -46,10 +46,10 @@ epicsTimerQueueActiveForC & timerQueueActiveMgr ::
46 }46 }
4747
48 epicsTimerQueueActiveForC & queue = 48 epicsTimerQueueActiveForC & queue =
49 * new epicsTimerQueueActiveForC ( refThis, okToShare, threadPriority );49 * new epicsTimerQueueActiveForC ( okToShare, threadPriority );
50 queue.timerQueueActiveMgrPrivate::referenceCount = 1u;50 queue.timerQueueActiveMgrPrivate::referenceCount = 1u;
51 if ( okToShare ) {51 if ( okToShare ) {
52 this->sharedQueueList.add ( queue );52 m_sharedQueueList.add ( queue );
53 }53 }
54 return queue;54 return queue;
55}55}
@@ -58,20 +58,20 @@ void timerQueueActiveMgr ::
58 release ( epicsTimerQueueActiveForC & queue )58 release ( epicsTimerQueueActiveForC & queue )
59{59{
60 {60 {
61 epicsGuard < epicsMutex > locker ( this->mutex );61 Guard locker ( m_mutex );
62 assert ( queue.timerQueueActiveMgrPrivate::referenceCount > 0u );62 assert ( queue.timerQueueActiveMgrPrivate::referenceCount > 0u );
63 queue.timerQueueActiveMgrPrivate::referenceCount--;63 queue.timerQueueActiveMgrPrivate::referenceCount--;
64 if ( queue.timerQueueActiveMgrPrivate::referenceCount > 0u ) {64 if ( queue.timerQueueActiveMgrPrivate::referenceCount > 0u ) {
65 return;65 return;
66 }66 }
67 else if ( queue.sharingOK () ) {67 else if ( queue.sharingOK () ) {
68 this->sharedQueueList.remove ( queue );68 m_sharedQueueList.remove ( queue );
69 }69 }
70 }70 }
71 // delete only after we release the guard in case the embedded 71 // delete only after we release the guard in case the embedded
72 // reference is the last one and this object is destroyed72 // reference is the last one and this object is destroyed
73 // as a side effect73 // as a side effect
74 timerQueueActiveMgrPrivate * pPriv = & queue;74 timerQueueActiveMgrPrivate * const pPriv = & queue;
75 delete pPriv;75 delete pPriv;
76}76}
7777
diff --git a/modules/libcom/src/timer/timerQueuePassive.cpp b/modules/libcom/src/timer/timerQueuePassive.cpp
index a352c56..5ac3186 100644
--- a/modules/libcom/src/timer/timerQueuePassive.cpp
+++ b/modules/libcom/src/timer/timerQueuePassive.cpp
@@ -1,11 +1,12 @@
1/*************************************************************************\1/*************************************************************************\
2* Copyright (c) 2020 Triad National Security, as operator of Los Alamos
3* National Laboratory
2* Copyright (c) 2002 The University of Chicago, as Operator of Argonne4* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3* National Laboratory.5* National Laboratory.
4* Copyright (c) 2002 The Regents of the University of California, as6* Copyright (c) 2002 The Regents of the University of California, as
5* Operator of Los Alamos National Laboratory.7* Operator of Los Alamos National Laboratory.
6* EPICS BASE Versions 3.13.78* EPICS BASE is distributed subject to a Software License Agreement found
7* and higher are distributed subject to a Software License Agreement found9* in file LICENSE that is included with this distribution.
8* in file LICENSE that is included with this distribution.
9\*************************************************************************/10\*************************************************************************/
10/*11/*
11 * Author Jeffrey O. Hill12 * Author Jeffrey O. Hill
@@ -21,48 +22,51 @@
21// in pool.22// in pool.
22// 23//
2324
24#include <stdio.h>25#include <cstdio>
2526
26#define epicsExportSharedSymbols27#define epicsExportSharedSymbols
27#include "timerPrivate.h"28#include "timerPrivate.h"
2829
29epicsTimerQueuePassive::~epicsTimerQueuePassive () {}30epicsTimerQueuePassive &
3031 epicsTimerQueuePassive :: create (
31epicsTimerQueuePassive & epicsTimerQueuePassive::create ( epicsTimerQueueNotify &notify )32 epicsTimerQueueNotify &notify )
32{33{
33 return * new timerQueuePassive ( notify );34 return * new timerQueuePassive ( notify );
34}35}
3536
36timerQueuePassive::timerQueuePassive ( epicsTimerQueueNotify &notifyIn ) :37timerQueuePassive :: timerQueuePassive ( epicsTimerQueueNotify &notifyIn ) :
37 queue ( notifyIn ) {}38 m_queue ( notifyIn ) {}
3839
39timerQueuePassive::~timerQueuePassive () {}40timerQueuePassive::~timerQueuePassive () {}
4041
41epicsTimer & timerQueuePassive::createTimer ()42epicsTimer & timerQueuePassive::createTimer ()
42{43{
43 return this->queue.createTimer ();44 return m_queue.createTimer ();
44}45}
4546
46epicsTimerForC & timerQueuePassive::createTimerForC ( epicsTimerCallback pCallback, void * pArg )47TimerForC & timerQueuePassive :: createTimerForC (
48 epicsTimerCallback pCallback, void * pArg )
47{49{
48 return this->queue.createTimerForC ( pCallback, pArg );50 return m_queue.createTimerForC ( pCallback, pArg );
49}51}
5052
51double timerQueuePassive::process ( const epicsTime & currentTime )53double timerQueuePassive :: process (
54 const epicsTime & currentTime )
52{55{
53 return this->queue.process ( currentTime );56 return m_queue.process ( currentTime );
54}57}
5558
56void timerQueuePassive::show ( unsigned int level ) const59void timerQueuePassive :: show (
60 unsigned int level ) const
57{61{
58 printf ( "EPICS non-threaded timer queue at %p\n", 62 printf ( "EPICS non-threaded timer queue at %p\n",
59 static_cast <const void *> ( this ) );63 static_cast <const void *> ( this ) );
60 if ( level >=1u ) {64 if ( level >=1u ) {
61 this->queue.show ( level - 1u );65 m_queue.show ( level - 1u );
62 }66 }
63}67}
6468
65epicsTimerQueue & timerQueuePassive::getEpicsTimerQueue () 69epicsTimerQueue & timerQueuePassive :: getEpicsTimerQueue ()
66{70{
67 return static_cast < epicsTimerQueue &> ( * this );71 return static_cast < epicsTimerQueue &> ( * this );
68}72}
diff --git a/modules/libcom/src/valgrind/epicsMemChk.h b/modules/libcom/src/valgrind/epicsMemChk.h
69new file mode 10064473new file mode 100644
index 0000000..a190605
--- /dev/null
+++ b/modules/libcom/src/valgrind/epicsMemChk.h
@@ -0,0 +1,42 @@
1/*************************************************************************\
2 * Copyright (c) 2020 Triad National Security, as operator of Los Alamos
3 * National Laboratory
4 * EPICS BASE is distributed subject to a Software License Agreement found
5 * in file LICENSE that is included with this distribution.
6\*************************************************************************/
7
8#ifndef epicsMemChk_h
9#define epicsMemChk_h
10
11
12#if defined ( __cplusplus )
13extern "C" {
14#endif
15
16#ifdef MEMCHECK
17# include "valgrind/memcheck.h"
18 typedef struct epicsMemChkRedZone { volatile char m_redZone[32]; } epicsMemChkRedZone;
19# define VALGRIND_RED_ZONE(memberName) epicsMemChkRedZone memberName;
20# define VALGRIND_RED_ZONE_SIZE ( sizeof ( epicsMemChkRedZone ) )
21#else
22# define VALGRIND_RED_ZONE(memberName)
23# define VALGRIND_RED_ZONE_SIZE 0
24# define VALGRIND_MAKE_MEM_NOACCESS(_qzz_addr, _qzz_len)
25# define VALGRIND_MAKE_MEM_UNDEFINED(_qzz_addr, _qzz_len)
26# define VALGRIND_MAKE_MEM_DEFINED(_qzz_addr, _qzz_len)
27# define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed)
28# define VALGRIND_CREATE_MEMPOOL_EXT(pool, rzB, is_zeroed, flags)
29# define VALGRIND_DESTROY_MEMPOOL(pool)
30# define VALGRIND_MEMPOOL_ALLOC(pool, addr, sz)
31# define VALGRIND_MEMPOOL_FREE(pool, addr)
32# define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed)
33# define VALGRIND_FREELIKE_BLOCK(addr, rzB)
34# define VALGRIND_MEMPOOL_METAPOOL 0
35#endif
36
37#if defined ( __cplusplus )
38} // end of extern C
39#endif
40
41#endif // ifdef epicsMemChk_h
42
diff --git a/modules/libcom/src/valgrind/memcheck.h b/modules/libcom/src/valgrind/memcheck.h
0new file mode 10064443new file mode 100644
index 0000000..bca7323
--- /dev/null
+++ b/modules/libcom/src/valgrind/memcheck.h
@@ -0,0 +1,303 @@
1
2/*
3 ----------------------------------------------------------------
4
5 Notice that the following BSD-style license applies to this one
6 file (memcheck.h) only. The rest of Valgrind is licensed under the
7 terms of the GNU General Public License, version 2, unless
8 otherwise indicated. See the COPYING file in the source
9 distribution for details.
10
11 ----------------------------------------------------------------
12
13 This file is part of MemCheck, a heavyweight Valgrind tool for
14 detecting memory errors.
15
16 Copyright (C) 2000-2017 Julian Seward. All rights reserved.
17
18 Redistribution and use in source and binary forms, with or without
19 modification, are permitted provided that the following conditions
20 are met:
21
22 1. Redistributions of source code must retain the above copyright
23 notice, this list of conditions and the following disclaimer.
24
25 2. The origin of this software must not be misrepresented; you must
26 not claim that you wrote the original software. If you use this
27 software in a product, an acknowledgment in the product
28 documentation would be appreciated but is not required.
29
30 3. Altered source versions must be plainly marked as such, and must
31 not be misrepresented as being the original software.
32
33 4. The name of the author may not be used to endorse or promote
34 products derived from this software without specific prior written
35 permission.
36
37 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
38 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
39 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
41 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
42 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
43 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
44 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
45 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
46 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
47 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48
49 ----------------------------------------------------------------
50
51 Notice that the above BSD-style license applies to this one file
52 (memcheck.h) only. The entire rest of Valgrind is licensed under
53 the terms of the GNU General Public License, version 2. See the
54 COPYING file in the source distribution for details.
55
56 ----------------------------------------------------------------
57*/
58
59
60#ifndef __MEMCHECK_H
61#define __MEMCHECK_H
62
63
64/* This file is for inclusion into client (your!) code.
65
66 You can use these macros to manipulate and query memory permissions
67 inside your own programs.
68
69 See comment near the top of valgrind.h on how to use them.
70*/
71
72#include "valgrind.h"
73
74/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !!
75 This enum comprises an ABI exported by Valgrind to programs
76 which use client requests. DO NOT CHANGE THE ORDER OF THESE
77 ENTRIES, NOR DELETE ANY -- add new ones at the end. */
78typedef
79 enum {
80 VG_USERREQ__MAKE_MEM_NOACCESS = VG_USERREQ_TOOL_BASE('M','C'),
81 VG_USERREQ__MAKE_MEM_UNDEFINED,
82 VG_USERREQ__MAKE_MEM_DEFINED,
83 VG_USERREQ__DISCARD,
84 VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE,
85 VG_USERREQ__CHECK_MEM_IS_DEFINED,
86 VG_USERREQ__DO_LEAK_CHECK,
87 VG_USERREQ__COUNT_LEAKS,
88
89 VG_USERREQ__GET_VBITS,
90 VG_USERREQ__SET_VBITS,
91
92 VG_USERREQ__CREATE_BLOCK,
93
94 VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE,
95
96 /* Not next to VG_USERREQ__COUNT_LEAKS because it was added later. */
97 VG_USERREQ__COUNT_LEAK_BLOCKS,
98
99 VG_USERREQ__ENABLE_ADDR_ERROR_REPORTING_IN_RANGE,
100 VG_USERREQ__DISABLE_ADDR_ERROR_REPORTING_IN_RANGE,
101
102 /* This is just for memcheck's internal use - don't use it */
103 _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR
104 = VG_USERREQ_TOOL_BASE('M','C') + 256
105 } Vg_MemCheckClientRequest;
106
107
108
109/* Client-code macros to manipulate the state of memory. */
110
111/* Mark memory at _qzz_addr as unaddressable for _qzz_len bytes. */
112#define VALGRIND_MAKE_MEM_NOACCESS(_qzz_addr,_qzz_len) \
113 VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \
114 VG_USERREQ__MAKE_MEM_NOACCESS, \
115 (_qzz_addr), (_qzz_len), 0, 0, 0)
116
117/* Similarly, mark memory at _qzz_addr as addressable but undefined
118 for _qzz_len bytes. */
119#define VALGRIND_MAKE_MEM_UNDEFINED(_qzz_addr,_qzz_len) \
120 VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \
121 VG_USERREQ__MAKE_MEM_UNDEFINED, \
122 (_qzz_addr), (_qzz_len), 0, 0, 0)
123
124/* Similarly, mark memory at _qzz_addr as addressable and defined
125 for _qzz_len bytes. */
126#define VALGRIND_MAKE_MEM_DEFINED(_qzz_addr,_qzz_len) \
127 VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \
128 VG_USERREQ__MAKE_MEM_DEFINED, \
129 (_qzz_addr), (_qzz_len), 0, 0, 0)
130
131/* Similar to VALGRIND_MAKE_MEM_DEFINED except that addressability is
132 not altered: bytes which are addressable are marked as defined,
133 but those which are not addressable are left unchanged. */
134#define VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(_qzz_addr,_qzz_len) \
135 VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \
136 VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE, \
137 (_qzz_addr), (_qzz_len), 0, 0, 0)
138
139/* Create a block-description handle. The description is an ascii
140 string which is included in any messages pertaining to addresses
141 within the specified memory range. Has no other effect on the
142 properties of the memory range. */
143#define VALGRIND_CREATE_BLOCK(_qzz_addr,_qzz_len, _qzz_desc) \
144 VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \
145 VG_USERREQ__CREATE_BLOCK, \
146 (_qzz_addr), (_qzz_len), (_qzz_desc), \
147 0, 0)
148
149/* Discard a block-description-handle. Returns 1 for an
150 invalid handle, 0 for a valid handle. */
151#define VALGRIND_DISCARD(_qzz_blkindex) \
152 VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \
153 VG_USERREQ__DISCARD, \
154 0, (_qzz_blkindex), 0, 0, 0)
155
156
157/* Client-code macros to check the state of memory. */
158
159/* Check that memory at _qzz_addr is addressable for _qzz_len bytes.
160 If suitable addressibility is not established, Valgrind prints an
161 error message and returns the address of the first offending byte.
162 Otherwise it returns zero. */
163#define VALGRIND_CHECK_MEM_IS_ADDRESSABLE(_qzz_addr,_qzz_len) \
164 VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
165 VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE, \
166 (_qzz_addr), (_qzz_len), 0, 0, 0)
167
168/* Check that memory at _qzz_addr is addressable and defined for
169 _qzz_len bytes. If suitable addressibility and definedness are not
170 established, Valgrind prints an error message and returns the
171 address of the first offending byte. Otherwise it returns zero. */
172#define VALGRIND_CHECK_MEM_IS_DEFINED(_qzz_addr,_qzz_len) \
173 VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
174 VG_USERREQ__CHECK_MEM_IS_DEFINED, \
175 (_qzz_addr), (_qzz_len), 0, 0, 0)
176
177/* Use this macro to force the definedness and addressibility of an
178 lvalue to be checked. If suitable addressibility and definedness
179 are not established, Valgrind prints an error message and returns
180 the address of the first offending byte. Otherwise it returns
181 zero. */
182#define VALGRIND_CHECK_VALUE_IS_DEFINED(__lvalue) \
183 VALGRIND_CHECK_MEM_IS_DEFINED( \
184 (volatile unsigned char *)&(__lvalue), \
185 (unsigned long)(sizeof (__lvalue)))
186
187
188/* Do a full memory leak check (like --leak-check=full) mid-execution. */
189#define VALGRIND_DO_LEAK_CHECK \
190 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \
191 0, 0, 0, 0, 0)
192
193/* Same as VALGRIND_DO_LEAK_CHECK but only showing the entries for
194 which there was an increase in leaked bytes or leaked nr of blocks
195 since the previous leak search. */
196#define VALGRIND_DO_ADDED_LEAK_CHECK \
197 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \
198 0, 1, 0, 0, 0)
199
200/* Same as VALGRIND_DO_ADDED_LEAK_CHECK but showing entries with
201 increased or decreased leaked bytes/blocks since previous leak
202 search. */
203#define VALGRIND_DO_CHANGED_LEAK_CHECK \
204 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \
205 0, 2, 0, 0, 0)
206
207/* Do a summary memory leak check (like --leak-check=summary) mid-execution. */
208#define VALGRIND_DO_QUICK_LEAK_CHECK \
209 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \
210 1, 0, 0, 0, 0)
211
212/* Return number of leaked, dubious, reachable and suppressed bytes found by
213 all previous leak checks. They must be lvalues. */
214#define VALGRIND_COUNT_LEAKS(leaked, dubious, reachable, suppressed) \
215 /* For safety on 64-bit platforms we assign the results to private
216 unsigned long variables, then assign these to the lvalues the user
217 specified, which works no matter what type 'leaked', 'dubious', etc
218 are. We also initialise '_qzz_leaked', etc because
219 VG_USERREQ__COUNT_LEAKS doesn't mark the values returned as
220 defined. */ \
221 { \
222 unsigned long _qzz_leaked = 0, _qzz_dubious = 0; \
223 unsigned long _qzz_reachable = 0, _qzz_suppressed = 0; \
224 VALGRIND_DO_CLIENT_REQUEST_STMT( \
225 VG_USERREQ__COUNT_LEAKS, \
226 &_qzz_leaked, &_qzz_dubious, \
227 &_qzz_reachable, &_qzz_suppressed, 0); \
228 leaked = _qzz_leaked; \
229 dubious = _qzz_dubious; \
230 reachable = _qzz_reachable; \
231 suppressed = _qzz_suppressed; \
232 }
233
234/* Return number of leaked, dubious, reachable and suppressed bytes found by
235 all previous leak checks. They must be lvalues. */
236#define VALGRIND_COUNT_LEAK_BLOCKS(leaked, dubious, reachable, suppressed) \
237 /* For safety on 64-bit platforms we assign the results to private
238 unsigned long variables, then assign these to the lvalues the user
239 specified, which works no matter what type 'leaked', 'dubious', etc
240 are. We also initialise '_qzz_leaked', etc because
241 VG_USERREQ__COUNT_LEAKS doesn't mark the values returned as
242 defined. */ \
243 { \
244 unsigned long _qzz_leaked = 0, _qzz_dubious = 0; \
245 unsigned long _qzz_reachable = 0, _qzz_suppressed = 0; \
246 VALGRIND_DO_CLIENT_REQUEST_STMT( \
247 VG_USERREQ__COUNT_LEAK_BLOCKS, \
248 &_qzz_leaked, &_qzz_dubious, \
249 &_qzz_reachable, &_qzz_suppressed, 0); \
250 leaked = _qzz_leaked; \
251 dubious = _qzz_dubious; \
252 reachable = _qzz_reachable; \
253 suppressed = _qzz_suppressed; \
254 }
255
256
257/* Get the validity data for addresses [zza..zza+zznbytes-1] and copy it
258 into the provided zzvbits array. Return values:
259 0 if not running on valgrind
260 1 success
261 2 [previously indicated unaligned arrays; these are now allowed]
262 3 if any parts of zzsrc/zzvbits are not addressable.
263 The metadata is not copied in cases 0, 2 or 3 so it should be
264 impossible to segfault your system by using this call.
265*/
266#define VALGRIND_GET_VBITS(zza,zzvbits,zznbytes) \
267 (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
268 VG_USERREQ__GET_VBITS, \
269 (const char*)(zza), \
270 (char*)(zzvbits), \
271 (zznbytes), 0, 0)
272
273/* Set the validity data for addresses [zza..zza+zznbytes-1], copying it
274 from the provided zzvbits array. Return values:
275 0 if not running on valgrind
276 1 success
277 2 [previously indicated unaligned arrays; these are now allowed]
278 3 if any parts of zza/zzvbits are not addressable.
279 The metadata is not copied in cases 0, 2 or 3 so it should be
280 impossible to segfault your system by using this call.
281*/
282#define VALGRIND_SET_VBITS(zza,zzvbits,zznbytes) \
283 (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
284 VG_USERREQ__SET_VBITS, \
285 (const char*)(zza), \
286 (const char*)(zzvbits), \
287 (zznbytes), 0, 0 )
288
289/* Disable and re-enable reporting of addressing errors in the
290 specified address range. */
291#define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(_qzz_addr,_qzz_len) \
292 VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \
293 VG_USERREQ__DISABLE_ADDR_ERROR_REPORTING_IN_RANGE, \
294 (_qzz_addr), (_qzz_len), 0, 0, 0)
295
296#define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(_qzz_addr,_qzz_len) \
297 VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \
298 VG_USERREQ__ENABLE_ADDR_ERROR_REPORTING_IN_RANGE, \
299 (_qzz_addr), (_qzz_len), 0, 0, 0)
300
301#endif
302
303
diff --git a/modules/libcom/src/valgrind/valgrind.h b/modules/libcom/src/valgrind/valgrind.h
0old mode 100755304old mode 100755
1new mode 100644305new mode 100644
index c503172..5b26c98
--- a/modules/libcom/src/valgrind/valgrind.h
+++ b/modules/libcom/src/valgrind/valgrind.h
@@ -12,7 +12,7 @@
12 This file is part of Valgrind, a dynamic binary instrumentation12 This file is part of Valgrind, a dynamic binary instrumentation
13 framework.13 framework.
1414
15 Copyright (C) 2000-2013 Julian Seward. All rights reserved.15 Copyright (C) 2000-2017 Julian Seward. All rights reserved.
1616
17 Redistribution and use in source and binary forms, with or without17 Redistribution and use in source and binary forms, with or without
18 modification, are permitted provided that the following conditions18 modification, are permitted provided that the following conditions
@@ -89,10 +89,14 @@
89 || (__VALGRIND_MAJOR__ == 3 && __VALGRIND_MINOR__ >= 6))89 || (__VALGRIND_MAJOR__ == 3 && __VALGRIND_MINOR__ >= 6))
90*/90*/
91#define __VALGRIND_MAJOR__ 391#define __VALGRIND_MAJOR__ 3
92#define __VALGRIND_MINOR__ 1092#define __VALGRIND_MINOR__ 16
9393
9494
95#include <stdarg.h>95#if defined ( __cplusplus )
96# include <cstdarg>
97#else
98# include <stdarg.h>
99#endif
96100
97/* Nb: this file might be included in a file compiled with -ansi. So101/* Nb: this file might be included in a file compiled with -ansi. So
98 we can't use C++ style "//" comments nor the "asm" keyword (instead102 we can't use C++ style "//" comments nor the "asm" keyword (instead
@@ -122,6 +126,8 @@
122#undef PLAT_s390x_linux126#undef PLAT_s390x_linux
123#undef PLAT_mips32_linux127#undef PLAT_mips32_linux
124#undef PLAT_mips64_linux128#undef PLAT_mips64_linux
129#undef PLAT_x86_solaris
130#undef PLAT_amd64_solaris
125131
126132
127#if defined(__APPLE__) && defined(__i386__)133#if defined(__APPLE__) && defined(__i386__)
@@ -130,14 +136,14 @@
130# define PLAT_amd64_darwin 1136# define PLAT_amd64_darwin 1
131#elif (defined(__MINGW32__) && !defined(__MINGW64__)) \137#elif (defined(__MINGW32__) && !defined(__MINGW64__)) \
132 || defined(__CYGWIN32__) \138 || defined(__CYGWIN32__) \
133 || (defined(_WIN32) && defined(_M_IX86) && defined(__GNUC__))139 || (defined(_WIN32) && defined(_M_IX86))
134# define PLAT_x86_win32 1140# define PLAT_x86_win32 1
135#elif defined(__MINGW64__) \141#elif defined(__MINGW64__) \
136 || (defined(_WIN64) && defined(_M_X64) && defined(__GNUC__))142 || (defined(_WIN64) && defined(_M_X64))
137# define PLAT_amd64_win64 1143# define PLAT_amd64_win64 1
138#elif defined(__linux__) && defined(__i386__)144#elif defined(__linux__) && defined(__i386__)
139# define PLAT_x86_linux 1145# define PLAT_x86_linux 1
140#elif defined(__linux__) && defined(__x86_64__)146#elif defined(__linux__) && defined(__x86_64__) && !defined(__ILP32__)
141# define PLAT_amd64_linux 1147# define PLAT_amd64_linux 1
142#elif defined(__linux__) && defined(__powerpc__) && !defined(__powerpc64__)148#elif defined(__linux__) && defined(__powerpc__) && !defined(__powerpc64__)
143# define PLAT_ppc32_linux 1149# define PLAT_ppc32_linux 1
@@ -157,6 +163,10 @@
157# define PLAT_mips64_linux 1163# define PLAT_mips64_linux 1
158#elif defined(__linux__) && defined(__mips__) && (__mips!=64)164#elif defined(__linux__) && defined(__mips__) && (__mips!=64)
159# define PLAT_mips32_linux 1165# define PLAT_mips32_linux 1
166#elif defined(__sun) && defined(__i386__)
167# define PLAT_x86_solaris 1
168#elif defined(__sun) && defined(__x86_64__)
169# define PLAT_amd64_solaris 1
160#else170#else
161/* If we're not compiling for our target platform, don't generate171/* If we're not compiling for our target platform, don't generate
162 any inline asms. */172 any inline asms. */
@@ -244,10 +254,11 @@
244 inline asm stuff to be useful.254 inline asm stuff to be useful.
245*/255*/
246256
247/* ------------------------- x86-{linux,darwin} ---------------- */257/* ----------------- x86-{linux,darwin,solaris} ---------------- */
248258
249#if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) \259#if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) \
250 || (defined(PLAT_x86_win32) && defined(__GNUC__))260 || (defined(PLAT_x86_win32) && defined(__GNUC__)) \
261 || defined(PLAT_x86_solaris)
251262
252typedef263typedef
253 struct { 264 struct {
@@ -307,7 +318,8 @@ typedef
307 ); \318 ); \
308 } while (0)319 } while (0)
309320
310#endif /* PLAT_x86_linux || PLAT_x86_darwin || (PLAT_x86_win32 && __GNUC__) */321#endif /* PLAT_x86_linux || PLAT_x86_darwin || (PLAT_x86_win32 && __GNUC__)
322 || PLAT_x86_solaris */
311323
312/* ------------------------- x86-Win32 ------------------------- */324/* ------------------------- x86-Win32 ------------------------- */
313325
@@ -382,14 +394,15 @@ valgrind_do_client_request_expr(uintptr_t _zzq_default, uintptr_t _zzq_request,
382394
383#endif /* PLAT_x86_win32 */395#endif /* PLAT_x86_win32 */
384396
385/* ------------------------ amd64-{linux,darwin} --------------- */397/* ----------------- amd64-{linux,darwin,solaris} --------------- */
386398
387#if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) \399#if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) \
400 || defined(PLAT_amd64_solaris) \
388 || (defined(PLAT_amd64_win64) && defined(__GNUC__))401 || (defined(PLAT_amd64_win64) && defined(__GNUC__))
389402
390typedef403typedef
391 struct { 404 struct {
392 unsigned long long int nraddr; /* where's the code? */405 unsigned long int nraddr; /* where's the code? */
393 }406 }
394 OrigFn;407 OrigFn;
395408
@@ -401,14 +414,14 @@ typedef
401 _zzq_default, _zzq_request, \414 _zzq_default, _zzq_request, \
402 _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \415 _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
403 __extension__ \416 __extension__ \
404 ({ volatile unsigned long long int _zzq_args[6]; \417 ({ volatile unsigned long int _zzq_args[6]; \
405 volatile unsigned long long int _zzq_result; \418 volatile unsigned long int _zzq_result; \
406 _zzq_args[0] = (unsigned long long int)(_zzq_request); \419 _zzq_args[0] = (unsigned long int)(_zzq_request); \
407 _zzq_args[1] = (unsigned long long int)(_zzq_arg1); \420 _zzq_args[1] = (unsigned long int)(_zzq_arg1); \
408 _zzq_args[2] = (unsigned long long int)(_zzq_arg2); \421 _zzq_args[2] = (unsigned long int)(_zzq_arg2); \
409 _zzq_args[3] = (unsigned long long int)(_zzq_arg3); \422 _zzq_args[3] = (unsigned long int)(_zzq_arg3); \
410 _zzq_args[4] = (unsigned long long int)(_zzq_arg4); \423 _zzq_args[4] = (unsigned long int)(_zzq_arg4); \
411 _zzq_args[5] = (unsigned long long int)(_zzq_arg5); \424 _zzq_args[5] = (unsigned long int)(_zzq_arg5); \
412 __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \425 __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
413 /* %RDX = client_request ( %RAX ) */ \426 /* %RDX = client_request ( %RAX ) */ \
414 "xchgq %%rbx,%%rbx" \427 "xchgq %%rbx,%%rbx" \
@@ -421,7 +434,7 @@ typedef
421434
422#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \435#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
423 { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \436 { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
424 volatile unsigned long long int __addr; \437 volatile unsigned long int __addr; \
425 __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \438 __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
426 /* %RAX = guest_NRADDR */ \439 /* %RAX = guest_NRADDR */ \
427 "xchgq %%rcx,%%rcx" \440 "xchgq %%rcx,%%rcx" \
@@ -445,7 +458,7 @@ typedef
445 ); \458 ); \
446 } while (0)459 } while (0)
447460
448#endif /* PLAT_amd64_linux || PLAT_amd64_darwin */461#endif /* PLAT_amd64_linux || PLAT_amd64_darwin || PLAT_amd64_solaris */
449462
450/* ------------------------- amd64-Win64 ------------------------- */463/* ------------------------- amd64-Win64 ------------------------- */
451464
@@ -530,8 +543,8 @@ typedef
530543
531typedef544typedef
532 struct { 545 struct {
533 unsigned long long int nraddr; /* where's the code? */546 unsigned long int nraddr; /* where's the code? */
534 unsigned long long int r2; /* what tocptr do we need? */547 unsigned long int r2; /* what tocptr do we need? */
535 }548 }
536 OrigFn;549 OrigFn;
537550
@@ -544,15 +557,15 @@ typedef
544 _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \557 _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
545 \558 \
546 __extension__ \559 __extension__ \
547 ({ unsigned long long int _zzq_args[6]; \560 ({ unsigned long int _zzq_args[6]; \
548 unsigned long long int _zzq_result; \561 unsigned long int _zzq_result; \
549 unsigned long long int* _zzq_ptr; \562 unsigned long int* _zzq_ptr; \
550 _zzq_args[0] = (unsigned long long int)(_zzq_request); \563 _zzq_args[0] = (unsigned long int)(_zzq_request); \
551 _zzq_args[1] = (unsigned long long int)(_zzq_arg1); \564 _zzq_args[1] = (unsigned long int)(_zzq_arg1); \
552 _zzq_args[2] = (unsigned long long int)(_zzq_arg2); \565 _zzq_args[2] = (unsigned long int)(_zzq_arg2); \
553 _zzq_args[3] = (unsigned long long int)(_zzq_arg3); \566 _zzq_args[3] = (unsigned long int)(_zzq_arg3); \
554 _zzq_args[4] = (unsigned long long int)(_zzq_arg4); \567 _zzq_args[4] = (unsigned long int)(_zzq_arg4); \
555 _zzq_args[5] = (unsigned long long int)(_zzq_arg5); \568 _zzq_args[5] = (unsigned long int)(_zzq_arg5); \
556 _zzq_ptr = _zzq_args; \569 _zzq_ptr = _zzq_args; \
557 __asm__ volatile("mr 3,%1\n\t" /*default*/ \570 __asm__ volatile("mr 3,%1\n\t" /*default*/ \
558 "mr 4,%2\n\t" /*ptr*/ \571 "mr 4,%2\n\t" /*ptr*/ \
@@ -568,7 +581,7 @@ typedef
568581
569#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \582#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
570 { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \583 { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
571 unsigned long long int __addr; \584 unsigned long int __addr; \
572 __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \585 __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
573 /* %R3 = guest_NRADDR */ \586 /* %R3 = guest_NRADDR */ \
574 "or 2,2,2\n\t" \587 "or 2,2,2\n\t" \
@@ -607,8 +620,8 @@ typedef
607620
608typedef621typedef
609 struct {622 struct {
610 unsigned long long int nraddr; /* where's the code? */623 unsigned long int nraddr; /* where's the code? */
611 unsigned long long int r2; /* what tocptr do we need? */624 unsigned long int r2; /* what tocptr do we need? */
612 }625 }
613 OrigFn;626 OrigFn;
614627
@@ -621,15 +634,15 @@ typedef
621 _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \634 _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
622 \635 \
623 __extension__ \636 __extension__ \
624 ({ unsigned long long int _zzq_args[6]; \637 ({ unsigned long int _zzq_args[6]; \
625 unsigned long long int _zzq_result; \638 unsigned long int _zzq_result; \
626 unsigned long long int* _zzq_ptr; \639 unsigned long int* _zzq_ptr; \
627 _zzq_args[0] = (unsigned long long int)(_zzq_request); \640 _zzq_args[0] = (unsigned long int)(_zzq_request); \
628 _zzq_args[1] = (unsigned long long int)(_zzq_arg1); \641 _zzq_args[1] = (unsigned long int)(_zzq_arg1); \
629 _zzq_args[2] = (unsigned long long int)(_zzq_arg2); \642 _zzq_args[2] = (unsigned long int)(_zzq_arg2); \
630 _zzq_args[3] = (unsigned long long int)(_zzq_arg3); \643 _zzq_args[3] = (unsigned long int)(_zzq_arg3); \
631 _zzq_args[4] = (unsigned long long int)(_zzq_arg4); \644 _zzq_args[4] = (unsigned long int)(_zzq_arg4); \
632 _zzq_args[5] = (unsigned long long int)(_zzq_arg5); \645 _zzq_args[5] = (unsigned long int)(_zzq_arg5); \
633 _zzq_ptr = _zzq_args; \646 _zzq_ptr = _zzq_args; \
634 __asm__ volatile("mr 3,%1\n\t" /*default*/ \647 __asm__ volatile("mr 3,%1\n\t" /*default*/ \
635 "mr 4,%2\n\t" /*ptr*/ \648 "mr 4,%2\n\t" /*ptr*/ \
@@ -645,7 +658,7 @@ typedef
645658
646#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \659#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
647 { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \660 { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
648 unsigned long long int __addr; \661 unsigned long int __addr; \
649 __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \662 __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
650 /* %R3 = guest_NRADDR */ \663 /* %R3 = guest_NRADDR */ \
651 "or 2,2,2\n\t" \664 "or 2,2,2\n\t" \
@@ -754,7 +767,7 @@ typedef
754767
755typedef768typedef
756 struct { 769 struct {
757 unsigned long long int nraddr; /* where's the code? */770 unsigned long int nraddr; /* where's the code? */
758 }771 }
759 OrigFn;772 OrigFn;
760773
@@ -767,14 +780,14 @@ typedef
767 _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \780 _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
768 \781 \
769 __extension__ \782 __extension__ \
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches