Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

root/tags/releases/0.99.9/tango/core/Atomic.d

Revision 5275, 58.0 kB (checked in by larsivi, 2 years ago)

Change D_Ddoc to TangoDoc? to not interfere with user code generating docs, closes #1814, thanks torhu

  • Property svn:mime-type set to text/x-dsrc
  • Property svn:eol-style set to native
Line 
1 /**
2  * The atomic module is intended to provide some basic support for lock-free
3  * concurrent programming.  Some common operations are defined, each of which
4  * may be performed using the specified memory barrier or a less granular
5  * barrier if the hardware does not support the version requested.  This
6  * model is based on a design by Alexander Terekhov as outlined in
7  * <a href=http://groups.google.com/groups?threadm=3E4820EE.6F408B25%40web.de>
8  * this thread</a>.  Another useful reference for memory ordering on modern
9  * architectures is <a href=http://www.linuxjournal.com/article/8211>this
10  * article by Paul McKenney</a>.
11  *
12  * Copyright: Copyright (C) 2005-2006 Sean Kelly.  All rights reserved.
13  * License:   BSD style: $(LICENSE)
14  * Authors:   Sean Kelly
15  */
16 module tango.core.Atomic;
17
18
19 ////////////////////////////////////////////////////////////////////////////////
20 // Synchronization Options
21 ////////////////////////////////////////////////////////////////////////////////
22
23
24 /**
25  * Memory synchronization flag.  If the supplied option is not available on the
26  * current platform then a stronger method will be used instead.
27  */
28 enum msync
29 {
30     raw,    /// not sequenced
31     hlb,    /// hoist-load barrier
32     hsb,    /// hoist-store barrier
33     slb,    /// sink-load barrier
34     ssb,    /// sink-store barrier
35     acq,    /// hoist-load + hoist-store barrier
36     rel,    /// sink-load + sink-store barrier
37     seq,    /// fully sequenced (acq + rel)
38 }
39
40
41 ////////////////////////////////////////////////////////////////////////////////
42 // Internal Type Checking
43 ////////////////////////////////////////////////////////////////////////////////
44
45
46 private
47 {
48     version( TangoDoc ) {} else
49     {
50         import tango.core.Traits;
51
52
53         template isValidAtomicType( T )
54         {
55             const bool isValidAtomicType = T.sizeof == byte.sizeof  ||
56                                            T.sizeof == short.sizeof ||
57                                            T.sizeof == int.sizeof   ||
58                                            T.sizeof == long.sizeof;
59         }
60
61
62         template isValidNumericType( T )
63         {
64             const bool isValidNumericType = isIntegerType!( T ) ||
65                                             isPointerType!( T );
66         }
67
68
69         template isHoistOp( msync ms )
70         {
71             const bool isHoistOp = ms == msync.hlb ||
72                                    ms == msync.hsb ||
73                                    ms == msync.acq ||
74                                    ms == msync.seq;
75         }
76
77
78         template isSinkOp( msync ms )
79         {
80             const bool isSinkOp = ms == msync.slb ||
81                                   ms == msync.ssb ||
82                                   ms == msync.rel ||
83                                   ms == msync.seq;
84         }
85     }
86 }
87
88
89 ////////////////////////////////////////////////////////////////////////////////
90 // DDoc Documentation for Atomic Functions
91 ////////////////////////////////////////////////////////////////////////////////
92
93
94 version( TangoDoc )
95 {
96     ////////////////////////////////////////////////////////////////////////////
97     // Atomic Load
98     ////////////////////////////////////////////////////////////////////////////
99
100
101     /**
102      * Supported msync values:
103      *  msync.raw
104      *  msync.hlb
105      *  msync.acq
106      *  msync.seq
107      */
108     template atomicLoad( msync ms, T )
109     {
110         /**
111          * Refreshes the contents of 'val' from main memory.  This operation is
112          * both lock-free and atomic.
113          *
114          * Params:
115          *  val = The value to load.  This value must be properly aligned.
116          *
117          * Returns:
118          *  The loaded value.
119          */
120         T atomicLoad( ref T val )
121         {
122             return val;
123         }
124     }
125
126
127     ////////////////////////////////////////////////////////////////////////////
128     // Atomic Store
129     ////////////////////////////////////////////////////////////////////////////
130
131
132     /**
133      * Supported msync values:
134      *  msync.raw
135      *  msync.ssb
136      *  msync.acq
137      *  msync.rel
138      *  msync.seq
139      */
140     template atomicStore( msync ms, T )
141     {
142         /**
143          * Stores 'newval' to the memory referenced by 'val'.  This operation
144          * is both lock-free and atomic.
145          *
146          * Params:
147          *  val     = The destination variable.
148          *  newval  = The value to store.
149          */
150         void atomicStore( ref T val, T newval )
151         {
152
153         }
154     }
155
156
157     ////////////////////////////////////////////////////////////////////////////
158     // Atomic StoreIf
159     ////////////////////////////////////////////////////////////////////////////
160
161
162     /**
163      * Supported msync values:
164      *  msync.raw
165      *  msync.ssb
166      *  msync.acq
167      *  msync.rel
168      *  msync.seq
169      */
170     template atomicStoreIf( msync ms, T )
171     {
172         /**
173          * Stores 'newval' to the memory referenced by 'val' if val is equal to
174          * 'equalTo'.  This operation is both lock-free and atomic.
175          *
176          * Params:
177          *  val     = The destination variable.
178          *  newval  = The value to store.
179          *  equalTo = The comparison value.
180          *
181          * Returns:
182          *  true if the store occurred, false if not.
183          */
184         bool atomicStoreIf( ref T val, T newval, T equalTo )
185         {
186             return false;
187         }
188     }
189
190
191     ////////////////////////////////////////////////////////////////////////////
192     // Atomic Increment
193     ////////////////////////////////////////////////////////////////////////////
194
195
196     /**
197      * Supported msync values:
198      *  msync.raw
199      *  msync.ssb
200      *  msync.acq
201      *  msync.rel
202      *  msync.seq
203      */
204     template atomicIncrement( msync ms, T )
205     {
206         /**
207          * This operation is only legal for built-in value and pointer types,
208          * and is equivalent to an atomic "val = val + 1" operation.  This
209          * function exists to facilitate use of the optimized increment
210          * instructions provided by some architecures.  If no such instruction
211          * exists on the target platform then the behavior will perform the
212          * operation using more traditional means.  This operation is both
213          * lock-free and atomic.
214          *
215          * Params:
216          *  val = The value to increment.
217          *
218          * Returns:
219          *  The result of an atomicLoad of val immediately following the
220          *  increment operation.  This value is not required to be equal to the
221          *  newly stored value.  Thus, competing writes are allowed to occur
222          *  between the increment and successive load operation.
223          */
224         T atomicIncrement( ref T val )
225         {
226             return val;
227         }
228     }
229
230
231     ////////////////////////////////////////////////////////////////////////////
232     // Atomic Decrement
233     ////////////////////////////////////////////////////////////////////////////
234
235
236     /**
237      * Supported msync values:
238      *  msync.raw
239      *  msync.ssb
240      *  msync.acq
241      *  msync.rel
242      *  msync.seq
243      */
244     template atomicDecrement( msync ms, T )
245     {
246         /**
247          * This operation is only legal for built-in value and pointer types,
248          * and is equivalent to an atomic "val = val - 1" operation.  This
249          * function exists to facilitate use of the optimized decrement
250          * instructions provided by some architecures.  If no such instruction
251          * exists on the target platform then the behavior will perform the
252          * operation using more traditional means.  This operation is both
253          * lock-free and atomic.
254          *
255          * Params:
256          *  val = The value to decrement.
257          *
258          * Returns:
259          *  The result of an atomicLoad of val immediately following the
260          *  increment operation.  This value is not required to be equal to the
261          *  newly stored value.  Thus, competing writes are allowed to occur
262          *  between the increment and successive load operation.
263          */
264         T atomicDecrement( ref T val )
265         {
266             return val;
267         }
268     }
269 }
270
271
272 ////////////////////////////////////////////////////////////////////////////////
273 // LDC Atomics Implementation
274 ////////////////////////////////////////////////////////////////////////////////
275
276
277 else version( LDC )
278 {
279     import ldc.intrinsics;
280
281
282     ////////////////////////////////////////////////////////////////////////////
283     // Atomic Load
284     ////////////////////////////////////////////////////////////////////////////
285
286
287     template atomicLoad( msync ms = msync.seq, T )
288     {
289         T atomicLoad(ref T val)
290         {
291             llvm_memory_barrier(
292                 ms == msync.hlb || ms == msync.acq || ms == msync.seq,
293                 ms == msync.hsb || ms == msync.acq || ms == msync.seq,
294                 ms == msync.slb || ms == msync.rel || ms == msync.seq,
295                 ms == msync.ssb || ms == msync.rel || ms == msync.seq,
296                 false);
297             static if (isPointerType!(T))
298             {
299                 return cast(T)llvm_atomic_load_add!(size_t)(cast(size_t*)&val, 0);
300             }
301             else static if (is(T == bool))
302             {
303                 return llvm_atomic_load_add!(ubyte)(cast(ubyte*)&val, cast(ubyte)0) ? 1 : 0;
304             }
305             else
306             {
307                 return llvm_atomic_load_add!(T)(&val, cast(T)0);
308             }
309         }
310     }
311
312
313     ////////////////////////////////////////////////////////////////////////////
314     // Atomic Store
315     ////////////////////////////////////////////////////////////////////////////
316
317
318     template atomicStore( msync ms = msync.seq, T )
319     {
320         void atomicStore( ref T val, T newval )
321         {
322             llvm_memory_barrier(
323                 ms == msync.hlb || ms == msync.acq || ms == msync.seq,
324                 ms == msync.hsb || ms == msync.acq || ms == msync.seq,
325                 ms == msync.slb || ms == msync.rel || ms == msync.seq,
326                 ms == msync.ssb || ms == msync.rel || ms == msync.seq,
327                 false);
328             static if (isPointerType!(T))
329             {
330                 llvm_atomic_swap!(size_t)(cast(size_t*)&val, cast(size_t)newval);
331             }
332             else static if (is(T == bool))
333             {
334                 llvm_atomic_swap!(ubyte)(cast(ubyte*)&val, newval?1:0);
335             }
336             else
337             {
338                 llvm_atomic_swap!(T)(&val, newval);
339             }
340         }
341     }
342
343
344     ////////////////////////////////////////////////////////////////////////////
345     // Atomic Store If
346     ////////////////////////////////////////////////////////////////////////////
347
348
349     template atomicStoreIf( msync ms = msync.seq, T )
350     {
351         bool atomicStoreIf( ref T val, T newval, T equalTo )
352         {
353             llvm_memory_barrier(
354                 ms == msync.hlb || ms == msync.acq || ms == msync.seq,
355                 ms == msync.hsb || ms == msync.acq || ms == msync.seq,
356                 ms == msync.slb || ms == msync.rel || ms == msync.seq,
357                 ms == msync.ssb || ms == msync.rel || ms == msync.seq,
358                 false);
359             T oldval = void;
360             static if (isPointerType!(T))
361             {
362                 oldval = cast(T)llvm_atomic_cmp_swap!(size_t)(cast(size_t*)&val, cast(size_t)equalTo, cast(size_t)newval);
363             }
364             else static if (is(T == bool))
365             {
366                 oldval = llvm_atomic_cmp_swap!(ubyte)(cast(ubyte*)&val, equalTo?1:0, newval?1:0)?0:1;
367             }
368             else
369             {
370                 oldval = llvm_atomic_cmp_swap!(T)(&val, equalTo, newval);
371             }
372             return oldval == equalTo;
373         }
374     }
375    
376    
377     ////////////////////////////////////////////////////////////////////////////
378     // Atomic Increment
379     ////////////////////////////////////////////////////////////////////////////
380
381
382     template atomicIncrement( msync ms = msync.seq, T )
383     {
384         //
385         // NOTE: This operation is only valid for integer or pointer types
386         //
387         static assert( isValidNumericType!(T) );
388
389
390         T atomicIncrement( ref T val )
391         {
392             static if (isPointerType!(T))
393             {
394                 llvm_atomic_load_add!(size_t)(cast(size_t*)&val, 1);
395             }
396             else
397             {
398                 llvm_atomic_load_add!(T)(&val, cast(T)1);
399             }
400             return val;
401         }
402     }
403    
404    
405     ////////////////////////////////////////////////////////////////////////////
406     // Atomic Decrement
407     ////////////////////////////////////////////////////////////////////////////
408
409
410     template atomicDecrement( msync ms = msync.seq, T )
411     {
412         //
413         // NOTE: This operation is only valid for integer or pointer types
414         //
415         static assert( isValidNumericType!(T) );
416
417
418         T atomicDecrement( ref T val )
419         {
420             static if (isPointerType!(T))
421             {
422                 llvm_atomic_load_sub!(size_t)(cast(size_t*)&val, 1);
423             }
424             else
425             {
426                 llvm_atomic_load_sub!(T)(&val, cast(T)1);
427             }
428             return val;
429         }
430     }
431 }
432
433 ////////////////////////////////////////////////////////////////////////////////
434 // x86 Atomic Function Implementation
435 ////////////////////////////////////////////////////////////////////////////////
436
437
438 else version( D_InlineAsm_X86 )
439 {
440     version( X86 )
441     {
442         version( BuildInfo )
443         {
444             pragma( msg, "tango.core.Atomic: using IA-32 inline asm" );
445         }
446
447         version(darwin){
448             extern(C) bool OSAtomicCompareAndSwap64(long oldValue, long newValue, long *theValue);
449             extern(C) bool OSAtomicCompareAndSwap64Barrier(long oldValue, long newValue, long *theValue);
450         }
451         version = Has64BitCAS;
452         version = Has32BitOps;
453     }
454     version( X86_64 )
455     {
456         version( BuildInfo )
457         {
458             pragma( msg, "tango.core.Atomic: using AMD64 inline asm" );
459         }
460
461         version = Has64BitOps;
462     }
463
464     private
465     {
466         ////////////////////////////////////////////////////////////////////////
467         // x86 Value Requirements
468         ////////////////////////////////////////////////////////////////////////
469
470
471         // NOTE: Strictly speaking, the x86 supports atomic operations on
472         //       unaligned values.  However, this is far slower than the
473         //       common case, so such behavior should be prohibited.
474         template atomicValueIsProperlyAligned( T )
475         {
476             bool atomicValueIsProperlyAligned( size_t addr )
477             {
478                 return addr % T.sizeof == 0;
479             }
480         }
481
482
483         ////////////////////////////////////////////////////////////////////////
484         // x86 Synchronization Requirements
485         ////////////////////////////////////////////////////////////////////////
486
487
488         // NOTE: While x86 loads have acquire semantics for stores, it appears
489         //       that independent loads may be reordered by some processors
490         //       (notably the AMD64).  This implies that the hoist-load barrier
491         //       op requires an ordering instruction, which also extends this
492         //       requirement to acquire ops (though hoist-store should not need
493         //       one if support is added for this later).  However, since no
494         //       modern architectures will reorder dependent loads to occur
495         //       before the load they depend on (except the Alpha), raw loads
496         //       are actually a possible means of ordering specific sequences
497         //       of loads in some instances.  The original atomic<>
498         //       implementation provides a 'ddhlb' ordering specifier for
499         //       data-dependent loads to handle this situation, but as there
500         //       are no plans to support the Alpha there is no reason to add
501         //       that option here.
502         //
503         //       For reference, the old behavior (acquire semantics for loads)
504         //       required a memory barrier if: ms == msync.seq || isSinkOp!(ms)
505         template needsLoadBarrier( msync ms )
506         {
507             const bool needsLoadBarrier = ms != msync.raw;
508         }
509
510
511         // NOTE: x86 stores implicitly have release semantics so a membar is only
512         //       necessary on acquires.
513         template needsStoreBarrier( msync ms )
514         {
515             const bool needsStoreBarrier = ms == msync.seq || isHoistOp!(ms);
516         }
517     }
518
519
520     ////////////////////////////////////////////////////////////////////////////
521     // Atomic Load
522     ////////////////////////////////////////////////////////////////////////////
523
524
525     template atomicLoad( msync ms = msync.seq, T )
526     {
527         T atomicLoad( ref T val )
528         in
529         {
530             assert( atomicValueIsProperlyAligned!(T)( cast(size_t) &val ) );
531         }
532         body
533         {
534             static if( T.sizeof == byte.sizeof )
535             {
536                 ////////////////////////////////////////////////////////////////
537                 // 1 Byte Load
538                 ////////////////////////////////////////////////////////////////
539
540
541                 static if( needsLoadBarrier!(ms) )
542                 {
543                     volatile asm
544                     {
545                         mov DL, 42;
546                         mov AL, 42;
547                         mov ECX, val;
548                         lock;
549                         cmpxchg [ECX], DL;
550                     }
551                 }
552                 else
553                 {
554                     volatile
555                     {
556                         return val;
557                     }
558                 }
559             }
560             else static if( T.sizeof == short.sizeof )
561             {
562                 ////////////////////////////////////////////////////////////////
563                 // 2 Byte Load
564                 ////////////////////////////////////////////////////////////////
565
566                 static if( needsLoadBarrier!(ms) )
567                 {
568                     volatile asm
569                     {
570                         mov DX, 42;
571                         mov AX, 42;
572                         mov ECX, val;
573                         lock;
574                         cmpxchg [ECX], DX;
575                     }
576                 }
577                 else
578                 {
579                     volatile
580                     {
581                         return val;
582                     }
583                 }
584             }
585             else static if( T.sizeof == int.sizeof )
586             {
587                 ////////////////////////////////////////////////////////////////
588                 // 4 Byte Load
589                 ////////////////////////////////////////////////////////////////
590
591
592                 static if( needsLoadBarrier!(ms) )
593                 {
594                     volatile asm
595                     {
596                         mov EDX, 42;
597                         mov EAX, 42;
598                         mov ECX, val;
599                         lock;
600                         cmpxchg [ECX], EDX;
601                     }
602                 }
603                 else
604                 {
605                     volatile
606                     {
607                         return val;
608                     }
609                 }
610             }
611             else static if( T.sizeof == long.sizeof )
612             {
613                 ////////////////////////////////////////////////////////////////
614                 // 8 Byte Load
615                 ////////////////////////////////////////////////////////////////
616
617
618                 version( Has64BitOps )
619                 {
620                     ////////////////////////////////////////////////////////////
621                     // 8 Byte Load on 64-Bit Processor
622                     ////////////////////////////////////////////////////////////
623
624
625                     static if( needsLoadBarrier!(ms) )
626                     {
627                         volatile asm
628                         {
629                             mov RAX, val;
630                             lock;
631                             mov RAX, [RAX];
632                         }
633                     }
634                     else
635                     {
636                         volatile
637                         {
638                             return val;
639                         }
640                     }
641                 }
642                 else
643                 {
644                     ////////////////////////////////////////////////////////////
645                     // 8 Byte Load on 32-Bit Processor
646                     ////////////////////////////////////////////////////////////
647
648
649                     pragma( msg, "This operation is only available on 64-bit platforms." );
650                     static assert( false );
651                 }
652             }
653             else
654             {
655                 ////////////////////////////////////////////////////////////////
656                 // Not a 1, 2, 4, or 8 Byte Type
657                 ////////////////////////////////////////////////////////////////
658
659
660                 pragma( msg, "Invalid template type specified." );
661                 static assert( false );
662             }
663         }
664     }
665
666
667     ////////////////////////////////////////////////////////////////////////////
668     // Atomic Store
669     ////////////////////////////////////////////////////////////////////////////
670
671
672     template atomicStore( msync ms = msync.seq, T )
673     {
674         void atomicStore( ref T val, T newval )
675         in
676         {
677             assert( atomicValueIsProperlyAligned!(T)( cast(size_t) &val ) );
678         }
679         body
680         {
681             static if( T.sizeof == byte.sizeof )
682             {
683                 ////////////////////////////////////////////////////////////////
684                 // 1 Byte Store
685                 ////////////////////////////////////////////////////////////////
686
687
688                 static if( needsStoreBarrier!(ms) )
689                 {
690                     volatile asm
691                     {
692                         mov EAX, val;
693                         mov DL, newval;
694                         lock;
695                         xchg [EAX], DL;
696                     }
697                 }
698                 else
699                 {
700                     volatile asm
701                     {
702                         mov EAX, val;
703                         mov DL, newval;
704                         mov [EAX], DL;
705                     }
706                 }
707             }
708             else static if( T.sizeof == short.sizeof )
709             {
710                 ////////////////////////////////////////////////////////////////
711                 // 2 Byte Store
712                 ////////////////////////////////////////////////////////////////
713
714
715                 static if( needsStoreBarrier!(ms) )
716                 {
717                     volatile asm
718                     {
719                         mov EAX, val;
720                         mov DX, newval;
721                         lock;
722                         xchg [EAX], DX;
723                     }
724                 }
725                 else
726                 {
727                     volatile asm
728                     {
729                         mov EAX, val;
730                         mov DX, newval;
731                         mov [EAX], DX;
732                     }
733                 }
734             }
735             else static if( T.sizeof == int.sizeof )
736             {
737                 ////////////////////////////////////////////////////////////////
738                 // 4 Byte Store
739                 ////////////////////////////////////////////////////////////////
740
741
742                 static if( needsStoreBarrier!(ms) )
743                 {
744                     volatile asm
745                     {
746                         mov EAX, val;
747                         mov EDX, newval;
748                         lock;
749                         xchg [EAX], EDX;
750                     }
751                 }
752                 else
753                 {
754                     volatile asm
755                     {
756                         mov EAX, val;
757                         mov EDX, newval;
758                         mov [EAX], EDX;
759                     }
760                 }
761             }
762             else static if( T.sizeof == long.sizeof )
763             {
764                 ////////////////////////////////////////////////////////////////
765                 // 8 Byte Store
766                 ////////////////////////////////////////////////////////////////
767
768
769                 version( Has64BitOps )
770                 {
771                     ////////////////////////////////////////////////////////////
772                     // 8 Byte Store on 64-Bit Processor
773                     ////////////////////////////////////////////////////////////
774
775
776                     static if( needsStoreBarrier!(ms) )
777                     {
778                         volatile asm
779                         {
780                             mov RAX, val;
781                             mov RDX, newval;
782                             lock;
783                             xchg [RAX], RDX;
784                         }
785                     }
786                     else
787                     {
788                         volatile asm
789                         {
790                             mov RAX, val;
791                             mov RDX, newval;
792                             mov [RAX], RDX;
793                         }
794                     }
795                 }
796                 else
797                 {
798                     ////////////////////////////////////////////////////////////
799                     // 8 Byte Store on 32-Bit Processor
800                     ////////////////////////////////////////////////////////////
801
802
803                     pragma( msg, "This operation is only available on 64-bit platforms." );
804                     static assert( false );
805                 }
806             }
807             else
808             {
809                 ////////////////////////////////////////////////////////////////
810                 // Not a 1, 2, 4, or 8 Byte Type
811                 ////////////////////////////////////////////////////////////////
812
813
814                 pragma( msg, "Invalid template type specified." );
815                 static assert( false );
816             }
817         }
818     }
819
820
821     ////////////////////////////////////////////////////////////////////////////
822     // Atomic Store If
823     ////////////////////////////////////////////////////////////////////////////
824
825
826     template atomicStoreIf( msync ms = msync.seq, T )
827     {
828         bool atomicStoreIf( ref T val, T newval, T equalTo )
829         in
830         {
831             // NOTE: 32 bit x86 systems support 8 byte CAS, which only requires
832             //       4 byte alignment, so use size_t as the align type here.
833             static if( T.sizeof > size_t.sizeof )
834                 assert( atomicValueIsProperlyAligned!(size_t)( cast(size_t) &val ) );
835             else
836                 assert( atomicValueIsProperlyAligned!(T)( cast(size_t) &val ) );
837         }
838         body
839         {
840             static if( T.sizeof == byte.sizeof )
841             {
842                 ////////////////////////////////////////////////////////////////
843                 // 1 Byte StoreIf
844                 ////////////////////////////////////////////////////////////////
845
846
847                 volatile asm
848                 {
849                     mov DL, newval;
850                     mov AL, equalTo;
851                     mov ECX, val;
852                     lock; // lock always needed to make this op atomic
853                     cmpxchg [ECX], DL;
854                     setz AL;
855                 }
856             }
857             else static if( T.sizeof == short.sizeof )
858             {
859                 ////////////////////////////////////////////////////////////////
860                 // 2 Byte StoreIf
861                 ////////////////////////////////////////////////////////////////
862
863
864                 volatile asm
865                 {
866                     mov DX, newval;
867                     mov AX, equalTo;
868                     mov ECX, val;
869                     lock; // lock always needed to make this op atomic
870                     cmpxchg [ECX], DX;
871                     setz AL;
872                 }
873             }
874             else static if( T.sizeof == int.sizeof )
875             {
876                 ////////////////////////////////////////////////////////////////
877                 // 4 Byte StoreIf
878                 ////////////////////////////////////////////////////////////////
879
880
881                 volatile asm
882                 {
883                     mov EDX, newval;
884                     mov EAX, equalTo;
885                     mov ECX, val;
886                     lock; // lock always needed to make this op atomic
887                     cmpxchg [ECX], EDX;
888                     setz AL;
889                 }
890             }
891             else static if( T.sizeof == long.sizeof )
892             {
893                 ////////////////////////////////////////////////////////////////
894                 // 8 Byte StoreIf
895                 ////////////////////////////////////////////////////////////////
896
897
898                 version( Has64BitOps )
899                 {
900                     ////////////////////////////////////////////////////////////
901                     // 8 Byte StoreIf on 64-Bit Processor
902                     ////////////////////////////////////////////////////////////
903
904
905                     volatile asm
906                     {
907                         mov RDX, newval;
908                         mov RAX, equalTo;
909                         mov RCX, val;
910                         lock; // lock always needed to make this op atomic
911                         cmpxchg [RCX], RDX;
912                         setz AL;
913                     }
914                 }
915                 else version( Has64BitCAS )
916                 {
917                     ////////////////////////////////////////////////////////////
918                     // 8 Byte StoreIf on 32-Bit Processor
919                     ////////////////////////////////////////////////////////////
920                     version(darwin){
921                         static if(ms==msync.raw){
922                             return OSAtomicCompareAndSwap64(cast(long)equalTo, cast(long)newval,  cast(long*)&val);
923                         } else {
924                             return OSAtomicCompareAndSwap64Barrier(cast(long)equalTo, cast(long)newval,  cast(long*)&val);
925                         }
926                     } else {
927                         volatile asm
928                         {
929                             push EDI;
930                             push EBX;
931                             lea EDI, newval;
932                             mov EBX, [EDI];
933                             mov ECX, 4[EDI];
934                             lea EDI, equalTo;
935                             mov EAX, [EDI];
936                             mov EDX, 4[EDI];
937                             mov EDI, val;
938                             lock; // lock always needed to make this op atomic
939                             cmpxch8b [EDI];
940                             setz AL;
941                             pop EBX;
942                             pop EDI;
943                         }
944                     }
945                 }
946             }
947             else
948             {
949                 ////////////////////////////////////////////////////////////////
950                 // Not a 1, 2, 4, or 8 Byte Type
951                 ////////////////////////////////////////////////////////////////
952
953
954                 pragma( msg, "Invalid template type specified." );
955                 static assert( false );
956             }
957         }
958     }
959
960
961     ////////////////////////////////////////////////////////////////////////////
962     // Atomic Increment
963     ////////////////////////////////////////////////////////////////////////////
964
965
966     template atomicIncrement( msync ms = msync.seq, T )
967     {
968         //
969         // NOTE: This operation is only valid for integer or pointer types
970         //
971         static assert( isValidNumericType!(T) );
972
973
974         T atomicIncrement( ref T val )
975         in
976         {
977             assert( atomicValueIsProperlyAligned!(T)( cast(size_t) &val ) );
978         }
979         body
980         {
981             static if( T.sizeof == byte.sizeof )
982             {
983                 ////////////////////////////////////////////////////////////////
984                 // 1 Byte Increment
985                 ////////////////////////////////////////////////////////////////
986
987
988                 volatile asm
989                 {
990                     mov EAX, val;
991                     lock; // lock always needed to make this op atomic
992                     inc [EAX];
993                     mov AL, [EAX];
994                 }
995             }
996             else static if( T.sizeof == short.sizeof )
997             {
998                 ////////////////////////////////////////////////////////////////
999                 // 2 Byte Increment
1000                 ////////////////////////////////////////////////////////////////
1001
1002
1003                 volatile asm
1004                 {
1005                     mov EAX, val;
1006                     lock; // lock always needed to make this op atomic
1007                     inc short ptr [EAX];
1008                     mov AX, [EAX];
1009                 }
1010             }
1011             else static if( T.sizeof == int.sizeof )
1012             {
1013                 ////////////////////////////////////////////////////////////////
1014                 // 4 Byte Increment
1015                 ////////////////////////////////////////////////////////////////
1016
1017
1018                 volatile asm
1019                 {
1020                     mov EAX, val;
1021                     lock; // lock always needed to make this op atomic
1022                     inc int ptr [EAX];
1023                     mov EAX, [EAX];
1024                 }
1025             }
1026             else static if( T.sizeof == long.sizeof )
1027             {
1028                 ////////////////////////////////////////////////////////////////
1029                 // 8 Byte Increment
1030                 ////////////////////////////////////////////////////////////////
1031
1032
1033                 version( Has64BitOps )
1034                 {
1035                     ////////////////////////////////////////////////////////////
1036                     // 8 Byte Increment on 64-Bit Processor
1037                     ////////////////////////////////////////////////////////////
1038
1039
1040                     volatile asm
1041                     {
1042                         mov RAX, val;
1043                         lock; // lock always needed to make this op atomic
1044                         inc qword ptr [RAX];
1045                         mov RAX, [RAX];
1046                     }
1047                 }
1048                 else
1049                 {
1050                     ////////////////////////////////////////////////////////////
1051                     // 8 Byte Increment on 32-Bit Processor
1052                     ////////////////////////////////////////////////////////////
1053
1054
1055                     pragma( msg, "This operation is only available on 64-bit platforms." );
1056                     static assert( false );
1057                 }
1058             }
1059             else
1060             {
1061                 ////////////////////////////////////////////////////////////////
1062                 // Not a 1, 2, 4, or 8 Byte Type
1063                 ////////////////////////////////////////////////////////////////
1064
1065
1066                 pragma( msg, "Invalid template type specified." );
1067                 static assert( false );
1068             }
1069         }
1070     }
1071
1072
1073     ////////////////////////////////////////////////////////////////////////////
1074     // Atomic Decrement
1075     ////////////////////////////////////////////////////////////////////////////
1076
1077
1078     template atomicDecrement( msync ms = msync.seq, T )
1079     {
1080         //
1081         // NOTE: This operation is only valid for integer or pointer types
1082         //
1083         static assert( isValidNumericType!(T) );
1084
1085
1086         T atomicDecrement( ref T val )
1087         in
1088         {
1089             assert( atomicValueIsProperlyAligned!(T)( cast(size_t) &val ) );
1090         }
1091         body
1092         {
1093             static if( T.sizeof == byte.sizeof )
1094             {
1095                 ////////////////////////////////////////////////////////////////
1096                 // 1 Byte Decrement
1097                 ////////////////////////////////////////////////////////////////
1098
1099
1100                 volatile asm
1101                 {
1102                     mov EAX, val;
1103                     lock; // lock always needed to make this op atomic
1104                     dec [EAX];
1105                     mov AL, [EAX];
1106                 }
1107             }
1108             else static if( T.sizeof == short.sizeof )
1109             {
1110                 ////////////////////////////////////////////////////////////////
1111                 // 2 Byte Decrement
1112                 ////////////////////////////////////////////////////////////////
1113
1114
1115                 volatile asm
1116                 {
1117                     mov EAX, val;
1118                     lock; // lock always needed to make this op atomic
1119                     dec short ptr [EAX];
1120                     mov AX, [EAX];
1121                 }
1122             }
1123             else static if( T.sizeof == int.sizeof )
1124             {
1125                 ////////////////////////////////////////////////////////////////
1126                 // 4 Byte Decrement
1127                 ////////////////////////////////////////////////////////////////
1128
1129
1130                 volatile asm
1131                 {
1132                     mov EAX, val;
1133                     lock; // lock always needed to make this op atomic
1134                     dec int ptr [EAX];
1135                     mov EAX, [EAX];
1136                 }
1137             }
1138             else static if( T.sizeof == long.sizeof )
1139             {
1140                 ////////////////////////////////////////////////////////////////
1141                 // 8 Byte Decrement
1142                 ////////////////////////////////////////////////////////////////
1143
1144
1145                 version( Has64BitOps )
1146                 {
1147                     ////////////////////////////////////////////////////////////
1148                     // 8 Byte Decrement on 64-Bit Processor
1149                     ////////////////////////////////////////////////////////////
1150
1151
1152                     volatile asm
1153                     {
1154                         mov RAX, val;
1155                         lock; // lock always needed to make this op atomic
1156                         dec qword ptr [RAX];
1157                         mov RAX, [RAX];
1158                     }
1159                 }
1160                 else
1161                 {
1162                     ////////////////////////////////////////////////////////////
1163                     // 8 Byte Decrement on 32-Bit Processor
1164                     ////////////////////////////////////////////////////////////
1165
1166
1167                     pragma( msg, "This operation is only available on 64-bit platforms." );
1168                     static assert( false );
1169                 }
1170             }
1171             else
1172             {
1173                 ////////////////////////////////////////////////////////////////
1174                 // Not a 1, 2, 4, or 8 Byte Type
1175                 ////////////////////////////////////////////////////////////////
1176
1177
1178                 pragma( msg, "Invalid template type specified." );
1179                 static assert( false );
1180             }
1181         }
1182     }
1183 }
1184 else
1185 {
1186     version( BuildInfo )
1187     {
1188         pragma( msg, "tango.core.Atomic: using synchronized ops" );
1189     }
1190
1191     private
1192     {
1193         ////////////////////////////////////////////////////////////////////////
1194         // Default Value Requirements
1195         ////////////////////////////////////////////////////////////////////////
1196
1197
1198         template atomicValueIsProperlyAligned( T )
1199         {
1200             bool atomicValueIsProperlyAligned( size_t addr )
1201             {
1202                 return addr % T.sizeof == 0;
1203             }
1204         }
1205
1206
1207         ////////////////////////////////////////////////////////////////////////
1208         // Default Synchronization Requirements
1209         ////////////////////////////////////////////////////////////////////////
1210
1211
1212         template needsLoadBarrier( msync ms )
1213         {
1214             const bool needsLoadBarrier = ms != msync.raw;
1215         }
1216
1217
1218         template needsStoreBarrier( msync ms )
1219         {
1220             const bool needsStoreBarrier = ms != msync.raw;
1221         }
1222     }
1223
1224
1225     ////////////////////////////////////////////////////////////////////////////
1226     // Atomic Load
1227     ////////////////////////////////////////////////////////////////////////////
1228
1229
1230     template atomicLoad( msync ms = msync.seq, T )
1231     {
1232         T atomicLoad( ref T val )
1233         in
1234         {
1235             assert( atomicValueIsProperlyAligned!(T)( cast(size_t) &val ) );
1236         }
1237         body
1238         {
1239             static if( T.sizeof <= (void*).sizeof )
1240             {
1241                 ////////////////////////////////////////////////////////////////
1242                 // <= (void*).sizeof Byte Load
1243                 ////////////////////////////////////////////////////////////////
1244
1245
1246                 static if( needsLoadBarrier!(ms) )
1247                 {
1248                     synchronized
1249                     {
1250                         return val;
1251                     }
1252                 }
1253                 else
1254                 {
1255                     volatile
1256                     {
1257                         return val;
1258                     }
1259                 }
1260             }
1261             else
1262             {
1263                 ////////////////////////////////////////////////////////////////
1264                 // > (void*).sizeof Byte Type
1265                 ////////////////////////////////////////////////////////////////
1266
1267
1268                 pragma( msg, "Invalid template type specified." );
1269                 static assert( false );
1270             }
1271         }
1272     }
1273
1274
1275     ////////////////////////////////////////////////////////////////////////////
1276     // Atomic Store
1277     ////////////////////////////////////////////////////////////////////////////
1278
1279
1280     template atomicStore( msync ms = msync.seq, T )
1281     {
1282         void atomicStore( ref T val, T newval )
1283         in
1284         {
1285             assert( atomicValueIsProperlyAligned!(T)( cast(size_t) &val ) );
1286         }
1287         body
1288         {
1289             static if( T.sizeof <= (void*).sizeof )
1290             {
1291                 ////////////////////////////////////////////////////////////////
1292                 // <= (void*).sizeof Byte Store
1293                 ////////////////////////////////////////////////////////////////
1294
1295
1296                 static if( needsStoreBarrier!(ms) )
1297                 {
1298                     synchronized
1299                     {
1300                         val = newval;
1301                     }
1302                 }
1303                 else
1304                 {
1305                     volatile
1306                     {
1307                         val = newval;
1308                     }
1309                 }
1310             }
1311             else
1312             {
1313                 ////////////////////////////////////////////////////////////////
1314                 // > (void*).sizeof Byte Type
1315                 ////////////////////////////////////////////////////////////////
1316
1317
1318                 pragma( msg, "Invalid template type specified." );
1319                 static assert( false );
1320             }
1321         }
1322     }
1323
1324
1325     ////////////////////////////////////////////////////////////////////////////
1326     // Atomic Store If
1327     ////////////////////////////////////////////////////////////////////////////
1328
1329
1330     template atomicStoreIf( msync ms = msync.seq, T )
1331     {
1332         bool atomicStoreIf( ref T val, T newval, T equalTo )
1333         in
1334         {
1335             assert( atomicValueIsProperlyAligned!(T)( cast(size_t) &val ) );
1336         }
1337         body
1338         {
1339             static if( T.sizeof <= (void*).sizeof )
1340             {
1341                 ////////////////////////////////////////////////////////////////
1342                 // <= (void*).sizeof Byte StoreIf
1343                 ////////////////////////////////////////////////////////////////
1344
1345
1346                 synchronized
1347                 {
1348                     if( val == equalTo )
1349                     {
1350                         val = newval;
1351                         return true;
1352                     }
1353                     return false;
1354                 }
1355             }
1356             else
1357             {
1358                 ////////////////////////////////////////////////////////////////
1359                 // > (void*).sizeof Byte Type
1360                 ////////////////////////////////////////////////////////////////
1361
1362
1363                 pragma( msg, "Invalid template type specified." );
1364                 static assert( false );
1365             }
1366         }
1367     }
1368
1369
1370     /////////////////////////////////////////////////////////////////////////////
1371     // Atomic Increment
1372     ////////////////////////////////////////////////////////////////////////////
1373
1374
1375     template atomicIncrement( msync ms = msync.seq, T )
1376     {
1377         //
1378         // NOTE: This operation is only valid for integer or pointer types
1379         //
1380         static assert( isValidNumericType!(T) );
1381
1382
1383         T atomicIncrement( ref T val )
1384         in
1385         {
1386             assert( atomicValueIsProperlyAligned!(T)( cast(size_t) &val ) );
1387         }
1388         body
1389         {
1390             static if( T.sizeof <= (void*).sizeof )
1391             {
1392                 ////////////////////////////////////////////////////////////////
1393                 // <= (void*).sizeof Byte Increment
1394                 ////////////////////////////////////////////////////////////////
1395
1396
1397                 synchronized
1398                 {
1399                     return ++val;
1400                 }
1401             }
1402             else
1403             {
1404                 ////////////////////////////////////////////////////////////////
1405                 // > (void*).sizeof Byte Type
1406                 ////////////////////////////////////////////////////////////////
1407
1408
1409                 pragma( msg, "Invalid template type specified." );
1410                 static assert( false );
1411             }
1412         }
1413     }
1414
1415
1416     ////////////////////////////////////////////////////////////////////////////
1417     // Atomic Decrement
1418     ////////////////////////////////////////////////////////////////////////////
1419
1420
1421     template atomicDecrement( msync ms = msync.seq, T )
1422     {
1423         //
1424         // NOTE: This operation is only valid for integer or pointer types
1425         //
1426         static assert( isValidNumericType!(T) );
1427
1428
1429         T atomicDecrement( ref T val )
1430         in
1431         {
1432             assert( atomicValueIsProperlyAligned!(T)( cast(size_t) &val ) );
1433         }
1434         body
1435         {
1436             static if( T.sizeof <= (void*).sizeof )
1437             {
1438                 ////////////////////////////////////////////////////////////////
1439                 // <= (void*).sizeof Byte Decrement
1440                 ////////////////////////////////////////////////////////////////
1441
1442
1443                 synchronized
1444                 {
1445                     return --val;
1446                 }
1447             }
1448             else
1449             {
1450                 ////////////////////////////////////////////////////////////////
1451                 // > (void*).sizeof Byte Type
1452                 ////////////////////////////////////////////////////////////////
1453
1454
1455                 pragma( msg, "Invalid template type specified." );
1456                 static assert( false );
1457             }
1458         }
1459     }
1460 }
1461
1462
1463 ////////////////////////////////////////////////////////////////////////////////
1464 // Atomic
1465 ////////////////////////////////////////////////////////////////////////////////
1466
1467
1468 /**
1469  * This struct represents a value which will be subject to competing access.
1470  * All accesses to this value will be synchronized with main memory, and
1471  * various memory barriers may be employed for instruction ordering.  Any
1472  * primitive type of size equal to or smaller than the memory bus size is
1473  * allowed, so 32-bit machines may use values with size <= int.sizeof and
1474  * 64-bit machines may use values with size <= long.sizeof.  The one exception
1475  * to this rule is that architectures that support DCAS will allow double-wide
1476  * storeIf operations.  The 32-bit x86 architecture, for example, supports
1477  * 64-bit storeIf operations.
1478  */
1479 struct Atomic( T )
1480 {
1481     ////////////////////////////////////////////////////////////////////////////
1482     // Atomic Load
1483     ////////////////////////////////////////////////////////////////////////////
1484
1485
1486     template load( msync ms = msync.seq )
1487     {
1488         static assert( ms == msync.raw || ms == msync.hlb ||
1489                        ms == msync.acq || ms == msync.seq,
1490                        "ms must be one of: msync.raw, msync.hlb, msync.acq, msync.seq" );
1491
1492         /**
1493          * Refreshes the contents of this value from main memory.  This
1494          * operation is both lock-free and atomic.
1495          *
1496          * Returns:
1497          *  The loaded value.
1498          */
1499         T load()
1500         {
1501             return atomicLoad!(ms,T)( m_val );
1502         }
1503     }
1504
1505
1506     ////////////////////////////////////////////////////////////////////////////
1507     // Atomic Store
1508     ////////////////////////////////////////////////////////////////////////////
1509
1510
1511     template store( msync ms = msync.seq )
1512     {
1513         static assert( ms == msync.raw || ms == msync.ssb ||
1514                        ms == msync.acq || ms == msync.rel ||
1515                        ms == msync.seq,
1516                        "ms must be one of: msync.raw, msync.ssb, msync.acq, msync.rel, msync.seq" );
1517
1518         /**
1519          * Stores 'newval' to the memory referenced by this value.  This
1520          * operation is both lock-free and atomic.
1521          *
1522          * Params:
1523          *  newval  = The value to store.
1524          */
1525         void store( T newval )
1526         {
1527             atomicStore!(ms,T)( m_val, newval );
1528         }
1529     }
1530
1531
1532     ////////////////////////////////////////////////////////////////////////////
1533     // Atomic StoreIf
1534     ////////////////////////////////////////////////////////////////////////////
1535
1536
1537     template storeIf( msync ms = msync.seq )
1538     {
1539         static assert( ms == msync.raw || ms == msync.ssb ||
1540                        ms == msync.acq || ms == msync.rel ||
1541                        ms == msync.seq,
1542                        "ms must be one of: msync.raw, msync.ssb, msync.acq, msync.rel, msync.seq" );
1543
1544         /**
1545          * Stores 'newval' to the memory referenced by this value if val is
1546          * equal to 'equalTo'.  This operation is both lock-free and atomic.
1547          *
1548          * Params:
1549          *  newval  = The value to store.
1550          *  equalTo = The comparison value.
1551          *
1552          * Returns:
1553          *  true if the store occurred, false if not.
1554          */
1555         bool storeIf( T newval, T equalTo )
1556         {
1557             return atomicStoreIf!(ms,T)( m_val, newval, equalTo );
1558         }
1559     }
1560
1561
1562     ////////////////////////////////////////////////////////////////////////////
1563     // Numeric Functions
1564     ////////////////////////////////////////////////////////////////////////////
1565
1566     version( TangoDoc )
1567     {
1568         /**
1569          * The following additional functions are available for integer types.
1570          */
1571         ////////////////////////////////////////////////////////////////////////
1572         // Atomic Increment
1573         ////////////////////////////////////////////////////////////////////////
1574
1575
1576         template increment( msync ms = msync.seq )
1577         {
1578             /**
1579              * This operation is only legal for built-in value and pointer
1580              * types, and is equivalent to an atomic "val = val + 1" operation.
1581              * This function exists to facilitate use of the optimized
1582              * increment instructions provided by some architecures.  If no
1583              * such instruction exists on the target platform then the
1584              * behavior will perform the operation using more traditional
1585              * means.  This operation is both lock-free and atomic.
1586              *
1587              * Returns:
1588              *  The result of an atomicLoad of val immediately following the
1589              *  increment operation.  This value is not required to be equal to
1590              *  the newly stored value.  Thus, competing writes are allowed to
1591              *  occur between the increment and successive load operation.
1592              */
1593             T increment()
1594             {
1595                 return m_val;
1596             }
1597         }
1598
1599
1600         ////////////////////////////////////////////////////////////////////////
1601         // Atomic Decrement
1602         ////////////////////////////////////////////////////////////////////////
1603
1604
1605         template decrement( msync ms = msync.seq )
1606         {
1607             /**
1608              * This operation is only legal for built-in value and pointer
1609              * types, and is equivalent to an atomic "val = val - 1" operation.
1610              * This function exists to facilitate use of the optimized
1611              * decrement instructions provided by some architecures.  If no
1612              * such instruction exists on the target platform then the behavior
1613              * will perform the operation using more traditional means.  This
1614              * operation is both lock-free and atomic.
1615              *
1616              * Returns:
1617              *  The result of an atomicLoad of val immediately following the
1618              *  increment operation.  This value is not required to be equal to
1619              *  the newly stored value.  Thus, competing writes are allowed to
1620              *  occur between the increment and successive load operation.
1621              */
1622             T decrement()
1623             {
1624                 return m_val;
1625             }
1626         }
1627     }
1628     else
1629     {
1630         static if( isValidNumericType!(T) )
1631         {
1632             ////////////////////////////////////////////////////////////////////////
1633             // Atomic Increment
1634             ////////////////////////////////////////////////////////////////////////
1635
1636
1637             template increment( msync ms = msync.seq )
1638             {
1639                 static assert( ms == msync.raw || ms == msync.ssb ||
1640                                ms == msync.acq || ms == msync.rel ||
1641                                ms == msync.seq,
1642                                "ms must be one of: msync.raw, msync.ssb, msync.acq, msync.rel, msync.seq" );
1643                 T increment()
1644                 {
1645                     return atomicIncrement!(ms,T)( m_val );
1646                 }
1647             }
1648
1649
1650             ////////////////////////////////////////////////////////////////////////
1651             // Atomic Decrement
1652             ////////////////////////////////////////////////////////////////////////
1653
1654
1655             template decrement( msync ms = msync.seq )
1656             {
1657                 static assert( ms == msync.raw || ms == msync.ssb ||
1658                                ms == msync.acq || ms == msync.rel ||
1659                                ms == msync.seq,
1660                                "ms must be one of: msync.raw, msync.ssb, msync.acq, msync.rel, msync.seq" );
1661                 T decrement()
1662                 {
1663                     return atomicDecrement!(ms,T)( m_val );
1664                 }
1665             }
1666         }
1667     }
1668
1669 private:
1670     T   m_val;
1671 }
1672
1673
1674 ////////////////////////////////////////////////////////////////////////////////
1675 // Support Code for Unit Tests
1676 ////////////////////////////////////////////////////////////////////////////////
1677
1678
1679 private
1680 {
1681     version( TangoDoc ) {} else
1682     {
1683         template testLoad( msync ms, T )
1684         {
1685             void testLoad( T val = T.init + 1)
1686             {
1687                 T          base;
1688                 Atomic!(T) atom;
1689
1690                 assert( atom.load!(ms)() == base );
1691                 base        = val;
1692                 atom.m_val  = val;
1693                 assert( atom.load!(ms)() == base );
1694             }
1695         }
1696
1697
1698         template testStore( msync ms, T )
1699         {
1700             void testStore( T val = T.init + 1)
1701             {
1702                 T          base;
1703                 Atomic!(T) atom;
1704
1705                 assert( atom.m_val == base );
1706                 base = val;
1707                 atom.store!(ms)( base );
1708                 assert( atom.m_val == base );
1709             }
1710         }
1711
1712
1713         template testStoreIf( msync ms, T )
1714         {
1715             void testStoreIf( T val = T.init + 1)
1716             {
1717                 T          base;
1718                 Atomic!(T) atom;
1719
1720                 assert( atom.m_val == base );
1721                 base = val;
1722                 atom.storeIf!(ms)( base, val );
1723                 assert( atom.m_val != base );
1724                 atom.storeIf!(ms)( base, T.init );
1725                 assert( atom.m_val == base );
1726             }
1727         }
1728
1729
1730         template testIncrement( msync ms, T )
1731         {
1732             void testIncrement( T val = T.init + 1)
1733             {
1734                 T          base = val;
1735                 T          incr = val;
1736                 Atomic!(T) atom;
1737
1738                 atom.m_val = val;
1739                 assert( atom.m_val == base && incr == base );
1740                 base = cast(T)( base + 1 );
1741                 incr = atom.increment!(ms)();
1742                 assert( atom.m_val == base && incr == base );
1743             }
1744         }
1745
1746
1747         template testDecrement( msync ms, T )
1748         {
1749             void testDecrement( T val = T.init + 1)
1750             {
1751                 T          base = val;
1752                 T          decr = val;
1753                 Atomic!(T) atom;
1754
1755                 atom.m_val = val;
1756                 assert( atom.m_val == base && decr == base );
1757                 base = cast(T)( base - 1 );
1758                 decr = atom.decrement!(ms)();
1759                 assert( atom.m_val == base && decr == base );
1760             }
1761         }
1762
1763
1764         template testType( T )
1765         {
1766             void testType( T val = T.init + 1)
1767             {
1768                 testLoad!(msync.raw, T)( val );
1769                 testLoad!(msync.hlb, T)( val );
1770                 testLoad!(msync.acq, T)( val );
1771                 testLoad!(msync.seq, T)( val );
1772
1773                 testStore!(msync.raw, T)( val );
1774                 testStore!(msync.ssb, T)( val );
1775                 testStore!(msync.acq, T)( val );
1776                 testStore!(msync.rel, T)( val );
1777                 testStore!(msync.seq, T)( val );
1778
1779                 testStoreIf!(msync.raw, T)( val );
1780                 testStoreIf!(msync.ssb, T)( val );
1781                 testStoreIf!(msync.acq, T)( val );
1782                 testStoreIf!(msync.rel, T)( val );
1783                 testStoreIf!(msync.seq, T)( val );
1784
1785                 static if( isValidNumericType!(T) )
1786                 {
1787                     testIncrement!(msync.raw, T)( val );
1788                     testIncrement!(msync.ssb, T)( val );
1789                     testIncrement!(msync.acq, T)( val );
1790                     testIncrement!(msync.rel, T)( val );
1791                     testIncrement!(msync.seq, T)( val );
1792
1793                     testDecrement!(msync.raw, T)( val );
1794                     testDecrement!(msync.ssb, T)( val );
1795                     testDecrement!(msync.acq, T)( val );
1796                     testDecrement!(msync.rel, T)( val );
1797                     testDecrement!(msync.seq, T)( val );
1798                 }
1799             }
1800         }
1801     }
1802 }
1803
1804
1805 ////////////////////////////////////////////////////////////////////////////////
1806 // Unit Tests
1807 ////////////////////////////////////////////////////////////////////////////////
1808
1809
1810 debug( UnitTest )
1811 {
1812     unittest
1813     {
1814         testType!(bool)();
1815
1816         testType!(byte)();
1817         testType!(ubyte)();
1818
1819         testType!(short)();
1820         testType!(ushort)();
1821
1822         testType!(int)();
1823         testType!(uint)();
1824
1825         version( Has64BitOps )
1826         {
1827             testType!(long)();
1828             testType!(ulong)();
1829         }
1830         else version( Has64BitCAS )
1831         {
1832             testStoreIf!(msync.raw, long)();
1833             testStoreIf!(msync.ssb, long)();
1834             testStoreIf!(msync.acq, long)();
1835             testStoreIf!(msync.rel, long)();
1836             testStoreIf!(msync.seq, long)();
1837
1838             testStoreIf!(msync.raw, ulong)();
1839             testStoreIf!(msync.ssb, ulong)();
1840             testStoreIf!(msync.acq, ulong)();
1841             testStoreIf!(msync.rel, ulong)();
1842             testStoreIf!(msync.seq, ulong)();
1843         }
1844     }
1845 }
1846
1847
1848 ////////////////////////////////////////////////////////////////////////////////
1849 // Unit Tests
1850 ////////////////////////////////////////////////////////////////////////////////
1851
1852
1853 debug(Atomic)
1854 {
1855         void main()
1856         {
1857                 Atomic!(int) i;
1858
1859                 i.store (1);
1860                 i.increment;
1861                 i.decrement;
1862                 auto x = i.load;
1863                 i.store (2);
1864
1865                 x = atomicLoad (x);
1866         }
1867 }
Note: See TracBrowser for help on using the browser.