Commit acdffd5a by Marcus Winter

Merge branch 'embb517_mutex_based_atomics' into development

# Conflicts:
#	README.md
parents 56b1fd02 8d67be2e
......@@ -85,6 +85,7 @@ option(INSTALL_DOCS "Specify whether Doxygen docs should be installed" ON)
option(WARNINGS_ARE_ERRORS "Specify whether warnings should be treated as errors" OFF)
option(USE_AUTOMATIC_INITIALIZATION "Specify whether the MTAPI C++ interface, algorithms and dataflow should automatically intialize the MTAPI node if no explicit initialization is present" ON)
option(BUILD_OPENCL_PLUGIN "Specify whether the MTAPI OpenCL plugin should be built" OFF)
option(THREADING_ANALYSIS_MODE "Replaces lock-free synchronization constructs by mutex-based implementations to support threading analysis tools" OFF)
## LOCAL INSTALLATION OF SUBPROJECT BINARIES
#
......@@ -106,6 +107,14 @@ else()
endif()
message(" (set with command line option -DUSE_AUTOMATIC_INITIALIZATION=ON/OFF)")
if (THREADING_ANALYSIS_MODE STREQUAL ON)
set(EMBB_THREADING_ANALYSIS_MODE 1)
message("-- Threading analysis mode enabled")
else()
message("-- Threading analysis mode disabled (default")
endif()
message(" (set with command line option -DTHREADING_ANALYSIS_MODE=ON/OFF)")
include(CMakeCommon/SetCompilerFlags.cmake)
SetGNUCompilerFlags(compiler_libs compiler_flags)
SetVisualStudioCompilerFlags(compiler_libs compiler_flags)
......
......@@ -125,6 +125,9 @@ EMB² can be built with C++ exception handling (default) or without exceptions.
Similarly, automatic initialization of the task scheduler by the MTAPI C++ interface can be disabled with `-DUSE_AUTOMATIC_INITIALIZATION=OFF`. This way, unexpected delays after startup can be avoided, e.g. for timing measurements.
Furthermore, EMB² can be built to work with threading analysis tools such as Helgrind or ThreadSanitizer with -DTHREADING_ANALYSIS_MODE=ON. This uses mutexes around atomics to avoid false positives but degrades performance significantly.
The tutorial of EMB² comes with a number of examples in `doc/examples/`. These can be built with the other source files using the option `-DBUILD_EXAMPLES=ON`. Note, however, that the examples use C++11 features and require an appropriate compiler.
By default, the included unit tests are built as part of the installation process. To override the default behavior, add the option `-DBUILD_TESTS=OFF`.
......
......@@ -46,6 +46,8 @@
#include <functional>
#include <embb/base/c/memory_allocation.h>
#include <embb/base/c/atomic.h>
#define THIS_DOMAIN_ID 1
#define THIS_NODE_ID 1
......@@ -81,7 +83,4 @@ PT_MAIN("Algorithms") {
embb::mtapi::Node::Finalize();
PT_EXPECT(embb_get_bytes_allocated() == 0);
// std::cout << "please press return to continue..." << std::endl;
// std::cin.get();
}
......@@ -85,9 +85,41 @@
#ifdef DOXYGEN
/**
* Initializes an atomic variable.
*
* \pre The atomic variable has not been initialized.
* \post The atomic variable has the value \c initial_value and can be used in
* atomic operations.
*
* \ingroup C_BASE_ATOMIC
* \notthreadsafe
*/
void embb_atomic_init_TYPE(
emb_atomic_TYPE* variable,
/**< [IN,OUT] Pointer to atomic variable to be initialized. */
TYPE initial_value
/**< [IN] Initial value to be assigned to atomic variable. */
);
/**
* Destroys an atomic variable and frees its resources.
*
* \pre The atomic variable has been initialized.
* \post The atomic variable is uninitialized.
*
* \ingroup C_BASE_ATOMIC
* \notthreadsafe
*/
void embb_atomic_destroy_TYPE(
emb_atomic_TYPE* variable
/**< [IN,OUT] Pointer to atomic variable to be destroyed. */
);
/**
* Computes the logical "and" of the value stored in \p variable and \c value.
*
* The result is stored in \p variable.
* \pre The atomic variable has been initialized with \c embb_atomic_init_TYPE
* \post The result is stored in \p variable.
*
* \see \ref general_desc_atomic_base "Detailed description" for general
* information and the meaning of \b TYPE.
......@@ -95,12 +127,12 @@
* \ingroup C_BASE_ATOMIC
* \waitfree
*/
EMBB_PLATFORM_INLINE void embb_atomic_and_assign_TYPE(
void embb_atomic_and_assign_TYPE(
embb_atomic_TYPE* variable,
/**< [IN,OUT] Pointer to atomic variable which serves as left-hand side for
the "and" operation and is used to store the result. */
TYPE value
/** [IN] Right-hand side of "and" operation, passed by value */
/**< [IN] Right-hand side of "and" operation, passed by value */
);
/**
......@@ -111,6 +143,8 @@ EMBB_PLATFORM_INLINE void embb_atomic_and_assign_TYPE(
* to the value of \p expected. Otherwise, stores the value of \p variable in
* \p expected.
*
* \pre The atomic variable has been initialized with \c embb_atomic_init_TYPE
*
* \return != 0 if the values of \p variable and \p expected were equivalent \n
* 0 otherwise
*
......@@ -120,7 +154,7 @@ EMBB_PLATFORM_INLINE void embb_atomic_and_assign_TYPE(
* \ingroup C_BASE_ATOMIC
* \waitfree
*/
EMBB_PLATFORM_INLINE int embb_atomic_compare_and_swap_TYPE(
int embb_atomic_compare_and_swap_TYPE(
embb_atomic_TYPE* variable,
/**< [IN,OUT] Pointer to atomic variable */
TYPE* expected,
......@@ -132,6 +166,8 @@ EMBB_PLATFORM_INLINE int embb_atomic_compare_and_swap_TYPE(
/**
* Adds \p value to \p variable and returns its old value.
*
* \pre The atomic variable has been initialized with \c embb_atomic_init_TYPE
*
* \return The value before the operation
*
* \see \ref general_desc_atomic_base "Detailed description" for general
......@@ -140,7 +176,7 @@ EMBB_PLATFORM_INLINE int embb_atomic_compare_and_swap_TYPE(
* \ingroup C_BASE_ATOMIC
* \waitfree
*/
EMBB_PLATFORM_INLINE TYPE embb_atomic_fetch_and_add_TYPE(
TYPE embb_atomic_fetch_and_add_TYPE(
embb_atomic_TYPE* variable,
/**< [IN,OUT] Pointer to atomic variable*/
TYPE value
......@@ -150,6 +186,8 @@ EMBB_PLATFORM_INLINE TYPE embb_atomic_fetch_and_add_TYPE(
/**
* Loads the value of \p variable and returns it.
*
* \pre The atomic variable has been initialized with \c embb_atomic_init_TYPE
*
* \return The value of the atomic variable.
*
* \see \ref general_desc_atomic_base "Detailed description" for general
......@@ -158,7 +196,7 @@ EMBB_PLATFORM_INLINE TYPE embb_atomic_fetch_and_add_TYPE(
* \ingroup C_BASE_ATOMIC
* \waitfree
*/
EMBB_PLATFORM_INLINE TYPE embb_atomic_load_TYPE(
TYPE embb_atomic_load_TYPE(
const embb_atomic_TYPE* variable
/**< [IN] Pointer to atomic variable */
);
......@@ -169,12 +207,13 @@ EMBB_PLATFORM_INLINE TYPE embb_atomic_load_TYPE(
* \ingroup C_BASE_ATOMIC
* \waitfree
*/
EMBB_PLATFORM_INLINE void embb_atomic_memory_barrier();
void embb_atomic_memory_barrier();
/**
* Computes the logical "or" of the value stored in \p variable and \c value.
*
* The result is stored in \p variable.
* \pre The atomic variable has been initialized with \c embb_atomic_init_TYPE
* \post The result is stored in \p variable.
*
* \see \ref general_desc_atomic_base "Detailed description" for general
* information and the meaning of \b TYPE.
......@@ -182,7 +221,7 @@ EMBB_PLATFORM_INLINE void embb_atomic_memory_barrier();
* \ingroup C_BASE_ATOMIC
* \waitfree
*/
EMBB_PLATFORM_INLINE void embb_atomic_or_assign_TYPE(
void embb_atomic_or_assign_TYPE(
embb_atomic_TYPE* variable,
/**< [IN,OUT] Pointer to atomic variable which serves as left-hand side for
the "or" operation and is used to store the result. */
......@@ -193,13 +232,15 @@ EMBB_PLATFORM_INLINE void embb_atomic_or_assign_TYPE(
/**
* Stores \p value in \p variable.
*
* \pre The atomic variable has been initialized with \c embb_atomic_init_TYPE
*
* \see \ref general_desc_atomic_base "Detailed description" for general
* information and the meaning of \b TYPE.
*
* \ingroup C_BASE_ATOMIC
* \waitfree
*/
EMBB_PLATFORM_INLINE void embb_atomic_store_TYPE(
void embb_atomic_store_TYPE(
embb_atomic_TYPE* variable,
/**< [IN,OUT] Pointer to atomic variable */
int value
......@@ -209,6 +250,8 @@ EMBB_PLATFORM_INLINE void embb_atomic_store_TYPE(
/**
* Swaps the current value of \p variable with \p value.
*
* \pre The atomic variable has been initialized with \c embb_atomic_init_TYPE
*
* \return The old value of \p variable
*
* \see \ref general_desc_atomic_base "Detailed description" for general
......@@ -217,7 +260,7 @@ EMBB_PLATFORM_INLINE void embb_atomic_store_TYPE(
* \ingroup C_BASE_ATOMIC
* \waitfree
*/
EMBB_PLATFORM_INLINE TYPE embb_atomic_swap_TYPE(
TYPE embb_atomic_swap_TYPE(
embb_atomic_TYPE* variable,
/**< [IN,OUT] Pointer to atomic variable whose value is swapped */
TYPE value
......@@ -227,7 +270,8 @@ EMBB_PLATFORM_INLINE TYPE embb_atomic_swap_TYPE(
/**
* Computes the logical "xor" of the value stored in \p variable and \c value.
*
* The result is stored in \p variable.
* \pre The atomic variable has been initialized with \c embb_atomic_init_TYPE
* \post The result is stored in \p variable.
*
* \see \ref general_desc_atomic_base "Detailed description" for general
* information and the meaning of \b TYPE.
......@@ -235,7 +279,7 @@ EMBB_PLATFORM_INLINE TYPE embb_atomic_swap_TYPE(
* \ingroup C_BASE_ATOMIC
* \waitfree
*/
EMBB_PLATFORM_INLINE void embb_atomic_xor_assign_TYPE(
void embb_atomic_xor_assign_TYPE(
embb_atomic_TYPE* variable,
/**< [IN,OUT] Pointer to atomic variable which serves as left-hand side for
the "xor" operation and is used to store the result. */
......@@ -248,10 +292,62 @@ EMBB_PLATFORM_INLINE void embb_atomic_xor_assign_TYPE(
extern "C" {
#endif
#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
);
int embb_mutex_unlock(
embb_mutex_t* 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))
#else
#define EMBB_ATOMIC_MUTEX_INIT(...)
#define EMBB_ATOMIC_MUTEX_LOCK(...)
#define EMBB_ATOMIC_MUTEX_UNLOCK(...)
#define EMBB_ATOMIC_MUTEX_DESTROY(...)
#endif
#ifdef EMBB_DEBUG
#define EMBB_ATOMIC_INIT_CHECK(variable) assert(variable->marker == 0x12345678)
#define EMBB_ATOMIC_INIT_MARKER(variable) variable->marker = 0x12345678
#else
#define EMBB_ATOMIC_INIT_CHECK(variable) (void)(variable)
#define EMBB_ATOMIC_INIT_MARKER(variable) (void)(variable)
#endif
#include <embb/base/c/internal/platform.h>
#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>
......
......@@ -152,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
......
......@@ -29,11 +29,54 @@
#include <stddef.h>
#include <embb/base/c/internal/macro_helper.h>
#include <embb/base/c/internal/cmake_config.h>
#ifdef EMBB_PLATFORM_COMPILER_MSVC
#include <intrin.h>
#endif
#ifdef EMBB_DEBUG
#ifdef EMBB_THREADING_ANALYSIS_MODE
#define EMBB_ATOMIC_INTERNAL_DEFINE_VARIABLE( \
EMBB_ATOMIC_PARAMETER_TYPE_NATIVE, \
EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX) \
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);
#else
#define EMBB_ATOMIC_INTERNAL_DEFINE_VARIABLE( \
EMBB_ATOMIC_PARAMETER_TYPE_NATIVE, \
EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX) \
typedef struct \
{ \
volatile EMBB_ATOMIC_PARAMETER_TYPE_NATIVE internal_variable; \
uint32_t marker; \
} EMBB_CAT2(embb_atomic_, EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX);
#endif
#else
#ifdef EMBB_THREADING_ANALYSIS_MODE
#define EMBB_ATOMIC_INTERNAL_DEFINE_VARIABLE( \
EMBB_ATOMIC_PARAMETER_TYPE_NATIVE, \
EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX) \
typedef struct \
{ \
volatile EMBB_ATOMIC_PARAMETER_TYPE_NATIVE internal_variable; \
embb_mutex_t internal_mutex; \
} EMBB_CAT2(embb_atomic_, EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX);
#else
#define EMBB_ATOMIC_INTERNAL_DEFINE_VARIABLE( \
EMBB_ATOMIC_PARAMETER_TYPE_NATIVE, \
EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX) \
......@@ -42,6 +85,10 @@
volatile EMBB_ATOMIC_PARAMETER_TYPE_NATIVE internal_variable; \
} EMBB_CAT2(embb_atomic_, EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX);
#endif
#endif
EMBB_ATOMIC_INTERNAL_DEFINE_VARIABLE(char, char)
EMBB_ATOMIC_INTERNAL_DEFINE_VARIABLE(short, short)
EMBB_ATOMIC_INTERNAL_DEFINE_VARIABLE(unsigned short, unsigned_short)
......
......@@ -138,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_
......@@ -107,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
......@@ -131,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 <embb/base/c/internal/atomic/store.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_PARAMETER_TYPE_NATIVE value) { \
EMBB_ATOMIC_MUTEX_INIT(variable->internal_mutex); \
EMBB_ATOMIC_INIT_MARKER(variable); \
EMBB_CAT2(embb_atomic_store_, EMBB_ATOMIC_PARAMETER_ATOMIC_TYPE_SUFFIX)(variable, value); \
}
#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_
......@@ -119,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; \
......
......@@ -123,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
......
......@@ -118,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
......
......@@ -127,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; \
......
......@@ -125,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
......
......@@ -53,7 +53,14 @@
*/
#cmakedefine EMBB_PLATFORM_HAS_GLIB_CPU
/**
* Enables mutex-based implementation of all synchronization constructs.
*/
#cmakedefine EMBB_THREADING_ANALYSIS_MODE
/**
* Version defines.
*/
#define EMBB_BASE_VERSION_MAJOR ${EMBB_BASE_VERSION_MAJOR}
#define EMBB_BASE_VERSION_MINOR ${EMBB_BASE_VERSION_MINOR}
#define EMBB_BASE_VERSION_PATCH ${EMBB_BASE_VERSION_PATCH}
......
......@@ -33,7 +33,7 @@ int embb_counter_init(embb_counter_t* counter) {
if (counter == NULL) {
return EMBB_ERROR;
}
embb_atomic_store_unsigned_int(&(counter->value), 0);
embb_atomic_init_unsigned_int(&(counter->value), 0);
return EMBB_SUCCESS;
}
......@@ -55,7 +55,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
......
......@@ -147,9 +147,7 @@ int embb_spin_init(embb_spinlock_t* spinlock) {
if (NULL == spinlock) {
return EMBB_ERROR;
}
// For now, store the initial value. In the future will use atomic init
// function (as soon as available).
embb_atomic_store_int(&spinlock->atomic_spin_variable_, 0);
embb_atomic_init_int(&spinlock->atomic_spin_variable_, 0);
return EMBB_SUCCESS;
}
......@@ -207,7 +205,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_);
}
......@@ -39,6 +39,7 @@
#include <embb/base/c/log.h>
#include <iostream>
#include <embb/base/c/atomic.h>
#include <embb/base/c/memory_allocation.h>
using embb::base::test::AllocTest;
......
......@@ -36,13 +36,21 @@ namespace embb {
namespace base {
namespace test {
embb_atomic_int flag;
ThreadIndexTest::ThreadIndexTest()
: number_threads_(partest::TestSuite::GetDefaultNumThreads()) {
embb_atomic_init_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 +86,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 +112,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(this->internal_mutex);
NativeType storage_value = fetch_and_add_implementation<NativeType>::
fetch_and_add(&this->AtomicValue, native_desired);
EMBB_ATOMIC_MUTEX_UNLOCK(this->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
mutable embb_mutex_t internal_mutex;
#endif
public:
/**
* Default constructor.
......@@ -73,6 +77,11 @@ class AtomicBase {
*/
explicit AtomicBase(BaseType val);
/**
* Destructor.
*/
~AtomicBase();
// The members below are documented in atomic.h
BaseType operator=(BaseType val);
operator BaseType() const;
......@@ -88,14 +97,21 @@ class AtomicBase {
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;
......@@ -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 {
BaseType return_value;
EMBB_ATOMIC_MUTEX_LOCK(internal_mutex);
NativeType storage_value =
load_implementation< NativeType >::Load(&AtomicValue);
EMBB_ATOMIC_MUTEX_UNLOCK(internal_mutex);
memcpy(&return_value, &storage_value, sizeof(return_value));
......@@ -155,8 +175,10 @@ inline BaseType AtomicBase<BaseType>::Swap(BaseType val) {
memcpy(&storage_value, &val, sizeof(storage_value));
EMBB_ATOMIC_MUTEX_LOCK(internal_mutex);
NativeType storage_value2 = swap_implementation< NativeType >
::Swap(&AtomicValue, storage_value);
EMBB_ATOMIC_MUTEX_UNLOCK(internal_mutex);
memcpy(&return_value, &storage_value2, sizeof(return_value));
......@@ -172,10 +194,12 @@ CompareAndSwap(BaseType& expected, BaseType desired) {
memcpy(&native_expected, &expected, sizeof(expected));
memcpy(&native_desired, &desired, sizeof(desired));
EMBB_ATOMIC_MUTEX_LOCK(internal_mutex);
bool return_val =
(compare_and_swap_implementation<NativeType>::
compare_and_swap(&AtomicValue, &native_expected, native_desired)) !=0
? true : false;
EMBB_ATOMIC_MUTEX_UNLOCK(internal_mutex);
memcpy(&expected, &native_expected, sizeof(expected));
......
......@@ -93,8 +93,10 @@ inline void AtomicInteger<BaseType>::operator&=(BaseType val) {
NativeType native_operand;
memcpy(&native_operand, &val, sizeof(val));
EMBB_ATOMIC_MUTEX_LOCK(this->internal_mutex);
and_assign_implementation<NativeType>::
and_assign(&this->AtomicValue, native_operand);
EMBB_ATOMIC_MUTEX_UNLOCK(this->internal_mutex);
}
template<typename BaseType>
......@@ -102,8 +104,10 @@ inline void AtomicInteger<BaseType>::operator|=(BaseType val) {
NativeType native_operand;
memcpy(&native_operand, &val, sizeof(val));
EMBB_ATOMIC_MUTEX_LOCK(this->internal_mutex);
or_assign_implementation<NativeType>::
or_assign(&this->AtomicValue, native_operand);
EMBB_ATOMIC_MUTEX_UNLOCK(this->internal_mutex);
}
template<typename BaseType>
......@@ -111,8 +115,10 @@ inline void AtomicInteger<BaseType>::operator^=(BaseType val) {
NativeType native_operand;
memcpy(&native_operand, &val, sizeof(val));
EMBB_ATOMIC_MUTEX_LOCK(this->internal_mutex);
xor_assign_implementation<NativeType>::
xor_assign(&this->AtomicValue, native_operand);
EMBB_ATOMIC_MUTEX_UNLOCK(this->internal_mutex);
}
} // namespace atomic
......
......@@ -36,6 +36,7 @@
#include <memory_allocation_test.h>
#include <log_test.h>
#include <embb/base/c/atomic.h>
#include <embb/base/c/memory_allocation.h>
using embb::base::test::CoreSetTest;
......
......@@ -39,6 +39,8 @@
#include <embb/containers/object_pool.h>
#include <embb/containers/lock_free_stack.h>
#include <embb/containers/lock_free_mpmc_queue.h>
#include <embb/base/c/memory_allocation.h>
#include <embb/base/c/atomic.h>
#ifdef EMBB_PLATFORM_COMPILER_MSVC
#pragma warning(pop) // Reset warning 4548
......
......@@ -84,13 +84,16 @@ class Inputs<T1, embb::base::internal::Nil, embb::base::internal::Nil,
embb::base::Allocation::Allocate(
sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) {
count_[ii] = 1;
new(count_+ii) embb::base::Atomic<int>(1);
}
}
this->template Get<0>().SetSlices(slices_);
}
~Inputs() {
if (NULL != count_) {
for (int ii = 0; ii < slices_; ii++) {
count_[ii].~Atomic<int>();
}
embb::base::Allocation::Free(count_);
}
}
......@@ -150,7 +153,7 @@ class Inputs<T1, T2, embb::base::internal::Nil,
embb::base::Allocation::Allocate(
sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) {
count_[ii] = 2;
new(count_ + ii) embb::base::Atomic<int>(2);
}
}
this->template Get<0>().SetSlices(slices_);
......@@ -158,6 +161,9 @@ class Inputs<T1, T2, embb::base::internal::Nil,
}
~Inputs() {
if (NULL != count_) {
for (int ii = 0; ii < slices_; ii++) {
count_[ii].~Atomic<int>();
}
embb::base::Allocation::Free(count_);
}
}
......@@ -222,7 +228,7 @@ class Inputs<T1, T2, T3, embb::base::internal::Nil,
embb::base::Allocation::Allocate(
sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) {
count_[ii] = 3;
new(count_ + ii) embb::base::Atomic<int>(3);
}
}
this->template Get<0>().SetSlices(slices_);
......@@ -231,6 +237,9 @@ class Inputs<T1, T2, T3, embb::base::internal::Nil,
}
~Inputs() {
if (NULL != count_) {
for (int ii = 0; ii < slices_; ii++) {
count_[ii].~Atomic<int>();
}
embb::base::Allocation::Free(count_);
}
}
......@@ -299,7 +308,7 @@ class Inputs<T1, T2, T3, T4, embb::base::internal::Nil>
embb::base::Allocation::Allocate(
sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) {
count_[ii] = 4;
new(count_ + ii) embb::base::Atomic<int>(4);
}
}
this->template Get<0>().SetSlices(slices_);
......@@ -309,6 +318,9 @@ class Inputs<T1, T2, T3, T4, embb::base::internal::Nil>
}
~Inputs() {
if (NULL != count_) {
for (int ii = 0; ii < slices_; ii++) {
count_[ii].~Atomic<int>();
}
embb::base::Allocation::Free(count_);
}
}
......@@ -383,7 +395,7 @@ class Inputs
embb::base::Allocation::Allocate(
sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) {
count_[ii] = 5;
new(count_ + ii) embb::base::Atomic<int>(5);
}
}
this->template Get<0>().SetSlices(slices_);
......@@ -394,6 +406,9 @@ class Inputs
}
~Inputs() {
if (NULL != count_) {
for (int ii = 0; ii < slices_; ii++) {
count_[ii].~Atomic<int>();
}
embb::base::Allocation::Free(count_);
}
}
......
......@@ -802,6 +802,9 @@ class Network : public internal::ClockListener {
sched_ = NULL;
}
if (NULL != sink_counter_) {
for (int ii = 0; ii < slices_; ii++) {
sink_counter_[ii].~Atomic<int>();
}
embb::base::Allocation::Free(sink_counter_);
sink_counter_ = NULL;
}
......@@ -1111,7 +1114,7 @@ class Network : public internal::ClockListener {
embb::base::Allocation::Allocate(
sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) {
sink_counter_[ii] = 0;
new(sink_counter_+ii) embb::base::Atomic<int>(0);
}
}
};
......
......@@ -31,6 +31,8 @@
#include <dataflow_cpp_test_simple.h>
#include <dataflow_cpp_test_tuple.h>
#include <embb/base/c/atomic.h>
PT_MAIN("Dataflow C++") {
PT_RUN(SimpleTest);
PT_RUN(TupleTest);
......
......@@ -62,7 +62,7 @@ mtapi_action_hndl_t mtapi_ext_plugin_action_create(
new_action->node_local_data_size = node_local_data_size;
new_action->enabled = MTAPI_TRUE;
new_action->is_plugin_action = MTAPI_TRUE;
embb_atomic_store_int(&new_action->num_tasks, 0);
embb_atomic_init_int(&new_action->num_tasks, 0);
new_action->plugin_task_start_function = task_start_function;
new_action->plugin_task_cancel_function = task_cancel_function;
......@@ -87,6 +87,7 @@ mtapi_action_hndl_t mtapi_ext_plugin_action_create(
action_handle = new_action->handle;
embb_mtapi_job_add_action(job, new_action);
} else {
embb_mtapi_action_finalize(new_action);
embb_mtapi_action_pool_deallocate(node->action_pool, new_action);
}
} else {
......
......@@ -49,6 +49,8 @@ embb_mtapi_pool_implementation(action)
/* ---- CLASS MEMBERS ------------------------------------------------------ */
void embb_mtapi_action_initialize(embb_mtapi_action_t* that) {
assert(MTAPI_NULL != that);
that->action_function = NULL;
that->job_id = MTAPI_JOB_ID_INVALID;
that->domain_id = MTAPI_DOMAIN_ID_INVALID;
......@@ -57,15 +59,25 @@ void embb_mtapi_action_initialize(embb_mtapi_action_t* that) {
that->node_local_data = NULL;
that->node_local_data_size = 0;
that->plugin_data = MTAPI_NULL;
embb_atomic_store_int(&that->num_tasks, 0);
embb_atomic_init_int(&that->num_tasks, 0);
}
void embb_mtapi_action_finalize(embb_mtapi_action_t* that) {
assert(MTAPI_NULL != that);
if (that->is_plugin_action) {
// TODO(mw): check status
that->plugin_action_finalize_function(that->handle, NULL);
}
embb_mtapi_action_initialize(that);
that->action_function = NULL;
that->job_id = MTAPI_JOB_ID_INVALID;
that->domain_id = MTAPI_DOMAIN_ID_INVALID;
that->node_id = MTAPI_NODE_ID_INVALID;
that->enabled = MTAPI_FALSE;
that->node_local_data = NULL;
that->node_local_data_size = 0;
that->plugin_data = MTAPI_NULL;
embb_atomic_destroy_int(&that->num_tasks);
}
static mtapi_boolean_t embb_mtapi_action_delete_visitor(
......@@ -140,7 +152,7 @@ mtapi_action_hndl_t mtapi_action_create(
new_action->node_local_data_size = node_local_data_size;
new_action->enabled = MTAPI_TRUE;
new_action->is_plugin_action = MTAPI_FALSE;
embb_atomic_store_int(&new_action->num_tasks, 0);
embb_atomic_init_int(&new_action->num_tasks, 0);
new_action->action_function = action_function;
......@@ -162,6 +174,7 @@ mtapi_action_hndl_t mtapi_action_create(
action_handle = new_action->handle;
embb_mtapi_job_add_action(job, new_action);
} else {
embb_mtapi_action_finalize(new_action);
embb_mtapi_action_pool_deallocate(node->action_pool, new_action);
}
} else {
......@@ -337,8 +350,7 @@ void mtapi_action_delete(
node, local_action->job_id);
embb_mtapi_job_remove_action(local_job, local_action);
}
/* this is done by pool deallocate:
embb_mtapi_action_finalize(local_action); */
embb_mtapi_action_finalize(local_action);
embb_mtapi_action_pool_deallocate(node->action_pool, local_action);
} else {
local_status = MTAPI_ERR_ACTION_INVALID;
......
......@@ -30,12 +30,12 @@
#include <embb_mtapi_alloc.h>
static embb_atomic_unsigned_int embb_mtapi_alloc_bytes_allocated = { 0 };
static EMBB_BASE_BASIC_TYPE_SIZE_4 embb_mtapi_alloc_bytes_allocated = 0;
void * embb_mtapi_alloc_allocate(unsigned int bytes) {
void * ptr = embb_alloc(bytes);
if (ptr != NULL) {
embb_atomic_fetch_and_add_unsigned_int(
embb_internal__atomic_fetch_and_add_4(
&embb_mtapi_alloc_bytes_allocated, sizeof(unsigned int)+bytes);
}
return ptr;
......@@ -48,9 +48,9 @@ void embb_mtapi_alloc_deallocate(void * ptr) {
}
void embb_mtapi_alloc_reset_bytes_allocated() {
embb_atomic_store_unsigned_int(&embb_mtapi_alloc_bytes_allocated, 0);
embb_internal__atomic_store_4(&embb_mtapi_alloc_bytes_allocated, 0);
}
unsigned int embb_mtapi_alloc_get_bytes_allocated() {
return embb_atomic_load_unsigned_int(&embb_mtapi_alloc_bytes_allocated);
return embb_internal__atomic_load_4(&embb_mtapi_alloc_bytes_allocated);
}
......@@ -55,8 +55,8 @@ void embb_mtapi_group_initialize(embb_mtapi_group_t * that) {
assert(MTAPI_NULL != that);
that->group_id = MTAPI_GROUP_ID_NONE;
embb_atomic_store_int(&that->deleted, MTAPI_FALSE);
that->num_tasks.internal_variable = 0;
embb_atomic_init_int(&that->deleted, MTAPI_FALSE);
embb_atomic_init_int(&that->num_tasks, 0);
embb_mtapi_task_queue_initialize(&that->queue);
}
......@@ -67,8 +67,8 @@ void embb_mtapi_group_initialize_with_node(
assert(MTAPI_NULL != node);
that->group_id = MTAPI_GROUP_ID_NONE;
embb_atomic_store_int(&that->deleted, MTAPI_FALSE);
that->num_tasks.internal_variable = 0;
embb_atomic_init_int(&that->deleted, MTAPI_FALSE);
embb_atomic_init_int(&that->num_tasks, 0);
embb_mtapi_task_queue_initialize_with_capacity(
&that->queue, node->attributes.queue_limit);
}
......@@ -77,7 +77,9 @@ void embb_mtapi_group_finalize(embb_mtapi_group_t * that) {
assert(MTAPI_NULL != that);
embb_atomic_store_int(&that->deleted, MTAPI_TRUE);
that->num_tasks.internal_variable = 0;
embb_atomic_destroy_int(&that->deleted);
embb_atomic_store_int(&that->num_tasks, 0);
embb_atomic_destroy_int(&that->num_tasks);
embb_mtapi_task_queue_finalize(&that->queue);
}
......
......@@ -105,7 +105,7 @@ void mtapi_initialize(
}
if (MTAPI_SUCCESS == local_status) {
embb_atomic_store_int(&node->is_scheduler_running, MTAPI_FALSE);
embb_atomic_init_int(&node->is_scheduler_running, MTAPI_FALSE);
/* initialize storage */
embb_mtapi_job_initialize_list(node);
......@@ -199,6 +199,8 @@ void mtapi_finalize(MTAPI_OUT mtapi_status_t* status) {
embb_mtapi_job_finalize_list(node);
}
embb_atomic_destroy_int(&node->is_scheduler_running);
/* free system instance */
embb_mtapi_alloc_deallocate(node);
embb_mtapi_node_instance = MTAPI_NULL;
......
......@@ -66,8 +66,6 @@ mtapi_boolean_t embb_mtapi_##TYPE##_pool_initialize( \
that->storage[ii].handle.id = EMBB_MTAPI_IDPOOL_INVALID_ID; \
that->storage[ii].handle.tag = 0; \
} \
/* use entry 0 as invalid */ \
embb_mtapi_##TYPE##_initialize(that->storage); \
return MTAPI_TRUE; \
} else { \
that->id_pool.ids_available = 0; \
......@@ -96,7 +94,6 @@ void embb_mtapi_##TYPE##_pool_deallocate( \
embb_mtapi_##TYPE##_pool_t * that, \
embb_mtapi_##TYPE##_t * object) { \
mtapi_uint_t pool_id = object->handle.id; \
embb_mtapi_##TYPE##_finalize(object); \
object->handle.id = EMBB_MTAPI_IDPOOL_INVALID_ID; \
object->handle.tag++; \
embb_mtapi_id_pool_deallocate(&that->id_pool, pool_id); \
......
......@@ -56,8 +56,8 @@ void embb_mtapi_queue_initialize(embb_mtapi_queue_t* that) {
mtapi_queueattr_init(&that->attributes, MTAPI_NULL);
that->queue_id = MTAPI_QUEUE_ID_NONE;
embb_atomic_store_char(&that->enabled, MTAPI_FALSE);
embb_atomic_store_int(&that->num_tasks, 0);
embb_atomic_init_char(&that->enabled, MTAPI_FALSE);
embb_atomic_init_int(&that->num_tasks, 0);
that->job_handle.id = 0;
that->job_handle.tag = 0;
}
......@@ -71,8 +71,8 @@ void embb_mtapi_queue_initialize_with_attributes_and_job(
that->attributes = *attributes;
that->queue_id = MTAPI_QUEUE_ID_NONE;
embb_atomic_store_char(&that->enabled, MTAPI_TRUE);
embb_atomic_store_int(&that->num_tasks, 0);
embb_atomic_init_char(&that->enabled, MTAPI_TRUE);
embb_atomic_init_int(&that->num_tasks, 0);
that->job_handle = job;
}
......@@ -81,6 +81,8 @@ void embb_mtapi_queue_finalize(embb_mtapi_queue_t* that) {
that->job_handle.id = 0;
that->job_handle.tag = 0;
embb_atomic_destroy_int(&that->num_tasks);
embb_atomic_destroy_char(&that->enabled);
embb_mtapi_queue_initialize(that);
}
......
......@@ -491,7 +491,7 @@ mtapi_boolean_t embb_mtapi_scheduler_initialize_with_mode(
assert(MTAPI_NULL != that);
assert(MTAPI_NULL != node);
embb_atomic_store_int(&that->affine_task_counter, 0);
embb_atomic_init_int(&that->affine_task_counter, 0);
/* Paranoia sanitizing of scheduler mode */
if (mode >= NUM_SCHEDULER_MODES) {
......@@ -573,6 +573,8 @@ void embb_mtapi_scheduler_finalize(embb_mtapi_scheduler_t * that) {
embb_mtapi_alloc_deallocate(that->worker_contexts);
that->worker_contexts = MTAPI_NULL;
}
embb_atomic_destroy_int(&that->affine_task_counter);
}
embb_mtapi_scheduler_t * embb_mtapi_scheduler_new() {
......
......@@ -79,20 +79,29 @@ void embb_mtapi_task_initialize(embb_mtapi_task_t* that) {
that->action.id = EMBB_MTAPI_IDPOOL_INVALID_ID;
that->job.id = EMBB_MTAPI_IDPOOL_INVALID_ID;
embb_atomic_store_int(&that->state, MTAPI_TASK_ERROR);
embb_atomic_init_int(&that->state, MTAPI_TASK_ERROR);
that->task_id = MTAPI_TASK_ID_NONE;
that->group.id = EMBB_MTAPI_IDPOOL_INVALID_ID;
that->queue.id = EMBB_MTAPI_IDPOOL_INVALID_ID;
that->error_code = MTAPI_SUCCESS;
embb_atomic_store_unsigned_int(&that->current_instance, 0);
embb_atomic_init_unsigned_int(&that->current_instance, 0);
embb_spin_init(&that->state_lock);
embb_atomic_init_unsigned_int(&that->instances_todo, 0);
}
void embb_mtapi_task_finalize(embb_mtapi_task_t* that) {
assert(MTAPI_NULL != that);
embb_mtapi_task_initialize(that);
that->action.id = EMBB_MTAPI_IDPOOL_INVALID_ID;
that->job.id = EMBB_MTAPI_IDPOOL_INVALID_ID;
embb_atomic_destroy_int(&that->state);
that->task_id = MTAPI_TASK_ID_NONE;
that->group.id = EMBB_MTAPI_IDPOOL_INVALID_ID;
that->queue.id = EMBB_MTAPI_IDPOOL_INVALID_ID;
that->error_code = MTAPI_SUCCESS;
embb_atomic_destroy_unsigned_int(&that->current_instance);
embb_spin_destroy(&that->state_lock);
embb_atomic_destroy_unsigned_int(&that->instances_todo);
}
mtapi_boolean_t embb_mtapi_task_execute(
......
......@@ -58,7 +58,9 @@ mtapi_boolean_t embb_mtapi_thread_context_initialize(
that->thread_priority = priority;
that->is_main_thread = (worker_index == 0) ?
node->attributes.reuse_main_thread : MTAPI_FALSE;
embb_atomic_store_int(&that->run, 0);
embb_atomic_init_int(&that->run, 0);
embb_atomic_init_int(&that->is_sleeping, 0);
that->queue = (embb_mtapi_task_queue_t**)embb_mtapi_alloc_allocate(
sizeof(embb_mtapi_task_queue_t)*that->priorities);
......@@ -101,7 +103,6 @@ mtapi_boolean_t embb_mtapi_thread_context_initialize(
embb_mutex_init(&that->work_available_mutex, EMBB_MUTEX_PLAIN);
embb_condition_init(&that->work_available);
embb_atomic_store_int(&that->is_sleeping, 0);
that->is_initialized = MTAPI_TRUE;
......@@ -208,6 +209,9 @@ void embb_mtapi_thread_context_finalize(embb_mtapi_thread_context_t* that) {
that->private_queue = MTAPI_NULL;
}
embb_atomic_destroy_int(&that->is_sleeping);
embb_atomic_destroy_int(&that->run);
that->priorities = 0;
that->is_initialized = MTAPI_FALSE;
......
......@@ -733,8 +733,12 @@ void TestContext() {
}
void ErrorTest::TestBasic() {
embb_atomic_init_int(&wait, 0);
TestNodeNotInit();
TestParameter();
TestLimits();
TestContext();
embb_atomic_destroy_int(&wait);
}
......@@ -84,8 +84,8 @@ void plugin_initialize(
plugin_task.id = 0;
plugin_task.tag = 0;
embb_atomic_store_int(&plugin_running, 1);
embb_atomic_store_int(&plugin_task_available, 0);
embb_atomic_init_int(&plugin_running, 1);
embb_atomic_init_int(&plugin_task_available, 0);
err = embb_thread_create(&plugin_thread, NULL, plugin_thread_function, NULL);
if (EMBB_SUCCESS == err) {
......@@ -108,6 +108,9 @@ void plugin_finalize(
local_status = MTAPI_SUCCESS;
}
embb_atomic_destroy_int(&plugin_task_available);
embb_atomic_destroy_int(&plugin_running);
mtapi_status_set(status, local_status);
}
......
......@@ -40,6 +40,7 @@
#include <embb_mtapi_test_id_pool.h>
#include <embb/base/c/memory_allocation.h>
#include <embb/base/c/atomic.h>
PT_MAIN("MTAPI C") {
embb_log_set_log_level(EMBB_LOG_LEVEL_NONE);
......
......@@ -32,7 +32,7 @@ namespace mtapi {
embb::mtapi::Node * embb::mtapi::Node::node_instance_ = NULL;
#if MTAPI_CPP_AUTOMATIC_INITIALIZE
static embb_spinlock_t init_mutex = { { 0 } };
static EMBB_BASE_BASIC_TYPE_SIZE_4 init_mutex = 0;
#endif
void Node::Initialize(
......@@ -68,13 +68,18 @@ void Node::Initialize(
Node & Node::GetInstance() {
#if MTAPI_CPP_AUTOMATIC_INITIALIZE
if (!IsInitialized()) {
embb_spin_lock(&init_mutex);
EMBB_BASE_BASIC_TYPE_SIZE_4 compare = 0;
while (0 == embb_internal__atomic_compare_and_swap_4(
&init_mutex, &compare, 1)) {
compare = 0;
embb_thread_yield();
}
if (!IsInitialized()) {
Node::Initialize(
MTAPI_CPP_AUTOMATIC_DOMAIN_ID, MTAPI_CPP_AUTOMATIC_NODE_ID);
atexit(Node::Finalize);
}
embb_spin_unlock(&init_mutex);
embb_internal__atomic_store_4(&init_mutex, 0);
}
return *node_instance_;
#else
......
......@@ -27,6 +27,7 @@
#include <partest/partest.h>
#include <embb/base/c/thread.h>
#include <embb/base/c/atomic.h>
#include <mtapi_cpp_test_task.h>
#include <mtapi_cpp_test_group.h>
......
......@@ -654,14 +654,16 @@ void mtapi_network_plugin_initialize(
plugin->socket_count = 0;
plugin->buffer_size = 0;
plugin->sockets = NULL;
embb_atomic_store_int(&plugin->run, 0);
err = embb_mtapi_network_initialize();
if (0 == err) return;
embb_atomic_init_int(&plugin->run, 0);
err = embb_mtapi_network_buffer_initialize(
&plugin->recv_buffer, (int)buffer_size);
if (0 == err) {
embb_atomic_destroy_int(&plugin->run);
embb_mtapi_network_finalize();
return;
}
......@@ -670,6 +672,7 @@ void mtapi_network_plugin_initialize(
&plugin->send_buffer, (int)buffer_size);
if (0 == err) {
embb_mtapi_network_buffer_finalize(&plugin->recv_buffer);
embb_atomic_destroy_int(&plugin->run);
embb_mtapi_network_finalize();
return;
}
......@@ -684,6 +687,7 @@ void mtapi_network_plugin_initialize(
embb_mtapi_network_buffer_finalize(&plugin->send_buffer);
embb_mtapi_network_buffer_finalize(&plugin->recv_buffer);
plugin->buffer_size = 0;
embb_atomic_destroy_int(&plugin->run);
embb_mtapi_network_finalize();
return;
}
......@@ -695,6 +699,7 @@ void mtapi_network_plugin_initialize(
embb_mtapi_network_buffer_finalize(&plugin->send_buffer);
embb_mtapi_network_buffer_finalize(&plugin->recv_buffer);
plugin->buffer_size = 0;
embb_atomic_destroy_int(&plugin->run);
embb_mtapi_network_finalize();
return;
}
......@@ -707,6 +712,7 @@ void mtapi_network_plugin_initialize(
embb_mtapi_network_buffer_finalize(&plugin->send_buffer);
embb_mtapi_network_buffer_finalize(&plugin->recv_buffer);
plugin->buffer_size = 0;
embb_atomic_destroy_int(&plugin->run);
embb_mtapi_network_finalize();
return;
}
......@@ -723,6 +729,7 @@ void mtapi_network_plugin_initialize(
embb_mtapi_network_buffer_finalize(&plugin->send_buffer);
embb_mtapi_network_buffer_finalize(&plugin->recv_buffer);
plugin->buffer_size = 0;
embb_atomic_destroy_int(&plugin->run);
embb_mtapi_network_finalize();
return;
}
......@@ -741,6 +748,7 @@ void mtapi_network_plugin_initialize(
embb_mtapi_network_buffer_finalize(&plugin->send_buffer);
embb_mtapi_network_buffer_finalize(&plugin->recv_buffer);
plugin->buffer_size = 0;
embb_atomic_destroy_int(&plugin->run);
embb_mtapi_network_finalize();
return;
}
......@@ -764,6 +772,9 @@ void mtapi_network_plugin_finalize(
embb_mtapi_network_socket_finalize(&plugin->sockets[0]);
embb_free(plugin->sockets);
embb_atomic_destroy_int(&plugin->run);
embb_mtapi_network_finalize();
mtapi_status_set(status, local_status);
......
......@@ -30,6 +30,8 @@
#include <embb_mtapi_network_test_socket.h>
#include <embb_mtapi_network_test_task.h>
#include <embb/base/c/atomic.h>
PT_MAIN("MTAPI NETWORK") {
PT_RUN(NetworkBufferTest);
PT_RUN(NetworkSocketTest);
......
......@@ -29,6 +29,7 @@
#include <embb_mtapi_opencl_test_linker.h>
#include <embb_mtapi_opencl_test_task.h>
#include <embb/base/c/atomic.h>
PT_MAIN("MTAPI OPENCL") {
PT_RUN(LinkerTest);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment