]>
Commit | Line | Data |
---|---|---|
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 | ||
28 | #if defined(HAVE_GCC_ATOMIC_BUILTINS) | |
29 | ||
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/ | |
34 | ||
35 | inline void wxAtomicInc (wxUint32 &value) | |
36 | { | |
37 | __sync_fetch_and_add(&value, 1); | |
38 | } | |
39 | ||
40 | inline wxUint32 wxAtomicDec (wxUint32 &value) | |
41 | { | |
42 | return __sync_sub_and_fetch(&value, 1); | |
43 | } | |
44 | ||
45 | ||
46 | #elif defined(__WXMSW__) | |
47 | ||
48 | // include standard Windows headers | |
49 | #include "wx/msw/wrapwin.h" | |
50 | ||
51 | inline void wxAtomicInc (wxUint32 &value) | |
52 | { | |
53 | InterlockedIncrement ((LONG*)&value); | |
54 | } | |
55 | ||
56 | inline wxUint32 wxAtomicDec (wxUint32 &value) | |
57 | { | |
58 | return InterlockedDecrement ((LONG*)&value); | |
59 | } | |
60 | ||
61 | #elif defined(__WXMAC__) || defined(__DARWIN__) | |
62 | ||
63 | #include "libkern/OSAtomic.h" | |
64 | inline void wxAtomicInc (wxUint32 &value) | |
65 | { | |
66 | OSAtomicIncrement32 ((int32_t*)&value); | |
67 | } | |
68 | ||
69 | inline wxUint32 wxAtomicDec (wxUint32 &value) | |
70 | { | |
71 | return OSAtomicDecrement32 ((int32_t*)&value); | |
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 wxNEEDS_GENERIC_ATOMIC_OPS | |
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 | #ifdef wxNEEDS_GENERIC_ATOMIC_OPS | |
109 | ||
110 | #include "wx/thread.h" // for wxCriticalSection | |
111 | ||
112 | class wxAtomicInt32 | |
113 | { | |
114 | public: | |
115 | wxAtomicInt32() { } // non initialized for consistency with basic int type | |
116 | wxAtomicInt32(wxInt32 v) : m_value(v) { } | |
117 | wxAtomicInt32(const wxAtomicInt32& a) : m_value(a.m_value) {} | |
118 | ||
119 | operator wxInt32() const { return m_value; } | |
120 | operator volatile wxInt32&() { return m_value; } | |
121 | ||
122 | wxAtomicInt32& operator=(wxInt32 v) { m_value = v; return *this; } | |
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 | ||
141 | inline void wxAtomicInc(wxAtomicInt32 &value) { value.Inc(); } | |
142 | inline wxInt32 wxAtomicDec(wxAtomicInt32 &value) { return value.Dec(); } | |
143 | ||
144 | #else // !wxNEEDS_GENERIC_ATOMIC_OPS | |
145 | ||
146 | #define wxHAS_ATOMIC_OPS | |
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 | ||
153 | #endif // wxNEEDS_GENERIC_ATOMIC_OPS | |
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_ |