1 /*
2  * %CopyrightBegin%
3  *
4  * Copyright Ericsson AB 2014-2016. All Rights Reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * %CopyrightEnd%
19  */
20 
21 /*
22  * Description: Native double word atomics using libatomic_ops
23  * Author: Rickard Green
24  */
25 
26 #ifndef ETHR_LIBATOMIC_OPS_DW_ATOMIC_H__
27 #define ETHR_LIBATOMIC_OPS_DW_ATOMIC_H__
28 
29 #if defined(AO_HAVE_double_t)						\
30     && (defined(AO_HAVE_double_load_acquire)				\
31 	|| defined(AO_HAVE_double_load))				\
32     && (defined(AO_HAVE_compare_double_and_swap_double)			\
33 	|| defined(AO_HAVE_compare_double_and_swap_double_full)		\
34 	|| defined(AO_HAVE_compare_double_and_swap_double_acquire)	\
35 	|| defined(AO_HAVE_compare_double_and_swap_double_release)	\
36 	|| defined(AO_HAVE_double_compare_and_swap)			\
37 	|| defined(AO_HAVE_double_compare_and_swap_full)		\
38 	|| defined(AO_HAVE_double_compare_and_swap_acquire)		\
39 	|| defined(AO_HAVE_double_compare_and_swap_release))
40 
41 #if ETHR_SIZEOF_PTR == 4
42 #  define ETHR_NATIVE_SU_DW_SINT_T ethr_sint64_t
43 #elif ETHR_SIZEOF_PTR == 8 && defined(ETHR_HAVE_INT128_T)
44 #  define ETHR_NATIVE_SU_DW_SINT_T ethr_sint128_t
45 #endif
46 
47 typedef union {
48     volatile AO_double_t dw_mem;
49 #if defined(ETHR_NATIVE_SU_DW_SINT_T)
50     ETHR_NATIVE_SU_DW_SINT_T su_dw_sint;
51 #endif
52 } ethr_native_dw_atomic_t;
53 
54 #if defined(ETHR_NATIVE_SU_DW_SINT_T)
55 #  define ETHR_HAVE_NATIVE_SU_DW_ATOMIC
56 #else
57 #  define ETHR_HAVE_NATIVE_DW_ATOMIC
58 #endif
59 
60 #define ETHR_NATIVE_DW_ATOMIC_IMPL ETHR_NATIVE_IMPL__
61 
62 #if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_ATOMIC_IMPL__)
63 
64 
65 #if defined(ETHR_NATIVE_SU_DW_SINT_T)
66 #  define ETHR_NDWA_FUNC__(Func) ethr_native_su_dw_atomic_ ## Func
67 #  define ETHR_NDWA_RET_3_TYPE__ ETHR_NATIVE_SU_DW_SINT_T
68 #  define ETHR_NDWA_RET_2_TYPE__ ETHR_NATIVE_SU_DW_SINT_T
69 #  define ETHR_NDWA_VAL_ARG_TYPE__ ETHR_NATIVE_SU_DW_SINT_T
70 #  define ETHR_NDWA_DECL_ARG__(Arg)
71 #  if defined(AO_HAVE_DOUBLE_PTR_STORAGE)
72 #    define ETHR_NDWA_VAL2AOVAL__(AOV, V)			\
73     ((AOV).AO_whole = (double_ptr_storage) (V))
74 #    define ETHR_NDWA_AOVAL2VAL__(AOV, V)			\
75     ((V) = (ETHR_NATIVE_SU_DW_SINT_T) (AOV).AO_whole)
76 #    define ETHR_NDWA_RETURN_VAL_3__(SUCCESS, AOVAL, VAL)	\
77     do {							\
78 	return (ETHR_NATIVE_SU_DW_SINT_T) (AOVAL).AO_whole;	\
79     } while (0)
80 #    define ETHR_NDWA_RETURN_VAL_2__(AOVAL, VAL)		\
81     do {							\
82 	return (ETHR_NATIVE_SU_DW_SINT_T) (AOVAL).AO_whole;	\
83     } while (0)
84 #    define ETHR_NDWA_AOVAL_EQ__(AOV1, AOV2)			\
85     ((AOV1).AO_whole == (AOV2).AO_whole)
86 #  else
87 typedef union {
88     ethr_sint_t sint[2];
89     ETHR_NATIVE_SU_DW_SINT_T dw_sint;
90 }  ethr_dw_splitter_t;
91 #    define ETHR_NDWA_VAL2AOVAL__(AOV, V)			\
92     do {							\
93 	ethr_dw_splitter_t tmp__;				\
94 	tmp__.dw_sint = (V);					\
95 	(AOV).AO_val1 = (AO_t) tmp__.sint[0];			\
96 	(AOV).AO_val2 = (AO_t) tmp__.sint[1];			\
97     } while (0)
98 #    define ETHR_NDWA_AOVAL2VAL__(AOV, V)			\
99     do {							\
100 	ethr_dw_splitter_t tmp__;				\
101 	tmp__.sint[0] = (ethr_sint_t) (AOV).AO_val1;		\
102 	tmp__.sint[1] = (ethr_sint_t) (AOV).AO_val2;		\
103 	(V) = tmp__.dw_sint;					\
104     } while (0)
105 #    define ETHR_NDWA_RETURN_VAL_3__(SUCCESS, AOVAL, VAL)	\
106     do {							\
107 	ethr_dw_splitter_t tmp__;				\
108 	tmp__.sint[0] = (ethr_sint_t) (AOVAL).AO_val1;		\
109 	tmp__.sint[1] = (ethr_sint_t) (AOVAL).AO_val2;		\
110 	return tmp__.dw_sint;					\
111     } while (0)
112 #    define ETHR_NDWA_AOVAL_EQ__(AOV1, AOV2)			\
113     ((AOV1).AO_val1 == (AOV2).AO_val1				\
114 	 && (AOV1).AO_val2 == (AOV2).AO_val2)
115 #  endif
116 #else
117 #  define ETHR_NDWA_FUNC__(Func) ethr_native_dw_atomic_ ## Func
118 #  define ETHR_NDWA_RET_3_TYPE__ int
119 #  define ETHR_NDWA_RET_2_TYPE__ void
120 #  define ETHR_NDWA_VAL_ARG_TYPE__ ethr_sint_t *
121 #  define ETHR_NDWA_DECL_ARG__(Arg) , ETHR_NDWA_VAL_ARG_TYPE__ Arg
122 #    define ETHR_NDWA_VAL2AOVAL__(AOV, V)			\
123     do {							\
124 	(AOV).AO_val1 = (AO_t) (V)[0];				\
125 	(AOV).AO_val2 = (AO_t) (V)[1];				\
126     } while (0)
127 #    define ETHR_NDWA_AOVAL2VAL__(AOV, V)			\
128     do {							\
129 	ethr_dw_splitter_t tmp__;				\
130 	(V)[0] = (ethr_sint_t) (AOV).AO_val1;			\
131 	(V)[1] = (ethr_sint_t) (AOV).AO_val2;			\
132     } while (0)
133 #    define ETHR_NDWA_RETURN_VAL_3__(SUCCESS, AOVAL, VAL)	\
134     do {							\
135 	(VAL)[0] = (ethr_sint_t) (AOVAL).AO_val1;		\
136 	(VAL)[1] = (ethr_sint_t) (AOVAL).AO_val2;		\
137 	return (SUCCESS);					\
138     } while (0)
139 #    define ETHR_NDWA_RETURN_VAL_2__(AOVAL, VAL)		\
140     do {							\
141 	(VAL)[0] = (ethr_sint_t) (AOVAL).AO_val1;		\
142 	(VAL)[1] = (ethr_sint_t) (AOVAL).AO_val2;		\
143 	return;							\
144     } while (0)
145 #  if defined(AO_HAVE_DOUBLE_PTR_STORAGE)
146 #    define ETHR_NDWA_AOVAL_EQ__(AOV1, AOV2)			\
147     ((AOV1).AO_whole == (AOV2).AO_whole)
148 #  else
149 #    define ETHR_NDWA_AOVAL_EQ__(AOV1, AOV2)			\
150     ((AOV1).AO_val1 == (AOV2).AO_val1				\
151 	 && (AOV1).AO_val2 == (AOV2).AO_val2)
152 #  endif
153 #endif
154 
155 #define ETHR_HAVE_ETHR_NATIVE_DW_ATOMIC_ADDR
156 static ETHR_INLINE ethr_sint_t *
ethr_native_dw_atomic_addr(ethr_native_dw_atomic_t * var)157 ethr_native_dw_atomic_addr(ethr_native_dw_atomic_t *var)
158 {
159     return (ethr_sint_t *) &var->dw_mem;
160 }
161 
162 #ifdef AO_HAVE_double_load
163 
164 #if defined(ETHR_NATIVE_SU_DW_SINT_T)
165 #  define ETHR_HAVE_ETHR_NATIVE_SU_DW_ATOMIC_READ
166 #else
167 #  define ETHR_HAVE_ETHR_NATIVE_DW_ATOMIC_READ
168 #endif
169 
170 static ETHR_INLINE ETHR_NDWA_RET_2_TYPE__
ETHR_NDWA_FUNC__(read)171 ETHR_NDWA_FUNC__(read)(ethr_native_dw_atomic_t *var
172 		       ETHR_NDWA_DECL_ARG__(val))
173 {
174     AO_double_t act = AO_double_load(&var->dw_mem);
175     ETHR_NDWA_RETURN_VAL_2__(act, val);
176 }
177 
178 #endif
179 
180 #ifdef AO_HAVE_double_load_read
181 
182 #if defined(ETHR_NATIVE_SU_DW_SINT_T)
183 #  define ETHR_HAVE_ETHR_NATIVE_SU_DW_ATOMIC_READ_RB
184 #else
185 #  define ETHR_HAVE_ETHR_NATIVE_DW_ATOMIC_READ_RB
186 #endif
187 
188 static ETHR_INLINE ETHR_NDWA_RET_2_TYPE__
ETHR_NDWA_FUNC__(read_rb)189 ETHR_NDWA_FUNC__(read_rb)(ethr_native_dw_atomic_t *var
190 			  ETHR_NDWA_DECL_ARG__(val))
191 {
192     AO_double_t act = AO_double_load_read(&var->dw_mem);
193     ETHR_NDWA_RETURN_VAL_2__(act, val);
194 }
195 
196 #endif
197 
198 #ifdef AO_HAVE_double_load_acquire
199 
200 #if defined(ETHR_NATIVE_SU_DW_SINT_T)
201 #  define ETHR_HAVE_ETHR_NATIVE_SU_DW_ATOMIC_READ_ACQB
202 #else
203 #  define ETHR_HAVE_ETHR_NATIVE_DW_ATOMIC_READ_ACQB
204 #endif
205 
206 static ETHR_INLINE ETHR_NDWA_RET_2_TYPE__
ETHR_NDWA_FUNC__(read_acqb)207 ETHR_NDWA_FUNC__(read_acqb)(ethr_native_dw_atomic_t *var
208 			    ETHR_NDWA_DECL_ARG__(val))
209 {
210     AO_double_t act = AO_double_load_acquire(&var->dw_mem);
211     ETHR_NDWA_RETURN_VAL_2__(act, val);
212 }
213 
214 #endif
215 
216 #ifdef AO_HAVE_double_store
217 
218 #if defined(ETHR_NATIVE_SU_DW_SINT_T)
219 #  define ETHR_HAVE_ETHR_NATIVE_SU_DW_ATOMIC_SET
220 #else
221 #  define ETHR_HAVE_ETHR_NATIVE_DW_ATOMIC_SET
222 #endif
223 
224 static ETHR_INLINE void
ETHR_NDWA_FUNC__(set)225 ETHR_NDWA_FUNC__(set)(ethr_native_dw_atomic_t *var,
226 		      ETHR_NDWA_VAL_ARG_TYPE__ val)
227 {
228     AO_double_t new;
229     ETHR_NDWA_VAL2AOVAL__(new, val);
230     AO_double_store(&var->dw_mem, new);
231 }
232 
233 #endif
234 
235 #ifdef AO_HAVE_double_store_write
236 
237 #if defined(ETHR_NATIVE_SU_DW_SINT_T)
238 #  define ETHR_HAVE_ETHR_NATIVE_SU_DW_ATOMIC_SET_WB
239 #else
240 #  define ETHR_HAVE_ETHR_NATIVE_DW_ATOMIC_SET_WB
241 #endif
242 
243 static ETHR_INLINE void
ETHR_NDWA_FUNC__(set_wb)244 ETHR_NDWA_FUNC__(set_wb)(ethr_native_dw_atomic_t *var,
245 			 ETHR_NDWA_VAL_ARG_TYPE__ val)
246 {
247     AO_double_t new;
248     ETHR_NDWA_VAL2AOVAL__(new, val);
249     AO_double_store_write(&var->dw_mem, new);
250 }
251 
252 #endif
253 
254 #ifdef AO_HAVE_double_store_release
255 
256 #if defined(ETHR_NATIVE_SU_DW_SINT_T)
257 #  define ETHR_HAVE_ETHR_NATIVE_SU_DW_ATOMIC_SET_RELB
258 #else
259 #  define ETHR_HAVE_ETHR_NATIVE_DW_ATOMIC_SET_RELB
260 #endif
261 
262 static ETHR_INLINE void
ETHR_NDWA_FUNC__(set_relb)263 ETHR_NDWA_FUNC__(set_relb)(ethr_native_dw_atomic_t *var,
264 			   ETHR_NDWA_VAL_ARG_TYPE__ val)
265 {
266     AO_double_t new;
267     ETHR_NDWA_VAL2AOVAL__(new, val);
268     AO_double_store_release(&var->dw_mem, new);
269 }
270 
271 #endif
272 
273 #if defined(AO_HAVE_double_compare_and_swap_full) || defined(AO_HAVE_compare_double_and_swap_double_full)
274 
275 #if defined(ETHR_NATIVE_SU_DW_SINT_T)
276 #  define ETHR_HAVE_ETHR_NATIVE_SU_DW_ATOMIC_CMPXCHG_MB
277 #else
278 #  define ETHR_HAVE_ETHR_NATIVE_DW_ATOMIC_CMPXCHG_MB
279 #endif
280 
281 static ETHR_INLINE ETHR_NDWA_RET_3_TYPE__
ETHR_NDWA_FUNC__(cmpxchg_mb)282 ETHR_NDWA_FUNC__(cmpxchg_mb)(ethr_native_dw_atomic_t *var,
283 			     ETHR_NDWA_VAL_ARG_TYPE__ new,
284 			     ETHR_NDWA_VAL_ARG_TYPE__ exp)
285 {
286     AO_double_t ao_act, ao_new, ao_exp;
287 
288     ETHR_NDWA_VAL2AOVAL__(ao_exp, exp);
289     ETHR_NDWA_VAL2AOVAL__(ao_new, new);
290 
291     do {
292 	int xchgd;
293 #if defined(AO_HAVE_double_compare_and_swap_full)
294 	xchgd = AO_double_compare_and_swap_full(&var->dw_mem, ao_exp, ao_new);
295 #elif defined(AO_HAVE_compare_double_and_swap_double_full)
296 	xchgd = AO_compare_double_and_swap_double_full(&var->dw_mem,
297 						       ao_exp.AO_val1,
298 						       ao_exp.AO_val2,
299 						       ao_new.AO_val1,
300 						       ao_new.AO_val2);
301 #endif
302 
303 	if (xchgd)
304 	    ETHR_NDWA_RETURN_VAL_3__(1, ao_exp, exp);
305 
306 #ifdef AO_HAVE_double_load_acquire
307 	ao_act = AO_double_load_acquire(&var->dw_mem);
308 #else
309 	ao_act = AO_double_load(&var->dw_mem);
310 #endif
311 
312     } while (ETHR_NDWA_AOVAL_EQ__(ao_exp, ao_act));
313 
314 #ifndef AO_HAVE_double_load_acquire
315     AO_nop_full();
316 #endif
317 
318     ETHR_NDWA_RETURN_VAL_3__(1, ao_act, exp);
319 }
320 
321 #endif
322 
323 #if defined(AO_HAVE_double_compare_and_swap) || defined(AO_HAVE_compare_double_and_swap_double)
324 
325 #if defined(ETHR_NATIVE_SU_DW_SINT_T)
326 #  define ETHR_HAVE_ETHR_NATIVE_SU_DW_ATOMIC_CMPXCHG
327 #else
328 #  define ETHR_HAVE_ETHR_NATIVE_DW_ATOMIC_CMPXCHG
329 #endif
330 
331 static ETHR_INLINE ETHR_NDWA_RET_3_TYPE__
ETHR_NDWA_FUNC__(cmpxchg)332 ETHR_NDWA_FUNC__(cmpxchg)(ethr_native_dw_atomic_t *var,
333 			  ETHR_NDWA_VAL_ARG_TYPE__ new,
334 			  ETHR_NDWA_VAL_ARG_TYPE__ exp)
335 {
336     AO_double_t ao_act, ao_new, ao_exp;
337 
338     ETHR_NDWA_VAL2AOVAL__(ao_exp, exp);
339     ETHR_NDWA_VAL2AOVAL__(ao_new, new);
340 
341     do {
342 	int xchgd;
343 #if defined(AO_HAVE_double_compare_and_swap)
344 	xchgd = AO_double_compare_and_swap(&var->dw_mem, ao_exp, ao_new);
345 #elif defined(AO_HAVE_compare_double_and_swap_double)
346 	xchgd = AO_compare_double_and_swap_double(&var->dw_mem,
347 						  ao_exp.AO_val1,
348 						  ao_exp.AO_val2,
349 						  ao_new.AO_val1,
350 						  ao_new.AO_val2);
351 #endif
352 
353 	if (xchgd)
354 	    ETHR_NDWA_RETURN_VAL_3__(1, ao_exp, exp);
355 
356 #ifdef AO_HAVE_double_load
357 	ao_act = AO_double_load(&var->dw_mem);
358 #else
359 	ao_act = AO_double_load_acquire(&var->dw_mem);
360 #endif
361 
362     } while (ETHR_NDWA_AOVAL_EQ__(ao_exp, ao_act));
363 
364     ETHR_NDWA_RETURN_VAL_3__(1, ao_act, exp);
365 }
366 
367 #endif
368 
369 #if defined(AO_HAVE_double_compare_and_swap_read) || defined(AO_HAVE_compare_double_and_swap_double_read)
370 
371 #if defined(ETHR_NATIVE_SU_DW_SINT_T)
372 #  define ETHR_HAVE_ETHR_NATIVE_SU_DW_ATOMIC_CMPXCHG_RB
373 #else
374 #  define ETHR_HAVE_ETHR_NATIVE_DW_ATOMIC_CMPXCHG_RB
375 #endif
376 
377 static ETHR_INLINE ETHR_NDWA_RET_3_TYPE__
ETHR_NDWA_FUNC__(cmpxchg_rb)378 ETHR_NDWA_FUNC__(cmpxchg_rb)(ethr_native_dw_atomic_t *var,
379 			     ETHR_NDWA_VAL_ARG_TYPE__ new,
380 			     ETHR_NDWA_VAL_ARG_TYPE__ exp)
381 {
382     AO_double_t ao_act, ao_new, ao_exp;
383 
384     ETHR_NDWA_VAL2AOVAL__(ao_exp, exp);
385     ETHR_NDWA_VAL2AOVAL__(ao_new, new);
386 
387     do {
388 	int xchgd;
389 #if defined(AO_HAVE_double_compare_and_swap_read)
390 	xchgd = AO_double_compare_and_swap_read(&var->dw_mem, ao_exp, ao_new);
391 #elif defined(AO_HAVE_compare_double_and_swap_double_read)
392 	xchgd = AO_compare_double_and_swap_double_read(&var->dw_mem,
393 							  ao_exp.AO_val1,
394 							  ao_exp.AO_val2,
395 							  ao_new.AO_val1,
396 							  ao_new.AO_val2);
397 #endif
398 
399 	if (xchgd)
400 	    ETHR_NDWA_RETURN_VAL_3__(1, ao_exp, exp);
401 
402 #if defined(AO_HAVE_double_load_read)
403 	ao_act = AO_double_load_read(&var->dw_mem);
404 #elif defined(AO_HAVE_double_load)
405 	ao_act = AO_double_load(&var->dw_mem);
406 #else
407 	ao_act = AO_double_load_acquire(&var->dw_mem);
408 #endif
409 
410     } while (ETHR_NDWA_AOVAL_EQ__(ao_exp, ao_act));
411 
412 #ifndef AO_HAVE_double_load_read
413 #ifdef AO_HAVE_nop_read
414     AO_nop_read();
415 #else
416     AO_nop_full();
417 #endif
418 #endif
419 
420     ETHR_NDWA_RETURN_VAL_3__(1, ao_act, exp);
421 }
422 
423 #endif
424 
425 #if defined(AO_HAVE_double_compare_and_swap_acquire) || defined(AO_HAVE_compare_double_and_swap_double_acquire)
426 
427 #if defined(ETHR_NATIVE_SU_DW_SINT_T)
428 #  define ETHR_HAVE_ETHR_NATIVE_SU_DW_ATOMIC_CMPXCHG_ACQB
429 #else
430 #  define ETHR_HAVE_ETHR_NATIVE_DW_ATOMIC_CMPXCHG_ACQB
431 #endif
432 
433 static ETHR_INLINE ETHR_NDWA_RET_3_TYPE__
ETHR_NDWA_FUNC__(cmpxchg_acqb)434 ETHR_NDWA_FUNC__(cmpxchg_acqb)(ethr_native_dw_atomic_t *var,
435 			       ETHR_NDWA_VAL_ARG_TYPE__ new,
436 			       ETHR_NDWA_VAL_ARG_TYPE__ exp)
437 {
438     AO_double_t ao_act, ao_new, ao_exp;
439 
440     ETHR_NDWA_VAL2AOVAL__(ao_exp, exp);
441     ETHR_NDWA_VAL2AOVAL__(ao_new, new);
442 
443     do {
444 	int xchgd;
445 #if defined(AO_HAVE_double_compare_and_swap_acquire)
446 	xchgd = AO_double_compare_and_swap_acquire(&var->dw_mem, ao_exp, ao_new);
447 #elif defined(AO_HAVE_compare_double_and_swap_double_acquire)
448 	xchgd = AO_compare_double_and_swap_double_acquire(&var->dw_mem,
449 							  ao_exp.AO_val1,
450 							  ao_exp.AO_val2,
451 							  ao_new.AO_val1,
452 							  ao_new.AO_val2);
453 #endif
454 
455 	if (xchgd)
456 	    ETHR_NDWA_RETURN_VAL_3__(1, ao_exp, exp);
457 
458 #ifdef AO_HAVE_double_load_acquire
459 	ao_act = AO_double_load_acquire(&var->dw_mem);
460 #else
461 	ao_act = AO_double_load(&var->dw_mem);
462 #endif
463 
464     } while (ETHR_NDWA_AOVAL_EQ__(ao_exp, ao_act));
465 
466 #ifndef AO_HAVE_double_load_acquire
467     AO_nop_full();
468 #endif
469 
470     ETHR_NDWA_RETURN_VAL_3__(1, ao_act, exp);
471 }
472 
473 #endif
474 
475 #if defined(AO_HAVE_double_compare_and_swap_write) || defined(AO_HAVE_compare_double_and_swap_double_write)
476 
477 #if defined(ETHR_NATIVE_SU_DW_SINT_T)
478 #  define ETHR_HAVE_ETHR_NATIVE_SU_DW_ATOMIC_CMPXCHG_WB
479 #else
480 #  define ETHR_HAVE_ETHR_NATIVE_DW_ATOMIC_CMPXCHG_WB
481 #endif
482 
483 static ETHR_INLINE ETHR_NDWA_RET_3_TYPE__
ETHR_NDWA_FUNC__(cmpxchg_wb)484 ETHR_NDWA_FUNC__(cmpxchg_wb)(ethr_native_dw_atomic_t *var,
485 			     ETHR_NDWA_VAL_ARG_TYPE__ new,
486 			     ETHR_NDWA_VAL_ARG_TYPE__ exp)
487 {
488     AO_double_t ao_act, ao_new, ao_exp;
489 
490     ETHR_NDWA_VAL2AOVAL__(ao_exp, exp);
491     ETHR_NDWA_VAL2AOVAL__(ao_new, new);
492 
493     do {
494 	int xchgd;
495 #if defined(AO_HAVE_double_compare_and_swap_write)
496 	xchgd = AO_double_compare_and_swap_write(&var->dw_mem, ao_exp, ao_new);
497 #elif defined(AO_HAVE_compare_double_and_swap_double_write)
498 	xchgd = AO_compare_double_and_swap_double_write(&var->dw_mem,
499 							ao_exp.AO_val1,
500 							ao_exp.AO_val2,
501 							ao_new.AO_val1,
502 							ao_new.AO_val2);
503 #endif
504 
505 	if (xchgd)
506 	    ETHR_NDWA_RETURN_VAL_3__(1, ao_exp, exp);
507 
508 #ifdef AO_HAVE_double_load
509 	ao_act = AO_double_load(&var->dw_mem);
510 #else
511 	ao_act = AO_double_load_acquire(&var->dw_mem);
512 #endif
513 
514     } while (ETHR_NDWA_AOVAL_EQ__(ao_exp, ao_act));
515 
516     ETHR_NDWA_RETURN_VAL_3__(1, ao_act, exp);
517 }
518 
519 #endif
520 
521 #if defined(AO_HAVE_double_compare_and_swap_release) || defined(AO_HAVE_compare_double_and_swap_double_release)
522 
523 #if defined(ETHR_NATIVE_SU_DW_SINT_T)
524 #  define ETHR_HAVE_ETHR_NATIVE_SU_DW_ATOMIC_CMPXCHG_RELB
525 #else
526 #  define ETHR_HAVE_ETHR_NATIVE_DW_ATOMIC_CMPXCHG_RELB
527 #endif
528 
529 static ETHR_INLINE ETHR_NDWA_RET_3_TYPE__
ETHR_NDWA_FUNC__(cmpxchg_relb)530 ETHR_NDWA_FUNC__(cmpxchg_relb)(ethr_native_dw_atomic_t *var,
531 			       ETHR_NDWA_VAL_ARG_TYPE__ new,
532 			       ETHR_NDWA_VAL_ARG_TYPE__ exp)
533 {
534     AO_double_t ao_act, ao_new, ao_exp;
535 
536     ETHR_NDWA_VAL2AOVAL__(ao_exp, exp);
537     ETHR_NDWA_VAL2AOVAL__(ao_new, new);
538 
539     do {
540 	int xchgd;
541 #if defined(AO_HAVE_double_compare_and_swap_release)
542 	xchgd = AO_double_compare_and_swap_release(&var->dw_mem, ao_exp, ao_new);
543 #elif defined(AO_HAVE_compare_double_and_swap_double_release)
544 	xchgd = AO_compare_double_and_swap_double_release(&var->dw_mem,
545 							  ao_exp.AO_val1,
546 							  ao_exp.AO_val2,
547 							  ao_new.AO_val1,
548 							  ao_new.AO_val2);
549 #endif
550 
551 	if (xchgd)
552 	    ETHR_NDWA_RETURN_VAL_3__(1, ao_exp, exp);
553 
554 	ao_act = AO_double_load(&var->dw_mem);
555 
556     } while (ETHR_NDWA_AOVAL_EQ__(ao_exp, ao_act));
557 
558     ETHR_NDWA_RETURN_VAL_3__(1, ao_act, exp);
559 }
560 
561 #endif
562 
563 #endif /* defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_ATOMIC_IMPL__) */
564 
565 #endif /* Have AO double functionality ... */
566 
567 #endif /* ETHR_LIBATOMIC_OPS_DW_ATOMIC_H__ */
568 
569