182 lines
5.3 KiB
Diff
182 lines
5.3 KiB
Diff
|
From: Robie Basak <robie.basak@canonical.com>
|
||
|
Date: Sat, 20 Apr 2013 22:05:50 -0300
|
||
|
Subject: ARM support for ASM operations in MongoDB
|
||
|
|
||
|
This is a modified version of Jon Masters' ARM patch. I have replaced some of
|
||
|
the calls whose return value semantics didn't quite match the existing x86
|
||
|
assembler.
|
||
|
|
||
|
Original-Author: Jon Masters <jcm@redhat.com>
|
||
|
Origin: http://lists.fedoraproject.org/pipermail/arm/2013-February/005388.html
|
||
|
Last-Update: 2013-03-15
|
||
|
---
|
||
|
src/mongo/platform/atomic_intrinsics_gcc.h | 69 +++++++++++++++++++++++++++++-
|
||
|
src/mongo/platform/bits.h | 2 +-
|
||
|
2 files changed, 68 insertions(+), 3 deletions(-)
|
||
|
|
||
|
diff --git src/mongo/platform/atomic_intrinsics_gcc.h src/mongo/platform/atomic_intrinsics_gcc.h
|
||
|
index f8f96f0..da36685 100644
|
||
|
--- src/mongo/platform/atomic_intrinsics_gcc.h
|
||
|
+++ src/mongo/platform/atomic_intrinsics_gcc.h
|
||
|
@@ -14,14 +14,19 @@
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
- * Implementation of the AtomicIntrinsics<T>::* operations for IA-32 and AMD64 systems using a
|
||
|
- * GCC-compatible compiler toolchain.
|
||
|
+ * Implementation of the AtomicIntrinsics<T>::* operations for IA-32, AMD64, and 32-bit ARM
|
||
|
+ * systems using a GCC-compatible compiler toolchain.
|
||
|
*/
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
#include <boost/utility.hpp>
|
||
|
|
||
|
+#if defined(__arm__)
|
||
|
+typedef int (__kuser_cmpxchg_t)(int oldval, int newval, volatile int *ptr);
|
||
|
+#define __kuser_cmpxchg (*(__kuser_cmpxchg_t *)0xffff0fc0)
|
||
|
+#endif
|
||
|
+
|
||
|
namespace mongo {
|
||
|
|
||
|
/**
|
||
|
@@ -37,31 +42,58 @@ namespace mongo {
|
||
|
static T compareAndSwap(volatile T* dest, T expected, T newValue) {
|
||
|
|
||
|
T result;
|
||
|
+
|
||
|
+#if defined(__i386__) || defined(__x86_64__)
|
||
|
asm volatile ("lock cmpxchg %[src], %[dest]"
|
||
|
: [dest] "+m" (*dest),
|
||
|
"=a" (result)
|
||
|
: [src] "r" (newValue),
|
||
|
"a" (expected)
|
||
|
: "memory", "cc");
|
||
|
+#endif
|
||
|
+
|
||
|
+#if defined(__arm__)
|
||
|
+ result = __sync_val_compare_and_swap(dest, expected, newValue);
|
||
|
+#endif
|
||
|
+
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
static T swap(volatile T* dest, T newValue) {
|
||
|
|
||
|
T result = newValue;
|
||
|
+
|
||
|
+#if defined(__i386__) || defined(__x86_64__)
|
||
|
// No need for "lock" prefix on "xchg".
|
||
|
asm volatile ("xchg %[r], %[dest]"
|
||
|
: [dest] "+m" (*dest),
|
||
|
[r] "+r" (result)
|
||
|
:
|
||
|
: "memory");
|
||
|
+#endif
|
||
|
+
|
||
|
+#if defined(__arm__)
|
||
|
+ __sync_synchronize();
|
||
|
+ result = __sync_lock_test_and_set(dest, newValue);
|
||
|
+#endif
|
||
|
+
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
static T load(volatile const T* value) {
|
||
|
+
|
||
|
+#if defined(__i386__) || defined(__x86_64__)
|
||
|
asm volatile ("mfence" ::: "memory");
|
||
|
T result = *value;
|
||
|
asm volatile ("mfence" ::: "memory");
|
||
|
+#endif
|
||
|
+
|
||
|
+#if defined(__arm__)
|
||
|
+ asm volatile("mcr p15, 0, r0, c7, c10, 5");
|
||
|
+ T result = *value;
|
||
|
+ asm volatile("mcr p15, 0, r0, c7, c10, 5");
|
||
|
+#endif
|
||
|
+
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
@@ -70,19 +102,44 @@ namespace mongo {
|
||
|
}
|
||
|
|
||
|
static void store(volatile T* dest, T newValue) {
|
||
|
+
|
||
|
+#if defined(__i386__) || defined(__x86_64__)
|
||
|
asm volatile ("mfence" ::: "memory");
|
||
|
*dest = newValue;
|
||
|
asm volatile ("mfence" ::: "memory");
|
||
|
+#endif
|
||
|
+
|
||
|
+#if defined(__arm__)
|
||
|
+ asm volatile("mcr p15, 0, r0, c7, c10, 5");
|
||
|
+ *dest = newValue;
|
||
|
+ asm volatile("mcr p15, 0, r0, c7, c10, 5");
|
||
|
+#endif
|
||
|
+
|
||
|
}
|
||
|
|
||
|
static T fetchAndAdd(volatile T* dest, T increment) {
|
||
|
|
||
|
T result = increment;
|
||
|
+
|
||
|
+#if defined(__i386__) || defined(__x86_64__)
|
||
|
asm volatile ("lock xadd %[src], %[dest]"
|
||
|
: [dest] "+m" (*dest),
|
||
|
[src] "+r" (result)
|
||
|
:
|
||
|
: "memory", "cc");
|
||
|
+#endif
|
||
|
+
|
||
|
+#if defined(__arm__)
|
||
|
+ int old;
|
||
|
+
|
||
|
+ do {
|
||
|
+ old = (int)(*dest);
|
||
|
+ } while(__kuser_cmpxchg((int)old, (int)(old+increment),
|
||
|
+ (volatile int *)dest));
|
||
|
+
|
||
|
+ result = old;
|
||
|
+#endif
|
||
|
+
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
@@ -105,6 +162,8 @@ namespace mongo {
|
||
|
public:
|
||
|
static T compareAndSwap(volatile T* dest, T expected, T newValue) {
|
||
|
T result = expected;
|
||
|
+
|
||
|
+#if defined(__i386__) || defined(__x86_64__)
|
||
|
asm volatile ("push %%eax\n"
|
||
|
"push %%ebx\n"
|
||
|
"push %%ecx\n"
|
||
|
@@ -125,6 +184,12 @@ namespace mongo {
|
||
|
"D" (&result),
|
||
|
"d" (&newValue)
|
||
|
: "memory", "cc");
|
||
|
+#endif
|
||
|
+
|
||
|
+#if defined(__arm__)
|
||
|
+ result = __sync_val_compare_and_swap(dest, expected, newValue);
|
||
|
+#endif
|
||
|
+
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
diff --git src/mongo/platform/bits.h src/mongo/platform/bits.h
|
||
|
index 7afc428..75343dd 100644
|
||
|
--- src/mongo/platform/bits.h
|
||
|
+++ src/mongo/platform/bits.h
|
||
|
@@ -21,7 +21,7 @@
|
||
|
|
||
|
#if defined(__x86_64__) || defined(__amd64__) || defined(_WIN64)
|
||
|
#define MONGO_PLATFORM_64
|
||
|
-#elif defined(__i386__) || defined(_WIN32)
|
||
|
+#elif defined(__i386__) || defined(_WIN32) || defined(__arm__)
|
||
|
#define MONGO_PLATFORM_32
|
||
|
#else
|
||
|
#error "unknown platform"
|