comparison src/atomic/qnx/SDL_atomic.c @ 3217:26ce0b98f2fb

Support for native and emulated atomic operations has been added.
author Mike Gorchak <lestat@i.com.ua>
date Sun, 19 Jul 2009 08:04:59 +0000
parents
children 70bfe3337f8a
comparison
equal deleted inserted replaced
3216:48a80f2a7ff2 3217:26ce0b98f2fb
1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2009 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21 */
22
23 #include "SDL_stdinc.h"
24 #include "SDL_atomic.h"
25
26 #include <atomic.h>
27
28 /*
29 This file provides 8, 16, 32, and 64 bit atomic operations. If the
30 operations are provided by the native hardware and operating system
31 they are used. If they are not then the operations are emulated
32 using the SDL mutex operations.
33 */
34
35 /*
36 First, detect whether the operations are supported and create
37 #defines that indicate that they do exist. The goal is to have all
38 the system dependent code in the top part of the file so that the
39 bottom can be use unchanged across all platforms.
40
41 Second, #define all the operations in each size class that are
42 supported. Doing this allows supported operations to be used along
43 side of emulated operations.
44 */
45
46 /*
47 Emmulated version.
48
49 Assume there is no support for atomic operations. All such
50 operations are implemented using SDL mutex operations.
51 */
52
53 #ifdef EMULATED_ATOMIC_OPERATIONS
54 #undef EMULATED_ATOMIC_OPERATIONS
55 #endif
56
57 #ifdef EMULATED_ATOMIC_OPERATIONS
58 #define HAVE_ALL_8_BIT_OPS
59
60 #define nativeExchange8(ptr, value) ()
61 #define nativeCompareThenSet8(ptr, oldvalue, newvalue) ()
62 #define nativeTestThenSet8(ptr) ()
63 #define nativeClear8(ptr) ()
64 #define nativeFetchThenIncrement8(ptr) ()
65 #define nativeFetchThenDecrement8(ptr) ()
66 #define nativeFetchThenAdd8(ptr, value) ()
67 #define nativeFetchThenSubtract8(ptr, value) ()
68 #define nativeIncrementThenFetch8(ptr) ()
69 #define nativeDecrementThenFetch8(ptr) ()
70 #define nativeAddThenFetch8(ptr, value) ()
71 #define nativeSubtractThenFetch8(ptr, value) ()
72 #endif
73
74 #ifdef EMULATED_ATOMIC_OPERATIONS
75 #define HAVE_ALL_16_BIT_OPS
76
77 #define nativeExchange16(ptr, value) ()
78 #define nativeCompareThenSet16(ptr, oldvalue, newvalue) ()
79 #define nativeTestThenSet16(ptr) ()
80 #define nativeClear16(ptr) ()
81 #define nativeFetchThenIncrement16(ptr) ()
82 #define nativeFetchThenDecrement16(ptr) ()
83 #define nativeFetchThenAdd16(ptr, value) ()
84 #define nativeFetchThenSubtract16(ptr, value) ()
85 #define nativeIncrementThenFetch16(ptr) ()
86 #define nativeDecrementThenFetch16(ptr) ()
87 #define nativeAddThenFetch16(ptr, value) ()
88 #define nativeSubtractThenFetch16(ptr, value) ()
89 #endif
90
91 #ifdef EMULATED_ATOMIC_OPERATIONS
92 #define HAVE_ALL_64_BIT_OPS
93
94 #define nativeExchange64(ptr, value) ()
95 #define nativeCompareThenSet64(ptr, oldvalue, newvalue) ()
96 #define nativeTestThenSet64(ptr) ()
97 #define nativeClear64(ptr) ()
98 #define nativeFetchThenIncrement64(ptr) ()
99 #define nativeFetchThenDecrement64(ptr) ()
100 #define nativeFetchThenAdd64(ptr, value) ()
101 #define nativeFetchThenSubtract64(ptr, value) ()
102 #define nativeIncrementThenFetch64(ptr) ()
103 #define nativeDecrementThenFetch64(ptr) ()
104 #define nativeAddThenFetch64(ptr, value) ()
105 #define nativeSubtractThenFetch64(ptr, value) ()
106 #endif
107
108 /*
109 If any of the operations are not provided then we must emulate some of
110 them.
111 */
112
113 #if !defined(HAVE_ALL_8_BIT_OPS) || !defined(HAVE_ALL_16_BIT_OPS) || !defined(HAVE_ALL_64_BIT_OPS)
114
115 #include "SDL_mutex.h"
116 #include "SDL_error.h"
117
118 static SDL_mutex * lock = NULL;
119
120 static __inline__ void
121 privateWaitLock()
122 {
123 if(NULL == lock)
124 {
125 lock = SDL_CreateMutex();
126 if (NULL == lock)
127 {
128 SDL_SetError("SDL_atomic.c: can't create a mutex");
129 return;
130 }
131 }
132
133 if (-1 == SDL_LockMutex(lock))
134 {
135 SDL_SetError("SDL_atomic.c: can't lock mutex");
136 }
137 }
138
139 static __inline__ void
140 privateUnlock()
141 {
142 if (-1 == SDL_UnlockMutex(lock))
143 {
144 SDL_SetError("SDL_atomic.c: can't unlock mutex");
145 }
146 }
147
148 #endif
149
150 /* 8 bit atomic operations */
151
152 Uint8
153 SDL_AtomicExchange8(volatile Uint8 * ptr, Uint8 value)
154 {
155 #ifdef nativeExchange8
156 return nativeExchange8(ptr, value);
157 #else
158 Uint8 tmp = 0;
159
160 privateWaitLock();
161 tmp = *ptr;
162 *ptr = value;
163 privateUnlock();
164
165 return tmp;
166 #endif
167 }
168
169 SDL_bool
170 SDL_AtomicCompareThenSet8(volatile Uint8 * ptr, Uint8 oldvalue, Uint8 newvalue)
171 {
172 #ifdef nativeCompareThenSet8
173 return (SDL_bool)nativeCompareThenSet8(ptr, oldvalue, newvalue);
174 #else
175 SDL_bool result = SDL_FALSE;
176
177 privateWaitLock();
178 result = (*ptr == oldvalue);
179 if (result)
180 {
181 *ptr = newvalue;
182 }
183 privateUnlock();
184
185 return result;
186 #endif
187 }
188
189 SDL_bool
190 SDL_AtomicTestThenSet8(volatile Uint8 * ptr)
191 {
192 #ifdef nativeTestThenSet8
193 return (SDL_bool)nativeTestThenSet8(ptr);
194 #else
195 SDL_bool result = SDL_FALSE;
196
197 privateWaitLock();
198 result = (*ptr == 0);
199 if (result)
200 {
201 *ptr = 1;
202 }
203 privateUnlock();
204
205 return result;
206 #endif
207 }
208
209 void
210 SDL_AtomicClear8(volatile Uint8 * ptr)
211 {
212 #ifdef nativeClear8
213 nativeClear8(ptr);
214 #else
215 privateWaitLock();
216 *ptr = 0;
217 privateUnlock();
218
219 return;
220 #endif
221 }
222
223 Uint8
224 SDL_AtomicFetchThenIncrement8(volatile Uint8 * ptr)
225 {
226 #ifdef nativeFetchThenIncrement8
227 return nativeFetchThenIncrement8(ptr);
228 #else
229 Uint8 tmp = 0;
230
231 privateWaitLock();
232 tmp = *ptr;
233 (*ptr)+= 1;
234 privateUnlock();
235
236 return tmp;
237 #endif
238 }
239
240 Uint8
241 SDL_AtomicFetchThenDecrement8(volatile Uint8 * ptr)
242 {
243 #ifdef nativeFetchThenDecrement8
244 return nativeFetchThenDecrement8(ptr);
245 #else
246 Uint8 tmp = 0;
247
248 privateWaitLock();
249 tmp = *ptr;
250 (*ptr) -= 1;
251 privateUnlock();
252
253 return tmp;
254 #endif
255 }
256
257 Uint8
258 SDL_AtomicFetchThenAdd8(volatile Uint8 * ptr, Uint8 value)
259 {
260 #ifdef nativeFetchThenAdd8
261 return nativeFetchThenAdd8(ptr, value);
262 #else
263 Uint8 tmp = 0;
264
265 privateWaitLock();
266 tmp = *ptr;
267 (*ptr)+= value;
268 privateUnlock();
269
270 return tmp;
271 #endif
272 }
273
274 Uint8
275 SDL_AtomicFetchThenSubtract8(volatile Uint8 * ptr, Uint8 value)
276 {
277 #ifdef nativeFetchThenSubtract8
278 return nativeFetchThenSubtract8(ptr, value);
279 #else
280 Uint8 tmp = 0;
281
282 privateWaitLock();
283 tmp = *ptr;
284 (*ptr)-= value;
285 privateUnlock();
286
287 return tmp;
288 #endif
289 }
290
291 Uint8
292 SDL_AtomicIncrementThenFetch8(volatile Uint8 * ptr)
293 {
294 #ifdef nativeIncrementThenFetch8
295 return nativeIncrementThenFetch8(ptr);
296 #else
297 Uint8 tmp = 0;
298
299 privateWaitLock();
300 (*ptr)+= 1;
301 tmp = *ptr;
302 privateUnlock();
303
304 return tmp;
305 #endif
306 }
307
308 Uint8
309 SDL_AtomicDecrementThenFetch8(volatile Uint8 * ptr)
310 {
311 #ifdef nativeDecrementThenFetch8
312 return nativeDecrementThenFetch8(ptr);
313 #else
314 Uint8 tmp = 0;
315
316 privateWaitLock();
317 (*ptr)-= 1;
318 tmp = *ptr;
319 privateUnlock();
320
321 return tmp;
322 #endif
323 }
324
325 Uint8
326 SDL_AtomicAddThenFetch8(volatile Uint8 * ptr, Uint8 value)
327 {
328 #ifdef nativeAddThenFetch8
329 return nativeAddThenFetch8(ptr, value);
330 #else
331 Uint8 tmp = 0;
332
333 privateWaitLock();
334 (*ptr)+= value;
335 tmp = *ptr;
336 privateUnlock();
337
338 return tmp;
339 #endif
340 }
341
342 Uint8
343 SDL_AtomicSubtractThenFetch8(volatile Uint8 * ptr, Uint8 value)
344 {
345 #ifdef nativeSubtractThenFetch8
346 return nativeSubtractThenFetch8(ptr, value);
347 #else
348 Uint8 tmp = 0;
349
350 privateWaitLock();
351 (*ptr)-= value;
352 tmp = *ptr;
353 privateUnlock();
354
355 return tmp;
356 #endif
357 }
358
359 /* 16 bit atomic operations */
360
361 Uint16
362 SDL_AtomicExchange16(volatile Uint16 * ptr, Uint16 value)
363 {
364 #ifdef nativeExchange16
365 return nativeExchange16(ptr, value);
366 #else
367 Uint16 tmp = 0;
368
369 privateWaitLock();
370 tmp = *ptr;
371 *ptr = value;
372 privateUnlock();
373
374 return tmp;
375 #endif
376 }
377
378 SDL_bool
379 SDL_AtomicCompareThenSet16(volatile Uint16 * ptr, Uint16 oldvalue, Uint16 newvalue)
380 {
381 #ifdef nativeCompareThenSet16
382 return (SDL_bool)nativeCompareThenSet16(ptr, oldvalue, newvalue);
383 #else
384 SDL_bool result = SDL_FALSE;
385
386 privateWaitLock();
387 result = (*ptr == oldvalue);
388 if (result)
389 {
390 *ptr = newvalue;
391 }
392 privateUnlock();
393
394 return result;
395 #endif
396 }
397
398 SDL_bool
399 SDL_AtomicTestThenSet16(volatile Uint16 * ptr)
400 {
401 #ifdef nativeTestThenSet16
402 return (SDL_bool)nativeTestThenSet16(ptr);
403 #else
404 SDL_bool result = SDL_FALSE;
405
406 privateWaitLock();
407 result = (*ptr == 0);
408 if (result)
409 {
410 *ptr = 1;
411 }
412 privateUnlock();
413
414 return result;
415 #endif
416 }
417
418 void
419 SDL_AtomicClear16(volatile Uint16 * ptr)
420 {
421 #ifdef nativeClear16
422 nativeClear16(ptr);
423 #else
424 privateWaitLock();
425 *ptr = 0;
426 privateUnlock();
427
428 return;
429 #endif
430 }
431
432 Uint16
433 SDL_AtomicFetchThenIncrement16(volatile Uint16 * ptr)
434 {
435 #ifdef nativeFetchThenIncrement16
436 return nativeFetchThenIncrement16(ptr);
437 #else
438 Uint16 tmp = 0;
439
440 privateWaitLock();
441 tmp = *ptr;
442 (*ptr)+= 1;
443 privateUnlock();
444
445 return tmp;
446 #endif
447 }
448
449 Uint16
450 SDL_AtomicFetchThenDecrement16(volatile Uint16 * ptr)
451 {
452 #ifdef nativeFetchThenDecrement16
453 return nativeFetchThenDecrement16(ptr);
454 #else
455 Uint16 tmp = 0;
456
457 privateWaitLock();
458 tmp = *ptr;
459 (*ptr) -= 1;
460 privateUnlock();
461
462 return tmp;
463 #endif
464 }
465
466 Uint16
467 SDL_AtomicFetchThenAdd16(volatile Uint16 * ptr, Uint16 value)
468 {
469 #ifdef nativeFetchThenAdd16
470 return nativeFetchThenAdd16(ptr, value);
471 #else
472 Uint16 tmp = 0;
473
474 privateWaitLock();
475 tmp = *ptr;
476 (*ptr)+= value;
477 privateUnlock();
478
479 return tmp;
480 #endif
481 }
482
483 Uint16
484 SDL_AtomicFetchThenSubtract16(volatile Uint16 * ptr, Uint16 value)
485 {
486 #ifdef nativeFetchThenSubtract16
487 return nativeFetchThenSubtract16(ptr, value);
488 #else
489 Uint16 tmp = 0;
490
491 privateWaitLock();
492 tmp = *ptr;
493 (*ptr)-= value;
494 privateUnlock();
495
496 return tmp;
497 #endif
498 }
499
500 Uint16
501 SDL_AtomicIncrementThenFetch16(volatile Uint16 * ptr)
502 {
503 #ifdef nativeIncrementThenFetch16
504 return nativeIncrementThenFetch16(ptr);
505 #else
506 Uint16 tmp = 0;
507
508 privateWaitLock();
509 (*ptr)+= 1;
510 tmp = *ptr;
511 privateUnlock();
512
513 return tmp;
514 #endif
515 }
516
517 Uint16
518 SDL_AtomicDecrementThenFetch16(volatile Uint16 * ptr)
519 {
520 #ifdef nativeDecrementThenFetch16
521 return nativeDecrementThenFetch16(ptr);
522 #else
523 Uint16 tmp = 0;
524
525 privateWaitLock();
526 (*ptr)-= 1;
527 tmp = *ptr;
528 privateUnlock();
529
530 return tmp;
531 #endif
532 }
533
534 Uint16
535 SDL_AtomicAddThenFetch16(volatile Uint16 * ptr, Uint16 value)
536 {
537 #ifdef nativeAddThenFetch16
538 return nativeAddThenFetch16(ptr, value);
539 #else
540 Uint16 tmp = 0;
541
542 privateWaitLock();
543 (*ptr)+= value;
544 tmp = *ptr;
545 privateUnlock();
546
547 return tmp;
548 #endif
549 }
550
551 Uint16
552 SDL_AtomicSubtractThenFetch16(volatile Uint16 * ptr, Uint16 value)
553 {
554 #ifdef nativeSubtractThenFetch16
555 return nativeSubtractThenFetch16(ptr, value);
556 #else
557 Uint16 tmp = 0;
558
559 privateWaitLock();
560 (*ptr)-= value;
561 tmp = *ptr;
562 privateUnlock();
563
564 return tmp;
565 #endif
566 }
567
568 /* 64 bit atomic operations */
569 #ifdef SDL_HAS_64BIT_TYPE
570
571 Uint64
572 SDL_AtomicExchange64(volatile Uint64 * ptr, Uint64 value)
573 {
574 #ifdef nativeExchange64
575 return nativeExchange64(ptr, value);
576 #else
577 Uint64 tmp = 0;
578
579 privateWaitLock();
580 tmp = *ptr;
581 *ptr = value;
582 privateUnlock();
583
584 return tmp;
585 #endif
586 }
587
588 SDL_bool
589 SDL_AtomicCompareThenSet64(volatile Uint64 * ptr, Uint64 oldvalue, Uint64 newvalue)
590 {
591 #ifdef nativeCompareThenSet64
592 return (SDL_bool)nativeCompareThenSet64(ptr, oldvalue, newvalue);
593 #else
594 SDL_bool result = SDL_FALSE;
595
596 privateWaitLock();
597 result = (*ptr == oldvalue);
598 if (result)
599 {
600 *ptr = newvalue;
601 }
602 privateUnlock();
603
604 return result;
605 #endif
606 }
607
608 SDL_bool
609 SDL_AtomicTestThenSet64(volatile Uint64 * ptr)
610 {
611 #ifdef nativeTestThenSet64
612 return (SDL_bool)nativeTestThenSet64(ptr);
613 #else
614 SDL_bool result = SDL_FALSE;
615
616 privateWaitLock();
617 result = (*ptr == 0);
618 if (result)
619 {
620 *ptr = 1;
621 }
622 privateUnlock();
623
624 return result;
625 #endif
626 }
627
628 void
629 SDL_AtomicClear64(volatile Uint64 * ptr)
630 {
631 #ifdef nativeClear64
632 nativeClear64(ptr);
633 #else
634 privateWaitLock();
635 *ptr = 0;
636 privateUnlock();
637
638 return;
639 #endif
640 }
641
642 Uint64
643 SDL_AtomicFetchThenIncrement64(volatile Uint64 * ptr)
644 {
645 #ifdef nativeFetchThenIncrement64
646 return nativeFetchThenIncrement64(ptr);
647 #else
648 Uint64 tmp = 0;
649
650 privateWaitLock();
651 tmp = *ptr;
652 (*ptr)+= 1;
653 privateUnlock();
654
655 return tmp;
656 #endif
657 }
658
659 Uint64
660 SDL_AtomicFetchThenDecrement64(volatile Uint64 * ptr)
661 {
662 #ifdef nativeFetchThenDecrement64
663 return nativeFetchThenDecrement64(ptr);
664 #else
665 Uint64 tmp = 0;
666
667 privateWaitLock();
668 tmp = *ptr;
669 (*ptr) -= 1;
670 privateUnlock();
671
672 return tmp;
673 #endif
674 }
675
676 Uint64
677 SDL_AtomicFetchThenAdd64(volatile Uint64 * ptr, Uint64 value)
678 {
679 #ifdef nativeFetchThenAdd64
680 return nativeFetchThenAdd64(ptr, value);
681 #else
682 Uint64 tmp = 0;
683
684 privateWaitLock();
685 tmp = *ptr;
686 (*ptr)+= value;
687 privateUnlock();
688
689 return tmp;
690 #endif
691 }
692
693 Uint64
694 SDL_AtomicFetchThenSubtract64(volatile Uint64 * ptr, Uint64 value)
695 {
696 #ifdef nativeFetchThenSubtract64
697 return nativeFetchThenSubtract64(ptr, value);
698 #else
699 Uint64 tmp = 0;
700
701 privateWaitLock();
702 tmp = *ptr;
703 (*ptr)-= value;
704 privateUnlock();
705
706 return tmp;
707 #endif
708 }
709
710 Uint64
711 SDL_AtomicIncrementThenFetch64(volatile Uint64 * ptr)
712 {
713 #ifdef nativeIncrementThenFetch64
714 return nativeIncrementThenFetch64(ptr);
715 #else
716 Uint64 tmp = 0;
717
718 privateWaitLock();
719 (*ptr)+= 1;
720 tmp = *ptr;
721 privateUnlock();
722
723 return tmp;
724 #endif
725 }
726
727 Uint64
728 SDL_AtomicDecrementThenFetch64(volatile Uint64 * ptr)
729 {
730 #ifdef nativeDecrementThenFetch64
731 return nativeDecrementThenFetch64(ptr);
732 #else
733 Uint64 tmp = 0;
734
735 privateWaitLock();
736 (*ptr)-= 1;
737 tmp = *ptr;
738 privateUnlock();
739
740 return tmp;
741 #endif
742 }
743
744 Uint64
745 SDL_AtomicAddThenFetch64(volatile Uint64 * ptr, Uint64 value)
746 {
747 #ifdef nativeAddThenFetch64
748 return nativeAddThenFetch64(ptr, value);
749 #else
750 Uint64 tmp = 0;
751
752 privateWaitLock();
753 (*ptr)+= value;
754 tmp = *ptr;
755 privateUnlock();
756
757 return tmp;
758 #endif
759 }
760
761 Uint64
762 SDL_AtomicSubtractThenFetch64(volatile Uint64 * ptr, Uint64 value)
763 {
764 #ifdef nativeSubtractThenFetch64
765 return nativeSubtractThenFetch64(ptr, value);
766 #else
767 Uint64 tmp = 0;
768
769 privateWaitLock();
770 (*ptr)-= value;
771 tmp = *ptr;
772 privateUnlock();
773
774 return tmp;
775 #endif
776 }
777 #endif
778
779 /* QNX native 32 bit atomic operations */
780
781 Uint32
782 SDL_AtomicExchange32(volatile Uint32 * ptr, Uint32 value)
783 {
784 Uint32 tmp = 0;
785
786 privateWaitLock();
787 tmp = *ptr;
788 *ptr = value;
789 privateUnlock();
790
791 return tmp;
792 }
793
794 SDL_bool
795 SDL_AtomicCompareThenSet32(volatile Uint32 * ptr, Uint32 oldvalue, Uint32 newvalue)
796 {
797 SDL_bool result = SDL_FALSE;
798
799 privateWaitLock();
800 result = (*ptr == oldvalue);
801 if (result)
802 {
803 *ptr = newvalue;
804 }
805 privateUnlock();
806
807 return result;
808 }
809
810 SDL_bool
811 SDL_AtomicTestThenSet32(volatile Uint32 * ptr)
812 {
813 SDL_bool result = SDL_FALSE;
814
815 privateWaitLock();
816 result = (*ptr == 0);
817 if (result)
818 {
819 *ptr = 1;
820 }
821 privateUnlock();
822
823 return result;
824 }
825
826 void
827 SDL_AtomicClear32(volatile Uint32 * ptr)
828 {
829 atomic_clr(ptr, 0xFFFFFFFF);
830 }
831
832 Uint32
833 SDL_AtomicFetchThenIncrement32(volatile Uint32 * ptr)
834 {
835 return atomic_add_value(ptr, 0x00000001);
836 }
837
838 Uint32
839 SDL_AtomicFetchThenDecrement32(volatile Uint32 * ptr)
840 {
841 return atomic_sub_value(ptr, 0x00000001);
842 }
843
844 Uint32
845 SDL_AtomicFetchThenAdd32(volatile Uint32 * ptr, Uint32 value)
846 {
847 return atomic_add_value(ptr, value);
848 }
849
850 Uint32
851 SDL_AtomicFetchThenSubtract32(volatile Uint32 * ptr, Uint32 value)
852 {
853 return atomic_sub_value(ptr, value);
854 }
855
856 Uint32
857 SDL_AtomicIncrementThenFetch32(volatile Uint32 * ptr)
858 {
859 atomic_add(ptr, 0x00000001);
860 return atomic_add_value(ptr, 0x00000000);
861 }
862
863 Uint32
864 SDL_AtomicDecrementThenFetch32(volatile Uint32 * ptr)
865 {
866 atomic_sub(ptr, 0x00000001);
867 return atomic_sub_value(ptr, 0x00000000);
868 }
869
870 Uint32
871 SDL_AtomicAddThenFetch32(volatile Uint32 * ptr, Uint32 value)
872 {
873 atomic_add(ptr, value);
874 return atomic_add_value(ptr, 0x00000000);
875 }
876
877 Uint32
878 SDL_AtomicSubtractThenFetch32(volatile Uint32 * ptr, Uint32 value)
879 {
880 atomic_sub(ptr, value);
881 return atomic_sub_value(ptr, 0x00000000);
882 }