0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-11-30 17:10:48 +01:00

SERVER-6018 Use gcc __sync primitives if they are available and useable

This commit is contained in:
Andrew Morrow 2014-05-14 10:41:00 -04:00
parent 9df8f46db0
commit 1134c0d1fc
6 changed files with 156 additions and 13 deletions

View File

@ -1441,17 +1441,52 @@ def doConfigure(myenv):
return 0;
}
"""
context.Message('Checking for gcc atomic builtins... ')
context.Message('Checking for gcc __atomic builtins... ')
ret = context.TryLink(textwrap.dedent(test_body), '.cpp')
context.Result(ret)
return ret
def CheckGCCSyncBuiltins(context):
test_body = """
int main(int argc, char **argv) {
int a = 0;
return __sync_fetch_and_add(&a, 1);
}
//
// Figure out if we are using gcc older than 4.2 to target 32-bit x86. If so, error out
// even if we were able to compile the __sync statement, due to
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=40693
//
#if defined(__i386__)
#if !defined(__clang__)
#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 2)
#error "Refusing to use __sync in 32-bit mode with gcc older than 4.2"
#endif
#endif
#endif
"""
context.Message('Checking for useable __sync builtins... ')
ret = context.TryLink(textwrap.dedent(test_body), '.cpp')
context.Result(ret)
return ret
conf = Configure(myenv, help=False, custom_tests = {
'CheckGCCAtomicBuiltins': CheckGCCAtomicBuiltins,
'CheckGCCSyncBuiltins': CheckGCCSyncBuiltins,
})
haveGCCAtomicBuiltins = conf.CheckGCCAtomicBuiltins()
conf.Finish()
if haveGCCAtomicBuiltins:
conf.env.Append(CPPDEFINES=["HAVE_GCC_ATOMIC_BUILTINS"])
# Prefer the __atomic builtins. If we don't have those, try for __sync. Otherwise
# atomic_intrinsics.h will try to fall back to the hand-rolled assembly implementations
# in atomic_intrinsics_gcc_intel for x86 platforms.
if conf.CheckGCCAtomicBuiltins():
conf.env.Append(CPPDEFINES=["MONGO_HAVE_GCC_ATOMIC_BUILTINS"])
else:
if conf.CheckGCCSyncBuiltins():
conf.env.Append(CPPDEFINES=["MONGO_HAVE_GCC_SYNC_BUILTINS"])
myenv = conf.Finish()
conf = Configure(myenv)
libdeps.setup_conftests(conf)

View File

@ -54,14 +54,12 @@
#if defined(_WIN32)
#include "mongo/platform/atomic_intrinsics_win32.h"
#elif defined(__GNUC__)
#if defined(HAVE_GCC_ATOMIC_BUILTINS)
#include "mongo/platform/atomic_intrinsics_gcc_generic.h"
#elif defined(MONGO_HAVE_GCC_ATOMIC_BUILTINS)
#include "mongo/platform/atomic_intrinsics_gcc_atomic.h"
#elif defined(MONGO_HAVE_GCC_SYNC_BUILTINS)
#include "mongo/platform/atomic_intrinsics_gcc_sync.h"
#elif defined(__i386__) || defined(__x86_64__)
#include "mongo/platform/atomic_intrinsics_gcc_intel.h"
#else
#error "Unsupported platform: no gcc atomic builtins or port available"
#endif
#else
#error "Unsupported os/compiler family"
#endif

View File

@ -32,8 +32,6 @@
#pragma once
#include <boost/utility.hpp>
namespace mongo {
/**

View File

@ -0,0 +1,110 @@
/* Copyright 2014 10gen Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Implementation of the AtomicIntrinsics<T>::* operations for systems on any
* architecture using a GCC 4.1+ compatible compiler toolchain.
*/
#pragma once
#include <boost/utility.hpp>
namespace mongo {
/**
* Instantiation of AtomicIntrinsics<> for all word types T.
*/
template <typename T, typename IsTLarge=void>
class AtomicIntrinsics {
public:
static T compareAndSwap(volatile T* dest, T expected, T newValue) {
return __sync_val_compare_and_swap(dest, expected, newValue);
}
static T swap(volatile T* dest, T newValue) {
T currentValue = *dest;
while (true) {
const T result = compareAndSwap(dest, currentValue, newValue);
if (result == currentValue)
return result;
currentValue = result;
}
}
static T load(volatile const T* value) {
__sync_synchronize();
T result = *value;
__sync_synchronize();
return result;
}
static T loadRelaxed(volatile const T* value) {
asm volatile("" ::: "memory");
return *value;
}
static void store(volatile T* dest, T newValue) {
__sync_synchronize();
*dest = newValue;
__sync_synchronize();
}
static T fetchAndAdd(volatile T* dest, T increment) {
return __sync_fetch_and_add(dest, increment);
}
private:
AtomicIntrinsics();
~AtomicIntrinsics();
};
template <typename T>
class AtomicIntrinsics<T, typename boost::disable_if_c<sizeof(T) <= sizeof(void*)>::type> {
public:
static T compareAndSwap(volatile T* dest, T expected, T newValue) {
return __sync_val_compare_and_swap(dest, expected, newValue);
}
static T swap(volatile T* dest, T newValue) {
T currentValue = *dest;
while (true) {
const T result = compareAndSwap(dest, currentValue, newValue);
if (result == currentValue)
return result;
currentValue = result;
}
}
static T load(volatile const T* value) {
return compareAndSwap(const_cast<volatile T*>(value), T(0), T(0));
}
static void store(volatile T* dest, T newValue) {
swap(dest, newValue);
}
static T fetchAndAdd(volatile T* dest, T increment) {
return __sync_fetch_and_add(dest, increment);
}
private:
AtomicIntrinsics();
~AtomicIntrinsics();
};
} // namespace mongo

View File

@ -30,6 +30,7 @@
#pragma once
#include <boost/scoped_ptr.hpp>
#include <boost/utility.hpp>
#include <string>
#include <vector>

View File

@ -38,6 +38,7 @@
#include <boost/scoped_array.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
#include "mongo/bson/util/misc.h"