diff --git a/CMakeCommon/SetCompilerFlags.cmake b/CMakeCommon/SetCompilerFlags.cmake index 9e18728..5de3734 100644 --- a/CMakeCommon/SetCompilerFlags.cmake +++ b/CMakeCommon/SetCompilerFlags.cmake @@ -26,36 +26,51 @@ # function(SetGNUCompilerFlags compiler_libs) if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) - set(compiler_libs pthread rt PARENT_SCOPE) - # -Wall -> All warnings - # -Wextra -> Even more warnings - # -Werror -> Warnings are errors - set(warning_flags "-Wall -Wextra") - if (WARNINGS_ARE_ERRORS STREQUAL ON) - set(warning_flags "${warning_flags} -Werror") - endif() - if(CMAKE_COMPILER_IS_GNUCC) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread -std=c99 ${warning_flags}" - PARENT_SCOPE) - set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DEMBB_DEBUG" - PARENT_SCOPE) - set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNDEBUG" - PARENT_SCOPE) - set(CMAKE_C_FLAGS_COVERAGE - "${CMAKE_C_FLAGS_COVERAGE} -O0 -fprofile-arcs -ftest-coverage" - PARENT_SCOPE) - endif() - if(CMAKE_COMPILER_IS_GNUCXX) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -std=c++03 ${warning_flags}" - PARENT_SCOPE) - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DEMBB_DEBUG" - PARENT_SCOPE) - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DNDEBUG" - PARENT_SCOPE) - set(CMAKE_CXX_FLAGS_COVERAGE - "${CMAKE_CXX_FLAGS_COVERAGE} -O0 -fprofile-arcs -ftest-coverage" - PARENT_SCOPE) - endif() + if(DEFINED CMAKE_SYSTEM_PROCESSOR) + set(compiler_libs PARENT_SCOPE) + set(common_flags "-fno-common -Os") + set(warning_flags "-W -Wall -Wextra -Wdiv-by-zero -Warray-bounds -Wcast-align -Wignored-qualifiers -Wformat -Wformat-security") + set(target_flags "-DAPPKIT_TC277TFT -fshort-double -mcpu=tc27xx -mversion-info") + + if (WARNINGS_ARE_ERRORS STREQUAL ON) + set(warning_flags "${warning_flags} -Werror") + endif() + if(CMAKE_COMPILER_IS_GNUCC) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${common_flags} ${warning_flags} ${target_flags}" + PARENT_SCOPE) + endif() + else() + set(compiler_libs pthread rt PARENT_SCOPE) + # -Wall -> All warnings + # -Wextra -> Even more warnings + # -Werror -> Warnings are errors + set(warning_flags "-Wall -Wextra") + if (WARNINGS_ARE_ERRORS STREQUAL ON) + set(warning_flags "${warning_flags} -Werror") + endif() + if(CMAKE_COMPILER_IS_GNUCC) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread -std=c99 ${warning_flags}" + PARENT_SCOPE) + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DEMBB_DEBUG" + PARENT_SCOPE) + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNDEBUG" + PARENT_SCOPE) + set(CMAKE_C_FLAGS_COVERAGE + "${CMAKE_C_FLAGS_COVERAGE} -O0 -fprofile-arcs -ftest-coverage" + PARENT_SCOPE) + endif() + if(CMAKE_COMPILER_IS_GNUCXX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -std=c++03 ${warning_flags}" + PARENT_SCOPE) + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DEMBB_DEBUG" + PARENT_SCOPE) + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DNDEBUG" + PARENT_SCOPE) + set(CMAKE_CXX_FLAGS_COVERAGE + "${CMAKE_CXX_FLAGS_COVERAGE} -O0 -fprofile-arcs -ftest-coverage" + PARENT_SCOPE) + endif() + endif() endif() endfunction() diff --git a/CMakeLists.txt b/CMakeLists.txt index c79dbd3..676c4a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,7 +76,7 @@ endif() # The set option will be converted to uppercase letters by cmake!! --> ON/OFF # Note that the help string (second argument) cannot be printed by cmake. # -option(BUILD_TESTS "Specify whether tests should be built" ON) +option(BUILD_TESTS "Specify whether tests should be built" OFF) option(BUILD_EXAMPLES "Specify whether examples should be built" OFF) option(USE_EXCEPTIONS "Specify whether exceptions should be activated in C++" ON) option(INSTALL_DOCS "Specify whether Doxygen docs should be installed" ON) @@ -104,6 +104,12 @@ else() endif() message(" (set with command line option -DUSE_AUTOMATIC_INITIALIZATION=ON/OFF)") +set(CMAKE_CXX_STANDARD_LIBRARIES ${FREE_RTOS_LIB_PATH}/iRom/libFreeRTOS_Lib.a) +set(CMAKE_C_STANDARD_LIBRARIES ${FREE_RTOS_LIB_PATH}/iRom/libFreeRTOS_Lib.a) +set(CMAKE_INSTALL_RPATH FREE_RTOS_LIB_PATH) + +set(__TriCore__ 1) + include(CMakeCommon/SetCompilerFlags.cmake) SetGNUCompilerFlags(compiler_libs compiler_flags) SetVisualStudioCompilerFlags(compiler_libs compiler_flags) diff --git a/TC_Toolchain.cmake b/TC_Toolchain.cmake index 49d5fd3..6d09948 100644 --- a/TC_Toolchain.cmake +++ b/TC_Toolchain.cmake @@ -2,7 +2,8 @@ SET(CMAKE_SYSTEM_NAME Generic) #this one not so much SET(CMAKE_SYSTEM_VERSION 1) -SET(CMAKE_SYSTEM_PROCESSOR TriCore) +SET(CMAKE_SYSTEM_PROCESSOR __TriCore__) +SET(__TriCore__ 1) # specify the cross compiler SET(CMAKE_C_COMPILER C:/HighTec/toolchains/tricore/v4.6.6.0-infineon-1.1/bin/tricore-gcc.exe) @@ -11,6 +12,9 @@ SET(CMAKE_CXX_COMPILER C:/HighTec/toolchains/tricore/v4.6.6.0-infineon-1.1/bin/t # where is the target environment SET(CMAKE_FIND_ROOT_PATH C:/HighTec/toolchains/tricore/v4.6.6.0-infineon-1.1) + +SET(FREE_RTOS_LIB_PATH C:/data/projekte/freeRTOS_lib/) + # search for programs in the build host directories SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH) # for libraries and headers in the target directories diff --git a/base_c/include/embb/base/c/internal/config.h b/base_c/include/embb/base/c/internal/config.h index 8a08174..e679577 100644 --- a/base_c/include/embb/base/c/internal/config.h +++ b/base_c/include/embb/base/c/internal/config.h @@ -46,6 +46,8 @@ */ #if defined(_M_IA64) || defined(_IA64) #define EMBB_PLATFORM_CACHE_LINE_SIZE 128 +#elif defined(__TriCore__) +#define EMBB_PLATFORM_CACHE_LINE_SIZE 32 #else #define EMBB_PLATFORM_CACHE_LINE_SIZE 64 #endif @@ -86,6 +88,8 @@ #define EMBB_PLATFORM_ARCH_X86 #elif defined(__arm__) #define EMBB_PLATFORM_ARCH_ARM +#elif defined(__TriCore__) +#define EMBB_PLATFORM_ARCH_TC #else #define EMBB_PLATFORM_ARCH_UNKNOWN #endif @@ -93,7 +97,11 @@ #if defined(EMBB_PLATFORM_COMPILER_MSVC) #define EMBB_PLATFORM_THREADING_WINTHREADS #elif defined(EMBB_PLATFORM_COMPILER_GNUC) -#define EMBB_PLATFORM_THREADING_POSIXTHREADS + #if defined(EMBB_PLATFORM_ARCH_TC) + #define EMBB_PLATFORM_THREADING_RTOSTASKS + #else + #define EMBB_PLATFORM_THREADING_POSIXTHREADS + #endif #else #error "No thread implementation could be determined" #endif diff --git a/base_c/include/embb/base/c/internal/platform.h b/base_c/include/embb/base/c/internal/platform.h index 5e21de6..3a6e505 100644 --- a/base_c/include/embb/base/c/internal/platform.h +++ b/base_c/include/embb/base/c/internal/platform.h @@ -71,6 +71,7 @@ typedef CONDITION_VARIABLE embb_condition_t; #define EMBB_THREAD_SPECIFIC static __declspec(thread) +/* EMBB_PLATFORM_THREADING_WINTHREADS */ #elif defined EMBB_PLATFORM_THREADING_POSIXTHREADS #include @@ -95,7 +96,31 @@ typedef pthread_cond_t embb_condition_t; #define EMBB_THREAD_SPECIFIC __thread -#else /* EMBB_PLATFORM_THREADING_POSIXTHREADS */ +/* EMBB_PLATFORM_THREADING_POSIXTHREADS */ +#elif defined EMBB_PLATFORM_THREADING_RTOSTASKS + +#include +#include + +struct embb_internal_thread_arg_t; + +/** +* Opaque handle for a thread. +*/ +typedef struct embb_thread_t { + TaskHandle_t embb_internal_handle; + struct embb_internal_thread_arg_t* embb_internal_arg; +} embb_thread_t; + +typedef TaskStatus_t embb_thread_id_t; +typedef SemaphoreHandle_t embb_mutex_t; +typedef SemaphoreHandle_t embb_condition_t; // scm34681: implement FreeRTOS condition variable + +#define EMBB_DURATION_MIN_NANOSECONDS 1000 + +#define EMBB_THREAD_SPECIFIC + +#else /* EMBB_PLATFORM_THREADING_RTOSTASKS */ #error "No threading platform defined!" diff --git a/base_c/src/condition_variable.c b/base_c/src/condition_variable.c index 9a513a2..f5b7fdd 100644 --- a/base_c/src/condition_variable.c +++ b/base_c/src/condition_variable.c @@ -185,3 +185,7 @@ int embb_condition_destroy(embb_condition_t* condition_var) { } #endif /* EMBB_PLATFORM_THREADING_POSIXTHREADS */ + +#ifdef EMBB_PLATFORM_THREADING_RTOSTASKS + +#endif /* EMBB_PLATFORM_THREADING_RTOSTASKS */ diff --git a/base_c/src/core_set.c b/base_c/src/core_set.c index 96ecdc0..0b27a3f 100644 --- a/base_c/src/core_set.c +++ b/base_c/src/core_set.c @@ -125,6 +125,32 @@ void embb_core_set_init(embb_core_set_t* core_set, int initializer) { #endif /* EMBB_PLATFORM_THREADING_POSIXTHREADS */ +#ifdef EMBB_PLATFORM_THREADING_RTOSTASKS +#ifdef __TriCore__ +#define CORE_COUNT 3 +#endif + + +unsigned int embb_core_count_available() { + return CORE_COUNT; +} + + + +void embb_core_set_init(embb_core_set_t* core_set, int initializer) { // scm34681: rework + assert(core_set != NULL); + assert(embb_core_count_available() < 64 && + "Core sets are only supported up to 64 processors!"); + if (initializer == 0) { + embb_bitset_clear_all(&core_set->rep); + } else { + embb_bitset_set_n(&core_set->rep, embb_core_count_available()); + } +} + + +#endif EMBB_PLATFORM_THREADING_RTOSTASKS + void embb_core_set_add(embb_core_set_t* core_set, unsigned int core_number) { assert(core_set != NULL); assert(core_number < embb_core_count_available()); diff --git a/base_c/src/memory_allocation.c b/base_c/src/memory_allocation.c index 46f2828..0a0b0fa 100644 --- a/base_c/src/memory_allocation.c +++ b/base_c/src/memory_allocation.c @@ -178,6 +178,14 @@ void *embb_alloc_aligned(size_t alignment, size_t size) { */ malloc_addr = _aligned_malloc(size, alignment); #elif defined EMBB_PLATFORM_COMPILER_GNUC +#ifdef __TRICORE__ + /* + * The TriCore Toolchain uses obsolete function memalign() for + * aligned memory allocation. + */ +#include // scm3681: rework + malloc_addr = memalign(alignment, size); +#else /* __TRICORE__ */ /* * From the Documentation: * The posix_memalign() function shall allocate size bytes aligned on a @@ -190,6 +198,7 @@ void *embb_alloc_aligned(size_t alignment, size_t size) { int status = posix_memalign(&malloc_addr, alignment, size); EMBB_UNUSED(status); #endif +#endif return malloc_addr; } diff --git a/base_c/src/mutex.c b/base_c/src/mutex.c index 5ccb0ab..a376590 100644 --- a/base_c/src/mutex.c +++ b/base_c/src/mutex.c @@ -1,28 +1,28 @@ /* - * 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. - */ +* 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. +*/ #include #include @@ -33,44 +33,44 @@ #ifdef EMBB_PLATFORM_THREADING_WINTHREADS int embb_mutex_init(embb_mutex_t* mutex, int type) { - if (NULL == mutex) { - return EMBB_ERROR; - } - /* Critical sections in Windows are always recursive */ - InitializeCriticalSection(mutex); - EMBB_UNUSED(type); - return EMBB_SUCCESS; + if (NULL == mutex) { + return EMBB_ERROR; + } + /* Critical sections in Windows are always recursive */ + InitializeCriticalSection(mutex); + EMBB_UNUSED(type); + return EMBB_SUCCESS; } int embb_mutex_lock(embb_mutex_t* mutex) { - if (NULL == mutex) { - return EMBB_ERROR; - } - EnterCriticalSection(mutex); - return EMBB_SUCCESS; + if (NULL == mutex) { + return EMBB_ERROR; + } + EnterCriticalSection(mutex); + return EMBB_SUCCESS; } int embb_mutex_try_lock(embb_mutex_t* mutex) { - if (NULL == mutex) { - return EMBB_ERROR; - } - BOOL success; - success = TryEnterCriticalSection(mutex); - if (success == FALSE) return EMBB_ERROR; - return EMBB_SUCCESS; + if (NULL == mutex) { + return EMBB_ERROR; + } + BOOL success; + success = TryEnterCriticalSection(mutex); + if (success == FALSE) return EMBB_ERROR; + return EMBB_SUCCESS; } int embb_mutex_unlock(embb_mutex_t* mutex) { - if (NULL == mutex) { - return EMBB_ERROR; - } - LeaveCriticalSection(mutex); - return EMBB_SUCCESS; + if (NULL == mutex) { + return EMBB_ERROR; + } + LeaveCriticalSection(mutex); + return EMBB_SUCCESS; } void embb_mutex_destroy(embb_mutex_t* mutex) { - assert(NULL != mutex); - DeleteCriticalSection(mutex); + assert(NULL != mutex); + DeleteCriticalSection(mutex); } #endif /* EMBB_PLATFORM_THREADING_WINTHREADS */ @@ -78,136 +78,208 @@ void embb_mutex_destroy(embb_mutex_t* mutex) { #ifdef EMBB_PLATFORM_THREADING_POSIXTHREADS int embb_mutex_init(embb_mutex_t* mutex, int type) { - if (NULL == mutex) { - return EMBB_ERROR; - } - if (type == EMBB_MUTEX_PLAIN) { - if (pthread_mutex_init(mutex, NULL) != 0) return EMBB_ERROR; - } else { - assert(type == EMBB_MUTEX_RECURSIVE); - pthread_mutexattr_t attributes; - if (pthread_mutexattr_init(&attributes) != 0) return EMBB_ERROR; - if (pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE) != 0) { - pthread_mutexattr_destroy(&attributes); - return EMBB_ERROR; - } - if (pthread_mutex_init(mutex, &attributes) != 0) { - pthread_mutexattr_destroy(&attributes); - return EMBB_ERROR; - } - if (pthread_mutexattr_destroy(&attributes) != 0) return EMBB_ERROR; - } - return EMBB_SUCCESS; + if (NULL == mutex) { + return EMBB_ERROR; + } + if (type == EMBB_MUTEX_PLAIN) { + if (pthread_mutex_init(mutex, NULL) != 0) return EMBB_ERROR; + } else { + assert(type == EMBB_MUTEX_RECURSIVE); + pthread_mutexattr_t attributes; + if (pthread_mutexattr_init(&attributes) != 0) return EMBB_ERROR; + if (pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE) != 0) { + pthread_mutexattr_destroy(&attributes); + return EMBB_ERROR; + } + if (pthread_mutex_init(mutex, &attributes) != 0) { + pthread_mutexattr_destroy(&attributes); + return EMBB_ERROR; + } + if (pthread_mutexattr_destroy(&attributes) != 0) return EMBB_ERROR; + } + return EMBB_SUCCESS; } int embb_mutex_lock(embb_mutex_t* mutex) { - if (NULL == mutex) { - return EMBB_ERROR; - } - int result = pthread_mutex_lock(mutex); - if (result != 0) { - return EMBB_ERROR; - } - return EMBB_SUCCESS; + if (NULL == mutex) { + return EMBB_ERROR; + } + int result = pthread_mutex_lock(mutex); + if (result != 0) { + return EMBB_ERROR; + } + return EMBB_SUCCESS; } int embb_mutex_try_lock(embb_mutex_t* mutex) { - if (NULL == mutex) { - return EMBB_ERROR; - } - int result = pthread_mutex_trylock(mutex); - if (result == 0) { - return EMBB_SUCCESS; - } - if (result == EBUSY) { - return EMBB_BUSY; - } - return EMBB_ERROR; + if (NULL == mutex) { + return EMBB_ERROR; + } + int result = pthread_mutex_trylock(mutex); + if (result == 0) { + return EMBB_SUCCESS; + } + if (result == EBUSY) { + return EMBB_BUSY; + } + return EMBB_ERROR; } int embb_mutex_unlock(embb_mutex_t* mutex) { - if (NULL == mutex) { - return EMBB_ERROR; - } - int result = pthread_mutex_unlock(mutex); - if (result != 0) { - return EMBB_ERROR; - } - return EMBB_SUCCESS; + if (NULL == mutex) { + return EMBB_ERROR; + } + int result = pthread_mutex_unlock(mutex); + if (result != 0) { + return EMBB_ERROR; + } + return EMBB_SUCCESS; } void embb_mutex_destroy(embb_mutex_t* mutex) { - assert(NULL != mutex); - pthread_mutex_destroy(mutex); + assert(NULL != mutex); + pthread_mutex_destroy(mutex); } #endif /* EMBB_PLATFORM_THREADING_POSIXTHREADS */ + +#ifdef EMBB_PLATFORM_THREADING_RTOSTASKS + +#include +#include + +int embb_mutex_init(embb_mutex_t* mutex, int type) { + if (NULL == mutex) { + return EMBB_ERROR; + } + + /* + * scm34681: + * Type of mutex cannot be determined from SemaphoreHandle_t, + * but mutex gets locked with two different functions. + * ==> only recursive mutexes are used. + * Check Queue_t for type checking. Queue_t not defined in queue.h + * but queue.c... + */ + /*if(type == EMBB_MUTEX_PLAIN) { + mutex = xSemaphoreCreateMutex(); + } + else { + assert(type == EMBB_MUTEX_RECURSIVE);*/ + mutex = xSemaphoreCreateRecursiveMutex(); + /*}*/ + + EMBB_UNUSED(type); + + if(mutex == NULL) { + return EMBB_ERROR; + } + + return EMBB_SUCCESS; +} + +int embb_mutex_lock(embb_mutex_t* mutex) { + if (NULL == mutex) { + return EMBB_ERROR; + } + int result = xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + if (result != 1) return EMBB_ERROR; + return EMBB_SUCCESS; +} + +int embb_mutex_try_lock(embb_mutex_t* mutex) { + if (NULL == mutex) { + return EMBB_ERROR; + } + + int result = xSemaphoreTakeRecursive(mutex, 0); + if (result != 1) return EMBB_ERROR; + return EMBB_SUCCESS; +} + +int embb_mutex_unlock(embb_mutex_t* mutex) { + if (NULL == mutex) { + return EMBB_ERROR; + } + int result = xSemaphoreGiveRecursive(mutex); + if(result != 1) return EMBB_ERROR; + return EMBB_SUCCESS; +} + +void embb_mutex_destroy(embb_mutex_t* mutex) { + assert(NULL != mutex); + vSemaphoreDelete(mutex); +} + + +#endif /* EMBB_PLATFORM_THREADING_RTOSTASKS */ + 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); - return EMBB_SUCCESS; + 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); + return EMBB_SUCCESS; } int embb_spin_lock(embb_spinlock_t* spinlock) { - if (NULL == spinlock) { - return EMBB_ERROR; - } - int expected = 0; - int spins = 1; - - // try to swap the - while (0 == embb_atomic_compare_and_swap_int( - &spinlock->atomic_spin_variable_, &expected, 1)) { - if (0 == (spins & 1023)) { - embb_thread_yield(); - } - spins++; - // reset expected, as CAS might change it... - expected = 0; - } - return EMBB_SUCCESS; + if (NULL == spinlock) { + return EMBB_ERROR; + } + int expected = 0; + int spins = 1; + + // try to swap the + while (0 == embb_atomic_compare_and_swap_int( + &spinlock->atomic_spin_variable_, &expected, 1)) { + if (0 == (spins & 1023)) { + embb_thread_yield(); + } + spins++; + // reset expected, as CAS might change it... + expected = 0; + } + return EMBB_SUCCESS; } int embb_spin_try_lock(embb_spinlock_t* spinlock, - unsigned int max_number_spins) { - if (NULL == spinlock) { - return EMBB_ERROR; - } - if (max_number_spins == 0) - return EMBB_BUSY; - - int expected = 0; - while (0 == embb_atomic_compare_and_swap_int( - &spinlock->atomic_spin_variable_, - &expected, 1)) { - max_number_spins--; - if (0 == max_number_spins) { - return EMBB_BUSY; - } - expected = 0; - } - - return EMBB_SUCCESS; +unsigned int max_number_spins) { + if (NULL == spinlock) { + return EMBB_ERROR; + } + if (max_number_spins == 0) + return EMBB_BUSY; + + int expected = 0; + while (0 == embb_atomic_compare_and_swap_int( + &spinlock->atomic_spin_variable_, + &expected, 1)) { + max_number_spins--; + if (0 == max_number_spins) { + return EMBB_BUSY; + } + expected = 0; + } + + return EMBB_SUCCESS; } int embb_spin_unlock(embb_spinlock_t* spinlock) { - if (NULL == spinlock) { - return EMBB_ERROR; - } - int expected = 1; - return embb_atomic_compare_and_swap_int(&spinlock->atomic_spin_variable_, - &expected, 0) ? - EMBB_SUCCESS : EMBB_ERROR; + if (NULL == spinlock) { + return EMBB_ERROR; + } + int expected = 1; + return embb_atomic_compare_and_swap_int(&spinlock->atomic_spin_variable_, + &expected, 0) ? + EMBB_SUCCESS : EMBB_ERROR; } 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); + assert(NULL != spinlock); + // for now, doing nothing here... in future, will call the respective + // destroy function for atomics... + EMBB_UNUSED(spinlock); } diff --git a/base_c/src/thread.c b/base_c/src/thread.c index f88b2ab..773e1ab 100644 --- a/base_c/src/thread.c +++ b/base_c/src/thread.c @@ -1,28 +1,28 @@ /* - * 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. - */ +* 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. +*/ #include #include @@ -33,135 +33,135 @@ #include unsigned int embb_thread_get_max_count() { - return (unsigned int)(embb_internal_thread_index_max()); + return (unsigned int)(embb_internal_thread_index_max()); } void embb_thread_set_max_count(unsigned int max) { - embb_internal_thread_index_set_max(max); + embb_internal_thread_index_set_max(max); } #ifdef EMBB_PLATFORM_THREADING_WINTHREADS /** - * Used to wrap client thread start function and argument when calling internal - * thread start function embb_internal_thread_start. - */ +* Used to wrap client thread start function and argument when calling internal +* thread start function embb_internal_thread_start. +*/ typedef struct embb_internal_thread_arg_t { - embb_thread_start_t func; - void* arg; + embb_thread_start_t func; + void* arg; } embb_internal_thread_arg_t; /** - * Used to offer a consistent thread start function signature. Windows threads - * have a different signature than Pthreads and C11. This internal start - * function for Windows threads just calls the client start function with the - * given argument. - */ +* Used to offer a consistent thread start function signature. Windows threads +* have a different signature than Pthreads and C11. This internal start +* function for Windows threads just calls the client start function with the +* given argument. +*/ DWORD WINAPI embb_internal_thread_start(LPVOID internalArg) { - int result = ((embb_internal_thread_arg_t*)internalArg)->func( - ((embb_internal_thread_arg_t*)internalArg)->arg); + int result = ((embb_internal_thread_arg_t*)internalArg)->func( + ((embb_internal_thread_arg_t*)internalArg)->arg); #if !defined(__cplusplus) - ExitThread((DWORD)result); /* In C, returning the result code doesn't work */ + ExitThread((DWORD)result); /* In C, returning the result code doesn't work */ #else - return (DWORD)result; + return (DWORD)result; #endif } embb_thread_t embb_thread_current() { - embb_thread_t thread; - thread.embb_internal_handle = GetCurrentThread(); - thread.embb_internal_arg = NULL; - return thread; + embb_thread_t thread; + thread.embb_internal_handle = GetCurrentThread(); + thread.embb_internal_arg = NULL; + return thread; } void embb_thread_yield() { - SwitchToThread(); + SwitchToThread(); } int embb_thread_create(embb_thread_t* thread, const embb_core_set_t* core_set, - embb_thread_start_t func, void *arg) { - if (thread == NULL) { - return EMBB_ERROR; - } - thread->embb_internal_arg = (embb_internal_thread_arg_t*) - embb_alloc(sizeof(embb_internal_thread_arg_t)); - if (thread->embb_internal_arg == NULL) { - thread->embb_internal_handle = NULL; - return EMBB_NOMEM; - } - thread->embb_internal_arg->func = func; - thread->embb_internal_arg->arg = arg; - - thread->embb_internal_handle = CreateThread( - 0, /* no security */ - 0, /* default stack size */ - embb_internal_thread_start, /* entry function */ - (LPVOID)thread->embb_internal_arg, /* parameters */ - 0, /* no creation arguments */ - 0); /* no system thread ID */ - if (thread->embb_internal_handle == NULL) { - embb_free(thread->embb_internal_arg); - thread->embb_internal_arg = NULL; - return EMBB_ERROR; - } - - if (core_set != NULL) { /* Set thread affinity, if a core set is given */ - DWORD_PTR core_mask = 0; - DWORD bit_mask = 1; - assert(embb_core_count_available() < 64); - for (unsigned int i = 0; i < embb_core_count_available(); i++) { - if (embb_core_set_contains(core_set, i)) { - core_mask |= bit_mask; - } - bit_mask <<= 1; - } - if (SetThreadAffinityMask(thread->embb_internal_handle, core_mask) - == (DWORD_PTR)NULL) { - return EMBB_ERROR; - } - } - - return EMBB_SUCCESS; +embb_thread_start_t func, void *arg) { + if (thread == NULL) { + return EMBB_ERROR; + } + thread->embb_internal_arg = (embb_internal_thread_arg_t*) + embb_alloc(sizeof(embb_internal_thread_arg_t)); + if (thread->embb_internal_arg == NULL) { + thread->embb_internal_handle = NULL; + return EMBB_NOMEM; + } + thread->embb_internal_arg->func = func; + thread->embb_internal_arg->arg = arg; + + thread->embb_internal_handle = CreateThread( + 0, /* no security */ + 0, /* default stack size */ + embb_internal_thread_start, /* entry function */ + (LPVOID)thread->embb_internal_arg, /* parameters */ + 0, /* no creation arguments */ + 0); /* no system thread ID */ + if (thread->embb_internal_handle == NULL) { + embb_free(thread->embb_internal_arg); + thread->embb_internal_arg = NULL; + return EMBB_ERROR; + } + + if (core_set != NULL) { /* Set thread affinity, if a core set is given */ + DWORD_PTR core_mask = 0; + DWORD bit_mask = 1; + assert(embb_core_count_available() < 64); + for (unsigned int i = 0; i < embb_core_count_available(); i++) { + if (embb_core_set_contains(core_set, i)) { + core_mask |= bit_mask; + } + bit_mask <<= 1; + } + if (SetThreadAffinityMask(thread->embb_internal_handle, core_mask) + == (DWORD_PTR)NULL) { + return EMBB_ERROR; + } + } + + return EMBB_SUCCESS; } int embb_thread_join(embb_thread_t* thread, int* result_code) { - if (thread == NULL) { - return EMBB_ERROR; - } - BOOL success; - DWORD result; - result = WaitForSingleObject(thread->embb_internal_handle, INFINITE); - embb_free(thread->embb_internal_arg); - if (result != WAIT_OBJECT_0) { - /* WAIT_OBJECT_0 indicates successful waiting */ - return EMBB_ERROR; - } - if (result_code != NULL) { /* != NULL means the client wants a result code */ - if (GetExitCodeThread(thread->embb_internal_handle, &result) != 0) { - *result_code = (int)result; - } else { - *result_code = 0; /* Error on obtaining result code */ - return EMBB_ERROR; - } - } - success = CloseHandle(thread->embb_internal_handle); - if (success == FALSE) { - return EMBB_ERROR; - } - /*return embb_internal_thread_counter_try_decrement();*/ - return EMBB_SUCCESS; + if (thread == NULL) { + return EMBB_ERROR; + } + BOOL success; + DWORD result; + result = WaitForSingleObject(thread->embb_internal_handle, INFINITE); + embb_free(thread->embb_internal_arg); + if (result != WAIT_OBJECT_0) { + /* WAIT_OBJECT_0 indicates successful waiting */ + return EMBB_ERROR; + } + if (result_code != NULL) { /* != NULL means the client wants a result code */ + if (GetExitCodeThread(thread->embb_internal_handle, &result) != 0) { + *result_code = (int)result; + } else { + *result_code = 0; /* Error on obtaining result code */ + return EMBB_ERROR; + } + } + success = CloseHandle(thread->embb_internal_handle); + if (success == FALSE) { + return EMBB_ERROR; + } + /*return embb_internal_thread_counter_try_decrement();*/ + return EMBB_SUCCESS; } int embb_thread_equal(const embb_thread_t* lhs, const embb_thread_t* rhs) { - if (lhs == NULL || rhs == NULL) { - return 0; - } - embb_thread_id_t idLhs = GetThreadId(lhs->embb_internal_handle); - embb_thread_id_t idRhs = GetThreadId(rhs->embb_internal_handle); - if (idLhs == idRhs) { - return 1; - } - return 0; + if (lhs == NULL || rhs == NULL) { + return 0; + } + embb_thread_id_t idLhs = GetThreadId(lhs->embb_internal_handle); + embb_thread_id_t idRhs = GetThreadId(rhs->embb_internal_handle); + if (idLhs == idRhs) { + return 1; + } + return 0; } #endif /* EMBB_PLATFORM_THREADING_WINTHREADS */ @@ -181,122 +181,247 @@ int embb_thread_equal(const embb_thread_t* lhs, const embb_thread_t* rhs) { #endif /* EMBB_PLATFORM_HAS_HEADER_SYSINFO */ /** - * Used to wrap client thread start function and argument when calling internal - * thread start function embb_internal_thread_start. - */ +* Used to wrap client thread start function and argument when calling internal +* thread start function embb_internal_thread_start. +*/ typedef struct embb_internal_thread_arg_t { - embb_thread_start_t func; - void* arg; - int result; + embb_thread_start_t func; + void* arg; + int result; } embb_internal_thread_arg_t; /** - * Used to offer a consistent thread start function signature. POSIX threads - * have a different signature than C11 threads. This internal start function - * for POSIX threads just calls the client start function with the given - * argument. - */ +* Used to offer a consistent thread start function signature. POSIX threads +* have a different signature than C11 threads. This internal start function +* for POSIX threads just calls the client start function with the given +* argument. +*/ void* embb_internal_thread_start(void* internalArg) { - ((embb_internal_thread_arg_t*)internalArg)->result = - ((embb_internal_thread_arg_t*)internalArg)->func( - ((struct embb_internal_thread_arg_t*)internalArg)->arg); - return NULL; + ((embb_internal_thread_arg_t*)internalArg)->result = + ((embb_internal_thread_arg_t*)internalArg)->func( + ((struct embb_internal_thread_arg_t*)internalArg)->arg); + return NULL; } embb_thread_t embb_thread_current() { - embb_thread_t thread; - thread.embb_internal_handle = pthread_self(); - thread.embb_internal_arg = NULL; - return thread; + embb_thread_t thread; + thread.embb_internal_handle = pthread_self(); + thread.embb_internal_arg = NULL; + return thread; } void embb_thread_yield() { - pthread_yield(); + pthread_yield(); } int embb_thread_create(embb_thread_t* thread, const embb_core_set_t* core_set, - embb_thread_start_t func, void* arg) { - if (thread == NULL) { - return EMBB_ERROR; - } - pthread_attr_t attr; /* Used to set thread affinities */ - int status = pthread_attr_init(&attr); - if (status != 0) return EMBB_ERROR; - if (core_set != NULL) { +embb_thread_start_t func, void* arg) { + if (thread == NULL) { + return EMBB_ERROR; + } + pthread_attr_t attr; /* Used to set thread affinities */ + int status = pthread_attr_init(&attr); + if (status != 0) return EMBB_ERROR; + if (core_set != NULL) { #if defined(EMBB_PLATFORM_HAS_GLIB_CPU) || \ - defined(EMBB_PLATFORM_HAS_HEADER_CPUSET) - assert(embb_core_count_available() < CPU_SETSIZE && - "Core sets are only supported up to CPU_SETSIZE processors!"); + defined(EMBB_PLATFORM_HAS_HEADER_CPUSET) + assert(embb_core_count_available() < CPU_SETSIZE && + "Core sets are only supported up to CPU_SETSIZE processors!"); #ifdef EMBB_PLATFORM_HAS_GLIB_CPU - cpu_set_t cpuset; + cpu_set_t cpuset; #else - cpuset_t cpuset; + cpuset_t cpuset; #endif - CPU_ZERO(&cpuset); /* Disable all processors */ - for (unsigned int i = 0; i < embb_core_count_available(); i++) { - if (embb_core_set_contains(core_set, i)) { - CPU_SET(i, &cpuset); - } - } - status = pthread_attr_setaffinity_np(&attr, sizeof(cpuset), &cpuset); - if (status != 0) { - thread->embb_internal_arg = NULL; - thread->embb_internal_handle = 0; - return EMBB_ERROR; - } + CPU_ZERO(&cpuset); /* Disable all processors */ + for (unsigned int i = 0; i < embb_core_count_available(); i++) { + if (embb_core_set_contains(core_set, i)) { + CPU_SET(i, &cpuset); + } + } + status = pthread_attr_setaffinity_np(&attr, sizeof(cpuset), &cpuset); + if (status != 0) { + thread->embb_internal_arg = NULL; + thread->embb_internal_handle = 0; + return EMBB_ERROR; + } #else - embb_log_write("base_c", EMBB_LOG_LEVEL_WARNING, "Could not set thread " - "affinity, since no implementation available!\n"); + embb_log_write("base_c", EMBB_LOG_LEVEL_WARNING, "Could not set thread " + "affinity, since no implementation available!\n"); #endif - } - - /* Dynamic allocation of thread arguments. Freed on call of join. */ - thread->embb_internal_arg = (embb_internal_thread_arg_t*) - embb_alloc(sizeof(embb_internal_thread_arg_t)); - if (thread->embb_internal_arg == NULL) { - thread->embb_internal_handle = 0; - pthread_attr_destroy(&attr); - return EMBB_NOMEM; - } - thread->embb_internal_arg->func = func; - thread->embb_internal_arg->arg = arg; - - status = pthread_create( - &(thread->embb_internal_handle), /* pthread handle */ - &attr, /* additional attributes, - e.g., affinities */ - embb_internal_thread_start, /* thread start function */ - (void*)(thread->embb_internal_arg)); /* arguments to thread start func. */ - if (status != 0) return EMBB_ERROR; - - status = pthread_attr_destroy(&attr); - if (status != 0) return EMBB_ERROR; - return EMBB_SUCCESS; + } + + /* Dynamic allocation of thread arguments. Freed on call of join. */ + thread->embb_internal_arg = (embb_internal_thread_arg_t*) + embb_alloc(sizeof(embb_internal_thread_arg_t)); + if (thread->embb_internal_arg == NULL) { + thread->embb_internal_handle = 0; + pthread_attr_destroy(&attr); + return EMBB_NOMEM; + } + thread->embb_internal_arg->func = func; + thread->embb_internal_arg->arg = arg; + + status = pthread_create( + &(thread->embb_internal_handle), /* pthread handle */ + &attr, /* additional attributes, + e.g., affinities */ + embb_internal_thread_start, /* thread start function */ + (void*)(thread->embb_internal_arg)); /* arguments to thread start func. */ + if (status != 0) return EMBB_ERROR; + + status = pthread_attr_destroy(&attr); + if (status != 0) return EMBB_ERROR; + return EMBB_SUCCESS; } int embb_thread_join(embb_thread_t* thread, int *result_code) { - if (thread == NULL) { - return EMBB_ERROR; - } - int status = 0; - status = pthread_join(thread->embb_internal_handle, NULL); - if (thread->embb_internal_arg != NULL) { - if (result_code != NULL) { - *result_code = thread->embb_internal_arg->result; - } - embb_free(thread->embb_internal_arg); - } - if (status != 0) { - return EMBB_ERROR; - } - return EMBB_SUCCESS; + if (thread == NULL) { + return EMBB_ERROR; + } + int status = 0; + status = pthread_join(thread->embb_internal_handle, NULL); + if (thread->embb_internal_arg != NULL) { + if (result_code != NULL) { + *result_code = thread->embb_internal_arg->result; + } + embb_free(thread->embb_internal_arg); + } + if (status != 0) { + return EMBB_ERROR; + } + return EMBB_SUCCESS; } int embb_thread_equal(const embb_thread_t* lhs, const embb_thread_t* rhs) { - if (lhs == NULL || rhs == NULL) { - return 0; - } - return pthread_equal(lhs->embb_internal_handle, rhs->embb_internal_handle); + if (lhs == NULL || rhs == NULL) { + return 0; + } + return pthread_equal(lhs->embb_internal_handle, rhs->embb_internal_handle); } #endif /* EMBB_PLATFORM_THREADING_POSIXTHREADS */ + +#ifdef EMBB_PLATFORM_THREADING_RTOSTASKS + +#include + +/** +* Used to wrap client thread start function and argument when calling internal +* thread start function embb_internal_thread_start. +*/ +typedef struct embb_internal_thread_arg_t { + embb_thread_start_t func; + void* arg; + int result; +} embb_internal_thread_arg_t; + + +/** +* Used to offer a consistent thread start function signature. POSIX threads +* have a different signature than C11 threads. This internal start function +* for POSIX threads just calls the client start function with the given +* argument. +*/ +void* embb_internal_thread_start(void* internalArg) { + for(;;) { + ((embb_internal_thread_arg_t*)internalArg)->result = + ((embb_internal_thread_arg_t*)internalArg)->func( + ((struct embb_internal_thread_arg_t*)internalArg)->arg); + + vTaskDelete(NULL); + } +} + +embb_thread_t embb_thread_current() { + embb_thread_t thread; + thread.embb_internal_handle = xTaskGetCurrentTaskHandle(); + thread.embb_internal_arg = NULL; + return thread; +} + +void embb_thread_yield() { + taskYIELD(); +} + + +int embb_thread_create(embb_thread_t* thread, const embb_core_set_t* core_set, +embb_thread_start_t func, void *arg) { + int status; + if (thread == NULL) { + return EMBB_ERROR; + } + thread->embb_internal_arg = (embb_internal_thread_arg_t*) + embb_alloc(sizeof(embb_internal_thread_arg_t)); + if (thread->embb_internal_arg == NULL) { + thread->embb_internal_handle = NULL; + return EMBB_NOMEM; + } + + thread->embb_internal_arg->func = func; + thread->embb_internal_arg->arg = arg; + + status = xTaskCreate( embb_internal_thread_start, // entry function + 0, // task name (not needed) + 128, // stack size + thread->embb_internal_arg, // parameters + 1, // priority + thread->embb_internal_handle); // thread handle + + + if (status != 1) { + embb_free(thread->embb_internal_arg); + thread->embb_internal_arg = NULL; + return EMBB_ERROR; + } + + /*if (core_set != NULL) { // scm34681: implement core affinity + DWORD_PTR core_mask = 0; + DWORD bit_mask = 1; + assert(embb_core_count_available() < 64); + for (unsigned int i = 0; i < embb_core_count_available(); i++) { + if (embb_core_set_contains(core_set, i)) { + core_mask |= bit_mask; + } + bit_mask <<= 1; + } + if (SetThreadAffinityMask(thread->embb_internal_handle, core_mask) + == (DWORD_PTR)NULL) { + return EMBB_ERROR; + } +}*/ + + return EMBB_SUCCESS; +} + +int embb_thread_join(embb_thread_t* thread, int *result_code) { + if (thread == NULL) { + return EMBB_ERROR; + } + int status = 0; + while(thread->embb_internal_handle != NULL && status++ < 10000); // scm34681: rework + + if (thread->embb_internal_arg != NULL) { + if (result_code != NULL) { + *result_code = thread->embb_internal_arg->result; + } + embb_free(thread->embb_internal_arg); + } + + + return EMBB_SUCCESS; +} + +int embb_thread_equal(const embb_thread_t* lhs, const embb_thread_t* rhs) { + if (lhs == NULL || rhs == NULL) { + return 0; + } + TaskStatus_t lhs_info; + TaskStatus_t rhs_info; + + vTaskGetInfo(lhs->embb_internal_handle, &lhs_info, 0, 0); + vTaskGetInfo(lhs->embb_internal_handle, &rhs_info, 0, 0); + + return lhs_info.xTaskNumber == rhs_info.xTaskNumber; +} + +#endif /* EMBB_PLATFORM_THREADING_RTOSTASKS */