~ubuntu-branches/ubuntu/quantal/open-vm-tools/quantal-201207201942

« back to all changes in this revision

Viewing changes to lib/include/vm_atomic.h

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Baumann
  • Date: 2009-10-18 12:28:19 UTC
  • mfrom: (1.1.7 upstream) (2.4.9 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091018122819-00vqew6m0ztpqcqp
Tags: 2009.10.15-201664-1
MergingĀ upstreamĀ versionĀ 2009.10.15-201664.

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
 * vm_atomic.h --
21
21
 *
22
22
 *      Atomic power
 
23
 *
 
24
 * Note: Only partially tested on ARM processors: Works for View Open
 
25
 *       Client, which shouldn't have threads.
 
26
 *
 
27
 *       In ARM, GCC intrinsics (__sync*) compile but might not
 
28
 *       work, while MS intrinsics (_Interlocked*) do not compile,
 
29
 *       and ARM has no equivalent to the "lock" instruction prior to
 
30
 *       ARMv6; the current ARM target is ARMv5.  According to glibc
 
31
 *       documentation, ARMv5 cannot have atomic code in user space.
 
32
 *       Instead a Linux system call to kernel code referenced in
 
33
 *       entry-armv.S is used to achieve atomic functions.  See bug
 
34
 *       478054 for details.
23
35
 */
24
36
 
25
37
#ifndef _ATOMIC_H_
26
38
#define _ATOMIC_H_
27
39
 
 
40
//#define FAKE_ATOMIC /* defined if true atomic not needed */
 
41
 
28
42
#define INCLUDE_ALLOW_USERLEVEL
29
43
#define INCLUDE_ALLOW_VMMEXT
30
44
#define INCLUDE_ALLOW_MODULE
52
66
   volatile uint64 value;
53
67
} Atomic_uint64 ALIGNED(8);
54
68
 
 
69
#ifdef __arm__
 
70
#ifndef NOT_IMPLEMENTED
 
71
#error NOT_IMPLEMENTED undefined
 
72
#endif
 
73
#ifdef __GNUC__
 
74
EXTERN Atomic_uint32 atomicLocked64bit;
 
75
#ifndef FAKE_ATOMIC
 
76
   /*
 
77
    * Definitions for kernel function call which attempts an
 
78
    * atomic exchange, returning 0 only upon success.
 
79
    * The code actually called is put in memory by the kernel,
 
80
    * and is in fact what the kernel uses for this atomic
 
81
    * instruction.  This does not work for Linux versions
 
82
    * before 2.6 or (obviously) for non-Linux implementations.
 
83
    * For other implementations on ARMv6 and up, use
 
84
    * LDREX/SUBS/STREXEQ/LDRNE/ADDS/BNE spin-lock; for pre-ARMv6,
 
85
    * use SWP-based spin-lock.
 
86
    */
 
87
#if !defined(__linux__)
 
88
#define __kernel_cmpxchg(x, y, z) NOT_IMPLEMENTED()
 
89
#else
 
90
   typedef int (__kernel_cmpxchg_t)(uint32 oldVal,
 
91
                                    uint32 newVal,
 
92
                                    volatile uint32 *mem);
 
93
#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0)
 
94
#endif
 
95
#endif // FAKE_ATOMIC
 
96
#endif // __GNUC__
 
97
#endif // __arm__
55
98
 
56
99
/*
57
100
 * Prototypes for msft atomics.  These are defined & inlined by the
154
197
     __GNUC__ >= 3 &&                                                   \
155
198
    (defined(__VMKERNEL__) || !defined(__FreeBSD__)) &&                 \
156
199
    (!defined(MODULE) || defined(__VMKERNEL_MODULE__)) &&               \
157
 
    !defined(__APPLE__) /* PR136775 */
 
200
    !defined(__APPLE__) &&                                              \
 
201
    (defined(__i386__) || defined(__x86_64__)) /* PR136775 */
158
202
#define ATOMIC_USE_FENCE
159
203
#endif
160
204
 
185
229
   AtomicUseFence = fenceAfterLock;
186
230
#if defined(__VMKERNEL__)
187
231
   extern void Atomic_SetFenceVMKAPI(Bool fenceAfterLock);
188
 
   Atomic_SetFenceVMKAPI(fenceAfterLock);  
 
232
   Atomic_SetFenceVMKAPI(fenceAfterLock);
189
233
#endif
190
234
   atomicFenceInitialized = TRUE;
191
235
}
203
247
                 "lfence\n\t"
204
248
                 "2:\n\t"
205
249
                 ".pushsection .patchtext\n\t"
206
 
#ifdef VMM32
207
 
                 ".long 1b\n\t"
208
 
                 ".long 0\n\t"
209
 
                 ".long 2b\n\t"
210
 
                 ".long 0\n\t"
211
 
#else 
212
250
                 ".quad 1b\n\t"
213
251
                 ".quad 2b\n\t"
214
 
#endif
215
252
                 ".popsection\n\t" ::: "memory");
216
253
#else
217
254
   if (UNLIKELY(AtomicUseFence)) {
326
363
static INLINE uint32
327
364
Atomic_ReadWrite(Atomic_uint32 *var, // IN
328
365
                 uint32 val)         // IN
329
 
#ifdef __GNUC__
330
366
{
 
367
#ifdef FAKE_ATOMIC
 
368
   uint32 retval = var->value;
 
369
   var->value = val;
 
370
   return retval;
 
371
#elif defined(__GNUC__)
 
372
#ifdef __arm__
 
373
   register uint32 retval;
 
374
   register volatile uint32 *mem = &(var->value);
 
375
   /* XXX - ARMv5 only: for ARMv6, use LDREX/STREX/CMP/BEQ spin-lock */
 
376
   __asm__ __volatile__("swp %0, %1, [%2]"
 
377
                        : "=&r,&r" (retval)
 
378
                        : "r,0" (val), "r,r" (mem) : "memory");
 
379
   return retval;
 
380
#else // __arm__ (assume x86*)
331
381
   /* Checked against the Intel manual and GCC --walken */
332
382
   __asm__ __volatile__(
333
383
      "xchgl %0, %1"
344
394
   );
345
395
   AtomicEpilogue();
346
396
   return val;
347
 
}
348
 
#elif _MSC_VER >= 1310
349
 
{
 
397
#endif // __arm__
 
398
#elif defined _MSC_VER
 
399
#if _MSC_VER >= 1310
350
400
   return _InterlockedExchange((long *)&var->value, (long)val);
351
 
}
352
 
#elif _MSC_VER
 
401
#else
353
402
#pragma warning(push)
354
403
#pragma warning(disable : 4035)         // disable no-return warning
355
 
{
356
 
   __asm mov eax, val
357
 
   __asm mov ebx, var
358
 
   __asm xchg [ebx]Atomic_uint32.value, eax
359
 
   // eax is the return value, this is documented to work - edward
360
 
}
 
404
   {
 
405
      __asm mov eax, val
 
406
      __asm mov ebx, var
 
407
      __asm xchg [ebx]Atomic_uint32.value, eax
 
408
      // eax is the return value, this is documented to work - edward
 
409
   }
361
410
#pragma warning(pop)
 
411
#endif
362
412
#else
363
413
#error No compiler defined for Atomic_ReadWrite
364
414
#endif
 
415
}
365
416
#define Atomic_ReadWrite32 Atomic_ReadWrite
366
417
 
367
418
 
385
436
Atomic_ReadIfEqualWrite(Atomic_uint32 *var, // IN
386
437
                        uint32 oldVal,      // IN
387
438
                        uint32 newVal)      // IN
388
 
#ifdef __GNUC__
389
439
{
 
440
#ifdef FAKE_ATOMIC
 
441
   uint32 readVal = var->value;
 
442
 
 
443
   if (oldVal == readVal) {
 
444
     var->value = newVal;
 
445
   }
 
446
   return oldVal;
 
447
#elif defined(__GNUC__)
 
448
#ifdef __arm__
 
449
   uint32 readVal;
 
450
   register volatile uint32 *mem = &(var->value);
 
451
 
 
452
   // loop until var not oldVal or var successfully replaced when var oldVal
 
453
   do {
 
454
      readVal = Atomic_Read(var);
 
455
      if (oldVal != readVal) {
 
456
         return readVal;
 
457
      }
 
458
   } while (__kernel_cmpxchg(oldVal, newVal, mem) != 0);
 
459
   return oldVal; // success
 
460
#else // __arm__ (assume x86*)
390
461
   uint32 val;
391
462
 
392
463
   /* Checked against the Intel manual and GCC --walken */
401
472
      : "=a" (val),
402
473
        "=m" (var->value)
403
474
      : "r" (newVal),
404
 
        "0" (oldVal) 
405
 
     /* 
 
475
        "0" (oldVal)
 
476
     /*
406
477
      * "1" (var->value): results in inconsistent constraints on gcc 2.7.2.3
407
478
      * when compiling enterprise-2.2.17-14-RH7.0-update.
408
479
      * The constraint has been commented out for now. We may consider doing
409
480
      * this systematically, but we need to be sure it is the right thing to
410
481
      * do. However, it is also possible that the offending use of this asm
411
 
      * function will be removed in the near future in which case we may 
 
482
      * function will be removed in the near future in which case we may
412
483
      * decide to reintroduce the constraint instead. hpreg & agesen.
413
484
      */
414
485
#   endif
416
487
   );
417
488
   AtomicEpilogue();
418
489
   return val;
419
 
}
420
 
#elif _MSC_VER >= 1310
421
 
{
 
490
#endif // __arm__
 
491
#elif defined _MSC_VER
 
492
#if _MSC_VER >= 1310
422
493
   return _InterlockedCompareExchange((long *)&var->value,
423
494
                                      (long)newVal,
424
495
                                      (long)oldVal);
425
 
}
426
 
#elif _MSC_VER
 
496
#else
427
497
#pragma warning(push)
428
498
#pragma warning(disable : 4035)         // disable no-return warning
429
 
{
430
 
   __asm mov eax, oldVal
431
 
   __asm mov ebx, var
432
 
   __asm mov ecx, newVal
433
 
   __asm lock cmpxchg [ebx]Atomic_uint32.value, ecx
434
 
   // eax is the return value, this is documented to work - edward
435
 
}
 
499
   {
 
500
      __asm mov eax, oldVal
 
501
      __asm mov ebx, var
 
502
      __asm mov ecx, newVal
 
503
      __asm lock cmpxchg [ebx]Atomic_uint32.value, ecx
 
504
      // eax is the return value, this is documented to work - edward
 
505
   }
436
506
#pragma warning(pop)
 
507
#endif
437
508
#else
438
509
#error No compiler defined for Atomic_ReadIfEqualWrite
439
510
#endif
 
511
}
440
512
#define Atomic_ReadIfEqualWrite32 Atomic_ReadIfEqualWrite
441
513
 
442
514
 
476
548
   );
477
549
   AtomicEpilogue();
478
550
   return val;
479
 
#elif _MSC_VER
 
551
#elif defined _MSC_VER
480
552
   return _InterlockedCompareExchange64((__int64 *)&var->value,
481
553
                                        (__int64)newVal,
482
554
                                        (__int64)oldVal);
507
579
Atomic_And(Atomic_uint32 *var, // IN
508
580
           uint32 val)         // IN
509
581
{
510
 
#ifdef __GNUC__
 
582
#ifdef FAKE_ATOMIC
 
583
   var->value &= val;
 
584
#elif defined(__GNUC__)
 
585
#ifdef __arm__
 
586
   /* same as Atomic_FetchAndAnd without return value */
 
587
   uint32 res;
 
588
   register volatile uint32 *mem = &(var->value);
 
589
 
 
590
   do {
 
591
     res = Atomic_Read(var);
 
592
   } while (__kernel_cmpxchg(res, res & val, mem) != 0);
 
593
#else // __arm__
511
594
   /* Checked against the Intel manual and GCC --walken */
512
595
   __asm__ __volatile__(
513
596
      "lock; andl %1, %0"
522
605
      : "cc"
523
606
   );
524
607
   AtomicEpilogue();
525
 
#elif _MSC_VER
 
608
#endif // __arm__
 
609
#elif defined _MSC_VER
526
610
#if defined(__x86_64__)
527
611
   _InterlockedAnd((long *)&var->value, (long)val);
528
612
#else
567
651
      : "cc"
568
652
   );
569
653
   AtomicEpilogue();
570
 
#elif _MSC_VER
 
654
#elif defined _MSC_VER
571
655
   _InterlockedAnd64((__int64 *)&var->value, (__int64)val);
572
656
#else
573
657
#error No compiler defined for Atomic_And64
596
680
Atomic_Or(Atomic_uint32 *var, // IN
597
681
          uint32 val)         // IN
598
682
{
599
 
#ifdef __GNUC__
 
683
#ifdef FAKE_ATOMIC
 
684
   var->value |= val;
 
685
#elif defined(__GNUC__)
 
686
#ifdef __arm__
 
687
   /* same as Atomic_FetchAndOr without return value */
 
688
   uint32 res;
 
689
   register volatile uint32 *mem = &(var->value);
 
690
 
 
691
   do {
 
692
     res = Atomic_Read(var);
 
693
   } while (__kernel_cmpxchg(res, res | val, mem) != 0);
 
694
#else // __arm__
600
695
   /* Checked against the Intel manual and GCC --walken */
601
696
   __asm__ __volatile__(
602
697
      "lock; orl %1, %0"
611
706
      : "cc"
612
707
   );
613
708
   AtomicEpilogue();
614
 
#elif _MSC_VER
 
709
#endif // __arm__
 
710
#elif defined _MSC_VER
615
711
#if defined(__x86_64__)
616
712
   _InterlockedOr((long *)&var->value, (long)val);
617
713
#else
656
752
      : "cc"
657
753
   );
658
754
   AtomicEpilogue();
659
 
#elif _MSC_VER
 
755
#elif defined _MSC_VER
660
756
   _InterlockedOr64((__int64 *)&var->value, (__int64)val);
661
757
#else
662
758
#error No compiler defined for Atomic_Or64
685
781
Atomic_Xor(Atomic_uint32 *var, // IN
686
782
           uint32 val)         // IN
687
783
{
688
 
#ifdef __GNUC__
 
784
#ifdef FAKE_ATOMIC
 
785
   var->value ^= val;
 
786
#elif defined(__GNUC__)
 
787
#ifdef __arm__
 
788
   uint32 res;
 
789
   register volatile uint32 *mem = &(var->value);
 
790
 
 
791
   do {
 
792
     res = Atomic_Read(var);
 
793
   } while (__kernel_cmpxchg(res, res ^ val, mem) != 0);
 
794
#else // __arm__
689
795
   /* Checked against the Intel manual and GCC --walken */
690
796
   __asm__ __volatile__(
691
797
      "lock; xorl %1, %0"
700
806
      : "cc"
701
807
   );
702
808
   AtomicEpilogue();
703
 
#elif _MSC_VER
 
809
#endif // __arm__
 
810
#elif defined _MSC_VER
704
811
#if defined(__x86_64__)
705
812
   _InterlockedXor((long *)&var->value, (long)val);
706
813
#else
745
852
      : "cc"
746
853
   );
747
854
   AtomicEpilogue();
748
 
#elif _MSC_VER
 
855
#elif defined _MSC_VER
749
856
   _InterlockedXor64((__int64 *)&var->value, (__int64)val);
750
857
#else
751
858
#error No compiler defined for Atomic_Xor64
774
881
Atomic_Add(Atomic_uint32 *var, // IN
775
882
           uint32 val)         // IN
776
883
{
777
 
#ifdef __GNUC__
 
884
#ifdef FAKE_ATOMIC
 
885
   var->value += val;
 
886
#elif defined(__GNUC__)
 
887
#ifdef __arm__
 
888
   /* same as Atomic_FetchAndAddUnfenced without return value */
 
889
   uint32 res;
 
890
   register volatile uint32 *mem = &(var->value);
 
891
 
 
892
   do {
 
893
     res = Atomic_Read(var);
 
894
   } while (__kernel_cmpxchg(res, res + val, mem) != 0);
 
895
#else // __arm__
778
896
   /* Checked against the Intel manual and GCC --walken */
779
897
   __asm__ __volatile__(
780
898
      "lock; addl %1, %0"
789
907
      : "cc"
790
908
   );
791
909
   AtomicEpilogue();
792
 
#elif _MSC_VER >= 1310
 
910
#endif // __arm__
 
911
#elif defined _MSC_VER
 
912
#if _MSC_VER >= 1310
793
913
   _InterlockedExchangeAdd((long *)&var->value, (long)val);
794
 
#elif _MSC_VER
 
914
#else
795
915
   __asm mov eax, val
796
916
   __asm mov ebx, var
797
917
   __asm lock add [ebx]Atomic_uint32.value, eax
 
918
#endif
798
919
#else
799
920
#error No compiler defined for Atomic_Add
800
921
#endif
832
953
      : "cc"
833
954
   );
834
955
   AtomicEpilogue();
835
 
#elif _MSC_VER
 
956
#elif defined _MSC_VER
836
957
   _InterlockedExchangeAdd64((__int64 *)&var->value, (__int64)val);
837
958
#else
838
959
#error No compiler defined for Atomic_Add64
861
982
Atomic_Sub(Atomic_uint32 *var, // IN
862
983
           uint32 val)         // IN
863
984
{
864
 
#ifdef __GNUC__
 
985
#ifdef FAKE_ATOMIC
 
986
   var->value -= val;
 
987
#elif defined(__GNUC__)
 
988
#ifdef __arm__
 
989
   uint32 res;
 
990
   register volatile uint32 *mem = &(var->value);
 
991
 
 
992
   do {
 
993
     res = Atomic_Read(var);
 
994
   } while (__kernel_cmpxchg(res, res - val, mem) != 0);
 
995
#else // __arm__
865
996
   /* Checked against the Intel manual and GCC --walken */
866
997
   __asm__ __volatile__(
867
998
      "lock; subl %1, %0"
876
1007
      : "cc"
877
1008
   );
878
1009
   AtomicEpilogue();
879
 
#elif _MSC_VER >= 1310
 
1010
#endif // __arm__
 
1011
#elif defined _MSC_VER
 
1012
#if _MSC_VER >= 1310
880
1013
   _InterlockedExchangeAdd((long *)&var->value, (long)-val);
881
 
#elif _MSC_VER
 
1014
#else
882
1015
   __asm mov eax, val
883
1016
   __asm mov ebx, var
884
1017
   __asm lock sub [ebx]Atomic_uint32.value, eax
 
1018
#endif
885
1019
#else
886
1020
#error No compiler defined for Atomic_Sub
887
1021
#endif
919
1053
      : "cc"
920
1054
   );
921
1055
   AtomicEpilogue();
922
 
#elif _MSC_VER
 
1056
#elif defined _MSC_VER
923
1057
   _InterlockedExchangeAdd64((__int64 *)&var->value, (__int64)-val);
924
1058
#else
925
1059
#error No compiler defined for Atomic_Sub64
948
1082
Atomic_Inc(Atomic_uint32 *var) // IN
949
1083
{
950
1084
#ifdef __GNUC__
 
1085
#ifdef __arm__
 
1086
   /* just use Atomic_Add */
 
1087
   Atomic_Add(var, 1);
 
1088
#else // __arm__
951
1089
   /* Checked against the Intel manual and GCC --walken */
952
1090
   __asm__ __volatile__(
953
1091
      "lock; incl %0"
961
1099
      : "cc"
962
1100
   );
963
1101
   AtomicEpilogue();
964
 
#elif _MSC_VER >= 1310
 
1102
#endif // __arm__
 
1103
#elif defined _MSC_VER
 
1104
#if _MSC_VER >= 1310
965
1105
   _InterlockedIncrement((long *)&var->value);
966
 
#elif _MSC_VER
 
1106
#else
967
1107
   __asm mov ebx, var
968
1108
   __asm lock inc [ebx]Atomic_uint32.value
 
1109
#endif
969
1110
#else
970
1111
#error No compiler defined for Atomic_Inc
971
1112
#endif
973
1114
#define Atomic_Inc32 Atomic_Inc
974
1115
 
975
1116
 
976
 
#if defined(__x86_64__)
977
 
/*
978
 
 *-----------------------------------------------------------------------------
979
 
 *
980
 
 * Atomic_Inc64 --
981
 
 *
982
 
 *      Atomic read, increment, write.
983
 
 *
984
 
 * Results:
985
 
 *      None
986
 
 *
987
 
 * Side effects:
988
 
 *      None
989
 
 *
990
 
 *-----------------------------------------------------------------------------
991
 
 */
992
 
 
993
 
static INLINE void
994
 
Atomic_Inc64(Atomic_uint64 *var) // IN
995
 
{
996
 
#if defined(__GNUC__)
997
 
   /* Checked against the AMD manual and GCC --hpreg */
998
 
   __asm__ __volatile__(
999
 
      "lock; incq %0"
1000
 
      : "+m" (var->value)
1001
 
      :
1002
 
      : "cc"
1003
 
   );
1004
 
   AtomicEpilogue();
1005
 
#elif _MSC_VER
1006
 
   _InterlockedIncrement64((__int64 *)&var->value);
1007
 
#else
1008
 
#error No compiler defined for Atomic_Inc64
1009
 
#endif
1010
 
}
1011
 
#endif
1012
 
 
1013
 
 
1014
1117
/*
1015
1118
 *-----------------------------------------------------------------------------
1016
1119
 *
1031
1134
Atomic_Dec(Atomic_uint32 *var) // IN
1032
1135
{
1033
1136
#ifdef __GNUC__
 
1137
#ifdef __arm__
 
1138
   /* just use Atomic_Sub */
 
1139
   Atomic_Sub(var, 1);
 
1140
#else // __arm__
1034
1141
   /* Checked against the Intel manual and GCC --walken */
1035
1142
   __asm__ __volatile__(
1036
1143
      "lock; decl %0"
1044
1151
      : "cc"
1045
1152
   );
1046
1153
   AtomicEpilogue();
1047
 
#elif _MSC_VER >= 1310
 
1154
#endif // __arm__
 
1155
#elif defined _MSC_VER
 
1156
#if _MSC_VER >= 1310
1048
1157
   _InterlockedDecrement((long *)&var->value);
1049
 
#elif _MSC_VER
 
1158
#else
1050
1159
   __asm mov ebx, var
1051
1160
   __asm lock dec [ebx]Atomic_uint32.value
 
1161
#endif
1052
1162
#else
1053
1163
#error No compiler defined for Atomic_Dec
1054
1164
#endif
1056
1166
#define Atomic_Dec32 Atomic_Dec
1057
1167
 
1058
1168
 
1059
 
#if defined(__x86_64__)
1060
 
/*
1061
 
 *-----------------------------------------------------------------------------
1062
 
 *
1063
 
 * Atomic_Dec64 --
1064
 
 *
1065
 
 *      Atomic read, decrement, write.
1066
 
 *
1067
 
 * Results:
1068
 
 *      None
1069
 
 *
1070
 
 * Side effects:
1071
 
 *      None
1072
 
 *
1073
 
 *-----------------------------------------------------------------------------
1074
 
 */
1075
 
 
1076
 
static INLINE void
1077
 
Atomic_Dec64(Atomic_uint64 *var) // IN
1078
 
{
1079
 
#if defined(__GNUC__)
1080
 
   /* Checked against the AMD manual and GCC --hpreg */
1081
 
   __asm__ __volatile__(
1082
 
      "lock; decq %0"
1083
 
      : "+m" (var->value)
1084
 
      :
1085
 
      : "cc"
1086
 
   );
1087
 
   AtomicEpilogue();
1088
 
#elif _MSC_VER
1089
 
   _InterlockedDecrement64((__int64 *)&var->value);
1090
 
#else
1091
 
#error No compiler defined for Atomic_Dec64
1092
 
#endif
1093
 
}
1094
 
#endif
1095
 
 
1096
 
 
1097
1169
/*
1098
1170
 * Note that the technique below can be used to implement ReadX(), where X is
1099
1171
 * an arbitrary mathematical function.
1122
1194
{
1123
1195
   uint32 res;
1124
1196
 
1125
 
   do {
1126
 
      res = var->value;
 
1197
#if defined(__arm__) && !defined(FAKE_ATOMIC)
 
1198
   register volatile uint32 *mem = &(var->value);
 
1199
   do {
 
1200
      res = Atomic_Read(var);
 
1201
   } while (__kernel_cmpxchg(res, res | val, mem) != 0);
 
1202
#else
 
1203
   do {
 
1204
      res = Atomic_Read(var);
1127
1205
   } while (res != Atomic_ReadIfEqualWrite(var, res, res | val));
1128
 
 
 
1206
#endif
1129
1207
   return res;
1130
1208
}
1131
1209
 
1152
1230
{
1153
1231
   uint32 res;
1154
1232
 
1155
 
   do {
1156
 
      res = var->value;
 
1233
#if defined(__arm__) && !defined(FAKE_ATOMIC)
 
1234
   register volatile uint32 *mem = &(var->value);
 
1235
   do {
 
1236
      res = Atomic_Read(var);
 
1237
   } while (__kernel_cmpxchg(res, res & val, mem) != 0);
 
1238
#else
 
1239
   do {
 
1240
      res = Atomic_Read(var);
1157
1241
   } while (res != Atomic_ReadIfEqualWrite(var, res, res & val));
1158
 
 
 
1242
#endif
1159
1243
   return res;
1160
1244
}
1161
1245
#define Atomic_ReadOr32 Atomic_FetchAndOr
1219
1303
static INLINE uint32
1220
1304
Atomic_FetchAndAddUnfenced(Atomic_uint32 *var, // IN
1221
1305
                           uint32 val)         // IN
1222
 
#ifdef __GNUC__
1223
1306
{
 
1307
#ifdef FAKE_ATOMIC
 
1308
   uint32 res = var->value;
 
1309
   var->value = res + val;
 
1310
   return res;
 
1311
#elif defined(__GNUC__)
 
1312
#ifdef __arm__
 
1313
   uint32 res;
 
1314
 
 
1315
   register volatile uint32 *mem = &(var->value);
 
1316
   do {
 
1317
      res = Atomic_Read(var);
 
1318
   } while (__kernel_cmpxchg(res, res + val, mem) != 0);
 
1319
 
 
1320
   return res;
 
1321
#else // __arm__
1224
1322
   /* Checked against the Intel manual and GCC --walken */
1225
1323
   __asm__ __volatile__(
1226
1324
#   if VM_ASM_PLUS
1238
1336
#   endif
1239
1337
   );
1240
1338
   return val;
1241
 
}
1242
 
#elif _MSC_VER >= 1310
1243
 
{
 
1339
#endif // __arm__
 
1340
#elif defined _MSC_VER
 
1341
#if _MSC_VER >= 1310
1244
1342
   return _InterlockedExchangeAdd((long *)&var->value, (long)val);
1245
 
}
1246
 
#elif _MSC_VER
 
1343
#else
1247
1344
#pragma warning(push)
1248
1345
#pragma warning(disable : 4035)         // disable no-return warning
1249
 
{
1250
 
   __asm mov eax, val
1251
 
   __asm mov ebx, var
1252
 
   __asm lock xadd [ebx]Atomic_uint32.value, eax
1253
 
}
 
1346
   {
 
1347
      __asm mov eax, val
 
1348
      __asm mov ebx, var
 
1349
      __asm lock xadd [ebx]Atomic_uint32.value, eax
 
1350
   }
1254
1351
#pragma warning(pop)
 
1352
#endif
1255
1353
#else
1256
1354
#error No compiler defined for Atomic_FetchAndAdd
1257
1355
#endif
 
1356
}
1258
1357
#define Atomic_ReadAdd32 Atomic_FetchAndAdd
1259
1358
 
1260
1359
 
1284
1383
static INLINE uint32
1285
1384
Atomic_FetchAndAdd(Atomic_uint32 *var, // IN
1286
1385
                   uint32 val)         // IN
1287
 
#ifdef __GNUC__
1288
1386
{
 
1387
#if defined(__GNUC__) && !defined(__arm__)
1289
1388
   val = Atomic_FetchAndAddUnfenced(var, val);
1290
1389
   AtomicEpilogue();
1291
1390
   return val;
1292
 
}
1293
1391
#else
1294
 
{
1295
1392
   return Atomic_FetchAndAddUnfenced(var, val);
 
1393
#endif
1296
1394
}
1297
 
#endif
1298
1395
 
1299
1396
 
1300
1397
#if defined(__x86_64__)
1329
1426
   );
1330
1427
   AtomicEpilogue();
1331
1428
   return val;
1332
 
#elif _MSC_VER
 
1429
#elif defined _MSC_VER
1333
1430
   return _InterlockedExchangeAdd64((__int64 *)&var->value, (__int64)val);
1334
1431
#else
1335
1432
#error No compiler defined for Atomic_ReadAdd64
1486
1583
 *
1487
1584
 *      Compare exchange: Read variable, if equal to oldVal, write newVal
1488
1585
 *
1489
 
 *      XXX: Ensure that if this function is to be inlined by gcc, it is 
1490
 
 *      compiled with -fno-strict-aliasing. Otherwise it will break. 
 
1586
 *      XXX: Ensure that if this function is to be inlined by gcc, it is
 
1587
 *      compiled with -fno-strict-aliasing. Otherwise it will break.
1491
1588
 *      Unfortunately we know that gcc 2.95.3 (used to build the FreeBSD 3.2
1492
 
 *      Tools) does not honor -fno-strict-aliasing. As a workaround, we avoid 
 
1589
 *      Tools) does not honor -fno-strict-aliasing. As a workaround, we avoid
1493
1590
 *      inlining the function entirely for versions of gcc under 3.0.
1494
1591
 *
1495
1592
 * Results:
1501
1598
 *-----------------------------------------------------------------------------
1502
1599
 */
1503
1600
 
 
1601
#ifdef __arm__
 
1602
#define Atomic_CMPXCHG64(x, y, z) NOT_IMPLEMENTED()
 
1603
#else // __arm__
1504
1604
#if defined(__GNUC__) && __GNUC__ < 3
1505
1605
static Bool
1506
1606
#else
1509
1609
Atomic_CMPXCHG64(Atomic_uint64 *var,   // IN/OUT
1510
1610
                 uint64 const *oldVal, // IN
1511
1611
                 uint64 const *newVal) // IN
1512
 
#ifdef __GNUC__
1513
1612
{
 
1613
#ifdef FAKE_ATOMIC
 
1614
   uint64 readVal = var->value;
 
1615
 
 
1616
   if (*oldVal == readVal) {
 
1617
     var->value = *newVal;
 
1618
   }
 
1619
   return (*oldVal == readVal);
 
1620
#elif defined(__GNUC__)
1514
1621
   Bool equal;
1515
1622
 
1516
1623
   /* Checked against the Intel manual and GCC --walken */
1517
 
#ifdef VMM64
 
1624
#if defined(__x86_64__)
1518
1625
   uint64 dummy;
1519
1626
   __asm__ __volatile__(
1520
1627
      "lock; cmpxchgq %3, %0" "\n\t"
1528
1635
   );
1529
1636
#else /* 32-bit version */
1530
1637
   int dummy1, dummy2;
1531
 
#   if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler.
 
1638
#   if defined __PIC__ // %ebx is reserved by the compiler.
1532
1639
#      if defined __GNUC__ && __GNUC__ < 3 // Part of #188541 - for RHL 6.2 etc.
1533
1640
   __asm__ __volatile__(
1534
1641
      "xchg %%ebx, %6\n\t"
1581
1688
      : "cc"
1582
1689
   );
1583
1690
#   endif
1584
 
#endif
 
1691
#endif /* 32-bit version */
1585
1692
   AtomicEpilogue();
1586
1693
   return equal;
1587
 
1588
 
#elif _MSC_VER
 
1694
#elif defined _MSC_VER
1589
1695
#if defined(__x86_64__)
1590
 
{
1591
1696
   return *oldVal == _InterlockedCompareExchange64((__int64 *)&var->value,
1592
 
                                                   (__int64)*newVal, 
 
1697
                                                   (__int64)*newVal,
1593
1698
                                                   (__int64)*oldVal);
1594
 
}
1595
1699
#else
1596
1700
#pragma warning(push)
1597
1701
#pragma warning(disable : 4035)         // disable no-return warning
1598
 
{
1599
 
   __asm mov esi, var
1600
 
   __asm mov edx, oldVal
1601
 
   __asm mov ecx, newVal
1602
 
   __asm mov eax, [edx]S_uint64.lowValue
1603
 
   __asm mov edx, [edx]S_uint64.highValue
1604
 
   __asm mov ebx, [ecx]S_uint64.lowValue
1605
 
   __asm mov ecx, [ecx]S_uint64.highValue
1606
 
   __asm lock cmpxchg8b [esi]
1607
 
   __asm sete al
1608
 
   __asm movzx eax, al
1609
 
   // eax is the return value, this is documented to work - edward
1610
 
 
1702
   {
 
1703
      __asm mov esi, var
 
1704
      __asm mov edx, oldVal
 
1705
      __asm mov ecx, newVal
 
1706
      __asm mov eax, [edx]S_uint64.lowValue
 
1707
      __asm mov edx, [edx]S_uint64.highValue
 
1708
      __asm mov ebx, [ecx]S_uint64.lowValue
 
1709
      __asm mov ecx, [ecx]S_uint64.highValue
 
1710
      __asm lock cmpxchg8b [esi]
 
1711
      __asm sete al
 
1712
      __asm movzx eax, al
 
1713
      // eax is the return value, this is documented to work - edward
 
1714
   }
1611
1715
#pragma warning(pop)
1612
1716
#endif
1613
1717
#else
1614
1718
#error No compiler defined for Atomic_CMPXCHG64
1615
1719
#endif
 
1720
}
 
1721
#endif // __arm__
1616
1722
 
1617
1723
 
1618
1724
/*
1636
1742
                 uint32 oldVal, // IN
1637
1743
                 uint32 newVal) // IN
1638
1744
{
1639
 
#ifdef __GNUC__
 
1745
#ifdef FAKE_ATOMIC
 
1746
   uint32 readVal = var->value;
 
1747
 
 
1748
   if (oldVal == readVal) {
 
1749
     var->value = newVal;
 
1750
   }
 
1751
   return (oldVal == readVal);
 
1752
#elif defined(__GNUC__)
 
1753
#ifdef __arm__
 
1754
   register volatile uint32 *mem = &(var->value);
 
1755
 
 
1756
   return !__kernel_cmpxchg(oldVal, newVal, mem);
 
1757
#else // __arm__
1640
1758
   Bool equal;
1641
1759
 
1642
1760
   uint32 dummy;
1661
1779
   );
1662
1780
   AtomicEpilogue();
1663
1781
   return equal;
1664
 
#else
 
1782
#endif // __arm__
 
1783
#else // defined(__GNUC__)
1665
1784
   return (Atomic_ReadIfEqualWrite(var, oldVal, newVal) == oldVal);
1666
 
#endif
1667
 
1668
 
 
 
1785
#endif // defined(__GNUC__)
 
1786
}
 
1787
 
 
1788
 
 
1789
#ifdef __arm__
 
1790
 
 
1791
#define Atomic_Read64(x)          NOT_IMPLEMENTED()
 
1792
#define Atomic_FetchAndAdd64(x,y) NOT_IMPLEMENTED()
 
1793
#define Atomic_FetchAndInc64(x)   NOT_IMPLEMENTED()
 
1794
#define Atomic_FetchAndDec64(x)   NOT_IMPLEMENTED()
 
1795
#define Atomic_Inc64(x)           NOT_IMPLEMENTED()
 
1796
#define Atomic_Dec64(x)           NOT_IMPLEMENTED()
 
1797
#define Atomic_ReadWrite64(x,y)   NOT_IMPLEMENTED()
 
1798
#define Atomic_Write64(x,y)       NOT_IMPLEMENTED()
 
1799
 
 
1800
#else // __arm__
1669
1801
 
1670
1802
/*
1671
1803
 *-----------------------------------------------------------------------------
1685
1817
 
1686
1818
static INLINE uint64
1687
1819
Atomic_Read64(Atomic_uint64 const *var) // IN
1688
 
#if defined(__x86_64__)
1689
1820
{
1690
 
   return var->value;
1691
 
}
 
1821
#if defined(FAKE_ATOMIC)
 
1822
   return var->value;
 
1823
#elif defined(__x86_64__)
 
1824
   return var->value;
1692
1825
#elif defined(__GNUC__) && defined(__i386__) /* GCC on x86 */
1693
 
{
1694
1826
   uint64 value;
1695
 
   /* 
 
1827
   /*
1696
1828
    * Since cmpxchg8b will replace the contents of EDX:EAX with the
1697
1829
    * value in memory if there is no match, we need only execute the
1698
1830
    * instruction once in order to atomically read 64 bits from
1711
1843
   );
1712
1844
   AtomicEpilogue();
1713
1845
   return value;
1714
 
}
1715
 
#elif _MSC_VER /* MSC (assume on x86 for now) */
 
1846
#elif defined _MSC_VER /* MSC (assume on x86 for now) */
1716
1847
#   pragma warning(push)
1717
1848
#   pragma warning(disable : 4035)              // disable no-return warning
1718
 
{
1719
 
   __asm mov ecx, var
1720
 
   __asm mov edx, ecx
1721
 
   __asm mov eax, ebx
1722
 
   __asm lock cmpxchg8b [ecx]
1723
 
   // edx:eax is the return value; this is documented to work. --mann
1724
 
}
 
1849
   {
 
1850
      __asm mov ecx, var
 
1851
      __asm mov edx, ecx
 
1852
      __asm mov eax, ebx
 
1853
      __asm lock cmpxchg8b [ecx]
 
1854
      // edx:eax is the return value; this is documented to work. --mann
 
1855
   }
1725
1856
#   pragma warning(pop)
1726
1857
#else
1727
1858
#   error No compiler defined for Atomic_Read64
1728
1859
#endif
 
1860
}
1729
1861
 
1730
1862
 
1731
1863
/*
1817
1949
/*
1818
1950
 *-----------------------------------------------------------------------------
1819
1951
 *
 
1952
 * Atomic_Inc64 --
 
1953
 *
 
1954
 *      Atomic read, increment, write.
 
1955
 *
 
1956
 * Results:
 
1957
 *      None
 
1958
 *
 
1959
 * Side effects:
 
1960
 *      None
 
1961
 *
 
1962
 *-----------------------------------------------------------------------------
 
1963
 */
 
1964
 
 
1965
static INLINE void
 
1966
Atomic_Inc64(Atomic_uint64 *var) // IN
 
1967
{
 
1968
#if !defined(__x86_64__)
 
1969
   Atomic_FetchAndInc64(var);
 
1970
#elif defined(__GNUC__)
 
1971
   /* Checked against the AMD manual and GCC --hpreg */
 
1972
   __asm__ __volatile__(
 
1973
      "lock; incq %0"
 
1974
      : "+m" (var->value)
 
1975
      :
 
1976
      : "cc"
 
1977
   );
 
1978
   AtomicEpilogue();
 
1979
#elif defined _MSC_VER
 
1980
   _InterlockedIncrement64((__int64 *)&var->value);
 
1981
#else
 
1982
#error No compiler defined for Atomic_Inc64
 
1983
#endif
 
1984
}
 
1985
 
 
1986
 
 
1987
/*
 
1988
 *-----------------------------------------------------------------------------
 
1989
 *
 
1990
 * Atomic_Dec64 --
 
1991
 *
 
1992
 *      Atomic read, decrement, write.
 
1993
 *
 
1994
 * Results:
 
1995
 *      None
 
1996
 *
 
1997
 * Side effects:
 
1998
 *      None
 
1999
 *
 
2000
 *-----------------------------------------------------------------------------
 
2001
 */
 
2002
 
 
2003
static INLINE void
 
2004
Atomic_Dec64(Atomic_uint64 *var) // IN
 
2005
{
 
2006
#if !defined(__x86_64__)
 
2007
   Atomic_FetchAndDec64(var);
 
2008
#elif defined(__GNUC__)
 
2009
   /* Checked against the AMD manual and GCC --hpreg */
 
2010
   __asm__ __volatile__(
 
2011
      "lock; decq %0"
 
2012
      : "+m" (var->value)
 
2013
      :
 
2014
      : "cc"
 
2015
   );
 
2016
   AtomicEpilogue();
 
2017
#elif defined _MSC_VER
 
2018
   _InterlockedDecrement64((__int64 *)&var->value);
 
2019
#else
 
2020
#error No compiler defined for Atomic_Dec64
 
2021
#endif
 
2022
}
 
2023
 
 
2024
 
 
2025
/*
 
2026
 *-----------------------------------------------------------------------------
 
2027
 *
1820
2028
 * Atomic_ReadWrite64 --
1821
2029
 *
1822
2030
 *      Read followed by write
1845
2053
   );
1846
2054
   AtomicEpilogue();
1847
2055
   return val;
1848
 
#elif _MSC_VER
 
2056
#elif defined _MSC_VER
1849
2057
   return _InterlockedExchange64((__int64 *)&var->value, (__int64)val);
1850
2058
#else
1851
2059
#error No compiler defined for Atomic_ReadWrite64
1888
2096
   (void)Atomic_ReadWrite64(var, val);
1889
2097
#endif
1890
2098
}
 
2099
#endif // __arm__
1891
2100
 
1892
2101
 
1893
2102
/*