]>
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 | |
bb5a9514 | 46 | #elif defined(__WINDOWS__) |
47964710 VS |
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 | |
42124e68 | 91 | #define wxNEEDS_GENERIC_ATOMIC_OPS |
cde76cf2 VZ |
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 | ||
42124e68 | 108 | #ifdef wxNEEDS_GENERIC_ATOMIC_OPS |
cde76cf2 | 109 | |
cde76cf2 VZ |
110 | #include "wx/thread.h" // for wxCriticalSection |
111 | ||
112 | class wxAtomicInt32 | |
113 | { | |
114 | public: | |
eb096b8e VS |
115 | wxAtomicInt32() { } // non initialized for consistency with basic int type |
116 | wxAtomicInt32(wxInt32 v) : m_value(v) { } | |
bc1d617a | 117 | wxAtomicInt32(const wxAtomicInt32& a) : m_value(a.m_value) {} |
cde76cf2 VZ |
118 | |
119 | operator wxInt32() const { return m_value; } | |
eb096b8e | 120 | operator volatile wxInt32&() { return m_value; } |
cde76cf2 | 121 | |
eb096b8e | 122 | wxAtomicInt32& operator=(wxInt32 v) { m_value = v; return *this; } |
cde76cf2 VZ |
123 | |
124 | void Inc() | |
125 | { | |
126 | wxCriticalSectionLocker lock(m_locker); | |
127 | ++m_value; | |
128 | } | |
129 | ||
130 | wxInt32 Dec() | |
131 | { | |
132 | wxCriticalSectionLocker lock(m_locker); | |
133 | return --m_value; | |
134 | } | |
135 | ||
136 | private: | |
137 | volatile wxInt32 m_value; | |
138 | wxCriticalSection m_locker; | |
139 | }; | |
140 | ||
eb096b8e VS |
141 | inline void wxAtomicInc(wxAtomicInt32 &value) { value.Inc(); } |
142 | inline wxInt32 wxAtomicDec(wxAtomicInt32 &value) { return value.Dec(); } | |
cde76cf2 | 143 | |
42124e68 VZ |
144 | #else // !wxNEEDS_GENERIC_ATOMIC_OPS |
145 | ||
146 | #define wxHAS_ATOMIC_OPS | |
cde76cf2 VZ |
147 | |
148 | inline void wxAtomicInc(wxInt32 &value) { wxAtomicInc((wxUint32&)value); } | |
149 | inline wxInt32 wxAtomicDec(wxInt32 &value) { return wxAtomicDec((wxUint32&)value); } | |
150 | ||
151 | typedef wxInt32 wxAtomicInt32; | |
152 | ||
42124e68 | 153 | #endif // wxNEEDS_GENERIC_ATOMIC_OPS |
cde76cf2 VZ |
154 | |
155 | // all the native implementations use 32 bits currently | |
156 | // for a 64 bits implementation we could use (a future) wxAtomicInt64 as | |
157 | // default type | |
158 | typedef wxAtomicInt32 wxAtomicInt; | |
159 | ||
160 | #endif // _WX_ATOMIC_H_ |