]>
Commit | Line | Data |
---|---|---|
cde76cf2 VZ |
1 | ///////////////////////////////////////////////////////////////////////////// |
2 | // Name: wx/atomic.h | |
3 | // Purpose: functions to manipulate atomically integers and pointers | |
4 | // Author: Armel Asselin | |
5 | // Created: 12/13/2006 | |
6 | // RCS-ID: $Id$ | |
7 | // Copyright: (c) Armel Asselin | |
8 | // Licence: wxWindows licence | |
9 | ///////////////////////////////////////////////////////////////////////////// | |
10 | ||
11 | #ifndef _WX_ATOMIC_H_ | |
12 | #define _WX_ATOMIC_H_ | |
13 | ||
14 | // ---------------------------------------------------------------------------- | |
15 | // headers | |
16 | // ---------------------------------------------------------------------------- | |
17 | ||
18 | // get the value of wxUSE_THREADS configuration flag | |
19 | #include "wx/defs.h" | |
20 | ||
21 | // constraints on the various functions: | |
22 | // - wxAtomicDec must return a zero value if the value is zero once | |
23 | // decremented else it must return any non-zero value (the true value is OK | |
24 | // but not necessary). | |
25 | ||
26 | #if wxUSE_THREADS | |
27 | ||
47964710 | 28 | #if defined(HAVE_GCC_ATOMIC_BUILTINS) |
cde76cf2 | 29 | |
47964710 VS |
30 | // NB: we intentionally don't use Linux's asm/atomic.h header, because it's |
31 | // an internal kernel header that doesn't always work in userspace: | |
32 | // http://bugs.mysql.com/bug.php?id=28456 | |
33 | // http://golubenco.org/blog/atomic-operations/ | |
cde76cf2 VZ |
34 | |
35 | inline void wxAtomicInc (wxUint32 &value) | |
36 | { | |
47964710 | 37 | __sync_fetch_and_add(&value, 1); |
cde76cf2 VZ |
38 | } |
39 | ||
40 | inline wxUint32 wxAtomicDec (wxUint32 &value) | |
41 | { | |
47964710 | 42 | return __sync_sub_and_fetch(&value, 1); |
cde76cf2 VZ |
43 | } |
44 | ||
cde76cf2 | 45 | |
47964710 VS |
46 | #elif defined(__WXMSW__) |
47 | ||
48 | // include standard Windows headers | |
49 | #include "wx/msw/wrapwin.h" | |
50 | ||
cde76cf2 VZ |
51 | inline void wxAtomicInc (wxUint32 &value) |
52 | { | |
47964710 | 53 | InterlockedIncrement ((LONG*)&value); |
cde76cf2 VZ |
54 | } |
55 | ||
56 | inline wxUint32 wxAtomicDec (wxUint32 &value) | |
57 | { | |
47964710 | 58 | return InterlockedDecrement ((LONG*)&value); |
cde76cf2 VZ |
59 | } |
60 | ||
47964710 | 61 | #elif defined(__WXMAC__) || defined(__DARWIN__) |
cde76cf2 | 62 | |
47964710 | 63 | #include "libkern/OSAtomic.h" |
cde76cf2 VZ |
64 | inline void wxAtomicInc (wxUint32 &value) |
65 | { | |
47964710 | 66 | OSAtomicIncrement32 ((int32_t*)&value); |
cde76cf2 VZ |
67 | } |
68 | ||
69 | inline wxUint32 wxAtomicDec (wxUint32 &value) | |
70 | { | |
47964710 | 71 | return OSAtomicDecrement32 ((int32_t*)&value); |
cde76cf2 VZ |
72 | } |
73 | ||
74 | #elif defined (__SOLARIS__) | |
75 | ||
76 | #include <atomic.h> | |
77 | ||
78 | inline void wxAtomicInc (wxUint32 &value) | |
79 | { | |
80 | atomic_add_32 ((uint32_t*)&value, 1); | |
81 | } | |
82 | ||
83 | inline wxUint32 wxAtomicDec (wxUint32 &value) | |
84 | { | |
85 | return atomic_add_32_nv ((uint32_t*)&value, (uint32_t)-1); | |
86 | } | |
87 | ||
88 | #else // unknown platform | |
89 | ||
90 | // it will result in inclusion if the generic implementation code a bit later in this page | |
91 | #define wxHAS_GENERIC_ATOMIC_OPS 1 | |
92 | ||
93 | #endif // unknown platform | |
94 | ||
95 | #else // else of wxUSE_THREADS | |
96 | // if no threads are used we can safely use simple ++/-- | |
97 | ||
98 | inline void wxAtomicInc (wxUint32 &value) { ++value; } | |
99 | inline wxUint32 wxAtomicDec (wxUint32 &value) { return --value; } | |
100 | ||
101 | #endif // !wxUSE_THREADS | |
102 | ||
103 | // ---------------------------------------------------------------------------- | |
104 | // proxies to actual implementations, but for various other types with same | |
105 | // behaviour | |
106 | // ---------------------------------------------------------------------------- | |
107 | ||
108 | #if !defined(wxHAS_GENERIC_ATOMIC_OPS) | |
109 | #define wxHAS_GENERIC_ATOMIC_OPS 0 | |
110 | #endif | |
111 | ||
112 | #if wxHAS_GENERIC_ATOMIC_OPS | |
113 | #include "wx/thread.h" // for wxCriticalSection | |
114 | ||
115 | class wxAtomicInt32 | |
116 | { | |
117 | public: | |
eb096b8e VS |
118 | wxAtomicInt32() { } // non initialized for consistency with basic int type |
119 | wxAtomicInt32(wxInt32 v) : m_value(v) { } | |
bc1d617a | 120 | wxAtomicInt32(const wxAtomicInt32& a) : m_value(a.m_value) {} |
cde76cf2 VZ |
121 | |
122 | operator wxInt32() const { return m_value; } | |
eb096b8e | 123 | operator volatile wxInt32&() { return m_value; } |
cde76cf2 | 124 | |
eb096b8e | 125 | wxAtomicInt32& operator=(wxInt32 v) { m_value = v; return *this; } |
cde76cf2 VZ |
126 | |
127 | void Inc() | |
128 | { | |
129 | wxCriticalSectionLocker lock(m_locker); | |
130 | ++m_value; | |
131 | } | |
132 | ||
133 | wxInt32 Dec() | |
134 | { | |
135 | wxCriticalSectionLocker lock(m_locker); | |
136 | return --m_value; | |
137 | } | |
138 | ||
139 | private: | |
140 | volatile wxInt32 m_value; | |
141 | wxCriticalSection m_locker; | |
142 | }; | |
143 | ||
eb096b8e VS |
144 | inline void wxAtomicInc(wxAtomicInt32 &value) { value.Inc(); } |
145 | inline wxInt32 wxAtomicDec(wxAtomicInt32 &value) { return value.Dec(); } | |
cde76cf2 VZ |
146 | |
147 | #else // !wxHAS_GENERIC_ATOMIC_OPS | |
148 | ||
149 | inline void wxAtomicInc(wxInt32 &value) { wxAtomicInc((wxUint32&)value); } | |
150 | inline wxInt32 wxAtomicDec(wxInt32 &value) { return wxAtomicDec((wxUint32&)value); } | |
151 | ||
152 | typedef wxInt32 wxAtomicInt32; | |
153 | ||
154 | #endif // wxHAS_GENERIC_ATOMIC_OPS | |
155 | ||
156 | // all the native implementations use 32 bits currently | |
157 | // for a 64 bits implementation we could use (a future) wxAtomicInt64 as | |
158 | // default type | |
159 | typedef wxAtomicInt32 wxAtomicInt; | |
160 | ||
161 | #endif // _WX_ATOMIC_H_ |