Commit 3926d7a1 by Marcus Winter

full implementation of threading analysis mode

parent 8aa76fe9
......@@ -68,8 +68,6 @@ int compute1_() {
}
PT_MAIN("Algorithms") {
embb_atomic_initialize();
embb::mtapi::Node::Initialize(THIS_DOMAIN_ID, THIS_NODE_ID);
PT_RUN(PartitionerTest);
......@@ -85,6 +83,4 @@ PT_MAIN("Algorithms") {
embb::mtapi::Node::Finalize();
PT_EXPECT(embb_get_bytes_allocated() == 0);
embb_atomic_finalize();
}
......@@ -295,6 +295,12 @@ extern "C" {
#include <embb/base/c/internal/cmake_config.h>
#ifdef EMBB_THREADING_ANALYSIS_MODE
#include <embb/base/c/internal/platform.h>
#include <assert.h>
int embb_mutex_init(
embb_mutex_t* mutex,
int type
);
int embb_mutex_lock(
embb_mutex_t* mutex
......@@ -304,13 +310,20 @@ int embb_mutex_unlock(
embb_mutex_t* mutex
);
#define EMBB_ATOMIC_MUTEX_LOCK embb_mutex_lock(&embb_atomic_mutex)
#define EMBB_ATOMIC_MUTEX_UNLOCK embb_mutex_unlock(&embb_atomic_mutex)
void embb_mutex_destroy(
embb_mutex_t* mutex
);
#define EMBB_ATOMIC_MUTEX_INIT(mutex) embb_mutex_init(&(mutex), 0)
#define EMBB_ATOMIC_MUTEX_LOCK(mutex) embb_mutex_lock(&(mutex))
#define EMBB_ATOMIC_MUTEX_UNLOCK(mutex) embb_mutex_unlock(&(mutex))
#define EMBB_ATOMIC_MUTEX_DESTROY(mutex) embb_mutex_destroy(&(mutex))
#define EMBB_ATOMIC_INIT_CHECK(variable) assert(variable->marker == 0x12345678)
#else
#define EMBB_ATOMIC_MUTEX_LOCK
#define EMBB_ATOMIC_MUTEX_UNLOCK
#define EMBB_ATOMIC_MUTEX_LOCK(mutex)
#define EMBB_ATOMIC_MUTEX_UNLOCK(mutex)
#endif
......@@ -318,6 +331,8 @@ int embb_mutex_unlock(
#include <embb/base/c/internal/atomic/atomic_sizes.h>
#include <embb/base/c/internal/atomic/atomic_variables.h>
#include <embb/base/c/internal/macro_helper.h>
#include <embb/base/c/internal/atomic/init.h>
#include <embb/base/c/internal/atomic/destroy.h>
#include <embb/base/c/internal/atomic/load.h>
#include <embb/base/c/internal/atomic/and_assign.h>
#include <embb/base/c/internal/atomic/store.h>
......
......@@ -69,12 +69,10 @@
#define EMBB_DEFINE_AND_ASSIGN(EMBB_PARAMETER_SIZE_BYTE, EMBB_ATOMIC_X86_SIZE_SUFFIX)\
EMBB_PLATFORM_INLINE void EMBB_CAT2(embb_internal__atomic_and_assign_, \
EMBB_PARAMETER_SIZE_BYTE)(EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) volatile* pointer_to_value, EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) value) { \
EMBB_ATOMIC_MUTEX_LOCK; \
__asm__ __volatile__("lock and" EMBB_ATOMIC_X86_SIZE_SUFFIX " %1, %0" \
: "+m" (*pointer_to_value), "+q" (value) \
: \
: "memory"); \
EMBB_ATOMIC_MUTEX_UNLOCK; \
}
#else
#error "No atomic fetch and store implementation found"
......@@ -154,8 +152,11 @@ EMBB_DEFINE_AND_ASSIGN(4, "")
EMBB_CAT2(embb_atomic_, EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX)* variable, EMBB_ATOMIC_PARAMETER_TYPE_NATIVE value) { \
EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE) value_pun;\
memcpy(&value_pun, &value, sizeof(EMBB_ATOMIC_PARAMETER_TYPE_NATIVE));\
EMBB_ATOMIC_INIT_CHECK(variable); \
EMBB_ATOMIC_MUTEX_LOCK(variable->internal_mutex); \
EMBB_CAT2(embb_internal__atomic_and_assign_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE)((EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE) volatile *) \
(&(variable->internal_variable)), value_pun); \
EMBB_ATOMIC_MUTEX_UNLOCK(variable->internal_mutex); \
}
#undef EMBB_ATOMIC_METHOD_TO_GENERATE
......
......@@ -41,6 +41,8 @@
typedef struct \
{ \
volatile EMBB_ATOMIC_PARAMETER_TYPE_NATIVE internal_variable; \
embb_mutex_t internal_mutex; \
uint32_t marker; \
} EMBB_CAT2(embb_atomic_, EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX);
EMBB_ATOMIC_INTERNAL_DEFINE_VARIABLE(char, char)
......@@ -58,16 +60,4 @@ EMBB_ATOMIC_INTERNAL_DEFINE_VARIABLE(size_t, size_t)
EMBB_ATOMIC_INTERNAL_DEFINE_VARIABLE(ptrdiff_t, ptrdiff_t)
EMBB_ATOMIC_INTERNAL_DEFINE_VARIABLE(uintmax_t, uintmax_t)
#ifdef EMBB_THREADING_ANALYSIS_MODE
#include <embb/base/c/mutex.h>
extern embb_mutex_t embb_atomic_mutex;
void embb_atomic_initialize();
void embb_atomic_finalize();
#else
#define embb_atomic_initialize()
#define embb_atomic_finalize()
#endif
#endif //EMBB_BASE_C_INTERNAL_ATOMIC_ATOMIC_VARIABLES_H_
......@@ -58,7 +58,6 @@
EMBB_PLATFORM_INLINE int EMBB_CAT2(embb_internal__atomic_compare_and_swap_, \
EMBB_PARAMETER_SIZE_BYTE)(EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) volatile* pointer_to_value, EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) volatile* expected, \
EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) desired) { \
EMBB_ATOMIC_MUTEX_LOCK; \
char result; \
__asm__ __volatile__ ("lock cmpxchg" EMBB_ATOMIC_X86_SIZE_SUFFIX\
" %3, %0 \n\t" \
......@@ -66,7 +65,6 @@
: "+m" (*pointer_to_value), "+a" (*expected), "=q" (result) \
: "q" (desired) \
: "memory", "cc" ); \
EMBB_ATOMIC_MUTEX_UNLOCK; \
return result; \
}
#else
......@@ -140,8 +138,12 @@ EMBB_DEFINE_COMPARE_AND_SWAP(4, "")
EMBB_CAT2(embb_atomic_, EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX)* variable, EMBB_ATOMIC_PARAMETER_TYPE_NATIVE* expected, EMBB_ATOMIC_PARAMETER_TYPE_NATIVE desired) {\
EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE) desired_pun;\
memcpy(&desired_pun, &desired, sizeof(EMBB_ATOMIC_PARAMETER_TYPE_NATIVE));\
return EMBB_CAT2(embb_internal__atomic_compare_and_swap_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE)((EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE) volatile *) \
EMBB_ATOMIC_INIT_CHECK(variable); \
EMBB_ATOMIC_MUTEX_LOCK(variable->internal_mutex); \
int result = EMBB_CAT2(embb_internal__atomic_compare_and_swap_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE)((EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE) volatile *) \
(&(variable->internal_variable)), (EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE) volatile *) expected, desired_pun); \
EMBB_ATOMIC_MUTEX_UNLOCK(variable->internal_mutex); \
return result;\
}
#undef EMBB_ATOMIC_METHOD_TO_GENERATE
......
/*
* Copyright (c) 2014-2016, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef EMBB_BASE_C_INTERNAL_ATOMIC_DESTROY_H_
#define EMBB_BASE_C_INTERNAL_ATOMIC_DESTROY_H_
#ifndef DOXYGEN
#include <embb/base/c/internal/config.h>
#include <embb/base/c/internal/atomic/atomic_sizes.h>
#include <embb/base/c/internal/macro_helper.h>
#include <embb/base/c/internal/atomic/atomic_variables.h>
#include <string.h>
/*
* See file and_assign.h for a detailed (and operation independent) description
* of the following macro.
*/
#define EMBB_ATOMIC_INTERNAL_DEFINE_DESTROY_METHOD(EMBB_ATOMIC_PARAMETER_TYPE_NATIVE, EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX, EMBB_ATOMIC_PARAMETER_TYPE_SIZE) \
EMBB_PLATFORM_INLINE void EMBB_CAT2(embb_atomic_destroy_, EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX)(\
EMBB_CAT2(embb_atomic_, EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX)* variable) { \
EMBB_ATOMIC_INIT_CHECK(variable); \
EMBB_ATOMIC_MUTEX_DESTROY(variable->internal_mutex); \
}
#undef EMBB_ATOMIC_METHOD_TO_GENERATE
#define EMBB_ATOMIC_METHOD_TO_GENERATE DESTROY_METHOD
#include <embb/base/c/internal/atomic/generate_atomic_implementation_template.h>
#undef EMBB_ATOMIC_METHOD_TO_GENERATE
#endif //DOXYGEN
#endif //EMBB_BASE_C_INTERNAL_ATOMIC_INIT_H_
......@@ -57,12 +57,10 @@
#define EMBB_DEFINE_FETCH_AND_ADD(EMBB_PARAMETER_SIZE_BYTE, EMBB_ATOMIC_X86_SIZE_SUFFIX) \
EMBB_PLATFORM_INLINE EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) EMBB_CAT2(embb_internal__atomic_fetch_and_add_, EMBB_PARAMETER_SIZE_BYTE) \
(EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) volatile* pointer_to_value, EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) new_value) { \
EMBB_ATOMIC_MUTEX_LOCK; \
__asm__ __volatile__ ("lock xadd" EMBB_ATOMIC_X86_SIZE_SUFFIX " %1, %0" \
: "+m" (*pointer_to_value), "+q" (new_value) \
: \
: "memory", "cc" ); \
EMBB_ATOMIC_MUTEX_UNLOCK; \
return new_value; \
}
#else
......@@ -109,9 +107,6 @@ EMBB_DEFINE_FETCH_AND_ADD(8, "q")
: "memory", "cc" ); \
return result; \
}
/* return __sync_fetch_and_add( \
pointer_to_value, new_value); \
}*/
#else
#error "No atomic fetch and store implementation found"
#endif
......@@ -133,9 +128,12 @@ EMBB_DEFINE_FETCH_AND_ADD(4, "")
EMBB_CAT2(embb_atomic_, EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX)* variable, EMBB_ATOMIC_PARAMETER_TYPE_NATIVE value) { \
EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE) value_pun; \
memcpy(&value_pun, &value, sizeof(EMBB_ATOMIC_PARAMETER_TYPE_NATIVE)); \
EMBB_ATOMIC_INIT_CHECK(variable); \
EMBB_ATOMIC_MUTEX_LOCK(variable->internal_mutex); \
EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE) return_val = EMBB_CAT2(embb_internal__atomic_fetch_and_add_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE)(\
(EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE) volatile *)\
(&(variable->internal_variable)), value_pun); \
EMBB_ATOMIC_MUTEX_UNLOCK(variable->internal_mutex); \
EMBB_ATOMIC_PARAMETER_TYPE_NATIVE return_val_pun; \
memcpy(&return_val_pun, &return_val, sizeof(EMBB_ATOMIC_PARAMETER_TYPE_NATIVE)); \
return return_val_pun; \
......
/*
* Copyright (c) 2014-2016, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef EMBB_BASE_C_INTERNAL_ATOMIC_INIT_H_
#define EMBB_BASE_C_INTERNAL_ATOMIC_INIT_H_
#ifndef DOXYGEN
#include <embb/base/c/internal/config.h>
#include <embb/base/c/internal/atomic/atomic_sizes.h>
#include <embb/base/c/internal/macro_helper.h>
#include <embb/base/c/internal/atomic/atomic_variables.h>
#include <string.h>
/*
* See file and_assign.h for a detailed (and operation independent) description
* of the following macro.
*/
#define EMBB_ATOMIC_INTERNAL_DEFINE_INIT_METHOD(EMBB_ATOMIC_PARAMETER_TYPE_NATIVE, EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX, EMBB_ATOMIC_PARAMETER_TYPE_SIZE) \
EMBB_PLATFORM_INLINE void EMBB_CAT2(embb_atomic_init_, EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX)(\
EMBB_CAT2(embb_atomic_, EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX)* variable) { \
EMBB_ATOMIC_MUTEX_INIT(variable->internal_mutex); \
variable->marker = 0x12345678; \
}
#undef EMBB_ATOMIC_METHOD_TO_GENERATE
#define EMBB_ATOMIC_METHOD_TO_GENERATE INIT_METHOD
#include <embb/base/c/internal/atomic/generate_atomic_implementation_template.h>
#undef EMBB_ATOMIC_METHOD_TO_GENERATE
#endif //DOXYGEN
#endif //EMBB_BASE_C_INTERNAL_ATOMIC_INIT_H_
......@@ -58,14 +58,12 @@
#define EMBB_DEFINE_LOAD(EMBB_PARAMETER_SIZE_BYTE, EMBB_ATOMIC_X86_SIZE_SUFFIX) \
EMBB_PLATFORM_INLINE EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) \
EMBB_CAT2(embb_internal__atomic_load_, EMBB_PARAMETER_SIZE_BYTE)(EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) volatile* pointer_to_value) { \
EMBB_ATOMIC_MUTEX_LOCK; \
/* no fence required for loads */ \
EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) result; \
__asm__ __volatile__("mov" EMBB_ATOMIC_X86_SIZE_SUFFIX " %1, %0" \
: "=q" (result) \
: "m" (*pointer_to_value) \
: "memory"); \
EMBB_ATOMIC_MUTEX_UNLOCK; \
return result; \
}
#else
......@@ -121,10 +119,13 @@ EMBB_DEFINE_LOAD(4, "")
*/
#define EMBB_ATOMIC_INTERNAL_DEFINE_LOAD_METHOD(EMBB_ATOMIC_PARAMETER_TYPE_NATIVE, EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX, EMBB_ATOMIC_PARAMETER_TYPE_SIZE) \
EMBB_PLATFORM_INLINE EMBB_ATOMIC_PARAMETER_TYPE_NATIVE EMBB_CAT2(embb_atomic_load_, EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX)(\
const EMBB_CAT2(embb_atomic_, EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX)* variable) { \
EMBB_CAT2(embb_atomic_, EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX)* variable) { \
EMBB_ATOMIC_INIT_CHECK(variable); \
EMBB_ATOMIC_MUTEX_LOCK(variable->internal_mutex); \
EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE) \
return_val = (EMBB_CAT2(embb_internal__atomic_load_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE)(\
(EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE) volatile *)(&(variable->internal_variable)))); \
EMBB_ATOMIC_MUTEX_UNLOCK(variable->internal_mutex); \
EMBB_ATOMIC_PARAMETER_TYPE_NATIVE return_val_pun; \
memcpy(&return_val_pun, &return_val, sizeof(EMBB_ATOMIC_PARAMETER_TYPE_NATIVE)); \
return return_val_pun; \
......
......@@ -56,12 +56,10 @@
#define EMBB_DEFINE_OR_ASSIGN(EMBB_PARAMETER_SIZE_BYTE, EMBB_ATOMIC_X86_SIZE_SUFFIX) \
EMBB_PLATFORM_INLINE void EMBB_CAT2(embb_internal__atomic_or_assign_, EMBB_PARAMETER_SIZE_BYTE)(\
EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) volatile* pointer_to_value, EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) value) { \
EMBB_ATOMIC_MUTEX_LOCK; \
__asm__ __volatile__("lock or" EMBB_ATOMIC_X86_SIZE_SUFFIX " %1, %0" \
: "+m" (*pointer_to_value), "+q" (value) \
: \
: "memory"); \
EMBB_ATOMIC_MUTEX_UNLOCK; \
}
#else
......@@ -125,8 +123,11 @@ EMBB_DEFINE_OR_ASSIGN(4, "")
EMBB_PLATFORM_INLINE void EMBB_CAT2(embb_atomic_or_assign_, EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX)(EMBB_CAT2(embb_atomic_, EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX)* variable, EMBB_ATOMIC_PARAMETER_TYPE_NATIVE value) { \
EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE) value_pun;\
memcpy(&value_pun, &value, sizeof(EMBB_ATOMIC_PARAMETER_TYPE_NATIVE));\
EMBB_ATOMIC_INIT_CHECK(variable); \
EMBB_ATOMIC_MUTEX_LOCK(variable->internal_mutex); \
EMBB_CAT2(embb_internal__atomic_or_assign_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE)((EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE) volatile *)\
(&(variable->internal_variable)), value_pun); \
EMBB_ATOMIC_MUTEX_UNLOCK(variable->internal_mutex); \
}
#undef EMBB_ATOMIC_METHOD_TO_GENERATE
......
......@@ -57,13 +57,11 @@
#define EMBB_DEFINE_STORE(EMBB_PARAMETER_SIZE_BYTE, EMBB_ATOMIC_X86_SIZE_SUFFIX)\
EMBB_PLATFORM_INLINE void EMBB_CAT2(embb_internal__atomic_store_, EMBB_PARAMETER_SIZE_BYTE)(EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) volatile* pointer_to_value, \
EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) new_value) {\
EMBB_ATOMIC_MUTEX_LOCK; \
/*the lock prefix is implicit for xchg*/ \
__asm__ __volatile__("xchg" EMBB_ATOMIC_X86_SIZE_SUFFIX " %1, %0" \
: "+m" (*pointer_to_value), "+q" (new_value) \
: \
: "memory"); \
EMBB_ATOMIC_MUTEX_UNLOCK; \
}
#else
#error "No atomic fetch and store implementation found"
......@@ -120,8 +118,11 @@ EMBB_DEFINE_STORE(4, "")
EMBB_PLATFORM_INLINE void EMBB_CAT2(embb_atomic_store_, EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX)(EMBB_CAT2(embb_atomic_, EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX)* variable, EMBB_ATOMIC_PARAMETER_TYPE_NATIVE value) { \
EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE) value_pun; \
memcpy(&value_pun, &value, sizeof(EMBB_ATOMIC_PARAMETER_TYPE_NATIVE)); \
EMBB_ATOMIC_INIT_CHECK(variable); \
EMBB_ATOMIC_MUTEX_LOCK(variable->internal_mutex); \
EMBB_CAT2(embb_internal__atomic_store_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE)((EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE) volatile *)\
(&(variable->internal_variable)), value_pun); \
EMBB_ATOMIC_MUTEX_UNLOCK(variable->internal_mutex); \
}
#undef EMBB_ATOMIC_METHOD_TO_GENERATE
......
......@@ -58,13 +58,11 @@
EMBB_PLATFORM_INLINE EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) EMBB_CAT2(embb_internal__atomic_swap_, EMBB_PARAMETER_SIZE_BYTE)(\
EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) volatile* pointer_to_value, EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) new_value)\
{ \
EMBB_ATOMIC_MUTEX_LOCK; \
/*the lock prefix is implicit for xchg*/ \
__asm__ __volatile__("xchg" EMBB_ATOMIC_X86_SIZE_SUFFIX " %1, %0" \
: "+m" (*pointer_to_value), "+q" (new_value) \
: \
: "memory"); \
EMBB_ATOMIC_MUTEX_UNLOCK; \
return new_value; \
}
#else
......@@ -129,8 +127,11 @@ EMBB_DEFINE_SWAP(4, "")
EMBB_CAT2(embb_atomic_, EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX)* variable, EMBB_ATOMIC_PARAMETER_TYPE_NATIVE value) { \
EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE) value_pun; \
memcpy(&value_pun, &value, sizeof(EMBB_ATOMIC_PARAMETER_TYPE_NATIVE)); \
EMBB_ATOMIC_INIT_CHECK(variable); \
EMBB_ATOMIC_MUTEX_LOCK(variable->internal_mutex); \
EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE) \
return_val = EMBB_CAT2(embb_internal__atomic_swap_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE)((EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE) volatile *)(&(variable->internal_variable)), value_pun); \
EMBB_ATOMIC_MUTEX_UNLOCK(variable->internal_mutex); \
EMBB_ATOMIC_PARAMETER_TYPE_NATIVE return_val_pun; \
memcpy(&return_val_pun, &return_val, sizeof(EMBB_ATOMIC_PARAMETER_TYPE_NATIVE)); \
return return_val_pun; \
......
......@@ -57,12 +57,10 @@
EMBB_PLATFORM_INLINE void EMBB_CAT2(embb_internal__atomic_xor_assign_, EMBB_PARAMETER_SIZE_BYTE)(\
EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) volatile* pointer_to_value, \
EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) value) { \
EMBB_ATOMIC_MUTEX_LOCK; \
__asm__ __volatile__("lock xor" EMBB_ATOMIC_X86_SIZE_SUFFIX " %1, %0" \
: "+m" (*pointer_to_value), "+q" (value) \
: \
: "memory"); \
EMBB_ATOMIC_MUTEX_UNLOCK; \
}
#else
......@@ -127,8 +125,11 @@ EMBB_DEFINE_XOR_ASSIGN(4, "")
EMBB_CAT2(embb_atomic_, EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX)* variable, EMBB_ATOMIC_PARAMETER_TYPE_NATIVE value) { \
EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE) value_pun;\
memcpy(&value_pun, &value, sizeof(EMBB_ATOMIC_PARAMETER_TYPE_NATIVE));\
EMBB_ATOMIC_INIT_CHECK(variable); \
EMBB_ATOMIC_MUTEX_LOCK(variable->internal_mutex); \
EMBB_CAT2(embb_internal__atomic_xor_assign_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE)((EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_ATOMIC_PARAMETER_TYPE_SIZE) volatile *)\
(&(variable->internal_variable)), value_pun); \
EMBB_ATOMIC_MUTEX_UNLOCK(variable->internal_mutex); \
}
#undef EMBB_ATOMIC_METHOD_TO_GENERATE
......
......@@ -46,17 +46,3 @@ void __embb_atomic_internal_compile_time_checks() {
BUILD_BUG_ON(sizeof(ptrdiff_t) != EMBB_PTRDIFF_T_TYPE_SIZE);
BUILD_BUG_ON(sizeof(uintmax_t) != EMBB_UINTMAX_T_TYPE_SIZE);
}
#ifdef EMBB_THREADING_ANALYSIS_MODE
embb_mutex_t embb_atomic_mutex;
void embb_atomic_initialize() {
embb_mutex_init(&embb_atomic_mutex, EMBB_MUTEX_PLAIN);
}
void embb_atomic_finalize() {
embb_mutex_destroy(&embb_atomic_mutex);
}
#endif
......@@ -33,6 +33,7 @@ int embb_counter_init(embb_counter_t* counter) {
if (counter == NULL) {
return EMBB_ERROR;
}
embb_atomic_init_unsigned_int(&(counter->value));
embb_atomic_store_unsigned_int(&(counter->value), 0);
return EMBB_SUCCESS;
}
......@@ -55,7 +56,7 @@ unsigned int embb_counter_decrement(embb_counter_t* counter) {
void embb_counter_destroy(embb_counter_t* counter) {
assert(counter != NULL);
EMBB_UNUSED_IN_RELEASE(counter);
embb_atomic_destroy_unsigned_int(&(counter->value));
}
......@@ -40,18 +40,18 @@
* This function has local scope.
*/
static int embb_max_number_thread_indices_max = 0;
static embb_atomic_int embb_max_number_thread_indices_flag = { 0 };
static EMBB_BASE_BASIC_TYPE_SIZE_4 embb_max_number_thread_indices_flag = 0;
unsigned int* embb_max_number_thread_indices() {
int compare_to = 0;
if (embb_atomic_load_int(&embb_max_number_thread_indices_flag) != 2) {
if (embb_atomic_compare_and_swap_int(
EMBB_BASE_BASIC_TYPE_SIZE_4 compare_to = 0;
if (embb_internal__atomic_load_4(&embb_max_number_thread_indices_flag) != 2) {
if (embb_internal__atomic_compare_and_swap_4(
&embb_max_number_thread_indices_flag, &compare_to, 1)) {
embb_max_number_thread_indices_max =
(int)(embb_core_count_available() * 2);
embb_atomic_store_int(&embb_max_number_thread_indices_flag, 2);
embb_internal__atomic_store_4(&embb_max_number_thread_indices_flag, 2);
}
while (embb_atomic_load_int(&embb_max_number_thread_indices_flag) != 2) {}
while (embb_internal__atomic_load_4(&embb_max_number_thread_indices_flag) != 2) {}
}
return (unsigned int*) &embb_max_number_thread_indices_max;
}
......@@ -61,17 +61,17 @@ unsigned int* embb_max_number_thread_indices() {
*
* This function has local scope.
*/
static embb_atomic_int embb_thread_index_counter_flag = { 0 };
static EMBB_BASE_BASIC_TYPE_SIZE_4 embb_thread_index_counter_flag = 0;
static embb_counter_t embb_thread_index_counter_index;
embb_counter_t* embb_thread_index_counter() {
int compare_to = 0;
if (embb_atomic_load_int(&embb_thread_index_counter_flag) != 2) {
if (embb_atomic_compare_and_swap_int(
EMBB_BASE_BASIC_TYPE_SIZE_4 compare_to = 0;
if (embb_internal__atomic_load_4(&embb_thread_index_counter_flag) != 2) {
if (embb_internal__atomic_compare_and_swap_4(
&embb_thread_index_counter_flag, &compare_to, 1)) {
embb_counter_init(&embb_thread_index_counter_index);
embb_atomic_store_int(&embb_thread_index_counter_flag, 2);
embb_internal__atomic_store_4(&embb_thread_index_counter_flag, 2);
}
while (embb_atomic_load_int(&embb_thread_index_counter_flag) != 2) {}
while (embb_internal__atomic_load_4(&embb_thread_index_counter_flag) != 2) {}
}
return &embb_thread_index_counter_index;
}
......
......@@ -33,7 +33,7 @@
#ifdef EMBB_DEBUG
static embb_atomic_long embb_bytes_allocated = { 0 };
static EMBB_BASE_BASIC_TYPE_SIZE_4 embb_bytes_allocated = 0;
enum {
// Make the marking unlikely to be something else
......@@ -49,7 +49,7 @@ void* embb_alloc(size_t bytes) {
if (allocated == NULL)
return NULL;
embb_atomic_fetch_and_add_long(
embb_internal__atomic_fetch_and_add_4(
&embb_bytes_allocated, (long)bytes_to_allocate);
size_t* x_as_size_type = (size_t*)allocated;
......@@ -72,7 +72,7 @@ void embb_free(void * ptr) {
(*alloc_type) = (size_t)INVALID_ALLOCATION;
embb_atomic_fetch_and_add_long(
embb_internal__atomic_fetch_and_add_4(
&embb_bytes_allocated, (long)(0 - (size_t)(*bytes_allocated)));
free((size_t*)ptr - 2);
......@@ -127,7 +127,7 @@ void* embb_alloc_aligned(size_t alignment, size_t size) {
x_as_size_type[-2] = (size_t)allocated;
x_as_size_type[-3] = bytes_to_allocate;
embb_atomic_fetch_and_add_long(
embb_internal__atomic_fetch_and_add_4(
&embb_bytes_allocated, (long)bytes_to_allocate);
return x;
......@@ -144,14 +144,14 @@ void embb_free_aligned(void* ptr) {
ptr_conv[-1] = (size_t)INVALID_ALLOCATION;
embb_atomic_fetch_and_add_long(
embb_internal__atomic_fetch_and_add_4(
&embb_bytes_allocated, (long)((long)0 - ptr_conv[-3]));
free((void*)ptr_conv[-2]);
}
size_t embb_get_bytes_allocated() {
return (size_t)(embb_atomic_load_long(&embb_bytes_allocated));
return (size_t)(embb_internal__atomic_load_4(&embb_bytes_allocated));
}
#else // EMBB_DEBUG
......
......@@ -149,6 +149,7 @@ int embb_spin_init(embb_spinlock_t* spinlock) {
}
// For now, store the initial value. In the future will use atomic init
// function (as soon as available).
embb_atomic_init_int(&spinlock->atomic_spin_variable_);
embb_atomic_store_int(&spinlock->atomic_spin_variable_, 0);
return EMBB_SUCCESS;
}
......@@ -207,7 +208,5 @@ int embb_spin_unlock(embb_spinlock_t* spinlock) {
void embb_spin_destroy(embb_spinlock_t* spinlock) {
assert(NULL != spinlock);
// for now, doing nothing here... in future, will call the respective
// destroy function for atomics...
EMBB_UNUSED(spinlock);
embb_atomic_destroy_int(&spinlock->atomic_spin_variable_);
}
......@@ -55,8 +55,6 @@ using embb::base::test::ThreadTest;
using embb::base::test::ThreadSpecificStorageTest;
PT_MAIN("Base C") {
embb_atomic_initialize();
embb_log_set_log_level(EMBB_LOG_LEVEL_WARNING);
unsigned int max_threads =
static_cast<unsigned int>(2 * partest::TestSuite::GetDefaultNumThreads());
......@@ -74,6 +72,4 @@ PT_MAIN("Base C") {
PT_RUN(ThreadTest);
PT_RUN(ThreadSpecificStorageTest);
PT_EXPECT(embb_get_bytes_allocated() == 0);
embb_atomic_finalize();
}
......@@ -36,13 +36,22 @@ namespace embb {
namespace base {
namespace test {
embb_atomic_int flag;
ThreadIndexTest::ThreadIndexTest()
: number_threads_(partest::TestSuite::GetDefaultNumThreads()) {
embb_atomic_init_int(&flag);
embb_atomic_store_int(&flag, 1);
CreateUnit("Test 0 indices").Add(&ThreadIndexTest::Test0, this);
CreateUnit("Test 1 index").Add(&ThreadIndexTest::Test1, this);
CreateUnit("Test N indices").Add(&ThreadIndexTest::TestN, this, 1);
}
ThreadIndexTest::~ThreadIndexTest() {
embb_atomic_destroy_int(&flag);
}
void ThreadIndexTest::Test0() {
embb_internal_thread_index_reset();
unsigned int old_max = embb_thread_get_max_count();
......@@ -78,8 +87,6 @@ void ThreadIndexTest::Test1() {
embb_internal_thread_index_set_max(old_max);
}
embb_atomic_int flag = { 1 };
void ThreadIndexTest::TestN() {
embb_internal_thread_index_reset();
unsigned int old_max = embb_thread_get_max_count();
......@@ -106,6 +113,8 @@ void ThreadIndexTest::TestN() {
embb_thread_join(&thread, NULL);
delete[] threads;
embb_internal_thread_index_set_max(old_max);
embb_atomic_destroy_int(&flag);
}
int ThreadStart(void* arg) {
......
......@@ -36,10 +36,15 @@ namespace test {
class ThreadIndexTest : public partest::TestCase {
public:
/**
* Adds test methods.
* Adds test methods and allocates temporary data.
*/
ThreadIndexTest();
/**
* Destroys temporary data.
*/
~ThreadIndexTest();
private:
/**
* Tests 0 available indices.
......
......@@ -117,8 +117,10 @@ FetchAndAdd(DifferenceType val) {
NativeType native_desired;
memcpy(&native_desired, &desired, sizeof(desired));
EMBB_ATOMIC_MUTEX_LOCK(internal_mutex);
NativeType storage_value = fetch_and_add_implementation<NativeType>::
fetch_and_add(&this->AtomicValue, native_desired);
EMBB_ATOMIC_MUTEX_UNLOCK(internal_mutex);
memcpy(&return_value, &storage_value, sizeof(return_value));
return return_value;
......
......@@ -58,6 +58,10 @@ class AtomicBase {
mutable NativeType AtomicValue;
#ifdef EMBB_THREADING_ANALYSIS_MODE
embb_mutex_t internal_mutex;
#endif
public:
/**
* Default constructor.
......@@ -73,36 +77,48 @@ class AtomicBase {
*/
explicit AtomicBase(BaseType val);
/**
* Destructor.
*/
~AtomicBase();
// The members below are documented in atomic.h
BaseType operator=(BaseType val);
operator BaseType() const;
operator BaseType();
bool IsLockFree() const;
bool IsArithmetic() const;
bool IsInteger() const;
bool IsPointer() const;
void Store(BaseType val);
BaseType Load() const;
BaseType Load();
BaseType Swap(BaseType val);
bool CompareAndSwap(BaseType& expected, BaseType desired);
};
template<typename BaseType>
inline AtomicBase<BaseType>::AtomicBase() : AtomicValue(0) {
EMBB_ATOMIC_MUTEX_INIT(internal_mutex);
}
template<typename BaseType>
inline AtomicBase<BaseType>::AtomicBase(BaseType val) /*: AtomicValue(val)*/ {
EMBB_ATOMIC_MUTEX_INIT(internal_mutex);
memcpy(&AtomicValue, &val, sizeof(AtomicValue));
}
template<typename BaseType>
inline AtomicBase<BaseType>::~AtomicBase() {
EMBB_ATOMIC_MUTEX_DESTROY(internal_mutex);
}
template<typename BaseType>
inline BaseType AtomicBase<BaseType>::operator=(BaseType val) {
Store(val);
return val;
}
template<typename BaseType>
inline AtomicBase<BaseType>::operator BaseType() const {
inline AtomicBase<BaseType>::operator BaseType() {
return Load();
}
......@@ -132,16 +148,20 @@ inline void AtomicBase<BaseType>::Store(BaseType val) {
// anyway...
memcpy(&storage_value, &val, sizeof(storage_value));
EMBB_ATOMIC_MUTEX_LOCK(internal_mutex);
store_implementation< NativeType >
::Store(&AtomicValue, storage_value);
EMBB_ATOMIC_MUTEX_UNLOCK(internal_mutex);
}
template<typename BaseType>
inline BaseType AtomicBase<BaseType>::Load() const {
inline BaseType AtomicBase<BaseType>::Load() {
BaseType return_value;
EMBB_ATOMIC_MUTEX_LOCK(internal_mutex);
NativeType storage_value =
load_implementation< NativeType >::Load(&AtomicValue);