Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
atomic_add.cpp
Go to the documentation of this file.
1
30#include <stdio.h>
31#include <string.h>
32
33#include <rw/_mutex.h>
34
35#include <rw_any.h>
36#include <rw_cmdopt.h>
37#include <rw_driver.h>
38#include <rw_thread.h> // for rw_thread_create()
39
40
43{
44 static enum tag_t {
49};
50
52
53template <class intT>
55{
56 unsigned threadno_; // thread ordinal number
57 static int inc_; // increment, decrement, or both
58 static unsigned nincr_; // number of increments
59 static intT *shared_; // shared variables
60 static unsigned nthreads_; // number of threads
61
62 static intT* get_array ();
63};
64
65template <class intT>
67
68template <class intT>
70
71template <class intT>
73
74template <class intT>
76
77// working around compiler bugs that prevent us from defining
78// a static array data member of a class template (PR #30009)
79template <class intT>
81{
82 static intT array [2];
83 return array;
84}
85
86
89template <class T>
91{
92#ifndef _RWSTD_REENTRANT
93
94 return ++x;
95
96#else // if defined (_RWSTD_REENTRANT)
97
98 return _RW::__rw_atomic_preincrement (x, false);
99
100#endif // _RWSTD_REENTRANT
101}
102
103
104template <class T>
106{
107#ifndef _RWSTD_REENTRANT
108
109 return --x;
110
111#else // if defined (_RWSTD_REENTRANT)
112
113 return _RW::__rw_atomic_predecrement (x, false);
114
115#endif // _RWSTD_REENTRANT
116}
117
118
121template <class intT>
123{
124 printf ("thread %u starting to %screment\n",
125 args->threadno_,
126 args->inc_ < 0 ? "de"
127 : args->inc_ > 0 ? "in"
128 : "decrement and in");
129
130 if (args->inc_ > 0) {
131
132 // exercise atomic_preincrement() in a tight loop
133
134 for (unsigned i = 0; i != args->nincr_; ++i) {
135 preincrement (args->shared_ [0]);
136 preincrement (args->shared_ [1]);
137 }
138 }
139 else if (args->inc_ < 0) {
140
141 // exercise atomic_predecrement() in a tight loop
142
143 for (unsigned i = 0; i != args->nincr_; ++i) {
144 predecrement (args->shared_ [0]);
145 predecrement (args->shared_ [1]);
146 }
147 }
148 else {
149
150 // exercise both atomic_preincrement() and atomic_predecrement()
151
152 for (unsigned i = 0; i != args->nincr_; ++i) {
153 preincrement (args->shared_ [0]);
154 predecrement (args->shared_ [0]);
155 preincrement (args->shared_ [1]);
156 predecrement (args->shared_ [1]);
157 }
158 }
159
160 return 0;
161}
162
163
165extern "C" void* thread_routine (void *arg)
166{
167 thr_args_base* const args = (thr_args_base*)arg;
168
169 switch (args->type_tag_) {
170
172 return thread_routine ((thr_args<char>*)(arg));
177
182
184 return thread_routine ((thr_args<int>*)(arg));
187
189 return thread_routine ((thr_args<long>*)(arg));
192
193#ifdef _RWSTD_LONG_LONG
194
199
200#endif // _RWSTD_LONG_LONG
201
202 };
203
204 return 0;
205}
206
207
209/* extern */ int rw_opt_nloops = 1024 * 1024;
210/* extern */ int rw_opt_nthreads = 4;
211
212#define MAX_THREADS 32
213
214
215template <class intT>
216void run_test (intT, thr_args_base::tag_t tag, int inc)
217{
218 static const char* const tname = rw_any_t (intT ()).type_name ();
219
220 if (!rw_enabled (tname)) {
221 rw_note (0, 0, 0, "%s test disabled", tname);
222 return;
223 }
224
225#if defined (_RWSTD_REENTRANT)
226
227 static const char* const fun =
228 inc < 0 ? "__rw_atomic_predecrement"
229 : inc > 0 ? ":__rw_atomic_preincrement"
230 : "__rw_atomic_pre{in,de}crement";
231
232 rw_info (0, 0, 0, "__rw::%s (%s&): %d iterations in %d threads",
234
236
237 typedef thr_args<intT> Args;
238
239 Args::nthreads_ = rw_opt_nthreads;
240 Args::type_tag_ = tag;
241 Args::inc_ = inc;
242 Args::nincr_ = unsigned (rw_opt_nloops);
243 Args::shared_ [0] = intT ();
244 Args::shared_ [1] = intT ();
245
246 _RWSTD_ASSERT (Args::nthreads_ < sizeof tid / sizeof *tid);
247
248 Args args [sizeof tid / sizeof *tid];
249
250 memset (args, 0, sizeof args);
251
252 for (unsigned i = 0; i != Args::nthreads_; ++i) {
253
254 args [i].threadno_ = i;
255
256 rw_fatal (0 == rw_thread_create (tid + i, 0, thread_routine, args + i),
257 0, __LINE__, "thread_create() failed");
258 }
259
260 for (unsigned i = 0; i != Args::nthreads_; ++i) {
261
262 rw_error (0 == rw_thread_join (tid [i], 0), 0, __LINE__,
263 "thread_join() failed");
264 }
265
266 // compute the expected result
267 intT expect = intT ();
268
269 if (inc < 0) {
270 for (unsigned i = 0; i != Args::nthreads_ * Args::nincr_; ++i)
271 --expect;
272 }
273 else if (inc > 0) {
274 for (unsigned i = 0; i != Args::nthreads_ * Args::nincr_; ++i)
275 ++expect;
276 }
277
278 // verify that the final value of the variable shared among all
279 // threads equals the number of increments or decrements performed
280 // by all threads
281 rw_assert (Args::shared_ [0] == expect, 0, __LINE__,
282 "1. %s (%s&); %s == %s failed",
283 fun, tname, TOSTR (Args::shared_ [0]), TOSTR (expect));
284
285 rw_assert (Args::shared_ [1] == expect, 0, __LINE__,
286 "2. %s (%s&); %s == %s failed",
287 fun, tname, TOSTR (Args::shared_ [1]), TOSTR (expect));
288
289#else // if !defined (_RWSTD_REENTRANT)
290
292 _RWSTD_UNUSED (inc);
293
294#endif // _RWSTD_REENTRANT
295}
296
297
299static int
300run_test (int, char**)
301{
302 // exercise atomic subtract
303 run_test ((char)0, thr_args_base::Char, -1);
304 run_test ((signed char)0, thr_args_base::SChar, -1);
305 run_test ((unsigned char)0, thr_args_base::UChar, -1);
306
307 run_test ((short)0, thr_args_base::Short, -1);
308 run_test ((unsigned short)0, thr_args_base::UShort, -1);
309
310 run_test ((int)0, thr_args_base::Int, -1);
311 run_test ((unsigned int)0, thr_args_base::UInt, -1);
312
313 run_test ((long)0, thr_args_base::Long, -1);
314 run_test ((unsigned long)0, thr_args_base::ULong, -1);
315
316#ifdef _RWSTD_LONG_LONG
317
320
321#endif // _RWSTD_LONG_LONG
322
323 // exercise atomic add
324 run_test ((char)0, thr_args_base::Char, +1);
325 run_test ((signed char)0, thr_args_base::SChar, +1);
326 run_test ((unsigned char)0, thr_args_base::UChar, +1);
327
328 run_test ((short)0, thr_args_base::Short, +1);
329 run_test ((unsigned short)0, thr_args_base::UShort, +1);
330
331 run_test ((int)0, thr_args_base::Int, +1);
332 run_test ((unsigned int)0, thr_args_base::UInt, +1);
333
334 run_test ((long)0, thr_args_base::Long, +1);
335 run_test ((unsigned long)0, thr_args_base::ULong, +1);
336
337#ifdef _RWSTD_LONG_LONG
338
341
342#endif // _RWSTD_LONG_LONG
343
344
345 // exercise both atomic add and subtract
346 run_test ((char)0, thr_args_base::Char, 0);
347 run_test ((signed char)0, thr_args_base::SChar, 0);
348 run_test ((unsigned char)0, thr_args_base::UChar, 0);
349
350 run_test ((short)0, thr_args_base::Short, 0);
351 run_test ((unsigned short)0, thr_args_base::UShort, 0);
352
353 run_test ((int)0, thr_args_base::Int, 0);
354 run_test ((unsigned int)0, thr_args_base::UInt, 0);
355
356 run_test ((long)0, thr_args_base::Long, 0);
357 run_test ((unsigned long)0, thr_args_base::ULong, 0);
358
359#ifdef _RWSTD_LONG_LONG
360
363
364#endif // _RWSTD_LONG_LONG
365
366 return 0;
367}
368
369
371int main (int argc, char *argv[])
372{
373 return rw_test (argc, argv, __FILE__,
374 0 /* no clause */,
375 0 /* no comment */,
376 run_test,
377 "|-nloops#0 " // must be non-negative
378 "|-nthreads#0-*" , // must be in [0, MAX_THREADS]
380 int (MAX_THREADS),
382}
#define i
Definition 17.names.cpp:126
#define T
Definition 17.names.cpp:163
#define fun
Definition 17.names.cpp:471
#define x
Definition 17.names.cpp:140
#define array
Definition 17.names.cpp:447
#define tag
Definition 17.names.cpp:551
#define main
IMPORT_C SInt32 printf(const Char *,...)
#define _RWSTD_LONG_LONG
#define _RWSTD_UNUSED(arg)
Definition _defs.h:972
#define _RWSTD_ASSERT(ignore)
Definition _defs.h:1108
int rw_opt_nthreads
void run_test(intT, thr_args_base::tag_t tag, int inc)
T predecrement(T &x)
#define MAX_THREADS
T preincrement(T &x)
void * thread_routine(thr_args< intT > *args)
int rw_opt_nloops
A TOML array.
Definition array.hpp:258
const char * type_name() const
Definition any.cpp:310
#define TOSTR(x)
Definition rw_any.h:148
_TEST_EXPORT int rw_enabled(const char *name)
_TEST_EXPORT int rw_test(int argc, char *argv[], const char *filename, const char *clause, const char *comment, int(*testfun)(int, char **), const char *optspec,...)
_TEST_EXPORT int rw_info(int, const char *, int, const char *,...)
Definition driver.cpp:1681
_TEST_EXPORT int rw_fatal(int expr, const char *filename, int line, const char *fmtspec,...)
Definition driver.cpp:1596
_TEST_EXPORT int rw_note(int, const char *, int, const char *,...)
Definition driver.cpp:1664
_TEST_EXPORT int rw_assert(int, const char *, int, const char *,...)
Definition driver.cpp:1630
_TEST_EXPORT int rw_error(int, const char *, int, const char *,...)
Definition driver.cpp:1613
_TEST_EXPORT int rw_thread_create(rw_thread_t *, rw_thread_attr_t *, rw_thread_proc *, void *)
Definition thread.cpp:379
_TEST_EXPORT int rw_thread_join(rw_thread_t, void **)
Definition thread.cpp:391
static enum thr_args_base::tag_t type_tag_
static unsigned nincr_
static intT * get_array()
static unsigned nthreads_
unsigned threadno_
static int inc_
static intT * shared_
int arg
Definition locale.cpp:2806