Merge lp:~epics-core/epics-base/rebased-atomics into lp:~epics-core/epics-base/3.15

Proposed by Andrew Johnson
Status: Merged
Merged at revision: 12249
Proposed branch: lp:~epics-core/epics-base/rebased-atomics
Merge into: lp:~epics-core/epics-base/3.15
Diff against target: 2718 lines (+2514/-18)
23 files modified
configure/RULES_BUILD (+1/-1)
configure/os/CONFIG.win32-x86.win32-x86 (+1/-1)
documentation/README.html (+12/-9)
src/libCom/osi/Makefile (+7/-0)
src/libCom/osi/compiler/clang/epicsAtomicCD.h (+31/-0)
src/libCom/osi/compiler/default/epicsAtomicCD.h (+30/-0)
src/libCom/osi/compiler/gcc/epicsAtomicCD.h (+172/-0)
src/libCom/osi/compiler/msvc/epicsAtomicCD.h (+124/-0)
src/libCom/osi/compiler/solStudio/epicsAtomicCD.h (+31/-0)
src/libCom/osi/epicsAtomic.h (+236/-0)
src/libCom/osi/epicsAtomicDefault.h (+227/-0)
src/libCom/osi/os/WIN32/epicsAtomicMS.h (+222/-0)
src/libCom/osi/os/WIN32/epicsAtomicOSD.cpp (+22/-0)
src/libCom/osi/os/WIN32/epicsAtomicOSD.h (+47/-0)
src/libCom/osi/os/posix/epicsAtomicOSD.cpp (+99/-0)
src/libCom/osi/os/posix/epicsAtomicOSD.h (+35/-0)
src/libCom/osi/os/solaris/epicsAtomicOSD.h (+178/-0)
src/libCom/osi/os/vxWorks/epicsAtomicOSD.cpp (+21/-0)
src/libCom/osi/os/vxWorks/epicsAtomicOSD.h (+256/-0)
src/libCom/osi/os/vxWorks/osdSock.h (+9/-7)
src/libCom/test/Makefile (+9/-0)
src/libCom/test/epicsAtomicPerform.cpp (+506/-0)
src/libCom/test/epicsAtomicTest.cpp (+238/-0)
To merge this branch: bzr merge lp:~epics-core/epics-base/rebased-atomics
Reviewer Review Type Date Requested Status
Andrew Johnson Approve
Review via email: mp+73915@code.launchpad.net

Description of the change

This is Jeff Hill's atomics branch, rebased onto the 3.15 trunk.

To post a comment you must log in.
Revision history for this message
Andrew Johnson (anj) wrote :

Hi Jeff,

I get this build failure on solaris-sparc:

/opt/SUNWspro/bin/CC -c -D_POSIX_C_SOURCE=199506L -D_XOPEN_SOURCE=500 -DUNIX -DSOLARIS=10 -mt -D__EXTENSIONS__ -O +w -xcode=pic32 -I. -I../O.Common -I. -I../../../src/libCom/osi/compiler/solStudio -I../../../src/libCom/osi/compiler/default -I. -I../../../src/libCom/osi/os/solaris -I../../../src/libCom/osi/os/posix -I../../../src/libCom/osi/os/default -I.. -I../../../src/libCom/as -I../../../src/libCom/bucketLib -I../../../src/libCom/calc -I../../../src/libCom/cvtFast -I../../../src/libCom/cppStd -I../../../src/libCom/cxxTemplates -I../../../src/libCom/dbmf -I../../../src/libCom/ellLib -I../../../src/libCom/env -I../../../src/libCom/error -I../../../src/libCom/fdmgr -I../../../src/libCom/flex -I../../../src/libCom/freeList -I../../../src/libCom/gpHash -I../../../src/libCom/iocsh -I../../../src/libCom/log -I../../../src/libCom/macLib -I../../../src/libCom/misc -I../../../src/libCom/osi -I../../../src/libCom/ring -I../../../src/libCom/taskwd -I../../../src/libCom/timer -I../../../src/libCom/tsDefs -I../../../src/libCom/yacc -I../../../include/compiler/solStudio -I../../../include/os/solaris -I../../../include ../../../src/libCom/osi/epicsAtomicLocked.cpp
"../../../src/libCom/osi/os/solaris/epicsAtomicOSD.h", line 99: Error: The function "atomic_inc_ptr_nv" must have a prototype.
"../../../src/libCom/osi/os/solaris/epicsAtomicOSD.h", line 119: Error: The function "atomic_dec_ptr_nv" must have a prototype.
"../../../src/libCom/osi/epicsAtomicLocked.cpp", line 69: Warning (Anachronism): Formal argument 2 of type extern "C" void(*)(void*) in call to epicsThreadOnce(epicsThreadOSD**, extern "C" void(*)(void*), void*) is being passed void(*)(void*).
2 Error(s) and 1 Warning(s) detected.
make[3]: *** [epicsAtomicLocked.o] Error 2

The sys/atomic.h file on solaris-sparc only contains the atomic_inc_* functions below. I'm also including a comment that appears about using the _nv versions:

/*
 * As above, but return the new value. Note that these _nv() variants are
 * substantially more expensive on some platforms than the no-return-value
 * versions above, so don't use them unless you really need to know the
 * new value *atomically* (e.g. when decrementing a reference count and
 * checking whether it went to zero).
 */

/*
 * Increment target and return new value.
 */
extern uint8_t atomic_inc_8_nv(volatile uint8_t *);
extern uchar_t atomic_inc_uchar_nv(volatile uchar_t *);
extern uint16_t atomic_inc_16_nv(volatile uint16_t *);
extern ushort_t atomic_inc_ushort_nv(volatile ushort_t *);
extern uint32_t atomic_inc_32_nv(volatile uint32_t *);
extern uint_t atomic_inc_uint_nv(volatile uint_t *);
extern ulong_t atomic_inc_ulong_nv(volatile ulong_t *);
#if defined(_KERNEL) || defined(_INT64_TYPE)
extern uint64_t atomic_inc_64_nv(volatile uint64_t *);
#endif

- Andrew

review: Needs Fixing
12280. By Jeff Hill

o hopefully fixed missing functions with sunos 5.10 or higher
o removed unused trash files which somehow reappeared after rebase

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

Committed a fix, but I am unable to build for this version of Solaris here so we may need to iterate.

The _nv versions are necessary because, in our interface, we return the result of the atomic operation to the user. Its slightly more efficient on certain architectures to, for example, increment a counter and not check the result but typically I check for overflow so perhaps the overhead is unavoidable in typical use cases. Admittedly, the interface design was a judgment call based on providing what we need while implementing a minimum set of data types and functions.

Revision history for this message
Andrew Johnson (anj) wrote :

Hi Jeff,

On 2011-09-02 you wrote:
> Committed a fix, but I am unable to build for this version of Solaris here
> so we may need to iterate.

/opt/SUNWspro/bin/CC -c -D_POSIX_C_SOURCE=199506L -D_XOPEN_SOURCE=500
-DUNIX -DSOLARIS=10 -mt -D__EXTENSIONS__ -O +w -xcode=pic32 -
I. -I../O.Common -I. -I../../../src/libCom/osi/compiler/solStudio -
I../../../src/libCom/osi/compiler/default -I. -
I../../../src/libCom/osi/os/solaris -I../../../src/libCom/osi/os/posix -
I../../../src/libCom/osi/os/default -I.. -I../../../src/libCom/as -
I../../../src/libCom/bucketLib -I../../../src/libCom/calc -
I../../../src/libCom/cvtFast -I../../../src/libCom/cppStd -
I../../../src/libCom/cxxTemplates -I../../../src/libCom/dbmf -
I../../../src/libCom/ellLib -I../../../src/libCom/env -
I../../../src/libCom/error -I../../../src/libCom/fdmgr -
I../../../src/libCom/flex -I../../../src/libCom/freeList -
I../../../src/libCom/gpHash -I../../../src/libCom/iocsh -
I../../../src/libCom/log -I../../../src/libCom/macLib -
I../../../src/libCom/misc -I../../../src/libCom/osi -I../../../src/libCom/ring
-I../../../src/libCom/taskwd -I../../../src/libCom/timer -
I../../../src/libCom/tsDefs -I../../../src/libCom/yacc -
I../../../include/compiler/solStudio -I../../../include/os/solaris -
I../../../include ../../../src/libCom/osi/os/posix/epicsAtomicOSD.cpp
"../../../src/libCom/osi/os/solaris/epicsAtomicOSD.h", line 67: Error: Formal
argument 1 of type volatile unsigned long* in call to
atomic_cas_ulong(volatile unsigned long*, unsigned long, unsigned long) is
being passed unsigned*.
"../../../src/libCom/osi/os/solaris/epicsAtomicOSD.h", line 97: Error: Formal
argument 1 of type volatile unsigned long* in call to
atomic_inc_ulong_nv(volatile unsigned long*) is being passed unsigned*.
"../../../src/libCom/osi/os/solaris/epicsAtomicOSD.h", line 116: Error: Formal
argument 1 of type volatile unsigned long* in call to
atomic_dec_ulong_nv(volatile unsigned long*) is being passed unsigned*.
"../../../src/libCom/osi/os/solaris/epicsAtomicOSD.h", line 136: Error: Formal
argument 1 of type volatile unsigned long* in call to
atomic_add_long_nv(volatile unsigned long*, long) is being passed unsigned*.
"../../../src/libCom/osi/os/solaris/epicsAtomicOSD.h", line 147: Error: Formal
argument 1 of type volatile unsigned long* in call to
atomic_add_long_nv(volatile unsigned long*, long) is being passed unsigned*.
5 Error(s) detected.

> The _nv versions are necessary because, in our interface, we return the
> result of the atomic operation to the user.

Not a problem, I was just making sure that was a conscious decision of yours,
although I thought it probably was; the comment said "on some platforms" and
you added the epicsAtomicPerformTest.c code so we can easily measure that.

- Andrew
--
Optimization is the process of taking something that works and
replacing it with something that almost works, but costs less.
-- Roger Needham

12281. By Andrew Johnson

Remove epicsAtomicLocked.{h,cpp} from Makefile too.

12282. By Jeff Hill

fixed sunos compiler issue (I dont have sunos 5.10 here)

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

Committed a fix, but I am unable to build for this version of Solaris here so we may need to iterate.

12283. By Andrew Johnson

libCom/osi: Clean up compiler warnings on vxWorks

12284. By Andrew Johnson

documentation/README: We now require vxWorks 5.5 or later

Revision history for this message
Andrew Johnson (anj) wrote :

Thanks Jeff, all tests now pass on Solaris and Darwin. I committed a couple of changes to the osi/os/vxWorks directory this morning to clean up compiler warnings on vxWorks 6.8.

One thing I want to point out so everyone is aware of this: By using C++ namespaces we are no longer compatible with the vxWorks 5.4.2 compiler:
  ../../../src/libCom/osi/epicsAtomic.h:108: sorry, not implemented: namespace
  make[3]: *** [epicsAtomicOSD.o] Error 1
I'm not objecting to this at all, just making the fact clear for the record, so the other core developers are all aware that we've taken the step to drop vxWorks 5.4 in Base 3.15. I have committed a note of the new requirement for at least vxWorks 5.5.x to the README.html file.

I would also like to see some documentation on the Atomics API in lp:epics-appdev — the more stuff we add to Base without documenting it at the time, the more work we'll have to do at release-time (or which may never get done). I don't mind converting someone else's words into LaTeX format if you're too busy, but I have no desire to write all the documentation updates myself. I am however currently working on the documentation for some of the other OSI changes which have already been merged, such as the compiler-specific and epicsEvent branches.

I won't hold up this merge waiting for documentation, but that might start to happen in the future if the AppDevGuide gets too far behind the code.

- Andrew

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'configure/RULES_BUILD'
2--- configure/RULES_BUILD 2011-09-02 21:24:09 +0000
3+++ configure/RULES_BUILD 2011-09-07 17:27:41 +0000
4@@ -410,7 +410,7 @@
5 $(INSTALL_INCLUDE)/os/$(OS_CLASS)/% : %
6 $(ECHO) "Installing OS dependent include file $@"
7 @$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)
8-
9+
10 $(INSTALL_INCLUDE)/compiler/$(CMPLR_CLASS)/% : %
11 $(ECHO) "Installing compiler dependent include file $@"
12 @$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)
13
14=== modified file 'configure/os/CONFIG.win32-x86.win32-x86'
15--- configure/os/CONFIG.win32-x86.win32-x86 2011-09-01 16:42:37 +0000
16+++ configure/os/CONFIG.win32-x86.win32-x86 2011-09-07 17:27:41 +0000
17@@ -124,7 +124,7 @@
18 # /D_CRTDBG_MAP_ALLOC
19 # /RTCsu catch bugs occurring only in optimized code
20 # /DEPICS_FREELIST_DEBUG good for detecting mem mrg bugs
21-OPT_CXXFLAGS_NO = /RTCsu /Zi
22+OPT_CXXFLAGS_NO = /RTCsu /Zi
23
24 # specify object file name and location
25 OBJ_CXXFLAG = /Fo
26
27=== modified file 'documentation/README.html'
28--- documentation/README.html 2010-11-28 03:06:40 +0000
29+++ documentation/README.html 2011-09-07 17:27:41 +0000
30@@ -88,15 +88,18 @@
31 as processes on the host platform.</P>
32
33 <P><B>vxWorks</B><BR>
34- You must have vxWorks installed if any of your target systems are
35- vxWorks systems. This provides the cross-compiler and header files
36- needed to build for these target systems. The absolute path to and version
37- number of the vxWorks installation is normally specified in the
38- base/configure/os/CONFIG_SITE.Common.vxWorksCommon file. Consult the EPICS web
39- pages about <a href="http://www.aps.anl.gov/epics/base/tornado.php">vxWorks
40- 5.x</a> and <a href="http://www.aps.anl.gov/epics/base/vxWorks6.php">vxWorks
41- 6.x</a> and the vxWorks documentation for information about configuring your
42- vxWorks operating system for use with EPICS.</P>
43+ You must have vxWorks 5.5.x or 6.x installed if any of your target systems are
44+ vxWorks systems; the C++ compiler for vxWorks 5.4 is now too old to support.
45+ The vxWorks installation provides the cross-compiler and header files needed to
46+ build for these targets. The absolute path to and the version number of the
47+ vxWorks installation must be set in the
48+ base/configure/os/CONFIG_SITE.Common.vxWorksCommon file or in one of its
49+ target-specific overrides.</P>
50+
51+<P>Consult the <a href="http://www.aps.anl.gov/epics/base/tornado.php">vxWorks
52+ 5.x</a> or <a href="http://www.aps.anl.gov/epics/base/vxWorks6.php">vxWorks
53+ 6.x</a> EPICS web pages about and the vxWorks documentation for information
54+ about configuring your vxWorks operating system for use with EPICS.</P>
55
56 <P><B>RTEMS</B><BR>
57 For RTEMS targets, you need RTEMS core and toolset version 4.9.2 or later.</P>
58
59=== modified file 'src/libCom/osi/Makefile'
60--- src/libCom/osi/Makefile 2011-09-01 16:42:37 +0000
61+++ src/libCom/osi/Makefile 2011-09-07 17:27:41 +0000
62@@ -44,6 +44,10 @@
63 INC += osiWireFormat.h
64 INC += osdWireFormat.h
65 INC += osdWireConfig.h
66+INC += epicsAtomic.h
67+INC += epicsAtomicDefault.h
68+INC += epicsAtomicOSD.h
69+INC += epicsAtomicCD.h
70 INC += epicsEndian.h
71 INC += epicsReadline.h
72 INC += epicsMessageQueue.h
73@@ -62,6 +66,7 @@
74 Com_SRCS += epicsTime.cpp
75 Com_SRCS += epicsMessageQueue.cpp
76 Com_SRCS += epicsMath.cpp
77+Com_SRCS += epicsAtomicOSD.cpp
78
79 Com_SRCS += epicsGeneralTime.c
80
81@@ -125,6 +130,8 @@
82 #This forces the vxWorks compatibility stuff to be loaded
83 OBJS_vxWorks = vxComLibrary
84
85+INC_WIN32 += epicsAtomicMS.h
86+
87 Com_SRCS_WIN32 += epicsGetopt.c
88 Com_SRCS_WIN32 += setThreadName.cpp
89 #Com_SRCS_WIN32 += dllmain.cpp
90
91=== added file 'src/libCom/osi/compiler/clang/epicsAtomicCD.h'
92--- src/libCom/osi/compiler/clang/epicsAtomicCD.h 1970-01-01 00:00:00 +0000
93+++ src/libCom/osi/compiler/clang/epicsAtomicCD.h 2011-09-07 17:27:41 +0000
94@@ -0,0 +1,31 @@
95+
96+/*************************************************************************\
97+* Copyright (c) 2011 LANS LLC, as Operator of
98+* Los Alamos National Laboratory.
99+* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
100+* National Laboratory.
101+* EPICS BASE is distributed subject to a Software License Agreement found
102+* in file LICENSE that is included with this distribution.
103+\*************************************************************************/
104+
105+/*
106+ * Author Jeffrey O. Hill
107+ * johill@lanl.gov
108+ */
109+
110+#ifndef epicsAtomicCD_h
111+#define epicsAtomicCD_h
112+
113+#if defined ( __cplusplus )
114+# define EPICS_ATOMIC_INLINE inline
115+#else
116+# define EPICS_ATOMIC_INLINE __inline__
117+#endif
118+
119+/*
120+ * we have an inline keyword so we can proceed
121+ * with an os specific inline instantiation
122+ */
123+#include "epicsAtomicOSD.h"
124+
125+#endif /* epicsAtomicCD_h */
126
127=== added file 'src/libCom/osi/compiler/default/epicsAtomicCD.h'
128--- src/libCom/osi/compiler/default/epicsAtomicCD.h 1970-01-01 00:00:00 +0000
129+++ src/libCom/osi/compiler/default/epicsAtomicCD.h 2011-09-07 17:27:41 +0000
130@@ -0,0 +1,30 @@
131+
132+/*************************************************************************\
133+* Copyright (c) 2011 LANS LLC, as Operator of
134+* Los Alamos National Laboratory.
135+* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
136+* National Laboratory.
137+* EPICS BASE is distributed subject to a Software License Agreement found
138+* in file LICENSE that is included with this distribution.
139+\*************************************************************************/
140+
141+/*
142+ * Author Jeffrey O. Hill
143+ * johill@lanl.gov
144+ */
145+
146+#ifndef epicsAtomicCD_h
147+#define epicsAtomicCD_h
148+
149+#if __STDC_VERSION__ >= 199901L || defined ( __cplusplus )
150+# define EPICS_ATOMIC_INLINE inline
151+ /*
152+ * We have already defined the public interface in epicsAtomic.h
153+ * so there is nothing more to implement if there isnt an inline
154+ * keyword available. Otherwise, if we have an inline keyword
155+ * we will proceed with an os specific inline implementation.
156+ */
157+# include "epicsAtomicOSD.h"
158+#endif
159+
160+#endif /* epicsAtomicCD_h */
161
162=== added file 'src/libCom/osi/compiler/gcc/epicsAtomicCD.h'
163--- src/libCom/osi/compiler/gcc/epicsAtomicCD.h 1970-01-01 00:00:00 +0000
164+++ src/libCom/osi/compiler/gcc/epicsAtomicCD.h 2011-09-07 17:27:41 +0000
165@@ -0,0 +1,172 @@
166+
167+/*************************************************************************\
168+* Copyright (c) 2011 LANS LLC, as Operator of
169+* Los Alamos National Laboratory.
170+* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
171+* National Laboratory.
172+* EPICS BASE is distributed subject to a Software License Agreement found
173+* in file LICENSE that is included with this distribution.
174+\*************************************************************************/
175+
176+/*
177+ * Author Jeffrey O. Hill
178+ * johill@lanl.gov
179+ */
180+
181+#ifndef epicsAtomicCD_h
182+#define epicsAtomicCD_h
183+
184+#ifndef __GNUC__
185+# error this header is only for use with the gnu compiler
186+#endif
187+
188+#define EPICS_ATOMIC_INLINE __inline__
189+
190+#define GCC_ATOMIC_CONCAT( A, B ) GCC_ATOMIC_CONCATR(A,B)
191+#define GCC_ATOMIC_CONCATR( A, B ) ( A ## B )
192+
193+#define GCC_ATOMIC_INTRINSICS_AVAIL_INT_T \
194+ GCC_ATOMIC_CONCAT ( \
195+ __GCC_HAVE_SYNC_COMPARE_AND_SWAP_, \
196+ __SIZEOF_INT__ )
197+
198+#define GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T \
199+ GCC_ATOMIC_CONCAT ( \
200+ __GCC_HAVE_SYNC_COMPARE_AND_SWAP_, \
201+ __SIZEOF_SIZE_T__ )
202+
203+#define GCC_ATOMIC_INTRINSICS_MIN_X86 \
204+ ( defined ( __i486 ) || defined ( __pentium ) || \
205+ defined ( __pentiumpro ) || defined ( __MMX__ ) )
206+
207+#define GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER \
208+ ( ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 401 )
209+
210+#define GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER \
211+ ( GCC_ATOMIC_INTRINSICS_MIN_X86 && \
212+ GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER )
213+
214+#ifdef __cplusplus
215+extern "C" {
216+#endif
217+
218+/*
219+ * We are optimistic that __sync_synchronize is implemented
220+ * in all version four gcc invarient of target. The gnu doc
221+ * seems to say that when not supported by architecture a call
222+ * to an external function is generated but in practice
223+ * this isnt the case for some of the atomic intrinsics, and
224+ * so there is an undefined symbol. So far we have not seen
225+ * that with __sync_synchronize, but we can only guess based
226+ * on experimental evidence.
227+ *
228+ * For example we know that when generating object code for
229+ * 386 most of the atomic instrinsics are not present and
230+ * we see undefined symbols with mingw, but we dont have
231+ * troubles with __sync_synchronize.
232+ */
233+#if GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER
234+
235+#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER
236+#define EPICS_ATOMIC_READ_MEMORY_BARRIER
237+EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier ()
238+{
239+ __sync_synchronize ();
240+}
241+#endif
242+
243+#ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER
244+#define EPICS_ATOMIC_WRITE_MEMORY_BARRIER
245+EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier ()
246+{
247+ __sync_synchronize ();
248+}
249+#endif
250+
251+#endif /* if GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER */
252+
253+#if GCC_ATOMIC_INTRINSICS_AVAIL_INT_T \
254+ || GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER
255+
256+#define EPICS_ATOMIC_INCR_INTT
257+EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget )
258+{
259+ return __sync_add_and_fetch ( pTarget, 1 );
260+}
261+
262+#define EPICS_ATOMIC_DECR_INTT
263+EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget )
264+{
265+ return __sync_sub_and_fetch ( pTarget, 1 );
266+}
267+
268+#define EPICS_ATOMIC_ADD_INTT
269+EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta )
270+{
271+ return __sync_add_and_fetch ( pTarget, delta );
272+}
273+
274+#define EPICS_ATOMIC_CAS_INTT
275+EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget,
276+ int oldVal, int newVal )
277+{
278+ return __sync_val_compare_and_swap ( pTarget, oldVal, newVal);
279+}
280+
281+#endif /* if GCC_ATOMIC_INTRINSICS_AVAIL_INT_T */
282+
283+#if GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T \
284+ || GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER
285+
286+#define EPICS_ATOMIC_INCR_SIZET
287+EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
288+{
289+ return __sync_add_and_fetch ( pTarget, 1u );
290+}
291+
292+#define EPICS_ATOMIC_DECR_SIZET
293+EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
294+{
295+ return __sync_sub_and_fetch ( pTarget, 1u );
296+}
297+
298+#define EPICS_ATOMIC_ADD_SIZET
299+EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta )
300+{
301+ return __sync_add_and_fetch ( pTarget, delta );
302+}
303+
304+#define EPICS_ATOMIC_SUB_SIZET
305+EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta )
306+{
307+ return __sync_sub_and_fetch ( pTarget, delta );
308+}
309+
310+#define EPICS_ATOMIC_CAS_SIZET
311+EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget,
312+ size_t oldVal, size_t newVal )
313+{
314+ return __sync_val_compare_and_swap ( pTarget, oldVal, newVal);
315+}
316+
317+#define EPICS_ATOMIC_CAS_PTRT
318+EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT (
319+ EpicsAtomicPtrT * pTarget,
320+ EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal )
321+{
322+ return __sync_val_compare_and_swap ( pTarget, oldVal, newVal);
323+}
324+
325+#endif /* if GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T */
326+
327+#ifdef __cplusplus
328+} /* end of extern "C" */
329+#endif
330+
331+/*
332+ * if currently unavailable as gcc intrinsics we
333+ * will try for an os specific inline solution
334+ */
335+#include "epicsAtomicOSD.h"
336+
337+#endif /* epicsAtomicCD_h */
338
339=== added file 'src/libCom/osi/compiler/msvc/epicsAtomicCD.h'
340--- src/libCom/osi/compiler/msvc/epicsAtomicCD.h 1970-01-01 00:00:00 +0000
341+++ src/libCom/osi/compiler/msvc/epicsAtomicCD.h 2011-09-07 17:27:41 +0000
342@@ -0,0 +1,124 @@
343+
344+/*************************************************************************\
345+* Copyright (c) 2011 LANS LLC, as Operator of
346+* Los Alamos National Laboratory.
347+* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
348+* National Laboratory.
349+* EPICS BASE is distributed subject to a Software License Agreement found
350+* in file LICENSE that is included with this distribution.
351+\*************************************************************************/
352+
353+/*
354+ * Author Jeffrey O. Hill
355+ * johill@lanl.gov
356+ */
357+
358+#ifndef epicsAtomicCD_h
359+#define epicsAtomicCD_h
360+
361+#include "epicsAssert.h"
362+
363+#ifndef _MSC_VER
364+# error this header file is only for use with with the Microsoft Compiler
365+#endif
366+
367+#ifdef _MSC_EXTENSIONS
368+
369+#include <intrin.h>
370+
371+#if _MSC_VER >= 1200
372+# define EPICS_ATOMIC_INLINE __forceinline
373+#else
374+# define EPICS_ATOMIC_INLINE __inline
375+#endif
376+
377+#if defined ( _M_IX86 )
378+# pragma warning( push )
379+# pragma warning( disable : 4793 )
380+ EPICS_ATOMIC_INLINE void epicsAtomicMemoryBarrier ()
381+ {
382+ long fence;
383+ __asm { xchg fence, eax }
384+ }
385+# pragma warning( pop )
386+#elif defined ( _M_X64 )
387+# define MS_ATOMIC_64
388+# pragma intrinsic ( __faststorefence )
389+ EPICS_ATOMIC_INLINE void epicsAtomicMemoryBarrier ()
390+ {
391+ __faststorefence ();
392+ }
393+#elif defined ( _M_IA64 )
394+# define MS_ATOMIC_64
395+# pragma intrinsic ( __mf )
396+ EPICS_ATOMIC_INLINE void epicsAtomicMemoryBarrier ()
397+ {
398+ __mf ();
399+ }
400+#else
401+# error unexpected target architecture, msvc version of epicsAtomicCD.h
402+#endif
403+
404+/*
405+ * The windows doc appears to recommend defining InterlockedExchange
406+ * to be _InterlockedExchange to cause it to be an intrinsic, but that
407+ * creates issues when later, in a windows os specific header, we include
408+ * windows.h. Therefore, we except some code duplication between the msvc
409+ * csAtomic.h and win32 osdAtomic.h to avoid problems, and to keep the
410+ * os specific windows.h header file out of the msvc cdAtomic.h
411+ */
412+#define MS_LONG long
413+#define MS_InterlockedExchange _InterlockedExchange
414+#define MS_InterlockedCompareExchange _InterlockedCompareExchange
415+#define MS_InterlockedIncrement _InterlockedIncrement
416+#define MS_InterlockedDecrement _InterlockedDecrement
417+#define MS_InterlockedExchange _InterlockedExchange
418+#define MS_InterlockedExchangeAdd _InterlockedExchangeAdd
419+#if defined ( MS_ATOMIC_64 )
420+# define MS_LONGLONG long long
421+# define MS_InterlockedIncrement64 _InterlockedIncrement64
422+# define MS_InterlockedDecrement64 _InterlockedDecrement64
423+# define MS_InterlockedExchange64 _InterlockedExchange64
424+# define MS_InterlockedExchangeAdd64 _InterlockedExchangeAdd64
425+# define MS_InterlockedCompareExchange64 _InterlockedCompareExchange64
426+#endif
427+
428+#ifdef __cplusplus
429+extern "C" {
430+#endif /* __cplusplus */
431+
432+#define EPICS_ATOMIC_READ_MEMORY_BARRIER
433+EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier ()
434+{
435+ epicsAtomicMemoryBarrier ();
436+}
437+
438+#define EPICS_ATOMIC_WRITE_MEMORY_BARRIER
439+EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier ()
440+{
441+ epicsAtomicMemoryBarrier ();
442+}
443+
444+#ifdef __cplusplus
445+} /* end of extern "C" */
446+#endif /* __cplusplus */
447+
448+#include "epicsAtomicMS.h"
449+#include "epicsAtomicDefault.h"
450+
451+#else /* ifdef _MSC_EXTENSIONS */
452+
453+#if defined ( __cplusplus )
454+# define EPICS_ATOMIC_INLINE inline
455+#endif
456+
457+/*
458+ * if unavailable as an intrinsic we will try
459+ * for os specific inline solution
460+ */
461+#include "epicsAtomicOSD.h"
462+
463+#endif /* ifdef _MSC_EXTENSIONS */
464+
465+#endif /* epicsAtomicCD_h */
466+
467
468=== added file 'src/libCom/osi/compiler/solStudio/epicsAtomicCD.h'
469--- src/libCom/osi/compiler/solStudio/epicsAtomicCD.h 1970-01-01 00:00:00 +0000
470+++ src/libCom/osi/compiler/solStudio/epicsAtomicCD.h 2011-09-07 17:27:41 +0000
471@@ -0,0 +1,31 @@
472+
473+/*************************************************************************\
474+* Copyright (c) 2011 LANS LLC, as Operator of
475+* Los Alamos National Laboratory.
476+* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
477+* National Laboratory.
478+* EPICS BASE is distributed subject to a Software License Agreement found
479+* in file LICENSE that is included with this distribution.
480+\*************************************************************************/
481+
482+/*
483+ * Author Jeffrey O. Hill
484+ * johill@lanl.gov
485+ */
486+
487+#ifndef epicsAtomicCD_h
488+#define epicsAtomicCD_h
489+
490+#if defined ( __cplusplus )
491+# define EPICS_ATOMIC_INLINE inline
492+#else
493+# define EPICS_ATOMIC_INLINE __inline
494+#endif
495+
496+/*
497+ * we have an inline keyword so we can proceed
498+ * with an os specific inline instantiation
499+ */
500+#include "epicsAtomicOSD.h"
501+
502+#endif /* epicsAtomicCD_h */
503
504=== added file 'src/libCom/osi/epicsAtomic.h'
505--- src/libCom/osi/epicsAtomic.h 1970-01-01 00:00:00 +0000
506+++ src/libCom/osi/epicsAtomic.h 2011-09-07 17:27:41 +0000
507@@ -0,0 +1,236 @@
508+/*************************************************************************\
509+* Copyright (c) 2011 LANS LLC, as Operator of
510+* Los Alamos National Laboratory.
511+* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
512+* National Laboratory.
513+* EPICS BASE is distributed subject to a Software License Agreement found
514+* in file LICENSE that is included with this distribution.
515+\*************************************************************************/
516+
517+/*
518+ * Author Jeffrey O. Hill
519+ * johill@lanl.gov
520+ */
521+
522+#ifndef epicsAtomic_h
523+#define epicsAtomic_h
524+
525+#include <stdlib.h> /* define size_t */
526+
527+#include "shareLib.h"
528+
529+#ifdef __cplusplus
530+extern "C" {
531+#endif
532+
533+typedef void * EpicsAtomicPtrT;
534+
535+/* load target into cache */
536+epicsShareFunc void epicsAtomicReadMemoryBarrier ();
537+
538+/* push cache version of target into target */
539+epicsShareFunc void epicsAtomicWriteMemoryBarrier ();
540+
541+/*
542+ * lock out other smp processors from accessing the target,
543+ * load target into cache, add one to target, flush cache
544+ * to target, allow other smp processors to access the target,
545+ * return new value of target as modified by this operation
546+ */
547+epicsShareFunc size_t epicsAtomicIncrSizeT ( size_t * pTarget );
548+epicsShareFunc int epicsAtomicIncrIntT ( int * pTarget );
549+
550+/*
551+ * lock out other smp processors from accessing the target,
552+ * load target into cache, subtract one from target, flush cache
553+ * to target, allow out other smp processors to access the target,
554+ * return new value of target as modified by this operation
555+ */
556+epicsShareFunc size_t epicsAtomicDecrSizeT ( size_t * pTarget );
557+epicsShareFunc int epicsAtomicDecrIntT ( int * pTarget );
558+
559+/*
560+ * lock out other smp processors from accessing the target,
561+ * load target into cache, add/sub delta to/from target, flush cache
562+ * to target, allow other smp processors to access the target,
563+ * return new value of target as modified by this operation
564+ */
565+epicsShareFunc size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta );
566+epicsShareFunc size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta );
567+epicsShareFunc int epicsAtomicAddIntT ( int * pTarget, int delta );
568+
569+/*
570+ * set cache version of target, flush cache to target
571+ */
572+epicsShareFunc void epicsAtomicSetSizeT ( size_t * pTarget, size_t newValue );
573+epicsShareFunc void epicsAtomicSetIntT ( int * pTarget, int newValue );
574+epicsShareFunc void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newValue );
575+
576+/*
577+ * fetch target into cache, return new value of target
578+ */
579+epicsShareFunc size_t epicsAtomicGetSizeT ( const size_t * pTarget );
580+epicsShareFunc int epicsAtomicGetIntT ( const int * pTarget );
581+epicsShareFunc EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget );
582+
583+/*
584+ * lock out other smp processors from accessing the target,
585+ * load target into cache, if target is equal to oldVal set target
586+ * to newVal, flush cache to target, allow other smp processors
587+ * to access the target, return the original value stored in the
588+ * target
589+ */
590+epicsShareFunc size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget,
591+ size_t oldVal, size_t newVal );
592+epicsShareFunc int epicsAtomicCmpAndSwapIntT ( int * pTarget,
593+ int oldVal, int newVal );
594+epicsShareFunc EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT (
595+ EpicsAtomicPtrT * pTarget,
596+ EpicsAtomicPtrT oldVal,
597+ EpicsAtomicPtrT newVal );
598+
599+#ifdef __cplusplus
600+} /* end of extern "C" */
601+#endif
602+
603+/*
604+ * options for inline compiler instrinsic or os specific
605+ * implementations of the above function prototypes
606+ *
607+ * for some of the compilers we must define the
608+ * inline functions before they get used in the c++
609+ * inine functions below
610+ */
611+#include "epicsAtomicCD.h"
612+
613+#ifdef __cplusplus
614+
615+namespace epics {
616+namespace atomic {
617+
618+/*
619+ * overloaded c++ interface
620+ */
621+epicsShareFunc size_t increment ( size_t & v );
622+epicsShareFunc int increment ( int & v );
623+epicsShareFunc size_t decrement ( size_t & v );
624+epicsShareFunc int decrement ( int & v );
625+epicsShareFunc size_t add ( size_t & v, size_t delta );
626+epicsShareFunc int add ( int & v, int delta );
627+epicsShareFunc size_t subtract ( size_t & v, size_t delta );
628+epicsShareFunc int subtract ( int & v, int delta );
629+epicsShareFunc void set ( size_t & v , size_t newValue );
630+epicsShareFunc void set ( int & v, int newValue );
631+epicsShareFunc void set ( EpicsAtomicPtrT & v,
632+ EpicsAtomicPtrT newValue );
633+epicsShareFunc size_t get ( const size_t & v );
634+epicsShareFunc int get ( const int & v );
635+epicsShareFunc EpicsAtomicPtrT get ( const EpicsAtomicPtrT & v );
636+epicsShareFunc size_t compareAndSwap ( size_t & v, size_t oldVal,
637+ size_t newVal );
638+epicsShareFunc int compareAndSwap ( int & v, int oldVal, int newVal );
639+epicsShareFunc EpicsAtomicPtrT compareAndSwap ( EpicsAtomicPtrT & v,
640+ EpicsAtomicPtrT oldVal,
641+ EpicsAtomicPtrT newVal );
642+
643+/************* incr ***************/
644+inline size_t increment ( size_t & v )
645+{
646+ return epicsAtomicIncrSizeT ( & v );
647+}
648+
649+inline int increment ( int & v )
650+{
651+ return epicsAtomicIncrIntT ( & v );
652+}
653+
654+/************* decr ***************/
655+inline size_t decrement ( size_t & v )
656+{
657+ return epicsAtomicDecrSizeT ( & v );
658+}
659+
660+inline int decrement ( int & v )
661+{
662+ return epicsAtomicDecrIntT ( & v );
663+}
664+
665+/************* add ***************/
666+inline size_t add ( size_t & v, size_t delta )
667+{
668+ return epicsAtomicAddSizeT ( & v, delta );
669+}
670+
671+inline int add ( int & v, int delta )
672+{
673+ return epicsAtomicAddIntT ( & v, delta );
674+}
675+
676+/************* sub ***************/
677+inline size_t subtract ( size_t & v, size_t delta )
678+{
679+ return epicsAtomicSubSizeT ( & v, delta );
680+}
681+
682+inline int subtract ( int & v, int delta )
683+{
684+ return epicsAtomicAddIntT ( & v, -delta );
685+}
686+
687+/************* set ***************/
688+inline void set ( size_t & v , size_t newValue )
689+{
690+ epicsAtomicSetSizeT ( & v, newValue );
691+}
692+
693+inline void set ( int & v, int newValue )
694+{
695+ epicsAtomicSetIntT ( & v, newValue );
696+}
697+
698+inline void set ( EpicsAtomicPtrT & v, EpicsAtomicPtrT newValue )
699+{
700+ epicsAtomicSetPtrT ( & v, newValue );
701+}
702+
703+/************* get ***************/
704+inline size_t get ( const size_t & v )
705+{
706+ return epicsAtomicGetSizeT ( & v );
707+}
708+
709+inline int get ( const int & v )
710+{
711+ return epicsAtomicGetIntT ( & v );
712+}
713+
714+inline EpicsAtomicPtrT get ( const EpicsAtomicPtrT & v )
715+{
716+ return epicsAtomicGetPtrT ( & v );
717+}
718+
719+/************* cas ***************/
720+inline size_t compareAndSwap ( size_t & v,
721+ size_t oldVal, size_t newVal )
722+{
723+ return epicsAtomicCmpAndSwapSizeT ( & v, oldVal, newVal );
724+}
725+
726+inline int compareAndSwap ( int & v, int oldVal, int newVal )
727+{
728+ return epicsAtomicCmpAndSwapIntT ( & v, oldVal, newVal );
729+}
730+
731+inline EpicsAtomicPtrT compareAndSwap ( EpicsAtomicPtrT & v,
732+ EpicsAtomicPtrT oldVal,
733+ EpicsAtomicPtrT newVal )
734+{
735+ return epicsAtomicCmpAndSwapPtrT ( & v, oldVal, newVal );
736+}
737+
738+} /* end of namespace atomic */
739+} /* end of namespace epics */
740+
741+#endif /* ifdef __cplusplus */
742+
743+#endif /* epicsAtomic_h */
744
745=== added file 'src/libCom/osi/epicsAtomicDefault.h'
746--- src/libCom/osi/epicsAtomicDefault.h 1970-01-01 00:00:00 +0000
747+++ src/libCom/osi/epicsAtomicDefault.h 2011-09-07 17:27:41 +0000
748@@ -0,0 +1,227 @@
749+
750+/*************************************************************************\
751+* Copyright (c) 2011 LANS LLC, as Operator of
752+* Los Alamos National Laboratory.
753+* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
754+* National Laboratory.
755+* EPICS BASE is distributed subject to a Software License Agreement found
756+* in file LICENSE that is included with this distribution.
757+\*************************************************************************/
758+
759+/*
760+ * Author Jeffrey O. Hill
761+ * johill@lanl.gov
762+ */
763+
764+#ifndef epicsAtomicDefault_h
765+#define epicsAtomicDefault_h
766+
767+#ifdef __cpluplus
768+extern "C" {
769+#endif
770+
771+/*
772+ * struct EpicsAtomicLockKey;
773+ * epicsShareFunc void epicsAtomicReadMemoryBarrier ();
774+ * epicsShareFunc void epicsAtomicWriteMemoryBarrier ();
775+ * epicsShareFunc void epicsAtomicLock ( struct EpicsAtomicLockKey * );
776+ * epicsShareFunc void epicsAtomicUnock ( struct EpicsAtomicLockKey * );
777+ */
778+
779+/*
780+ * incr
781+ */
782+#ifndef EPICS_ATOMIC_INCR_INTT
783+EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget )
784+{
785+ EpicsAtomicLockKey key;
786+ epicsAtomicLock ( & key );
787+ const int result = ++(*pTarget);
788+ epicsAtomicUnlock ( & key );
789+ return result;
790+}
791+#endif
792+
793+#ifndef EPICS_ATOMIC_INCR_SIZET
794+EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
795+{
796+ EpicsAtomicLockKey key;
797+ epicsAtomicLock ( & key );
798+ const size_t result = ++(*pTarget);
799+ epicsAtomicUnlock ( & key );
800+ return result;
801+}
802+#endif
803+
804+/*
805+ * decr
806+ */
807+#ifndef EPICS_ATOMIC_DECR_INTT
808+EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget )
809+{
810+ EpicsAtomicLockKey key;
811+ epicsAtomicLock ( & key );
812+ const int result = --(*pTarget);
813+ epicsAtomicUnlock ( & key );
814+ return result;
815+}
816+#endif
817+
818+#ifndef EPICS_ATOMIC_DECR_SIZET
819+EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
820+{
821+ EpicsAtomicLockKey key;
822+ epicsAtomicLock ( & key );
823+ const size_t result = --(*pTarget);
824+ epicsAtomicUnlock ( & key );
825+ return result;
826+}
827+#endif
828+
829+/*
830+ * add/sub
831+ */
832+#ifndef EPICS_ATOMIC_ADD_INTT
833+EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta )
834+{
835+ EpicsAtomicLockKey key;
836+ epicsAtomicLock ( & key );
837+ const int result = *pTarget += delta;
838+ epicsAtomicUnlock ( & key );
839+ return result;
840+}
841+#endif
842+
843+#ifndef EPICS_ATOMIC_ADD_SIZET
844+EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta )
845+{
846+ EpicsAtomicLockKey key;
847+ epicsAtomicLock ( & key );
848+ const size_t result = *pTarget += delta;
849+ epicsAtomicUnlock ( & key );
850+ return result;
851+}
852+#endif
853+
854+#ifndef EPICS_ATOMIC_SUB_SIZET
855+EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta )
856+{
857+ EpicsAtomicLockKey key;
858+ epicsAtomicLock ( & key );
859+ const size_t result = *pTarget -= delta;
860+ epicsAtomicUnlock ( & key );
861+ return result;
862+}
863+#endif
864+
865+/*
866+ * set
867+ */
868+#ifndef EPICS_ATOMIC_SET_INTT
869+EPICS_ATOMIC_INLINE void epicsAtomicSetIntT ( int * pTarget, int newVal )
870+{
871+ *pTarget = newVal;
872+ epicsAtomicWriteMemoryBarrier ();
873+}
874+#endif
875+
876+#ifndef EPICS_ATOMIC_SET_SIZET
877+EPICS_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal )
878+{
879+ *pTarget = newVal;
880+ epicsAtomicWriteMemoryBarrier ();
881+}
882+#endif
883+
884+#ifndef EPICS_ATOMIC_SET_PTRT
885+EPICS_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget,
886+ EpicsAtomicPtrT newVal )
887+{
888+ *pTarget = newVal;
889+ epicsAtomicWriteMemoryBarrier ();
890+}
891+#endif
892+
893+/*
894+ * get
895+ */
896+#ifndef EPICS_ATOMIC_GET_INTT
897+EPICS_ATOMIC_INLINE int epicsAtomicGetIntT ( const int * pTarget )
898+{
899+ epicsAtomicReadMemoryBarrier ();
900+ return *pTarget;
901+}
902+#endif
903+
904+#ifndef EPICS_ATOMIC_GET_SIZET
905+EPICS_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget )
906+{
907+ epicsAtomicReadMemoryBarrier ();
908+ return *pTarget;
909+}
910+#endif
911+
912+#ifndef EPICS_ATOMIC_GET_PTRT
913+EPICS_ATOMIC_INLINE EpicsAtomicPtrT
914+ epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget )
915+{
916+ epicsAtomicReadMemoryBarrier ();
917+ return *pTarget;
918+}
919+#endif
920+
921+/*
922+ * cmp and swap
923+ */
924+#ifndef EPICS_ATOMIC_CAS_INTT
925+EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget, int oldval, int newval )
926+{
927+ EpicsAtomicLockKey key;
928+ epicsAtomicLock ( & key );
929+ const int cur = *pTarget;
930+ if ( cur == oldval ) {
931+ *pTarget = newval;
932+ }
933+ epicsAtomicUnlock ( & key );
934+ return cur;
935+}
936+#endif
937+
938+#ifndef EPICS_ATOMIC_CAS_SIZET
939+EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget,
940+ size_t oldval, size_t newval )
941+{
942+ EpicsAtomicLockKey key;
943+ epicsAtomicLock ( & key );
944+ const size_t cur = *pTarget;
945+ if ( cur == oldval ) {
946+ *pTarget = newval;
947+ }
948+ epicsAtomicUnlock ( & key );
949+ return cur;
950+}
951+#endif
952+
953+#ifndef EPICS_ATOMIC_CAS_PTRT
954+EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT (
955+ EpicsAtomicPtrT * pTarget,
956+ EpicsAtomicPtrT oldval, EpicsAtomicPtrT newval )
957+{
958+ EpicsAtomicLockKey key;
959+ epicsAtomicLock ( & key );
960+ const EpicsAtomicPtrT cur = *pTarget;
961+ if ( cur == oldval ) {
962+ *pTarget = newval;
963+ }
964+ epicsAtomicUnlock ( & key );
965+ return cur;
966+}
967+#endif
968+
969+#ifdef __cpluplus
970+} /* end of extern "C" */
971+#endif
972+
973+#endif /* epicsAtomicDefault_h */
974+
975+
976
977=== added file 'src/libCom/osi/os/WIN32/epicsAtomicMS.h'
978--- src/libCom/osi/os/WIN32/epicsAtomicMS.h 1970-01-01 00:00:00 +0000
979+++ src/libCom/osi/os/WIN32/epicsAtomicMS.h 2011-09-07 17:27:41 +0000
980@@ -0,0 +1,222 @@
981+
982+/*************************************************************************\
983+* Copyright (c) 2011 LANS LLC, as Operator of
984+* Los Alamos National Laboratory.
985+* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
986+* National Laboratory.
987+* EPICS BASE is distributed subject to a Software License Agreement found
988+* in file LICENSE that is included with this distribution.
989+\*************************************************************************/
990+
991+/*
992+ * Author Jeffrey O. Hill
993+ * johill@lanl.gov
994+ */
995+
996+#ifndef epicsAtomicMS_h
997+#define epicsAtomicMS_h
998+
999+#include "epicsAssert.h"
1000+
1001+#ifdef __cplusplus
1002+extern "C" {
1003+#endif /* __cplusplus */
1004+
1005+#ifndef EPICS_ATOMIC_INCR_INTT
1006+#define EPICS_ATOMIC_INCR_INTT
1007+EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget )
1008+{
1009+ STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) );
1010+ MS_LONG * const pTarg = ( MS_LONG * ) pTarget;
1011+ return MS_InterlockedIncrement ( pTarg );
1012+}
1013+#endif
1014+
1015+#ifndef EPICS_ATOMIC_DECR_INTT
1016+#define EPICS_ATOMIC_DECR_INTT
1017+EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget )
1018+{
1019+ STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) );
1020+ MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget );
1021+ return MS_InterlockedDecrement ( pTarg );
1022+}
1023+#endif
1024+
1025+#ifndef EPICS_ATOMIC_ADD_INTT
1026+#define EPICS_ATOMIC_ADD_INTT
1027+EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta )
1028+{
1029+ STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) );
1030+ MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget );
1031+ /* we dont use InterlockedAdd because only latest windows is supported */
1032+ return delta + ( int ) MS_InterlockedExchangeAdd ( pTarg,
1033+ ( MS_LONG ) delta );
1034+}
1035+#endif
1036+
1037+#ifndef EPICS_ATOMIC_CAS_INTT
1038+#define EPICS_ATOMIC_CAS_INTT
1039+EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget,
1040+ int oldVal, int newVal )
1041+{
1042+ STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) );
1043+ MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget );
1044+ return (int) MS_InterlockedCompareExchange ( pTarg,
1045+ (MS_LONG) newVal, (MS_LONG) oldVal );
1046+}
1047+#endif
1048+
1049+#if ! defined ( MS_ATOMIC_64 )
1050+
1051+/*
1052+ * necessary for next three functions
1053+ *
1054+ * looking at the MS documentation it appears that they will
1055+ * keep type long the same size as an int on 64 bit builds
1056+ */
1057+STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( size_t ) );
1058+
1059+#ifndef EPICS_ATOMIC_INCR_SIZET
1060+#define EPICS_ATOMIC_INCR_SIZET
1061+EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
1062+{
1063+ MS_LONG * const pTarg = ( MS_LONG * ) pTarget;
1064+ return MS_InterlockedIncrement ( pTarg );
1065+}
1066+#endif
1067+
1068+#ifndef EPICS_ATOMIC_DECR_SIZET
1069+#define EPICS_ATOMIC_DECR_SIZET
1070+EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
1071+{
1072+ MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget );
1073+ return MS_InterlockedDecrement ( pTarg );
1074+}
1075+#endif
1076+
1077+#ifndef EPICS_ATOMIC_ADD_SIZET
1078+#define EPICS_ATOMIC_ADD_SIZET
1079+EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget,
1080+ size_t delta )
1081+{
1082+ MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget );
1083+ /* we dont use InterlockedAdd because only latest windows is supported */
1084+ return delta + ( size_t ) MS_InterlockedExchangeAdd ( pTarg,
1085+ ( MS_LONG ) delta );
1086+}
1087+#endif
1088+
1089+#ifndef EPICS_ATOMIC_SUB_SIZET
1090+#define EPICS_ATOMIC_SUB_SIZET
1091+EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta )
1092+{
1093+ MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget );
1094+ MS_LONG ldelta = (MS_LONG) delta;
1095+ /* we dont use InterlockedAdd because only latest windows is supported */
1096+ return ( ( size_t ) MS_InterlockedExchangeAdd ( pTarg, -ldelta ) ) - delta;
1097+}
1098+#endif
1099+
1100+#ifndef EPICS_ATOMIC_CAS_SIZET
1101+#define EPICS_ATOMIC_CAS_SIZET
1102+EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT (
1103+ size_t * pTarget,
1104+ size_t oldVal, size_t newVal )
1105+{
1106+ MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget );
1107+ return (size_t) MS_InterlockedCompareExchange ( pTarg,
1108+ (MS_LONG) newVal, (MS_LONG) oldVal );
1109+}
1110+#endif
1111+
1112+#ifndef EPICS_ATOMIC_CAS_PTRT
1113+#define EPICS_ATOMIC_CAS_PTRT
1114+EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT (
1115+ EpicsAtomicPtrT * pTarget,
1116+ EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal )
1117+{
1118+ MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget );
1119+ return (EpicsAtomicPtrT) MS_InterlockedCompareExchange ( pTarg,
1120+ (MS_LONG) newVal, (MS_LONG) oldVal );
1121+}
1122+#endif
1123+
1124+#else /* ! MS_ATOMIC_64 */
1125+
1126+/*
1127+ * necessary for next three functions
1128+ */
1129+STATIC_ASSERT ( sizeof ( MS_LONGLONG ) == sizeof ( size_t ) );
1130+
1131+#ifndef EPICS_ATOMIC_INCR_SIZET
1132+#define EPICS_ATOMIC_INCR_SIZET
1133+EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
1134+{
1135+ MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) pTarget;
1136+ return ( size_t ) MS_InterlockedIncrement64 ( pTarg );
1137+}
1138+#endif
1139+
1140+#ifndef EPICS_ATOMIC_DECR_SIZET
1141+#define EPICS_ATOMIC_DECR_SIZET
1142+EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
1143+{
1144+ MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget );
1145+ return ( size_t ) MS_InterlockedDecrement64 ( pTarg );
1146+}
1147+#endif
1148+
1149+#ifndef EPICS_ATOMIC_ADD_SIZET
1150+#define EPICS_ATOMIC_ADD_SIZET
1151+EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta )
1152+{
1153+ MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget );
1154+ /* we dont use InterlockedAdd64 because only latest windows is supported */
1155+ return delta + ( size_t ) MS_InterlockedExchangeAdd64 ( pTarg,
1156+ ( MS_LONGLONG ) delta );
1157+}
1158+#endif
1159+
1160+#ifndef EPICS_ATOMIC_SUB_SIZET
1161+#define EPICS_ATOMIC_SUB_SIZET
1162+EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta )
1163+{
1164+ MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget );
1165+ MS_LONGLONG ldelta = (MS_LONGLONG) delta;
1166+ /* we dont use InterlockedAdd64 because only latest windows is supported */
1167+ return (( size_t ) MS_InterlockedExchangeAdd64 ( pTarg, -ldelta )) - delta;
1168+}
1169+#endif
1170+
1171+#ifndef EPICS_ATOMIC_CAS_SIZET
1172+#define EPICS_ATOMIC_CAS_SIZET
1173+EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget,
1174+ size_t oldVal, size_t newVal )
1175+{
1176+ MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget );
1177+ return (size_t) MS_InterlockedCompareExchange64 ( pTarg,
1178+ (MS_LONGLONG) newVal,
1179+ (MS_LONGLONG) oldVal );
1180+}
1181+#endif
1182+
1183+#ifndef EPICS_ATOMIC_CAS_PTRT
1184+#define EPICS_ATOMIC_CAS_PTRT
1185+EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT (
1186+ EpicsAtomicPtrT * pTarget,
1187+ EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal )
1188+{
1189+ MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget );
1190+ return (EpicsAtomicPtrT) MS_InterlockedCompareExchange64 ( pTarg,
1191+ (MS_LONGLONG) newVal, (MS_LONGLONG) oldVal );
1192+}
1193+#endif
1194+
1195+#endif /* ! MS_ATOMIC_64 */
1196+
1197+#ifdef __cplusplus
1198+} /* end of extern "C" */
1199+#endif /* __cplusplus */
1200+
1201+#endif /* ifdef epicsAtomicMS_h */
1202+
1203
1204=== added file 'src/libCom/osi/os/WIN32/epicsAtomicOSD.cpp'
1205--- src/libCom/osi/os/WIN32/epicsAtomicOSD.cpp 1970-01-01 00:00:00 +0000
1206+++ src/libCom/osi/os/WIN32/epicsAtomicOSD.cpp 2011-09-07 17:27:41 +0000
1207@@ -0,0 +1,22 @@
1208+
1209+/*************************************************************************\
1210+* Copyright (c) 2011 LANS LLC, as Operator of
1211+* Los Alamos National Laboratory.
1212+* EPICS BASE is distributed subject to a Software License Agreement found
1213+* in file LICENSE that is included with this distribution.
1214+\*************************************************************************/
1215+
1216+/*
1217+ * Author Jeffrey O. Hill
1218+ * johill@lanl.gov
1219+ */
1220+
1221+#define epicsExportSharedSymbols
1222+#include "epicsAtomic.h"
1223+
1224+// if the compiler is unable to inline then instantiate out-of-line
1225+#ifndef EPICS_ATOMIC_INLINE
1226+# define EPICS_ATOMIC_INLINE
1227+# include "epicsAtomicOSD.h"
1228+#endif
1229+
1230
1231=== added file 'src/libCom/osi/os/WIN32/epicsAtomicOSD.h'
1232--- src/libCom/osi/os/WIN32/epicsAtomicOSD.h 1970-01-01 00:00:00 +0000
1233+++ src/libCom/osi/os/WIN32/epicsAtomicOSD.h 2011-09-07 17:27:41 +0000
1234@@ -0,0 +1,47 @@
1235+
1236+/*************************************************************************\
1237+* Copyright (c) 2011 LANS LLC, as Operator of
1238+* Los Alamos National Laboratory.
1239+* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
1240+* National Laboratory.
1241+* EPICS BASE is distributed subject to a Software License Agreement found
1242+* in file LICENSE that is included with this distribution.
1243+\*************************************************************************/
1244+
1245+/*
1246+ * Author Jeffrey O. Hill
1247+ * johill@lanl.gov
1248+ */
1249+
1250+#ifndef epicsAtomicOSD_h
1251+#define epicsAtomicOSD_h
1252+
1253+#define VC_EXTRALEAN
1254+#define STRICT
1255+#include "windows.h"
1256+
1257+#if defined ( _WIN64 )
1258+# define MS_ATOMIC_64
1259+#endif
1260+
1261+#define MS_LONG LONG
1262+#define MS_InterlockedExchange InterlockedExchange
1263+#define MS_InterlockedCompareExchange InterlockedCompareExchange
1264+#define MS_InterlockedIncrement InterlockedIncrement
1265+#define MS_InterlockedDecrement InterlockedDecrement
1266+#define MS_InterlockedExchange InterlockedExchange
1267+#define MS_InterlockedExchangeAdd InterlockedExchangeAdd
1268+#if defined ( MS_ATOMIC_64 )
1269+# define MS_LONGLONG LONGLONG
1270+# define MS_InterlockedIncrement64 InterlockedIncrement64
1271+# define MS_InterlockedDecrement64 InterlockedDecrement64
1272+# define MS_InterlockedExchange64 InterlockedExchange64
1273+# define MS_InterlockedExchangeAdd64 InterlockedExchangeAdd64
1274+# define MS_InterlockedCompareExchange InterlockedCompareExchange64
1275+#endif
1276+
1277+#include "epicsAtomicMS.h"
1278+#include "epicsAtomicDefault.h"
1279+
1280+#endif /* epicsAtomicOSD_h */
1281+
1282
1283=== added file 'src/libCom/osi/os/posix/epicsAtomicOSD.cpp'
1284--- src/libCom/osi/os/posix/epicsAtomicOSD.cpp 1970-01-01 00:00:00 +0000
1285+++ src/libCom/osi/os/posix/epicsAtomicOSD.cpp 2011-09-07 17:27:41 +0000
1286@@ -0,0 +1,99 @@
1287+
1288+/*************************************************************************\
1289+* Copyright (c) 2011 LANS LLC, as Operator of
1290+* Los Alamos National Laboratory.
1291+* EPICS BASE is distributed subject to a Software License Agreement found
1292+* in file LICENSE that is included with this distribution.
1293+\*************************************************************************/
1294+
1295+/*
1296+ * Author: Jeffrey O. Hill
1297+ * johill@lanl.gov
1298+ */
1299+
1300+#include <errno.h>
1301+#include <unistd.h>
1302+#include <pthread.h>
1303+
1304+#define epicsExportSharedSymbols
1305+#include "epicsAssert.h"
1306+#include "epicsAtomic.h"
1307+
1308+// if the compiler is unable to inline then instantiate out-of-line
1309+#ifndef EPICS_ATOMIC_INLINE
1310+# define EPICS_ATOMIC_INLINE
1311+# include "epicsAtomicOSD.h"
1312+#endif
1313+
1314+#ifndef EPICS_ATOMIC_LOCK
1315+
1316+/*
1317+ * Slow, but probably correct on all systems.
1318+ * Useful only if something more efficent isnt
1319+ * provided based on knowledge of the compiler
1320+ * or OS
1321+ *
1322+ * A statically initialized pthread mutex doesnt
1323+ * need to be destroyed
1324+ *
1325+ * !!!!!
1326+ * !!!!! WARNING
1327+ * !!!!!
1328+ * !!!!! Do not use this implementation on systems where
1329+ * !!!!! code runs at interrupt context. If so, then
1330+ * !!!!! an implementation must be provided that is based
1331+ * !!!!! on a compiler intrinsic or an interrpt lock and or
1332+ * !!!!! a spin lock primitive
1333+ * !!!!!
1334+ */
1335+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
1336+
1337+void epicsAtomicLock ( EpicsAtomicLockKey * )
1338+{
1339+ unsigned countDown = 1000u;
1340+ int status;
1341+ while ( true ) {
1342+ status = pthread_mutex_lock ( & mutex );
1343+ if ( status == 0 ) return;
1344+ assert ( status == EINTR );
1345+ static const useconds_t retryDelayUSec = 100000;
1346+ usleep ( retryDelayUSec );
1347+ countDown--;
1348+ assert ( countDown );
1349+ }
1350+}
1351+
1352+void epicsAtomicUnlock ( EpicsAtomicLockKey * )
1353+{
1354+ const int status = pthread_mutex_unlock ( & mutex );
1355+ assert ( status == 0 );
1356+}
1357+
1358+#endif // ifndef EPICS_ATOMIC_LOCK
1359+
1360+#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER
1361+// Slow, but probably correct on all systems.
1362+// Useful only if something more efficent isnt
1363+// provided based on knowledge of the compiler
1364+// or OS
1365+void epicsAtomicReadMemoryBarrier ()
1366+{
1367+ EpicsAtomicLockKey key;
1368+ epicsAtomicLock ( & key );
1369+ epicsAtomicUnlock ( & key );
1370+}
1371+#endif
1372+
1373+#ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER
1374+// Slow, but probably correct on all systems.
1375+// Useful only if something more efficent isnt
1376+// provided based on knowledge of the compiler
1377+// or OS
1378+void epicsAtomicWriteMemoryBarrier ()
1379+{
1380+ EpicsAtomicLockKey key;
1381+ epicsAtomicLock ( & key );
1382+ epicsAtomicUnlock ( & key );
1383+}
1384+#endif
1385+
1386
1387=== added file 'src/libCom/osi/os/posix/epicsAtomicOSD.h'
1388--- src/libCom/osi/os/posix/epicsAtomicOSD.h 1970-01-01 00:00:00 +0000
1389+++ src/libCom/osi/os/posix/epicsAtomicOSD.h 2011-09-07 17:27:41 +0000
1390@@ -0,0 +1,35 @@
1391+
1392+/*************************************************************************\
1393+* Copyright (c) 2011 LANS LLC, as Operator of
1394+* Los Alamos National Laboratory.
1395+* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
1396+* National Laboratory.
1397+* EPICS BASE is distributed subject to a Software License Agreement found
1398+* in file LICENSE that is included with this distribution.
1399+\*************************************************************************/
1400+
1401+/*
1402+ * Author Jeffrey O. Hill
1403+ * johill@lanl.gov
1404+ */
1405+
1406+#ifndef epicsAtomicOSD_h
1407+#define epicsAtomicOSD_h
1408+
1409+struct EpicsAtomicLockKey {};
1410+
1411+#ifdef __cplusplus
1412+extern "C" {
1413+#endif /* __cplusplus */
1414+
1415+epicsShareFunc void epicsAtomicLock ( struct EpicsAtomicLockKey * );
1416+epicsShareFunc void epicsAtomicUnlock ( struct EpicsAtomicLockKey * );
1417+
1418+#ifdef __cplusplus
1419+} /* end of extern "C" */
1420+#endif /* __cplusplus */
1421+
1422+#include "epicsAtomicDefault.h"
1423+
1424+#endif /* epicsAtomicOSD_h */
1425+
1426
1427=== added file 'src/libCom/osi/os/solaris/epicsAtomicOSD.h'
1428--- src/libCom/osi/os/solaris/epicsAtomicOSD.h 1970-01-01 00:00:00 +0000
1429+++ src/libCom/osi/os/solaris/epicsAtomicOSD.h 2011-09-07 17:27:41 +0000
1430@@ -0,0 +1,178 @@
1431+
1432+/*************************************************************************\
1433+* Copyright (c) 2011 LANS LLC, as Operator of
1434+* Los Alamos National Laboratory.
1435+* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
1436+* National Laboratory.
1437+* EPICS BASE is distributed subject to a Software License Agreement found
1438+* in file LICENSE that is included with this distribution.
1439+\*************************************************************************/
1440+
1441+/*
1442+ * Author Jeffrey O. Hill
1443+ * johill@lanl.gov
1444+ */
1445+
1446+#ifndef epicsAtomicOSD_h
1447+#define epicsAtomicOSD_h
1448+
1449+#if defined ( __SunOS_5_10 )
1450+
1451+/*
1452+ * atomic.h exists only in Solaris 10 or higher
1453+ */
1454+#include <atomic.h>
1455+
1456+#include "epicsAssert.h"
1457+
1458+#ifdef __cplusplus
1459+extern "C" {
1460+#endif /* __cplusplus */
1461+
1462+#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER
1463+#define EPICS_ATOMIC_READ_MEMORY_BARRIER
1464+EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier ()
1465+{
1466+ membar_consumer ();
1467+}
1468+#endif
1469+
1470+#ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER
1471+#define EPICS_ATOMIC_WRITE_MEMORY_BARRIER
1472+EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier ()
1473+{
1474+ membar_producer ();
1475+}
1476+#endif
1477+
1478+#ifndef EPICS_ATOMIC_CAS_INTT
1479+#define EPICS_ATOMIC_CAS_INTT
1480+EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget,
1481+ int oldVal, int newVal )
1482+{
1483+ STATIC_ASSERT ( sizeof ( int ) == sizeof ( unsigned ) );
1484+ unsigned * const pTarg = ( unsigned * ) pTarget;
1485+ return ( int ) atomic_cas_uint ( pTarg, ( unsigned ) oldVal,
1486+ ( unsigned ) newVal );
1487+}
1488+#endif
1489+
1490+#ifndef EPICS_ATOMIC_CAS_SIZET
1491+#define EPICS_ATOMIC_CAS_SIZET
1492+EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT (
1493+ size_t * pTarget,
1494+ size_t oldVal, size_t newVal )
1495+{
1496+ STATIC_ASSERT ( sizeof ( ulong_t ) == sizeof ( size_t ) );
1497+ ulong_t * const pTarg = ( ulong_t * ) pTarget;
1498+ return ( size_t ) atomic_cas_ulong ( pTarg, oldVal, newVal );
1499+}
1500+#endif
1501+
1502+#ifndef EPICS_ATOMIC_CAS_PTRT
1503+#define EPICS_ATOMIC_CAS_PTRT
1504+EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT (
1505+ EpicsAtomicPtrT * pTarget,
1506+ EpicsAtomicPtrT oldVal,
1507+ EpicsAtomicPtrT newVal )
1508+{
1509+ return atomic_cas_ptr ( pTarget, oldVal, newVal );
1510+}
1511+#endif
1512+
1513+#ifndef EPICS_ATOMIC_INCR_INTT
1514+#define EPICS_ATOMIC_INCR_INTT
1515+EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget )
1516+{
1517+ STATIC_ASSERT ( sizeof ( unsigned ) == sizeof ( int ) );
1518+ unsigned * const pTarg = ( unsigned * ) ( pTarget );
1519+ return ( int ) atomic_inc_uint_nv ( pTarg );
1520+}
1521+#endif
1522+
1523+#ifndef EPICS_ATOMIC_INCR_SIZET
1524+#define EPICS_ATOMIC_INCR_SIZET
1525+EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
1526+{
1527+ STATIC_ASSERT ( sizeof ( ulong_t ) == sizeof ( size_t ) );
1528+ ulong_t * const pTarg = ( ulong_t * ) pTarget;
1529+ return ( size_t ) atomic_inc_ulong_nv ( pTarg );
1530+}
1531+#endif
1532+
1533+#ifndef EPICS_ATOMIC_DECR_INTT
1534+#define EPICS_ATOMIC_DECR_INTT
1535+EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget )
1536+{
1537+ STATIC_ASSERT ( sizeof ( unsigned ) == sizeof ( int ) );
1538+ unsigned * const pTarg = ( unsigned * ) ( pTarget );
1539+ return ( int ) atomic_dec_uint_nv ( pTarg );
1540+}
1541+#endif
1542+
1543+#ifndef EPICS_ATOMIC_DECR_SIZET
1544+#define EPICS_ATOMIC_DECR_SIZET
1545+EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
1546+{
1547+ STATIC_ASSERT ( sizeof ( ulong_t ) == sizeof ( size_t ) );
1548+ ulong_t * const pTarg = ( ulong_t * ) pTarget;
1549+ return ( size_t ) atomic_dec_ulong_nv ( pTarg );
1550+}
1551+#endif
1552+
1553+#ifndef EPICS_ATOMIC_ADD_INTT
1554+#define EPICS_ATOMIC_ADD_INTT
1555+EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta )
1556+{
1557+ STATIC_ASSERT ( sizeof ( unsigned ) == sizeof ( int ) );
1558+ unsigned * const pTarg = ( unsigned * ) ( pTarget );
1559+ return ( int ) atomic_add_int_nv ( pTarg, delta );
1560+}
1561+#endif
1562+
1563+#ifndef EPICS_ATOMIC_ADD_SIZET
1564+#define EPICS_ATOMIC_ADD_SIZET
1565+EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget,
1566+ size_t delta )
1567+{
1568+ STATIC_ASSERT ( sizeof ( ulong_t ) == sizeof ( size_t ) );
1569+ ulong_t * const pTarg = ( ulong_t * ) pTarget;
1570+ return ( size_t ) atomic_add_long_nv ( pTarg, ( long ) delta );
1571+}
1572+#endif
1573+
1574+#ifndef EPICS_ATOMIC_SUB_SIZET
1575+#define EPICS_ATOMIC_SUB_SIZET
1576+EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget,
1577+ size_t delta )
1578+{
1579+ STATIC_ASSERT ( sizeof ( ulong_t ) == sizeof ( size_t ) );
1580+ ulong_t * const pTarg = ( ulong_t * ) pTarget;
1581+ long sdelta = ( long ) delta;
1582+ return ( size_t ) atomic_add_long_nv ( pTarg, -sdelta );
1583+}
1584+#endif
1585+
1586+#ifdef __cplusplus
1587+} /* end of extern "C" */
1588+#endif /* __cplusplus */
1589+
1590+#endif /* ifdef __SunOS_5_10 */
1591+
1592+struct EpicsAtomicLockKey {};
1593+
1594+#ifdef __cplusplus
1595+extern "C" {
1596+#endif /* __cplusplus */
1597+
1598+epicsShareFunc void epicsAtomicLock ( struct EpicsAtomicLockKey * );
1599+epicsShareFunc void epicsAtomicUnlock ( struct EpicsAtomicLockKey * );
1600+
1601+#ifdef __cplusplus
1602+} /* end of extern "C" */
1603+#endif /* __cplusplus */
1604+
1605+#include "epicsAtomicDefault.h"
1606+
1607+#endif /* epicsAtomicOSD_h */
1608+
1609
1610=== added file 'src/libCom/osi/os/vxWorks/epicsAtomicOSD.cpp'
1611--- src/libCom/osi/os/vxWorks/epicsAtomicOSD.cpp 1970-01-01 00:00:00 +0000
1612+++ src/libCom/osi/os/vxWorks/epicsAtomicOSD.cpp 2011-09-07 17:27:41 +0000
1613@@ -0,0 +1,21 @@
1614+
1615+/*************************************************************************\
1616+* Copyright (c) 2011 LANS LLC, as Operator of
1617+* Los Alamos National Laboratory.
1618+* EPICS BASE is distributed subject to a Software License Agreement found
1619+* in file LICENSE that is included with this distribution.
1620+\*************************************************************************/
1621+
1622+/*
1623+ * Author Jeffrey O. Hill
1624+ * johill@lanl.gov
1625+ */
1626+
1627+#define epicsExportSharedSymbols
1628+#include "epicsAtomic.h"
1629+
1630+// if the compiler is unable to inline then instantiate out-of-line
1631+#ifndef EPICS_ATOMIC_INLINE
1632+# define EPICS_ATOMIC_INLINE
1633+# include "epicsAtomicOSD.h"
1634+#endif
1635
1636=== added file 'src/libCom/osi/os/vxWorks/epicsAtomicOSD.h'
1637--- src/libCom/osi/os/vxWorks/epicsAtomicOSD.h 1970-01-01 00:00:00 +0000
1638+++ src/libCom/osi/os/vxWorks/epicsAtomicOSD.h 2011-09-07 17:27:41 +0000
1639@@ -0,0 +1,256 @@
1640+/*************************************************************************\
1641+* Copyright (c) 2011 LANS LLC, as Operator of
1642+* Los Alamos National Laboratory.
1643+* Copyright (c) 2011 UChicago Argonne, LLC, as Operator of
1644+* Argonne National Laboratory.
1645+* EPICS BASE is distributed subject to a Software License Agreement found
1646+* in file LICENSE that is included with this distribution.
1647+\*************************************************************************/
1648+
1649+/*
1650+ * Author Jeffrey O. Hill
1651+ * johill@lanl.gov
1652+ */
1653+
1654+#ifndef epicsAtomicOSD_h
1655+#define epicsAtomicOSD_h
1656+
1657+/* This is needed for vxWorks 6.8 to prevent an obnoxious compiler warning */
1658+#ifndef _VSB_CONFIG_FILE
1659+# define _VSB_CONFIG_FILE <../lib/h/config/vsbConfig.h>
1660+#endif
1661+
1662+#include "vxWorks.h" /* obtain the version of vxWorks */
1663+#include "epicsAssert.h"
1664+
1665+/*
1666+ * With vxWorks 6.6 and later we need to use vxAtomicLib
1667+ * to implement this functionality correctly on SMP systems
1668+ */
1669+#if _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606
1670+
1671+#include <limits.h>
1672+#include <vxAtomicLib.h>
1673+
1674+#ifdef __cplusplus
1675+extern "C" {
1676+#endif /* __cplusplus */
1677+
1678+#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER
1679+#define EPICS_ATOMIC_READ_MEMORY_BARRIER
1680+EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier ()
1681+{
1682+ VX_MEM_BARRIER_R ();
1683+}
1684+#endif
1685+
1686+#ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER
1687+#define EPICS_ATOMIC_WRITE_MEMORY_BARRIER
1688+EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier ()
1689+{
1690+ VX_MEM_BARRIER_W ();
1691+}
1692+#endif
1693+
1694+/*
1695+ * we make the probably correct guess that if ULONG_MAX
1696+ * is the same as UINT_MAX then sizeof ( atomic_t )
1697+ * will be the same as sizeof ( size_t )
1698+ *
1699+ * if ULONG_MAX != UINT_MAX then its 64 bit vxWorks and
1700+ * WRS doesnt not supply at this time the atomic interface
1701+ * for 8 byte integers that is needed - so that architecture
1702+ * receives the lock synchronized version
1703+ */
1704+#if ULONG_MAX == UINT_MAX
1705+
1706+STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( size_t ) );
1707+STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( EpicsAtomicPtrT ) );
1708+
1709+
1710+#ifndef EPICS_ATOMIC_INCR_SIZET
1711+#define EPICS_ATOMIC_INCR_SIZET
1712+EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
1713+{
1714+ atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
1715+ const atomic_t oldVal = vxAtomicInc ( pTarg );
1716+ return 1 + ( size_t ) ( oldVal );
1717+}
1718+#endif
1719+
1720+#ifndef EPICS_ATOMIC_DECR_SIZET
1721+#define EPICS_ATOMIC_DECR_SIZET
1722+EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
1723+{
1724+ atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
1725+ const atomic_t oldVal = vxAtomicDec ( pTarg );
1726+ return ( ( size_t ) oldVal ) - 1u;
1727+}
1728+#endif
1729+
1730+#ifndef EPICS_ATOMIC_ADD_SIZET
1731+#define EPICS_ATOMIC_ADD_SIZET
1732+EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta )
1733+{
1734+ /*
1735+ * vxAtomicLib doc indicates that vxAtomicAdd is
1736+ * implemented using signed arithmetic, but it
1737+ * does not change the end result because twos
1738+ * complement addition is used in either case
1739+ */
1740+ atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
1741+ const atomic_t oldVal = vxAtomicAdd ( pTarg, (atomic_t) delta );
1742+ return delta + ( size_t ) oldVal;
1743+}
1744+#endif
1745+
1746+#ifndef EPICS_ATOMIC_SUB_SIZET
1747+#define EPICS_ATOMIC_SUB_SIZET
1748+EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta )
1749+{
1750+ /*
1751+ * vxAtomicLib doc indicates that vxAtomicSub is
1752+ * implemented using signed arithmetic, but it
1753+ * does not change the end result because twos
1754+ * complement subtraction is used in either case
1755+ */
1756+ atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
1757+ const atomic_t oldVal = vxAtomicSub ( pTarg, (atomic_t) delta );
1758+ return ( ( size_t ) oldVal ) - delta;
1759+}
1760+#endif
1761+
1762+#ifndef EPICS_ATOMIC_CAS_SIZET
1763+#define EPICS_ATOMIC_CAS_SIZET
1764+EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget,
1765+ size_t oldVal, size_t newVal )
1766+{
1767+ atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
1768+ return ( size_t ) vxCas ( pTarg, (atomic_t) oldVal, (atomic_t) newVal );
1769+}
1770+#endif
1771+
1772+#ifndef EPICS_ATOMIC_CAS_PTRT
1773+#define EPICS_ATOMIC_CAS_PTRT
1774+EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget,
1775+ EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal )
1776+{
1777+ atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
1778+ return (EpicsAtomicPtrT) vxCas ( pTarg, (atomic_t) oldVal, (atomic_t) newVal );
1779+}
1780+#endif
1781+
1782+#else /* ULONG_MAX == UINT_MAX */
1783+
1784+/*
1785+ * if its 64 bit SMP vxWorks and the compiler doesnt
1786+ * have an intrinsic then maybe there isnt any way to
1787+ * implement these without using a global lock because
1788+ * size_t is maybe bigger than atomic_t
1789+ *
1790+ * I dont yet have access to vxWorks manuals for
1791+ * 64 bit systems so this is still undecided, but is
1792+ * defaulting now to a global lock
1793+ */
1794+
1795+#endif /* ULONG_MAX == UINT_MAX */
1796+
1797+STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( int ) );
1798+
1799+#ifndef EPICS_ATOMIC_INCR_INTT
1800+#define EPICS_ATOMIC_INCR_INTT
1801+EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget )
1802+{
1803+ atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
1804+ const atomic_t oldVal = vxAtomicInc ( pTarg );
1805+ return 1 + ( int ) oldVal;
1806+}
1807+#endif
1808+
1809+#ifndef EPICS_ATOMIC_DECR_INTT
1810+#define EPICS_ATOMIC_DECR_INTT
1811+EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget )
1812+{
1813+ atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
1814+ const atomic_t oldVal = vxAtomicDec ( pTarg );
1815+ return ( ( int ) oldVal ) - 1;
1816+}
1817+#endif
1818+
1819+#ifndef EPICS_ATOMIC_ADD_INTT
1820+#define EPICS_ATOMIC_ADD_INTT
1821+EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta )
1822+{
1823+ atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
1824+ const atomic_t oldVal = vxAtomicAdd ( pTarg, (atomic_t) delta );
1825+ return delta + ( int ) oldVal;
1826+}
1827+#endif
1828+
1829+#ifndef EPICS_ATOMIC_CAS_INTT
1830+#define EPICS_ATOMIC_CAS_INTT
1831+EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget,
1832+ int oldVal, int newVal )
1833+{
1834+ atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
1835+ return ( int ) vxCas ( pTarg, (atomic_t) oldVal, (atomic_t) newVal );
1836+}
1837+#endif
1838+
1839+#ifdef __cplusplus
1840+} /* end of extern "C" */
1841+#endif /* __cplusplus */
1842+
1843+#else /* _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606 */
1844+
1845+#include "vxLib.h"
1846+#include "intLib.h"
1847+
1848+#ifdef __cplusplus
1849+extern "C" {
1850+#endif /* __cplusplus */
1851+
1852+#ifndef EPICS_ATOMIC_LOCK
1853+#define EPICS_ATOMIC_LOCK
1854+
1855+typedef struct EpicsAtomicLockKey { int m_key; } EpicsAtomicLockKey;
1856+
1857+EPICS_ATOMIC_INLINE void epicsAtomicLock ( EpicsAtomicLockKey * pKey )
1858+{
1859+ pKey->m_key = intLock ();
1860+}
1861+
1862+EPICS_ATOMIC_INLINE void epicsAtomicUnlock ( EpicsAtomicLockKey * pKey )
1863+{
1864+ intUnlock ( pKey->m_key );
1865+}
1866+#endif
1867+
1868+#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER
1869+#define EPICS_ATOMIC_READ_MEMORY_BARRIER
1870+/*
1871+ * no need for memory barrior since prior to vxWorks 6.6 it is a single cpu system
1872+ * (we are not protecting against multiple access to memory mapped IO)
1873+ */
1874+EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier () {}
1875+#endif
1876+
1877+#ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER
1878+#define EPICS_ATOMIC_WRITE_MEMORY_BARRIER
1879+/*
1880+ * no need for memory barrior since prior to vxWorks 6.6 it is a single cpu system
1881+ * (we are not protecting against multiple access to memory mapped IO)
1882+ */
1883+EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier () {}
1884+#endif
1885+
1886+#ifdef __cplusplus
1887+} /* end of extern "C" */
1888+#endif /* __cplusplus */
1889+
1890+#endif /* _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606 */
1891+
1892+#include "epicsAtomicDefault.h"
1893+
1894+#endif /* epicsAtomicOSD_h */
1895+
1896
1897=== modified file 'src/libCom/osi/os/vxWorks/osdSock.h'
1898--- src/libCom/osi/os/vxWorks/osdSock.h 2010-08-11 15:45:17 +0000
1899+++ src/libCom/osi/os/vxWorks/osdSock.h 2011-09-07 17:27:41 +0000
1900@@ -3,8 +3,7 @@
1901 * National Laboratory.
1902 * Copyright (c) 2002 The Regents of the University of California, as
1903 * Operator of Los Alamos National Laboratory.
1904-* EPICS BASE Versions 3.13.7
1905-* and higher are distributed subject to a Software License Agreement found
1906+* EPICS BASE is distributed subject to a Software License Agreement found
1907 * in file LICENSE that is included with this distribution.
1908 \*************************************************************************/
1909 /*
1910@@ -14,12 +13,10 @@
1911 #ifndef osdSockH
1912 #define osdSockH
1913
1914-#ifdef __cplusplus
1915-extern "C" {
1916-#endif
1917-
1918 /* This is needed for vxWorks 6.8 to prevent an obnoxious compiler warning */
1919-#define _VSB_CONFIG_FILE <../lib/h/config/vsbConfig.h>
1920+#ifndef _VSB_CONFIG_FILE
1921+# define _VSB_CONFIG_FILE <../lib/h/config/vsbConfig.h>
1922+#endif
1923
1924 #include <errno.h>
1925
1926@@ -36,6 +33,11 @@
1927 #include <ioLib.h>
1928 #include <hostLib.h>
1929 #include <selectLib.h>
1930+
1931+#ifdef __cplusplus
1932+extern "C" {
1933+#endif
1934+
1935 /*This following is not defined in any vxWorks header files*/
1936 int sysClkRateGet(void);
1937
1938
1939=== modified file 'src/libCom/test/Makefile'
1940--- src/libCom/test/Makefile 2011-09-07 15:05:42 +0000
1941+++ src/libCom/test/Makefile 2011-09-07 17:27:41 +0000
1942@@ -109,6 +109,11 @@
1943 testHarness_SRCS += epicsMutexTest.cpp
1944 TESTS += epicsMutexTest
1945
1946+TESTPROD_HOST += epicsAtomicTest
1947+epicsAtomicTest_SRCS += epicsAtomicTest.cpp
1948+testHarness_SRCS += epicsAtomicTest.cpp
1949+TESTS += epicsAtomicTest
1950+
1951 TESTPROD_HOST += epicsExceptionTest
1952 epicsExceptionTest_SRCS += epicsExceptionTest.cpp
1953 testHarness_SRCS += epicsExceptionTest.cpp
1954@@ -179,6 +184,10 @@
1955 fdmgrTest_LIBS += ca
1956 # FIXME: program never exits.
1957
1958+TESTPROD_HOST += epicsAtomicPerform
1959+epicsAtomicPerform_SRCS += epicsAtomicPerform.cpp
1960+testHarness_SRCS += epicsAtomicPerform.cpp
1961+
1962 TESTPROD_HOST += cvtFastPerform
1963 cvtFastPerform_SRCS += cvtFastPerform.cpp
1964 testHarness_SRCS += cvtFastPerform.cpp
1965
1966=== added file 'src/libCom/test/epicsAtomicPerform.cpp'
1967--- src/libCom/test/epicsAtomicPerform.cpp 1970-01-01 00:00:00 +0000
1968+++ src/libCom/test/epicsAtomicPerform.cpp 2011-09-07 17:27:41 +0000
1969@@ -0,0 +1,506 @@
1970+
1971+#include <cstdlib>
1972+#include <cstdio>
1973+#include <cassert>
1974+#include <typeinfo>
1975+
1976+#include "epicsInterrupt.h"
1977+#include "epicsAtomic.h"
1978+#include "epicsTime.h"
1979+#include "epicsUnitTest.h"
1980+#include "testMain.h"
1981+
1982+using std :: size_t;
1983+using namespace epics;
1984+using namespace atomic;
1985+
1986+class RefCtr {
1987+public:
1988+ RefCtr ();
1989+ ~RefCtr ();
1990+ void reference ();
1991+ void unreference ();
1992+private:
1993+ size_t m_cnt;
1994+};
1995+
1996+class Ownership {
1997+public:
1998+ Ownership ();
1999+ Ownership ( RefCtr & refCtr );
2000+ Ownership ( const Ownership & );
2001+ ~Ownership ();
2002+ Ownership & operator = ( const Ownership & );
2003+private:
2004+ RefCtr * _pRefCtr;
2005+ static RefCtr m_noOwnership;
2006+};
2007+
2008+inline RefCtr :: RefCtr ()
2009+{
2010+ epicsAtomicSetSizeT ( & m_cnt, 0 );
2011+}
2012+
2013+inline RefCtr :: ~RefCtr ()
2014+{
2015+ unsigned cnt = epicsAtomicGetSizeT ( & m_cnt );
2016+ assert ( cnt == 0u );
2017+}
2018+
2019+inline void RefCtr :: reference ()
2020+{
2021+ epicsAtomicIncrSizeT ( & m_cnt );
2022+}
2023+
2024+inline void RefCtr :: unreference ()
2025+{
2026+ epicsAtomicDecrSizeT ( & m_cnt );
2027+}
2028+
2029+RefCtr Ownership :: m_noOwnership;
2030+
2031+inline Ownership :: Ownership () :
2032+ _pRefCtr ( & m_noOwnership )
2033+{
2034+ m_noOwnership.reference ();
2035+}
2036+
2037+inline Ownership :: Ownership ( RefCtr & refCtr ) :
2038+ _pRefCtr ( & refCtr )
2039+{
2040+ refCtr.reference ();
2041+}
2042+
2043+inline Ownership :: Ownership ( const Ownership & ownership ) :
2044+ _pRefCtr ( ownership._pRefCtr )
2045+{
2046+ _pRefCtr->reference ();
2047+}
2048+
2049+inline Ownership :: ~Ownership ()
2050+{
2051+ _pRefCtr->unreference ();
2052+}
2053+
2054+inline Ownership & Ownership ::
2055+ operator = ( const Ownership & ownership )
2056+{
2057+ RefCtr * const pOldRefCtr = _pRefCtr;
2058+ _pRefCtr = ownership._pRefCtr;
2059+ _pRefCtr->reference ();
2060+ pOldRefCtr->unreference ();
2061+ return *this;
2062+}
2063+
2064+inline Ownership retOwnership ( const Ownership & ownership )
2065+{
2066+ return Ownership ( ownership );
2067+}
2068+
2069+inline Ownership recurRetOwner10 ( const Ownership & ownershipIn )
2070+{
2071+ Ownership ownership =
2072+ retOwnership (
2073+ retOwnership (
2074+ retOwnership (
2075+ retOwnership (
2076+ retOwnership ( ownershipIn ) ) ) ) );
2077+ return retOwnership (
2078+ retOwnership (
2079+ retOwnership (
2080+ retOwnership (
2081+ retOwnership ( ownership ) ) ) ) );
2082+}
2083+
2084+inline Ownership recurRetOwner100 ( const Ownership & ownershipIn )
2085+{
2086+ Ownership ownership =
2087+ recurRetOwner10 (
2088+ recurRetOwner10 (
2089+ recurRetOwner10 (
2090+ recurRetOwner10 (
2091+ recurRetOwner10 ( ownershipIn ) ) ) ) );
2092+ return recurRetOwner10 (
2093+ recurRetOwner10 (
2094+ recurRetOwner10 (
2095+ recurRetOwner10 (
2096+ recurRetOwner10 ( ownership ) ) ) ) );
2097+}
2098+
2099+inline Ownership recurRetOwner1000 ( const Ownership & ownershipIn )
2100+{
2101+ Ownership ownership =
2102+ recurRetOwner100 (
2103+ recurRetOwner100 (
2104+ recurRetOwner100 (
2105+ recurRetOwner100 (
2106+ recurRetOwner100 ( ownershipIn ) ) ) ) );
2107+ return recurRetOwner100 (
2108+ recurRetOwner100 (
2109+ recurRetOwner100 (
2110+ recurRetOwner100 (
2111+ recurRetOwner100 ( ownership ) ) ) ) );
2112+}
2113+
2114+inline void passRefOwnership ( const Ownership & ownershipIn, Ownership & ownershipOut )
2115+{
2116+ ownershipOut = ownershipIn;
2117+}
2118+
2119+inline void passRefOwnership10 ( const Ownership & ownershipIn, Ownership & ownershipOut )
2120+{
2121+ Ownership ownershipTmp0;
2122+ passRefOwnership ( ownershipIn, ownershipTmp0 );
2123+ Ownership ownershipTmp1;
2124+ passRefOwnership ( ownershipTmp0, ownershipTmp1 );
2125+ Ownership ownershipTmp2;
2126+ passRefOwnership ( ownershipTmp1, ownershipTmp2 );
2127+ Ownership ownershipTmp3;
2128+ passRefOwnership ( ownershipTmp2, ownershipTmp3 );
2129+ Ownership ownershipTmp4;
2130+ passRefOwnership ( ownershipTmp3, ownershipTmp4 );
2131+ Ownership ownershipTmp5;
2132+ passRefOwnership ( ownershipTmp4, ownershipTmp5 );
2133+ Ownership ownershipTmp6;
2134+ passRefOwnership ( ownershipTmp5, ownershipTmp6 );
2135+ Ownership ownershipTmp7;
2136+ passRefOwnership ( ownershipTmp6, ownershipTmp7 );
2137+ Ownership ownershipTmp8;
2138+ passRefOwnership ( ownershipTmp7, ownershipTmp8 );
2139+ passRefOwnership ( ownershipTmp8, ownershipOut );
2140+}
2141+
2142+inline void passRefOwnership100 ( const Ownership & ownershipIn, Ownership & ownershipOut )
2143+{
2144+ Ownership ownershipTmp0;
2145+ passRefOwnership10 ( ownershipIn, ownershipTmp0 );
2146+ Ownership ownershipTmp1;
2147+ passRefOwnership10 ( ownershipTmp0, ownershipTmp1 );
2148+ Ownership ownershipTmp2;
2149+ passRefOwnership10 ( ownershipTmp1, ownershipTmp2 );
2150+ Ownership ownershipTmp3;
2151+ passRefOwnership10 ( ownershipTmp2, ownershipTmp3 );
2152+ Ownership ownershipTmp4;
2153+ passRefOwnership10 ( ownershipTmp3, ownershipTmp4 );
2154+ Ownership ownershipTmp5;
2155+ passRefOwnership10 ( ownershipTmp4, ownershipTmp5 );
2156+ Ownership ownershipTmp6;
2157+ passRefOwnership10 ( ownershipTmp5, ownershipTmp6 );
2158+ Ownership ownershipTmp7;
2159+ passRefOwnership10 ( ownershipTmp6, ownershipTmp7 );
2160+ Ownership ownershipTmp8;
2161+ passRefOwnership10 ( ownershipTmp7, ownershipTmp8 );
2162+ passRefOwnership10 ( ownershipTmp8, ownershipOut );
2163+}
2164+
2165+inline void passRefOwnership1000 ( const Ownership & ownershipIn, Ownership & ownershipOut )
2166+{
2167+ Ownership ownershipTmp0;
2168+ passRefOwnership100 ( ownershipIn, ownershipTmp0 );
2169+ Ownership ownershipTmp1;
2170+ passRefOwnership100 ( ownershipTmp0, ownershipTmp1 );
2171+ Ownership ownershipTmp2;
2172+ passRefOwnership100 ( ownershipTmp1, ownershipTmp2 );
2173+ Ownership ownershipTmp3;
2174+ passRefOwnership100 ( ownershipTmp2, ownershipTmp3 );
2175+ Ownership ownershipTmp4;
2176+ passRefOwnership100 ( ownershipTmp3, ownershipTmp4 );
2177+ Ownership ownershipTmp5;
2178+ passRefOwnership100 ( ownershipTmp4, ownershipTmp5 );
2179+ Ownership ownershipTmp6;
2180+ passRefOwnership100 ( ownershipTmp5, ownershipTmp6 );
2181+ Ownership ownershipTmp7;
2182+ passRefOwnership100 ( ownershipTmp6, ownershipTmp7 );
2183+ Ownership ownershipTmp8;
2184+ passRefOwnership100 ( ownershipTmp7, ownershipTmp8 );
2185+ passRefOwnership100 ( ownershipTmp8, ownershipOut );
2186+}
2187+
2188+time_t extTime = 0;
2189+
2190+template < class T >
2191+class OrdinaryIncr {
2192+public:
2193+ OrdinaryIncr () : m_target ( 0 ) {}
2194+ void run ();
2195+ void diagnostic ( double delay );
2196+private:
2197+ T m_target;
2198+};
2199+
2200+// tests the time it takes to perform a call to an external
2201+// function and also increment an integer word. The
2202+// epicsInterruptIsInterruptContext function is an
2203+// out-of-line function implemented in a sharable library
2204+// so hopefully it wont be optimized away.
2205+template < class T >
2206+inline void OrdinaryIncr < T > :: run ()
2207+{
2208+ m_target += epicsInterruptIsInterruptContext ();
2209+ m_target += epicsInterruptIsInterruptContext ();
2210+ m_target += epicsInterruptIsInterruptContext ();
2211+ m_target += epicsInterruptIsInterruptContext ();
2212+ m_target += epicsInterruptIsInterruptContext ();
2213+ m_target += epicsInterruptIsInterruptContext ();
2214+ m_target += epicsInterruptIsInterruptContext ();
2215+ m_target += epicsInterruptIsInterruptContext ();
2216+ m_target += epicsInterruptIsInterruptContext ();
2217+ m_target += epicsInterruptIsInterruptContext ();
2218+}
2219+
2220+template < class T >
2221+void OrdinaryIncr < T > :: diagnostic ( double delay )
2222+{
2223+ delay /= 10.0;
2224+ delay *= 1e6;
2225+ const char * const pName = typeid ( T ) . name ();
2226+ testDiag ( "raw incr of \"%s\" and a NOOP function call takes %f microseconds",
2227+ pName, delay );
2228+}
2229+
2230+template < class T >
2231+class AtomicIncr {
2232+public:
2233+ AtomicIncr () : m_target ( 0 ) {}
2234+ void run ();
2235+ void diagnostic ( double delay );
2236+private:
2237+ T m_target;
2238+};
2239+
2240+template < class T >
2241+inline void AtomicIncr < T > :: run ()
2242+{
2243+ increment ( m_target );
2244+ increment ( m_target );
2245+ increment ( m_target );
2246+ increment ( m_target );
2247+ increment ( m_target );
2248+ increment ( m_target );
2249+ increment ( m_target );
2250+ increment ( m_target );
2251+ increment ( m_target );
2252+ increment ( m_target );
2253+}
2254+
2255+template < class T >
2256+void AtomicIncr < T > :: diagnostic ( double delay )
2257+{
2258+ delay /= 10.0;
2259+ delay *= 1e6;
2260+ const char * const pName = typeid ( T ) . name ();
2261+ testDiag ( "epicsAtomicIncr \"%s\" takes %f microseconds",
2262+ pName, delay );
2263+}
2264+
2265+template < class T > T trueValue ();
2266+template < class T > T falseValue ();
2267+
2268+// int
2269+template <>
2270+inline int trueValue < int > () { return 1; }
2271+
2272+template <>
2273+inline int falseValue < int > () { return 0; }
2274+
2275+// size_t
2276+template <>
2277+inline size_t trueValue < size_t > () { return 1u; }
2278+
2279+template <>
2280+inline size_t falseValue < size_t > () { return 0u; }
2281+
2282+// EpicsAtomicPtrT
2283+template <>
2284+inline EpicsAtomicPtrT trueValue < EpicsAtomicPtrT > ()
2285+{ static char c; return & c; }
2286+
2287+template <>
2288+inline EpicsAtomicPtrT falseValue < EpicsAtomicPtrT > ()
2289+{ return 0u; }
2290+
2291+template < class T >
2292+class AtomicCmpAndSwap {
2293+public:
2294+ AtomicCmpAndSwap () : m_target ( 0 ) {}
2295+ void run ();
2296+ void diagnostic ( double delay );
2297+private:
2298+ T m_target;
2299+};
2300+
2301+template < class T >
2302+inline void AtomicCmpAndSwap < T > :: run ()
2303+{
2304+ compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
2305+ compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
2306+ compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
2307+ compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
2308+ compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
2309+ compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
2310+ compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
2311+ compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
2312+ compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
2313+ compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
2314+}
2315+
2316+template < class T >
2317+void AtomicCmpAndSwap < T > :: diagnostic ( double delay )
2318+{
2319+ delay /= 10.0;
2320+ delay *= 1e6;
2321+ const char * const pName = typeid ( T ) . name ();
2322+ testDiag ( "epicsAtomicCmpAndSwap of \"%s\" takes %f microseconds",
2323+ pName, delay );
2324+}
2325+
2326+template < class T >
2327+class AtomicSet {
2328+public:
2329+ AtomicSet () : m_target ( 0 ) {}
2330+ void run ();
2331+ void diagnostic ( double delay );
2332+private:
2333+ T m_target;
2334+};
2335+
2336+template < class T >
2337+inline void AtomicSet < T > :: run ()
2338+{
2339+ set ( m_target, 0 );
2340+ set ( m_target, 0 );
2341+ set ( m_target, 0 );
2342+ set ( m_target, 0 );
2343+ set ( m_target, 0 );
2344+ set ( m_target, 0 );
2345+ set ( m_target, 0 );
2346+ set ( m_target, 0 );
2347+ set ( m_target, 0 );
2348+ set ( m_target, 0 );
2349+}
2350+
2351+template < class T >
2352+void AtomicSet < T > :: diagnostic ( double delay )
2353+{
2354+ delay /= 10.0;
2355+ delay *= 1e6;
2356+ const char * const pName = typeid ( T ) . name ();
2357+ testDiag ( "epicsAtomicSet of \"%s\" takes %f microseconds",
2358+ pName, delay );
2359+}
2360+
2361+static const unsigned N = 10000;
2362+
2363+void recursiveOwnershipRetPerformance ()
2364+{
2365+ RefCtr refCtr;
2366+ epicsTime begin = epicsTime::getCurrent ();
2367+ for ( size_t i = 0; i < N; i++ ) {
2368+ Ownership ownership ( refCtr );
2369+ recurRetOwner1000 ( ownership );
2370+ }
2371+ double delay = epicsTime::getCurrent () - begin;
2372+ delay /= N * 1000u; // convert to delay per call
2373+ delay *= 1e6; // convert to micro seconds
2374+ testDiag ( "retOwnership() takes %f microseconds", delay );
2375+}
2376+
2377+void ownershipPassRefPerformance ()
2378+{
2379+ RefCtr refCtr;
2380+ epicsTime begin = epicsTime::getCurrent ();
2381+ for ( size_t i = 0; i < N; i++ ) {
2382+ Ownership ownershipSrc ( refCtr );
2383+ Ownership ownershipDest;
2384+ passRefOwnership1000 ( ownershipSrc, ownershipDest );
2385+ }
2386+ double delay = epicsTime::getCurrent () - begin;
2387+ delay /= N * 1000u; // convert to delay per call
2388+ delay *= 1e6; // convert to micro seconds
2389+ testDiag ( "passRefOwnership() takes %f microseconds", delay );
2390+}
2391+
2392+template < class T >
2393+class Ten
2394+{
2395+public:
2396+ void run ();
2397+ void diagnostic ( double delay );
2398+ typedef Ten < Ten < T > > Hundred;
2399+ typedef Ten < Hundred > Thousand;
2400+private:
2401+ T m_target;
2402+};
2403+
2404+template < class T >
2405+inline void Ten < T > :: run ()
2406+{
2407+ m_target.run ();
2408+ m_target.run ();
2409+ m_target.run ();
2410+ m_target.run ();
2411+ m_target.run ();
2412+ m_target.run ();
2413+ m_target.run ();
2414+ m_target.run ();
2415+ m_target.run ();
2416+ m_target.run ();
2417+}
2418+
2419+template < class T >
2420+void Ten < T > :: diagnostic ( double delay )
2421+{
2422+ m_target.diagnostic ( delay / 10.0 );
2423+}
2424+
2425+template < class T >
2426+void measurePerformance ()
2427+{
2428+ epicsTime begin = epicsTime::getCurrent ();
2429+ T target;
2430+ for ( size_t i = 0; i < N; i++ ) {
2431+ target.run ();
2432+ target.run ();
2433+ target.run ();
2434+ target.run ();
2435+ target.run ();
2436+ target.run ();
2437+ target.run ();
2438+ target.run ();
2439+ target.run ();
2440+ target.run ();
2441+ }
2442+ double delay = epicsTime::getCurrent () - begin;
2443+ delay /= ( N * 10u ); // convert to delay per call
2444+ target.diagnostic ( delay );
2445+}
2446+
2447+template < class T >
2448+void measure ()
2449+{
2450+ measurePerformance < typename Ten < T > :: Hundred > ();
2451+}
2452+
2453+MAIN ( epicsAtomicPerform )
2454+{
2455+ testPlan ( 0 );
2456+ //
2457+ // The tests running here are measuring fast
2458+ // functions so they tend to be impacted
2459+ // by where the cache lines are wrt to the
2460+ // virtual pages perhap
2461+ //
2462+ measure < AtomicSet < int > > ();
2463+ measure < AtomicSet < size_t > > ();
2464+ measure < AtomicSet < void * > > ();
2465+ measure < OrdinaryIncr < int > > ();
2466+ measure < OrdinaryIncr < size_t > > ();
2467+ measure < AtomicIncr < int > > ();
2468+ measure < AtomicIncr < size_t > > ();
2469+ measure < AtomicCmpAndSwap < int > > ();
2470+ measure < AtomicCmpAndSwap < size_t > > ();
2471+ measure < AtomicCmpAndSwap < void * > > ();
2472+ recursiveOwnershipRetPerformance ();
2473+ ownershipPassRefPerformance ();
2474+ return testDone();
2475+}
2476
2477=== added file 'src/libCom/test/epicsAtomicTest.cpp'
2478--- src/libCom/test/epicsAtomicTest.cpp 1970-01-01 00:00:00 +0000
2479+++ src/libCom/test/epicsAtomicTest.cpp 2011-09-07 17:27:41 +0000
2480@@ -0,0 +1,238 @@
2481+
2482+#include <stdlib.h>
2483+#include <assert.h>
2484+
2485+#include "epicsAtomic.h"
2486+#include "epicsTime.h"
2487+#include "epicsThread.h"
2488+#include "epicsUnitTest.h"
2489+#include "testMain.h"
2490+
2491+using namespace epics;
2492+using namespace atomic;
2493+
2494+template < class T >
2495+struct TestDataIncrDecr {
2496+ T m_testValue;
2497+ size_t m_testIterations;
2498+};
2499+
2500+template < class T >
2501+struct TestDataAddSub {
2502+ T m_testValue;
2503+ size_t m_testIterations;
2504+ static const T delta = 17;
2505+};
2506+
2507+template < class T >
2508+static void incr ( void *arg )
2509+{
2510+ TestDataIncrDecr < T > * const pTestData =
2511+ reinterpret_cast < TestDataIncrDecr < T > * > ( arg );
2512+ increment ( pTestData->m_testValue );
2513+ increment ( pTestData->m_testIterations );
2514+}
2515+
2516+template < class T >
2517+static void decr ( void *arg )
2518+{
2519+ TestDataIncrDecr < T > * const pTestData =
2520+ reinterpret_cast < TestDataIncrDecr < T > * > ( arg );
2521+ decrement ( pTestData->m_testValue );
2522+ increment ( pTestData->m_testIterations );
2523+}
2524+
2525+
2526+template < class T >
2527+static void add ( void *arg )
2528+{
2529+ TestDataAddSub < T > * const pTestData =
2530+ reinterpret_cast < TestDataAddSub < T > * > ( arg );
2531+ add ( pTestData->m_testValue, TestDataAddSub < T > :: delta );
2532+ increment ( pTestData->m_testIterations );
2533+}
2534+
2535+template < class T >
2536+static void sub ( void *arg )
2537+{
2538+ TestDataAddSub < T > * const pTestData =
2539+ reinterpret_cast < TestDataAddSub < T > * > ( arg );
2540+ subtract ( pTestData->m_testValue, TestDataAddSub < T > :: delta );
2541+ increment ( pTestData->m_testIterations );
2542+}
2543+
2544+template < class T >
2545+struct TestDataCAS {
2546+ T m_testValue;
2547+ size_t m_testIterationsSet;
2548+ size_t m_testIterationsNotSet;
2549+};
2550+
2551+int isModulo ( size_t N, size_t n )
2552+{
2553+ return ( n % N ) == 0u;
2554+}
2555+
2556+template < class T >
2557+static T trueValue ();
2558+template < class T >
2559+static T falseValue ();
2560+
2561+// int
2562+template <>
2563+inline int trueValue < int > () { return 1; }
2564+
2565+template <>
2566+inline int falseValue < int > () { return 0; }
2567+
2568+// size_t
2569+template <>
2570+inline size_t trueValue < size_t > () { return 1u; }
2571+
2572+template <>
2573+inline size_t falseValue < size_t > () { return 0u; }
2574+
2575+// EpicsAtomicPtrT
2576+template <>
2577+inline EpicsAtomicPtrT trueValue < EpicsAtomicPtrT > ()
2578+{ static char c; return & c; }
2579+
2580+template <>
2581+inline EpicsAtomicPtrT falseValue < EpicsAtomicPtrT > ()
2582+{ return 0u; }
2583+
2584+template < class T >
2585+static void cas ( void *arg )
2586+{
2587+ TestDataCAS < T > * const pTestData =
2588+ reinterpret_cast < TestDataCAS < T > * > ( arg );
2589+ /*
2590+ * intentionally waste cpu and maximize
2591+ * contention for the shared data
2592+ */
2593+ increment ( pTestData->m_testIterationsNotSet );
2594+ while ( ! compareAndSwap ( pTestData->m_testValue,
2595+ falseValue < T > (),
2596+ trueValue < T > () ) ) {
2597+ }
2598+ decrement ( pTestData->m_testIterationsNotSet );
2599+ set ( pTestData->m_testValue, falseValue < T > () );
2600+ increment ( pTestData->m_testIterationsSet );
2601+}
2602+
2603+template < class T >
2604+void testIncrDecr ()
2605+{
2606+ static const size_t N = 100;
2607+ static const T NT = static_cast < T > ( N );
2608+
2609+ const unsigned int stackSize =
2610+ epicsThreadGetStackSize ( epicsThreadStackSmall );
2611+
2612+ TestDataIncrDecr < T > testData = { 0, N };
2613+ set ( testData.m_testValue, NT );
2614+ testOk ( get ( testData.m_testValue ) == NT,
2615+ "set/get %u", testData.m_testValue );
2616+ set ( testData.m_testIterations, 0u );
2617+ testOk ( get ( testData.m_testIterations ) == 0u,
2618+ "set/get %u", testData.m_testIterations );
2619+ for ( size_t i = 0u; i < N; i++ ) {
2620+ epicsThreadCreate ( "incr",
2621+ 50, stackSize, incr < T >, & testData );
2622+ epicsThreadCreate ( "decr",
2623+ 50, stackSize, decr < T >, & testData );
2624+ }
2625+ while ( testData.m_testIterations < 2 * N ) {
2626+ epicsThreadSleep ( 0.01 );
2627+ }
2628+ testOk ( get ( testData.m_testIterations ) == 2 * N,
2629+ "incr/decr iterations %u",
2630+ testData.m_testIterations );
2631+ testOk ( get ( testData.m_testValue ) == NT,
2632+ "incr/decr final value %u",
2633+ testData.m_testValue );
2634+}
2635+
2636+template < class T >
2637+void testAddSub ()
2638+{
2639+ static const size_t N = 100;
2640+ static const T NDT = TestDataAddSub < T > :: delta *
2641+ static_cast < T > ( N );
2642+
2643+ const unsigned int stackSize =
2644+ epicsThreadGetStackSize ( epicsThreadStackSmall );
2645+
2646+ TestDataIncrDecr < T > testData = { 0, N };
2647+ set ( testData.m_testValue, NDT );
2648+ testOk ( get ( testData.m_testValue ) == NDT,
2649+ "set/get %u", testData.m_testValue );
2650+ set ( testData.m_testIterations, 0u );
2651+ testOk ( get ( testData.m_testIterations ) == 0u,
2652+ "set/get %u", testData.m_testIterations );
2653+ for ( size_t i = 0u; i < N; i++ ) {
2654+ epicsThreadCreate ( "add",
2655+ 50, stackSize, add < T >, & testData );
2656+ epicsThreadCreate ( "sub",
2657+ 50, stackSize, sub < T >, & testData );
2658+ }
2659+ while ( testData.m_testIterations < 2 * N ) {
2660+ epicsThreadSleep ( 0.01 );
2661+ }
2662+ testOk ( get ( testData.m_testIterations ) == 2 * N,
2663+ "add/sub iterations %u",
2664+ testData.m_testIterations );
2665+ testOk ( get ( testData.m_testValue ) == NDT,
2666+ "add/sub final value %u",
2667+ testData.m_testValue );
2668+}
2669+
2670+template < class T >
2671+void testCAS ()
2672+{
2673+ static const size_t N = 10;
2674+
2675+ const unsigned int stackSize =
2676+ epicsThreadGetStackSize ( epicsThreadStackSmall );
2677+
2678+ TestDataCAS < T > testData = { 0, N, N };
2679+ set ( testData.m_testIterationsSet, 0 );
2680+ testOk ( get ( testData.m_testIterationsSet ) == 0u,
2681+ "set/get %u", testData.m_testIterationsSet );
2682+ set ( testData.m_testIterationsNotSet, 0 );
2683+ testOk ( get ( testData.m_testIterationsNotSet ) == 0u,
2684+ "set/get %u", testData.m_testIterationsNotSet );
2685+ set ( testData.m_testValue, trueValue < T > () );
2686+ testOk ( get ( testData.m_testValue ) == trueValue < T > (),
2687+ "set/get a true value" );
2688+ for ( size_t i = 0u; i < N; i++ ) {
2689+ epicsThreadCreate ( "tns",
2690+ 50, stackSize, cas < T >, & testData );
2691+ }
2692+ set ( testData.m_testValue, falseValue < T > () );
2693+ while ( testData.m_testIterationsSet < N ) {
2694+ epicsThreadSleep ( 0.01 );
2695+ }
2696+ testOk ( get ( testData.m_testIterationsSet ) == N,
2697+ "test and set iterations %u",
2698+ testData.m_testIterationsSet );
2699+ testOk ( get ( testData.m_testIterationsNotSet ) == 0u,
2700+ "test and set not-set tracking = %u",
2701+ testData.m_testIterationsNotSet );
2702+}
2703+
2704+MAIN ( epicsAtomicTest )
2705+{
2706+
2707+ testPlan ( 31 );
2708+
2709+ testIncrDecr < int > ();
2710+ testIncrDecr < size_t > ();
2711+ testAddSub < int > ();
2712+ testAddSub < size_t > ();
2713+ testCAS < int > ();
2714+ testCAS < size_t > ();
2715+ testCAS < EpicsAtomicPtrT > ();
2716+
2717+ return testDone ();
2718+}

Subscribers

People subscribed via source and target branches

to all changes: