Commit 3bac4c22 by Marcus Winter

Merge branch 'development' into embb517_mutex_based_atomics

# Conflicts:
#	algorithms_cpp/test/main.cc
#	containers_cpp/test/main.cc
#	tasks_cpp/test/main.cc
parents 37f9fa13 298a6e03
......@@ -99,9 +99,9 @@ endif()
message(" (set with command line option -DWARNINGS_ARE_ERRORS=ON/OFF)")
if (USE_AUTOMATIC_INITIALIZATION STREQUAL ON)
message("-- MTAPI/Tasks automatic initialization enabled (default)")
message("-- MTAPI automatic initialization enabled (default)")
else()
message("-- MTAPI/Tasks automatic initialization disabled")
message("-- MTAPI automatic initialization disabled")
endif()
message(" (set with command line option -DUSE_AUTOMATIC_INITIALIZATION=ON/OFF)")
......@@ -146,7 +146,6 @@ set(EXPECTED_EMBB_TEST_EXECUTABLES "embb_algorithms_cpp_test"
"embb_mtapi_c_test"
"embb_mtapi_cpp_test"
"embb_mtapi_network_c_test"
"embb_tasks_cpp_test"
)
# if opencl is there, we also expect the mtapi opencl test to be generated
......@@ -189,7 +188,6 @@ add_subdirectory(mtapi_plugins_c/mtapi_network_c)
if(BUILD_OPENCL_PLUGIN STREQUAL ON)
add_subdirectory(mtapi_plugins_c/mtapi_opencl_c)
endif()
add_subdirectory(tasks_cpp)
add_subdirectory(mtapi_cpp)
add_subdirectory(containers_cpp)
add_subdirectory(algorithms_cpp)
......
......@@ -59,7 +59,7 @@ Subscription:
Contact:
- embb.info@gmail.com or
- tobias.schuele@siemens.com
- tobias.schuele@siemens.com, sebnem.rusitschka@siemens.com
License
......@@ -100,7 +100,6 @@ Currently, EMB² contains the following components:
- base: base_c, base_cpp
- mtapi: mtapi_c, mtapi_cpp and
mtapi_plugins_c (mtapi_network_c and mtapi_opencl_c)
- tasks: tasks_cpp
- algorithms: algorithms_cpp
- dataflow: dataflow_cpp
- containers: containers_cpp
......@@ -114,10 +113,9 @@ implemented in C. Component base_cpp is mainly a C++ wrapper around the base_c
functions. Component mtapi_c is a task scheduler written in C and mtapi_cpp a
C++ wrapper for the scheduler (mtapi_network_c and mtapi_opencl_c are scheduler
plugins for distributed and OpenCL-based heterogeneous systems, respectively).
To simplify programming of homogeneous systems, tasks_cpp contains abstractions
to the MTAPI interfaces. Component algorithms_cpp provides high-level constructs
for typical parallelization tasks in C++, and dataflow_cpp generic skeletons for
the development of parallel stream-based applications. Finally, containers_cpp
Component algorithms_cpp provides high-level constructs for typical
parallelization tasks in C++, and dataflow_cpp generic skeletons for the
development of parallel stream-based applications. Finally, containers_cpp
provides data structures for storing objects in a thread-safe way.
......@@ -370,6 +368,10 @@ Important Notes
performance measurements, explicit initialization is strongly recommended
since the measurements will otherwise include the initialization time of
MTAPI.
- When using ThreadSanitizer there is a bug that causes the built-in CMake type
size determination to fail which in turn leads to a broken configuration.
Therefore, you have to do a normal build first and then rerun CMake with
flags and libs configured for ThreadSanitizer.
Links
......
......@@ -17,18 +17,18 @@ include_directories(${EMBB_ALGORITHMS_CPP_INCLUDE_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/../base_cpp/include
${CMAKE_CURRENT_BINARY_DIR}/../base_cpp/include
${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_c/include
${CMAKE_CURRENT_SOURCE_DIR}/../tasks_cpp/include
${CMAKE_CURRENT_BINARY_DIR}/../tasks_cpp/include)
${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_cpp/include
${CMAKE_CURRENT_BINARY_DIR}/../mtapi_cpp/include)
add_library(embb_algorithms_cpp ${EMBB_ALGORITHMS_CPP_SOURCES}
${EMBB_ALGORITHMS_CPP_HEADERS})
target_link_libraries(embb_algorithms_cpp embb_tasks_cpp)
target_link_libraries(embb_algorithms_cpp embb_mtapi_cpp)
if (BUILD_TESTS STREQUAL ON)
include_directories(${CMAKE_CURRENT_BINARY_DIR}/../partest/include)
add_executable (embb_algorithms_cpp_test ${EMBB_ALGORITHMS_CPP_TEST_SOURCES})
target_link_libraries(embb_algorithms_cpp_test embb_algorithms_cpp
embb_tasks_cpp embb_mtapi_c partest embb_base_cpp
embb_mtapi_cpp embb_mtapi_c partest embb_base_cpp
embb_base_c ${compiler_libs})
CopyBin(BIN embb_algorithms_cpp_test DEST ${local_install_dir})
endif()
......@@ -36,3 +36,8 @@ endif()
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/embb
DESTINATION include FILES_MATCHING PATTERN "*.h")
install(TARGETS embb_algorithms_cpp DESTINATION lib)
if (MSVC)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/embb_algorithms_cpp.pdb
DESTINATION lib
CONFIGURATIONS Debug)
endif()
......@@ -27,7 +27,7 @@
#ifndef EMBB_ALGORITHMS_COUNT_H_
#define EMBB_ALGORITHMS_COUNT_H_
#include <embb/tasks/execution_policy.h>
#include <embb/mtapi/execution_policy.h>
#include <iterator>
namespace embb {
......@@ -132,7 +132,7 @@ typename std::iterator_traits<RAI>::difference_type Count(
RAI first,
RAI last,
const ValueType& value,
const embb::tasks::ExecutionPolicy& policy,
const embb::mtapi::ExecutionPolicy& policy,
size_t block_size
);
......@@ -145,7 +145,7 @@ typename std::iterator_traits<RAI>::difference_type Count(
RAI last,
const ValueType& value
) {
return Count(first, last, value, embb::tasks::ExecutionPolicy(), 0);
return Count(first, last, value, embb::mtapi::ExecutionPolicy(), 0);
}
/**
......@@ -156,7 +156,7 @@ typename std::iterator_traits<RAI>::difference_type Count(
RAI first,
RAI last,
const ValueType& value,
const embb::tasks::ExecutionPolicy& policy
const embb::mtapi::ExecutionPolicy& policy
) {
return Count(first, last, value, policy, 0);
}
......@@ -169,7 +169,7 @@ typename std::iterator_traits<RAI>::difference_type CountIf(
RAI first,
RAI last,
ComparisonFunction comparison,
const embb::tasks::ExecutionPolicy& policy,
const embb::mtapi::ExecutionPolicy& policy,
size_t block_size
);
......@@ -182,7 +182,7 @@ typename std::iterator_traits<RAI>::difference_type CountIf(
RAI last,
ComparisonFunction comparison
) {
return CountIf(first, last, comparison, embb::tasks::ExecutionPolicy(), 0);
return CountIf(first, last, comparison, embb::mtapi::ExecutionPolicy(), 0);
}
/**
......@@ -193,7 +193,7 @@ typename std::iterator_traits<RAI>::difference_type CountIf(
RAI first,
RAI last,
ComparisonFunction comparison,
const embb::tasks::ExecutionPolicy& policy
const embb::mtapi::ExecutionPolicy& policy
) {
return CountIf(first, last, comparison, policy, 0);
}
......
......@@ -27,7 +27,7 @@
#ifndef EMBB_ALGORITHMS_FOR_EACH_H_
#define EMBB_ALGORITHMS_FOR_EACH_H_
#include <embb/tasks/execution_policy.h>
#include <embb/mtapi/execution_policy.h>
namespace embb {
namespace algorithms {
......@@ -88,7 +88,7 @@ void ForEach(
RAI first,
RAI last,
Function unary,
const embb::tasks::ExecutionPolicy& policy,
const embb::mtapi::ExecutionPolicy& policy,
size_t block_size
);
......@@ -101,7 +101,7 @@ void ForEach(
RAI last,
Function unary
) {
ForEach(first, last, unary, embb::tasks::ExecutionPolicy(), 0);
ForEach(first, last, unary, embb::mtapi::ExecutionPolicy(), 0);
}
/**
......@@ -112,7 +112,7 @@ void ForEach(
RAI first,
RAI last,
Function unary,
const embb::tasks::ExecutionPolicy& policy
const embb::mtapi::ExecutionPolicy& policy
) {
ForEach(first, last, unary, policy, 0);
}
......
......@@ -83,7 +83,7 @@ class FunctionComparisonFunction{
template<typename RAI, typename ValueType>
typename std::iterator_traits<RAI>::difference_type
Count(RAI first, RAI last, const ValueType& value,
const embb::tasks::ExecutionPolicy& policy, size_t block_size) {
const embb::mtapi::ExecutionPolicy& policy, size_t block_size) {
typedef typename std::iterator_traits<RAI>::difference_type Difference;
return Reduce(first, last, Difference(0), std::plus<Difference>(),
internal::ValueComparisonFunction<ValueType>(value), policy,
......@@ -93,7 +93,7 @@ typename std::iterator_traits<RAI>::difference_type
template<typename RAI, typename ComparisonFunction>
typename std::iterator_traits<RAI>::difference_type
CountIf(RAI first, RAI last, ComparisonFunction comparison,
const embb::tasks::ExecutionPolicy& policy, size_t block_size) {
const embb::mtapi::ExecutionPolicy& policy, size_t block_size) {
typedef typename std::iterator_traits<RAI>::difference_type Difference;
return Reduce(first, last, Difference(0), std::plus<Difference>(),
internal::FunctionComparisonFunction<ComparisonFunction>
......
......@@ -30,7 +30,7 @@
#include <cassert>
#include <embb/base/exceptions.h>
#include <embb/tasks/tasks.h>
#include <embb/mtapi/mtapi.h>
#include <embb/algorithms/internal/partition.h>
#include <embb/algorithms/zip_iterator.h>
......@@ -46,13 +46,13 @@ class ForEachFunctor {
* Constructs a for-each functor with arguments.
*/
ForEachFunctor(size_t chunk_first, size_t chunk_last, Function unary,
const embb::tasks::ExecutionPolicy& policy,
const embb::mtapi::ExecutionPolicy& policy,
const BlockSizePartitioner<RAI>& partitioner)
: chunk_first_(chunk_first), chunk_last_(chunk_last),
unary_(unary), policy_(policy), partitioner_(partitioner) {
}
void Action(embb::tasks::TaskContext&) {
void Action(embb::mtapi::TaskContext&) {
if (chunk_first_ == chunk_last_) {
// Leaf case, recursed to single chunk. Do work on chunk:
ChunkDescriptor<RAI> chunk = partitioner_[chunk_first_];
......@@ -71,14 +71,13 @@ class ForEachFunctor {
self_t functor_r(chunk_split_index + 1,
chunk_last_,
unary_, policy_, partitioner_);
embb::tasks::Task task_l = embb::tasks::Node::GetInstance().Spawn(
embb::tasks::Action(
base::MakeFunction(functor_l, &self_t::Action),
policy_));
embb::tasks::Task task_r = embb::tasks::Node::GetInstance().Spawn(
embb::tasks::Action(
base::MakeFunction(functor_r, &self_t::Action),
policy_));
embb::mtapi::Node& node = embb::mtapi::Node::GetInstance();
embb::mtapi::Task task_l = node.Start(
embb::base::MakeFunction(functor_l, &self_t::Action),
policy_);
embb::mtapi::Task task_r = node.Start(
embb::base::MakeFunction(functor_r, &self_t::Action),
policy_);
task_l.Wait(MTAPI_INFINITE);
task_r.Wait(MTAPI_INFINITE);
}
......@@ -91,7 +90,7 @@ class ForEachFunctor {
size_t chunk_first_;
size_t chunk_last_;
Function unary_;
const embb::tasks::ExecutionPolicy& policy_;
const embb::mtapi::ExecutionPolicy& policy_;
const BlockSizePartitioner<RAI>& partitioner_;
/**
......@@ -102,7 +101,7 @@ class ForEachFunctor {
template<typename RAI, typename Function>
void ForEachRecursive(RAI first, RAI last, Function unary,
const embb::tasks::ExecutionPolicy& policy, size_t block_size) {
const embb::mtapi::ExecutionPolicy& policy, size_t block_size) {
typedef typename std::iterator_traits<RAI>::difference_type difference_type;
difference_type distance = std::distance(first, last);
if (distance == 0) {
......@@ -114,7 +113,7 @@ void ForEachRecursive(RAI first, RAI last, Function unary,
if (num_cores == 0) {
EMBB_THROW(embb::base::ErrorException, "No cores in execution policy");
}
embb::tasks::Node& node = embb::tasks::Node::GetInstance();
embb::mtapi::Node& node = embb::mtapi::Node::GetInstance();
// Determine actually used block size
if (block_size == 0) {
block_size = (static_cast<size_t>(distance) / num_cores);
......@@ -129,19 +128,19 @@ void ForEachRecursive(RAI first, RAI last, Function unary,
}
BlockSizePartitioner<RAI> partitioner(first, last, block_size);
ForEachFunctor<RAI, Function> functor(0,
partitioner.Size() - 1,
unary, policy, partitioner);
embb::tasks::Task task = node.Spawn(embb::tasks::Action(
base::MakeFunction(functor,
&ForEachFunctor<RAI, Function>::Action),
policy));
typedef ForEachFunctor<RAI, Function> functor_t;
functor_t functor(0,
partitioner.Size() - 1,
unary, policy, partitioner);
embb::mtapi::Task task = node.Start(
embb::base::MakeFunction(functor, &functor_t::Action),
policy);
task.Wait(MTAPI_INFINITE);
}
template<typename RAI, typename Function>
void ForEachIteratorCheck(RAI first, RAI last, Function unary,
const embb::tasks::ExecutionPolicy& policy, size_t block_size,
const embb::mtapi::ExecutionPolicy& policy, size_t block_size,
std::random_access_iterator_tag) {
return ForEachRecursive(first, last, unary, policy, block_size);
}
......@@ -150,7 +149,7 @@ void ForEachIteratorCheck(RAI first, RAI last, Function unary,
template<typename RAI, typename Function>
void ForEach(RAI first, const RAI last, Function unary,
const embb::tasks::ExecutionPolicy& policy, size_t block_size) {
const embb::mtapi::ExecutionPolicy& policy, size_t block_size) {
typename std::iterator_traits<RAI>::iterator_category category;
internal::ForEachIteratorCheck(first, last, unary, policy, block_size,
category);
......
......@@ -32,7 +32,7 @@
#include <functional>
#include <embb/base/exceptions.h>
#include <embb/tasks/tasks.h>
#include <embb/mtapi/mtapi.h>
#include <embb/algorithms/internal/partition.h>
namespace embb {
......@@ -50,7 +50,7 @@ class MergeSortFunctor {
MergeSortFunctor(size_t chunk_first, size_t chunk_last,
RAITemp temporary_first, ComparisonFunction comparison,
const embb::tasks::ExecutionPolicy& policy,
const embb::mtapi::ExecutionPolicy& policy,
const BlockSizePartitioner<RAI>& partitioner,
const RAI& global_first, int depth)
: chunk_first_(chunk_first), chunk_last_(chunk_last),
......@@ -59,7 +59,7 @@ class MergeSortFunctor {
global_first_(global_first), depth_(depth) {
}
void Action(embb::tasks::TaskContext&) {
void Action(embb::mtapi::TaskContext&) {
size_t chunk_split_index = (chunk_first_ + chunk_last_) / 2;
if (chunk_first_ == chunk_last_) {
// Leaf case: recurse into a single chunk's elements:
......@@ -77,15 +77,13 @@ class MergeSortFunctor {
temp_first_,
comparison_, policy_, partitioner_,
global_first_, depth_ + 1);
embb::tasks::Node& node = embb::tasks::Node::GetInstance();
embb::tasks::Task task_l = node.Spawn(
embb::tasks::Action(
base::MakeFunction(functor_l, &self_t::Action),
policy_));
embb::tasks::Task task_r = node.Spawn(
embb::tasks::Action(
base::MakeFunction(functor_r, &self_t::Action),
policy_));
embb::mtapi::Node& node = embb::mtapi::Node::GetInstance();
embb::mtapi::Task task_l = node.Start(
base::MakeFunction(functor_l, &self_t::Action),
policy_);
embb::mtapi::Task task_r = node.Start(
base::MakeFunction(functor_r, &self_t::Action),
policy_);
task_l.Wait(MTAPI_INFINITE);
task_r.Wait(MTAPI_INFINITE);
......@@ -177,7 +175,7 @@ class MergeSortFunctor {
size_t chunk_last_;
RAITemp temp_first_;
ComparisonFunction comparison_;
const embb::tasks::ExecutionPolicy& policy_;
const embb::mtapi::ExecutionPolicy& policy_;
const BlockSizePartitioner<RAI>& partitioner_;
const RAI& global_first_;
int depth_;
......@@ -219,7 +217,7 @@ void MergeSortIteratorCheck(
RAI last,
RAITemp temporary_first,
ComparisonFunction comparison,
const embb::tasks::ExecutionPolicy& policy,
const embb::mtapi::ExecutionPolicy& policy,
size_t block_size,
std::random_access_iterator_tag
) {
......@@ -257,10 +255,9 @@ void MergeSortIteratorCheck(
partitioner,
first,
0);
embb::tasks::Task task = embb::tasks::Node::GetInstance().Spawn(
embb::tasks::Action(
base::MakeFunction(functor, &functor_t::Action),
policy));
embb::mtapi::Task task = embb::mtapi::Node::GetInstance().Start(
base::MakeFunction(functor, &functor_t::Action),
policy);
task.Wait(MTAPI_INFINITE);
}
......@@ -269,7 +266,7 @@ void MergeSortIteratorCheck(
template<typename RAI, typename RAITemp, typename ComparisonFunction>
void MergeSort(RAI first, RAI last, RAITemp temporary_first,
ComparisonFunction comparison, const embb::tasks::ExecutionPolicy& policy,
ComparisonFunction comparison, const embb::mtapi::ExecutionPolicy& policy,
size_t block_size) {
typedef typename std::iterator_traits<RAI>::iterator_category category;
internal::MergeSortIteratorCheck(first, last, temporary_first, comparison,
......
......@@ -93,7 +93,7 @@ ChunkPartitioner<RAI>::ChunkPartitioner(
size_ = amountChunks;
} else {
// if no concrete chunk size was given, use number of cores
embb::tasks::Node& node = embb::tasks::Node::GetInstance();
embb::mtapi::Node& node = embb::mtapi::Node::GetInstance();
size_ = node.GetWorkerThreadCount();
}
elements_count_ = static_cast<size_t>(std::distance(first_, last_));
......
......@@ -27,7 +27,7 @@
#ifndef EMBB_ALGORITHMS_INTERNAL_PARTITION_H_
#define EMBB_ALGORITHMS_INTERNAL_PARTITION_H_
#include <embb/tasks/tasks.h>
#include <embb/mtapi/mtapi.h>
namespace embb {
namespace algorithms {
......
......@@ -33,7 +33,7 @@
#include <functional>
#include <embb/base/exceptions.h>
#include <embb/tasks/tasks.h>
#include <embb/mtapi/mtapi.h>
#include <embb/algorithms/internal/partition.h>
namespace embb {
......@@ -48,7 +48,7 @@ class QuickSortFunctor {
* Constructs a functor.
*/
QuickSortFunctor(RAI first, RAI last, ComparisonFunction comparison,
const embb::tasks::ExecutionPolicy& policy, size_t block_size)
const embb::mtapi::ExecutionPolicy& policy, size_t block_size)
: first_(first), last_(last), comparison_(comparison), policy_(policy),
block_size_(block_size) {
}
......@@ -56,7 +56,7 @@ class QuickSortFunctor {
/**
* MTAPI action function and starting point of the parallel quick sort.
*/
void Action(embb::tasks::TaskContext&) {
void Action(embb::mtapi::TaskContext&) {
Difference distance = last_ - first_;
if (distance <= 1) {
return;
......@@ -68,15 +68,17 @@ class QuickSortFunctor {
SerialQuickSort(first_, mid);
SerialQuickSort(mid, last_);
} else {
embb::tasks::Node& node = embb::tasks::Node::GetInstance();
embb::mtapi::Node& node = embb::mtapi::Node::GetInstance();
QuickSortFunctor functor_l(first_, mid, comparison_, policy_,
block_size_);
embb::tasks::Task task_l = node.Spawn(embb::tasks::Action(
base::MakeFunction(functor_l, &QuickSortFunctor::Action)));
embb::mtapi::Task task_l = node.Start(
base::MakeFunction(functor_l, &QuickSortFunctor::Action),
policy_);
QuickSortFunctor functor_r(mid, last_, comparison_, policy_,
block_size_);
embb::tasks::Task task_r = node.Spawn(embb::tasks::Action(
base::MakeFunction(functor_r, &QuickSortFunctor::Action)));
embb::mtapi::Task task_r = node.Start(
base::MakeFunction(functor_r, &QuickSortFunctor::Action),
policy_);
task_l.Wait(MTAPI_INFINITE);
task_r.Wait(MTAPI_INFINITE);
}
......@@ -87,7 +89,7 @@ class QuickSortFunctor {
RAI first_;
RAI last_;
ComparisonFunction comparison_;
const embb::tasks::ExecutionPolicy& policy_;
const embb::mtapi::ExecutionPolicy& policy_;
size_t block_size_;
typedef typename std::iterator_traits<RAI>::difference_type Difference;
......@@ -189,10 +191,10 @@ class QuickSortFunctor {
template <typename RAI, typename ComparisonFunction>
void QuickSortIteratorCheck(RAI first, RAI last,
ComparisonFunction comparison,
const embb::tasks::ExecutionPolicy& policy,
const embb::mtapi::ExecutionPolicy& policy,
size_t block_size,
std::random_access_iterator_tag) {
embb::tasks::Node& node = embb::tasks::Node::GetInstance();
embb::mtapi::Node& node = embb::mtapi::Node::GetInstance();
typedef typename std::iterator_traits<RAI>::difference_type difference_type;
difference_type distance = std::distance(first, last);
if (distance == 0) {
......@@ -215,8 +217,10 @@ void QuickSortIteratorCheck(RAI first, RAI last,
}
QuickSortFunctor<RAI, ComparisonFunction> functor(
first, last, comparison, policy, block_size);
embb::tasks::Task task = node.Spawn(embb::tasks::Action(base::MakeFunction(
functor, &QuickSortFunctor<RAI, ComparisonFunction>::Action)));
embb::mtapi::Task task = node.Start(
embb::base::MakeFunction(functor,
&QuickSortFunctor<RAI, ComparisonFunction>::Action),
policy);
task.Wait(MTAPI_INFINITE);
}
......@@ -224,7 +228,7 @@ void QuickSortIteratorCheck(RAI first, RAI last,
template <typename RAI, typename ComparisonFunction>
void QuickSort(RAI first, RAI last, ComparisonFunction comparison,
const embb::tasks::ExecutionPolicy& policy, size_t block_size) {
const embb::mtapi::ExecutionPolicy& policy, size_t block_size) {
typedef typename std::iterator_traits<RAI>::iterator_category category;
internal::QuickSortIteratorCheck(first, last, comparison,
policy, block_size, category());
......
......@@ -27,7 +27,7 @@
#ifndef EMBB_ALGORITHMS_INTERNAL_REDUCE_INL_H_
#define EMBB_ALGORITHMS_INTERNAL_REDUCE_INL_H_
#include <embb/tasks/tasks.h>
#include <embb/mtapi/mtapi.h>
#include <embb/algorithms/internal/partition.h>
#include <functional>
......@@ -46,7 +46,7 @@ class ReduceFunctor {
ReturnType neutral,
ReductionFunction reduction,
TransformationFunction transformation,
const embb::tasks::ExecutionPolicy& policy,
const embb::mtapi::ExecutionPolicy& policy,
const BlockSizePartitioner<RAI>& partitioner,
ReturnType& result)
: chunk_first_(chunk_first), chunk_last_(chunk_last), neutral_(neutral),
......@@ -54,7 +54,7 @@ class ReduceFunctor {
partitioner_(partitioner), result_(result) {
}
void Action(embb::tasks::TaskContext&) {
void Action(embb::mtapi::TaskContext&) {
if (chunk_first_ == chunk_last_) {
// Leaf case, recursed to single chunk. Do work on chunk:
ChunkDescriptor<RAI> chunk = partitioner_[chunk_first_];
......@@ -81,16 +81,12 @@ class ReduceFunctor {
neutral_, reduction_, transformation_, policy_,
partitioner_,
result_r);
embb::tasks::Task task_l = embb::tasks::Node::GetInstance().Spawn(
embb::tasks::Action(
base::MakeFunction(
functor_l, &self_t::Action),
policy_));
embb::tasks::Task task_r = embb::tasks::Node::GetInstance().Spawn(
embb::tasks::Action(
base::MakeFunction(
functor_r, &self_t::Action),
policy_));
embb::mtapi::Task task_l = embb::mtapi::Node::GetInstance().Start(
base::MakeFunction(functor_l, &self_t::Action),
policy_);
embb::mtapi::Task task_r = embb::mtapi::Node::GetInstance().Start(
base::MakeFunction(functor_r, &self_t::Action),
policy_);
task_l.Wait(MTAPI_INFINITE);
task_r.Wait(MTAPI_INFINITE);
result_ = reduction_(result_l, result_r);
......@@ -108,7 +104,7 @@ class ReduceFunctor {
ReturnType neutral_;
ReductionFunction reduction_;
TransformationFunction transformation_;
const embb::tasks::ExecutionPolicy& policy_;
const embb::mtapi::ExecutionPolicy& policy_;
const BlockSizePartitioner<RAI>& partitioner_;
ReturnType& result_;
......@@ -124,7 +120,7 @@ template<typename RAI, typename ReturnType, typename ReductionFunction,
ReturnType ReduceRecursive(RAI first, RAI last, ReturnType neutral,
ReductionFunction reduction,
TransformationFunction transformation,
const embb::tasks::ExecutionPolicy& policy,
const embb::mtapi::ExecutionPolicy& policy,
size_t block_size) {
typedef typename std::iterator_traits<RAI>::difference_type difference_type;
difference_type distance = std::distance(first, last);
......@@ -137,7 +133,7 @@ ReturnType ReduceRecursive(RAI first, RAI last, ReturnType neutral,
if (num_cores == 0) {
EMBB_THROW(embb::base::ErrorException, "No cores in execution policy");
}
embb::tasks::Node& node = embb::tasks::Node::GetInstance();
embb::mtapi::Node& node = embb::mtapi::Node::GetInstance();
// Determine actually used block size
if (block_size == 0) {
block_size = (static_cast<size_t>(distance) / num_cores);
......@@ -162,9 +158,9 @@ ReturnType ReduceRecursive(RAI first, RAI last, ReturnType neutral,
policy,
partitioner,
result);
embb::tasks::Task task = node.Spawn(
embb::tasks::Action(base::MakeFunction(
functor, &Functor::Action), policy));
embb::mtapi::Task task = node.Start(
base::MakeFunction(functor, &Functor::Action),
policy);
task.Wait(MTAPI_INFINITE);
return result;
}
......@@ -174,7 +170,7 @@ template<typename RAI, typename TransformationFunction,
ReturnType ReduceIteratorCheck(RAI first, RAI last, ReductionFunction reduction,
TransformationFunction transformation,
ReturnType neutral,
const embb::tasks::ExecutionPolicy& policy,
const embb::mtapi::ExecutionPolicy& policy,
size_t block_size,
std::random_access_iterator_tag) {
return ReduceRecursive(first, last, neutral, reduction, transformation,
......@@ -188,7 +184,7 @@ template<typename RAI, typename ReturnType, typename ReductionFunction,
ReturnType Reduce(RAI first, RAI last, ReturnType neutral,
ReductionFunction reduction,
TransformationFunction transformation,
const embb::tasks::ExecutionPolicy& policy,
const embb::mtapi::ExecutionPolicy& policy,
size_t block_size) {
typename std::iterator_traits<RAI>::iterator_category category;
return internal::ReduceIteratorCheck(first, last, reduction, transformation,
......
......@@ -29,8 +29,8 @@
#include <cassert>
#include <embb/base/exceptions.h>
#include <embb/tasks/tasks.h>
#include <embb/tasks/execution_policy.h>
#include <embb/base/function.h>
#include <embb/mtapi/mtapi.h>
#include <embb/algorithms/internal/partition.h>
namespace embb {
......@@ -44,7 +44,7 @@ class ScanFunctor {
ScanFunctor(size_t chunk_first, size_t chunk_last, RAIOut output_iterator,
ReturnType neutral, ScanFunction scan,
TransformationFunction transformation,
const embb::tasks::ExecutionPolicy& policy,
const embb::mtapi::ExecutionPolicy& policy,
const BlockSizePartitioner<RAIIn>& partitioner,
ReturnType* tree_values, size_t node_id,
bool going_down)
......@@ -55,7 +55,7 @@ class ScanFunctor {
node_id_(node_id), parent_value_(neutral), is_first_pass_(going_down) {
}
void Action(embb::tasks::TaskContext&) {
void Action(embb::mtapi::TaskContext&) {
if (chunk_first_ == chunk_last_) {
ChunkDescriptor<RAIIn> chunk = partitioner_[chunk_first_];
RAIIn iter_in = chunk.GetFirst();
......@@ -104,15 +104,13 @@ class ScanFunctor {
functor_r.parent_value_ = functor_l.GetTreeValue() + parent_value_;
}
// Spawn tasks to recurse:
embb::tasks::Node& node = embb::tasks::Node::GetInstance();
embb::tasks::Task task_l = node.Spawn(
embb::tasks::Action(
base::MakeFunction(functor_l, &ScanFunctor::Action),
policy_));
embb::tasks::Task task_r = node.Spawn(
embb::tasks::Action(
base::MakeFunction(functor_r, &ScanFunctor::Action),
policy_));
embb::mtapi::Node& node = embb::mtapi::Node::GetInstance();
embb::mtapi::Task task_l = node.Start(
base::MakeFunction(functor_l, &ScanFunctor::Action),
policy_);
embb::mtapi::Task task_r = node.Start(
base::MakeFunction(functor_r, &ScanFunctor::Action),
policy_);
// Wait for tasks to complete:
task_l.Wait(MTAPI_INFINITE);
task_r.Wait(MTAPI_INFINITE);
......@@ -131,7 +129,7 @@ class ScanFunctor {
private:
static const int LEFT = 1;
static const int RIGHT = 2;
const embb::tasks::ExecutionPolicy& policy_;
const embb::mtapi::ExecutionPolicy& policy_;
size_t chunk_first_;
size_t chunk_last_;
RAIOut output_iterator_;
......@@ -168,7 +166,7 @@ typename ScanFunction, typename TransformationFunction>
void ScanIteratorCheck(RAIIn first, RAIIn last, RAIOut output_iterator,
ReturnType neutral, ScanFunction scan,
TransformationFunction transformation,
const embb::tasks::ExecutionPolicy& policy,
const embb::mtapi::ExecutionPolicy& policy,
size_t block_size,
std::random_access_iterator_tag) {
typedef typename std::iterator_traits<RAIIn>::difference_type difference_type;
......@@ -199,14 +197,15 @@ void ScanIteratorCheck(RAIIn first, RAIIn last, RAIOut output_iterator,
// it creates the tree.
typedef ScanFunctor<RAIIn, RAIOut, ReturnType, ScanFunction,
TransformationFunction> Functor;
embb::tasks::Node& node = embb::tasks::Node::GetInstance();
embb::mtapi::Node& node = embb::mtapi::Node::GetInstance();
BlockSizePartitioner<RAIIn> partitioner_down(first, last, block_size);
Functor functor_down(0, partitioner_down.Size() - 1, output_iterator,
neutral, scan, transformation, policy, partitioner_down,
values, 0, true);
embb::tasks::Task task_down = node.Spawn(embb::tasks::Action(
base::MakeFunction(functor_down, &Functor::Action), policy));
embb::mtapi::Task task_down = node.Start(
base::MakeFunction(functor_down, &Functor::Action),
policy);
task_down.Wait(MTAPI_INFINITE);
// Second pass. Gives to each leaf the part of the prefix missing
......@@ -214,8 +213,9 @@ void ScanIteratorCheck(RAIIn first, RAIIn last, RAIOut output_iterator,
Functor functor_up(0, partitioner_up.Size() - 1, output_iterator,
neutral, scan, transformation, policy, partitioner_up,
values, 0, false);
embb::tasks::Task task_up = node.Spawn(embb::tasks::Action(
base::MakeFunction(functor_up, &Functor::Action), policy));
embb::mtapi::Task task_up = node.Start(
base::MakeFunction(functor_up, &Functor::Action),
policy);
task_up.Wait(MTAPI_INFINITE);
}
......@@ -225,7 +225,7 @@ template<typename RAIIn, typename RAIOut, typename ReturnType,
typename ScanFunction, typename TransformationFunction>
void Scan(RAIIn first, RAIIn last, RAIOut output_iterator, ReturnType neutral,
ScanFunction scan, TransformationFunction transformation,
const embb::tasks::ExecutionPolicy& policy, size_t block_size) {
const embb::mtapi::ExecutionPolicy& policy, size_t block_size) {
typedef typename std::iterator_traits<RAIIn>::iterator_category category;
internal::ScanIteratorCheck(first, last, output_iterator, neutral,
scan, transformation, policy, block_size, category());
......
......@@ -28,7 +28,7 @@
#define EMBB_ALGORITHMS_INVOKE_H_
#include <embb/base/function.h>
#include <embb/tasks/tasks.h>
#include <embb/mtapi/mtapi.h>
namespace embb {
namespace algorithms {
......@@ -78,8 +78,8 @@ void Invoke(
Function2 func2,
/**< [in] Second function object to invoke */
...,
const embb::tasks::ExecutionPolicy & policy
/**< [in] embb::tasks::ExecutionPolicy to use */
const embb::mtapi::ExecutionPolicy & policy
/**< [in] embb::mtapi::ExecutionPolicy to use */
);
#else // DOXYGEN
......@@ -98,11 +98,11 @@ class TaskWrapper {
*/
explicit TaskWrapper(
Function function,
const embb::tasks::ExecutionPolicy& policy)
const embb::mtapi::ExecutionPolicy& policy)
: function_(function), task_() {
embb::tasks::Action action(embb::base::MakeFunction(
*this, &TaskWrapper::Run), policy);
task_ = embb::tasks::Node::GetInstance().Spawn(action);
task_ = embb::mtapi::Node::GetInstance().Start(
embb::base::MakeFunction(*this, &TaskWrapper::Run),
policy);
}
/**
......@@ -114,9 +114,9 @@ class TaskWrapper {
private:
Function function_;
embb::tasks::Task task_;
embb::mtapi::Task task_;
void Run(embb::tasks::TaskContext&) {
void Run(embb::mtapi::TaskContext&) {
function_();
}
};
......@@ -126,7 +126,7 @@ template<typename Function1, typename Function2>
void Invoke(
Function1 func1,
Function2 func2,
const embb::tasks::ExecutionPolicy& policy) {
const embb::mtapi::ExecutionPolicy& policy) {
internal::TaskWrapper<Function1> wrap1(func1, policy);
internal::TaskWrapper<Function2> wrap2(func2, policy);
}
......@@ -136,7 +136,7 @@ void Invoke(
Function1 func1,
Function2 func2,
Function3 func3,
const embb::tasks::ExecutionPolicy& policy) {
const embb::mtapi::ExecutionPolicy& policy) {
internal::TaskWrapper<Function1> wrap1(func1, policy);
internal::TaskWrapper<Function2> wrap2(func2, policy);
internal::TaskWrapper<Function3> wrap3(func3, policy);
......@@ -149,7 +149,7 @@ template<typename Function1, typename Function2, typename Function3,
Function2 func2,
Function3 func3,
Function4 func4,
const embb::tasks::ExecutionPolicy& policy) {
const embb::mtapi::ExecutionPolicy& policy) {
internal::TaskWrapper<Function1> wrap1(func1, policy);
internal::TaskWrapper<Function2> wrap2(func2, policy);
internal::TaskWrapper<Function3> wrap3(func3, policy);
......@@ -164,7 +164,7 @@ template<typename Function1, typename Function2, typename Function3,
Function3 func3,
Function4 func4,
Function5 func5,
const embb::tasks::ExecutionPolicy& policy) {
const embb::mtapi::ExecutionPolicy& policy) {
internal::TaskWrapper<Function1> wrap1(func1, policy);
internal::TaskWrapper<Function2> wrap2(func2, policy);
internal::TaskWrapper<Function3> wrap3(func3, policy);
......@@ -181,7 +181,7 @@ template<typename Function1, typename Function2, typename Function3,
Function4 func4,
Function5 func5,
Function6 func6,
const embb::tasks::ExecutionPolicy& policy) {
const embb::mtapi::ExecutionPolicy& policy) {
internal::TaskWrapper<Function1> wrap1(func1, policy);
internal::TaskWrapper<Function2> wrap2(func2, policy);
internal::TaskWrapper<Function3> wrap3(func3, policy);
......@@ -201,7 +201,7 @@ template<typename Function1, typename Function2, typename Function3,
Function5 func5,
Function6 func6,
Function7 func7,
const embb::tasks::ExecutionPolicy& policy) {
const embb::mtapi::ExecutionPolicy& policy) {
internal::TaskWrapper<Function1> wrap1(func1, policy);
internal::TaskWrapper<Function2> wrap2(func2, policy);
internal::TaskWrapper<Function3> wrap3(func3, policy);
......@@ -223,7 +223,7 @@ template<typename Function1, typename Function2, typename Function3,
Function6 func6,
Function7 func7,
Function8 func8,
const embb::tasks::ExecutionPolicy& policy) {
const embb::mtapi::ExecutionPolicy& policy) {
internal::TaskWrapper<Function1> wrap1(func1, policy);
internal::TaskWrapper<Function2> wrap2(func2, policy);
internal::TaskWrapper<Function3> wrap3(func3, policy);
......@@ -247,7 +247,7 @@ template<typename Function1, typename Function2, typename Function3,
Function7 func7,
Function8 func8,
Function9 func9,
const embb::tasks::ExecutionPolicy& policy) {
const embb::mtapi::ExecutionPolicy& policy) {
internal::TaskWrapper<Function1> wrap1(func1, policy);
internal::TaskWrapper<Function2> wrap2(func2, policy);
internal::TaskWrapper<Function3> wrap3(func3, policy);
......@@ -274,7 +274,7 @@ template<typename Function1, typename Function2, typename Function3,
Function8 func8,
Function9 func9,
Function10 func10,
const embb::tasks::ExecutionPolicy& policy) {
const embb::mtapi::ExecutionPolicy& policy) {
internal::TaskWrapper<Function1> wrap1(func1, policy);
internal::TaskWrapper<Function2> wrap2(func2, policy);
internal::TaskWrapper<Function3> wrap3(func3, policy);
......@@ -291,14 +291,14 @@ template<typename Function1, typename Function2>
void Invoke(
Function1 func1,
Function2 func2) {
Invoke(func1, func2, embb::tasks::ExecutionPolicy());
Invoke(func1, func2, embb::mtapi::ExecutionPolicy());
}
template<typename Function1, typename Function2, typename Function3>
void Invoke(
Function1 func1,
Function2 func2,
Function3 func3) {
Invoke(func1, func2, func3, embb::tasks::ExecutionPolicy());
Invoke(func1, func2, func3, embb::mtapi::ExecutionPolicy());
}
template<typename Function1, typename Function2, typename Function3,
......@@ -308,7 +308,7 @@ void Invoke(
Function2 func2,
Function3 func3,
Function4 func4) {
Invoke(func1, func2, func3, func4, embb::tasks::ExecutionPolicy());
Invoke(func1, func2, func3, func4, embb::mtapi::ExecutionPolicy());
}
template<typename Function1, typename Function2, typename Function3,
......@@ -319,7 +319,7 @@ void Invoke(
Function3 func3,
Function4 func4,
Function5 func5) {
Invoke(func1, func2, func3, func4, func5, embb::tasks::ExecutionPolicy());
Invoke(func1, func2, func3, func4, func5, embb::mtapi::ExecutionPolicy());
}
template<typename Function1, typename Function2, typename Function3,
......@@ -332,7 +332,7 @@ void Invoke(
Function5 func5,
Function6 func6) {
Invoke(func1, func2, func3, func4, func5, func6,
embb::tasks::ExecutionPolicy());
embb::mtapi::ExecutionPolicy());
}
template<typename Function1, typename Function2, typename Function3,
......@@ -347,7 +347,7 @@ void Invoke(
Function6 func6,
Function7 func7) {
Invoke(func1, func2, func3, func4, func5, func6, func7,
embb::tasks::ExecutionPolicy());
embb::mtapi::ExecutionPolicy());
}
template<typename Function1, typename Function2, typename Function3,
......@@ -363,7 +363,7 @@ void Invoke(
Function7 func7,
Function8 func8) {
Invoke(func1, func2, func3, func4, func5, func6, func7, func8,
embb::tasks::ExecutionPolicy());
embb::mtapi::ExecutionPolicy());
}
template<typename Function1, typename Function2, typename Function3,
......@@ -380,7 +380,7 @@ void Invoke(
Function8 func8,
Function9 func9) {
Invoke(func1, func2, func3, func4, func5, func6, func7, func8, func9,
embb::tasks::ExecutionPolicy());
embb::mtapi::ExecutionPolicy());
}
template<typename Function1, typename Function2, typename Function3,
......@@ -399,7 +399,7 @@ void Invoke(
Function9 func9,
Function10 func10) {
Invoke(func1, func2, func3, func4, func5, func6, func7, func8, func9, func10,
embb::tasks::ExecutionPolicy());
embb::mtapi::ExecutionPolicy());
}
#endif // else DOXYGEN
......
......@@ -28,7 +28,7 @@
#define EMBB_ALGORITHMS_MERGE_SORT_H_
#include <functional>
#include <embb/tasks/execution_policy.h>
#include <embb/mtapi/execution_policy.h>
#include <embb/base/memory_allocation.h>
namespace embb {
......@@ -149,7 +149,7 @@ void MergeSort(
RAI last,
RAITemp temporary_first,
ComparisonFunction comparison,
const embb::tasks::ExecutionPolicy& policy,
const embb::mtapi::ExecutionPolicy& policy,
size_t block_size
);
......@@ -161,7 +161,7 @@ void MergeSortAllocate(
RAI first,
RAI last,
ComparisonFunction comparison,
const embb::tasks::ExecutionPolicy& policy,
const embb::mtapi::ExecutionPolicy& policy,
size_t block_size
) {
typedef base::Allocation Alloc;
......@@ -200,7 +200,7 @@ void MergeSortAllocate(
) {
MergeSortAllocate(first, last,
std::less<typename std::iterator_traits<RAI>::value_type>(),
embb::tasks::ExecutionPolicy(), 0);
embb::mtapi::ExecutionPolicy(), 0);
}
/**
......@@ -212,7 +212,7 @@ void MergeSortAllocate(
RAI last,
ComparisonFunction comparison
) {
MergeSortAllocate(first, last, comparison, embb::tasks::ExecutionPolicy(), 0);
MergeSortAllocate(first, last, comparison, embb::mtapi::ExecutionPolicy(), 0);
}
/**
......@@ -223,7 +223,7 @@ void MergeSortAllocate(
RAI first,
RAI last,
ComparisonFunction comparison,
const embb::tasks::ExecutionPolicy& policy
const embb::mtapi::ExecutionPolicy& policy
) {
MergeSortAllocate(first, last, comparison, policy, 0);
}
......@@ -239,7 +239,7 @@ void MergeSort(
) {
MergeSort(first, last, temporary_first,
std::less<typename std::iterator_traits<RAI>::value_type>(),
embb::tasks::ExecutionPolicy(), 0);
embb::mtapi::ExecutionPolicy(), 0);
}
/**
......@@ -253,7 +253,7 @@ void MergeSort(
ComparisonFunction comparison
) {
MergeSort(first, last, temporary_first, comparison,
embb::tasks::ExecutionPolicy(), 0);
embb::mtapi::ExecutionPolicy(), 0);
}
/**
......@@ -265,7 +265,7 @@ void MergeSort(
RAI last,
RAITemp temporary_first,
ComparisonFunction comparison,
const embb::tasks::ExecutionPolicy& policy
const embb::mtapi::ExecutionPolicy& policy
) {
MergeSort(first, last, temporary_first, comparison, policy, 0);
}
......
......@@ -28,7 +28,7 @@
#define EMBB_ALGORITHMS_QUICK_SORT_H_
#include <functional>
#include <embb/tasks/execution_policy.h>
#include <embb/mtapi/execution_policy.h>
namespace embb {
namespace algorithms {
......@@ -72,7 +72,7 @@ void QuickSort(
\c a appears before an element \c b in the sorted range if
<tt>comparison(a, b) == true</tt>. The default value uses the
less-than relation. */
const embb::tasks::ExecutionPolicy& policy = embb::tasks::ExecutionPolicy(),
const embb::mtapi::ExecutionPolicy& policy = embb::mtapi::ExecutionPolicy(),
/**< [IN] embb::mtapi::ExecutionPolicy for the quick sort algorithm */
size_t block_size = 0
/**< [IN] Lower bound for partitioning the range of elements into blocks that
......@@ -95,7 +95,7 @@ void QuickSort(
RAI first,
RAI last,
ComparisonFunction comparison,
const embb::tasks::ExecutionPolicy& policy,
const embb::mtapi::ExecutionPolicy& policy,
size_t block_size
);
......@@ -109,7 +109,7 @@ void QuickSort(
) {
QuickSort(first, last,
std::less<typename std::iterator_traits<RAI>::value_type>(),
embb::tasks::ExecutionPolicy(), 0);
embb::mtapi::ExecutionPolicy(), 0);
}
/**
......@@ -121,7 +121,7 @@ void QuickSort(
RAI last,
ComparisonFunction comparison
) {
QuickSort(first, last, comparison, embb::tasks::ExecutionPolicy(), 0);
QuickSort(first, last, comparison, embb::mtapi::ExecutionPolicy(), 0);
}
/**
......@@ -132,7 +132,7 @@ void QuickSort(
RAI first,
RAI last,
ComparisonFunction comparison,
const embb::tasks::ExecutionPolicy& policy
const embb::mtapi::ExecutionPolicy& policy
) {
QuickSort(first, last, comparison, policy, 0);
}
......
......@@ -27,7 +27,7 @@
#ifndef EMBB_ALGORITHMS_REDUCE_H_
#define EMBB_ALGORITHMS_REDUCE_H_
#include <embb/tasks/execution_policy.h>
#include <embb/mtapi/execution_policy.h>
#include <embb/algorithms/identity.h>
namespace embb {
......@@ -113,7 +113,7 @@ ReturnType Reduce(
ReturnType neutral,
ReductionFunction reduction,
TransformationFunction transformation,
const embb::tasks::ExecutionPolicy& policy,
const embb::mtapi::ExecutionPolicy& policy,
size_t block_size
);
......@@ -128,7 +128,7 @@ ReturnType Reduce(
ReductionFunction reduction
) {
return Reduce(first, last, neutral, reduction, Identity(),
embb::tasks::ExecutionPolicy(), 0);
embb::mtapi::ExecutionPolicy(), 0);
}
/**
......@@ -144,7 +144,7 @@ ReturnType Reduce(
TransformationFunction transformation
) {
return Reduce(first, last, neutral, reduction, transformation,
embb::tasks::ExecutionPolicy(), 0);
embb::mtapi::ExecutionPolicy(), 0);
}
/**
......@@ -158,7 +158,7 @@ ReturnType Reduce(
ReturnType neutral,
ReductionFunction reduction,
TransformationFunction transformation,
const embb::tasks::ExecutionPolicy& policy
const embb::mtapi::ExecutionPolicy& policy
) {
return Reduce(first, last, neutral, reduction, transformation, policy, 0);
}
......
......@@ -27,7 +27,7 @@
#ifndef EMBB_ALGORITHMS_SCAN_H_
#define EMBB_ALGORITHMS_SCAN_H_
#include <embb/tasks/execution_policy.h>
#include <embb/mtapi/execution_policy.h>
#include <embb/algorithms/identity.h>
namespace embb {
......@@ -121,7 +121,7 @@ void Scan(
ReturnType neutral,
ScanFunction scan,
TransformationFunction transformation,
const embb::tasks::ExecutionPolicy& policy,
const embb::mtapi::ExecutionPolicy& policy,
size_t block_size
);
......@@ -138,7 +138,7 @@ void Scan(
ScanFunction scan
) {
Scan(first, last, output_iterator, neutral, scan, Identity(),
embb::tasks::ExecutionPolicy(), 0);
embb::mtapi::ExecutionPolicy(), 0);
}
/**
......@@ -155,7 +155,7 @@ void Scan(
TransformationFunction transformation
) {
Scan(first, last, output_iterator, neutral, scan, transformation,
embb::tasks::ExecutionPolicy(), 0);
embb::mtapi::ExecutionPolicy(), 0);
}
/**
......@@ -170,7 +170,7 @@ void Scan(
ReturnType neutral,
ScanFunction scan,
TransformationFunction transformation,
const embb::tasks::ExecutionPolicy& policy
const embb::mtapi::ExecutionPolicy& policy
) {
Scan(first, last, output_iterator, neutral, scan, transformation, policy, 0);
}
......
......@@ -26,7 +26,7 @@
#include <count_test.h>
#include <embb/algorithms/count.h>
#include <embb/tasks/execution_policy.h>
#include <embb/mtapi/execution_policy.h>
#include <deque>
#include <vector>
#include <functional>
......@@ -122,7 +122,7 @@ void CountTest::TestBlockSizes() {
void CountTest::TestPolicy() {
using embb::algorithms::Count;
using embb::tasks::ExecutionPolicy;
using embb::mtapi::ExecutionPolicy;
int a[] = { 10, 20, 30, 30, 20, 10, 10, 20, 20, 20 };
std::vector<int> vector(a, a + (sizeof a / sizeof a[0]));
PT_EXPECT_EQ(Count(vector.begin(), vector.end(), 10, ExecutionPolicy()), 3);
......@@ -134,7 +134,7 @@ void CountTest::TestPolicy() {
void CountTest::StressTest() {
using embb::algorithms::Count;
size_t count = embb::tasks::Node::GetInstance().GetCoreCount() * 10;
size_t count = embb::mtapi::Node::GetInstance().GetCoreCount() * 10;
std::vector<int> large_vector(count);
for (size_t i = 0; i < count; i++) {
large_vector[i] = static_cast<int>(0);
......
......@@ -26,7 +26,7 @@
#include <for_each_test.h>
#include <embb/algorithms/for_each.h>
#include <embb/tasks/execution_policy.h>
#include <embb/mtapi/execution_policy.h>
#include <vector>
#include <deque>
#include <sstream>
......@@ -166,7 +166,7 @@ void ForEachTest::TestRanges() {
void ForEachTest::TestBlockSizes() {
using embb::algorithms::ForEach;
using embb::tasks::ExecutionPolicy;
using embb::mtapi::ExecutionPolicy;
size_t count = 4;
std::vector<int> init(count);
std::vector<int> vector(count);
......@@ -186,7 +186,7 @@ void ForEachTest::TestBlockSizes() {
void ForEachTest::TestPolicy() {
using embb::algorithms::ForEach;
using embb::tasks::ExecutionPolicy;
using embb::mtapi::ExecutionPolicy;
size_t count = 4;
std::vector<int> init(count);
std::vector<int> vector(count);
......@@ -240,8 +240,8 @@ void ForEachTest::TestPolicy() {
void ForEachTest::StressTest() {
using embb::algorithms::ForEach;
using embb::tasks::ExecutionPolicy;
size_t count = embb::tasks::Node::GetInstance().GetCoreCount() * 10;
using embb::mtapi::ExecutionPolicy;
size_t count = embb::mtapi::Node::GetInstance().GetCoreCount() * 10;
std::vector<int> large_vector(count);
for (size_t i = 0; i < count; i++) {
large_vector[i] = static_cast<int>((i + 2) % 1000);
......
......@@ -61,7 +61,7 @@ void InvokeTest::Test() {
Invoke(&Invocable1, &Invocable2, &Invocable3, &Invocable4, &Invocable5,
&Invocable6, &Invocable7, &Invocable8, &Invocable9, &Invocable10);
embb::tasks::ExecutionPolicy policy;
embb::mtapi::ExecutionPolicy policy;
Invoke(&Invocable1, &Invocable2, policy);
Invoke(&Invocable1, &Invocable2, &Invocable3, policy);
Invoke(&Invocable1, &Invocable2, &Invocable3, &Invocable4, policy);
......
......@@ -25,7 +25,7 @@
*/
#include <partest/partest.h>
#include <embb/tasks/tasks.h>
#include <embb/mtapi/mtapi.h>
#include <iostream>
#include <sstream>
......@@ -70,7 +70,7 @@ int compute1_() {
PT_MAIN("Algorithms") {
embb_atomic_initialize();
embb::tasks::Node::Initialize(THIS_DOMAIN_ID, THIS_NODE_ID);
embb::mtapi::Node::Initialize(THIS_DOMAIN_ID, THIS_NODE_ID);
PT_RUN(PartitionerTest);
PT_RUN(ForEachTest);
......@@ -82,7 +82,7 @@ PT_MAIN("Algorithms") {
PT_RUN(MergeSortTest);
PT_RUN(InvokeTest);
embb::tasks::Node::Finalize();
embb::mtapi::Node::Finalize();
PT_EXPECT(embb_get_bytes_allocated() == 0);
......
......@@ -26,7 +26,7 @@
#include <merge_sort_test.h>
#include <embb/algorithms/merge_sort.h>
#include <embb/tasks/execution_policy.h>
#include <embb/mtapi/execution_policy.h>
#include <vector>
#include <deque>
#include <sstream>
......@@ -50,7 +50,7 @@ MergeSortTest::MergeSortTest() {
void MergeSortTest::TestDataStructures() {
using embb::algorithms::MergeSortAllocate;
using embb::tasks::ExecutionPolicy;
using embb::mtapi::ExecutionPolicy;
int array[kCountSize];
std::vector<int> vector(kCountSize);
std::deque<int> deque(kCountSize);
......@@ -75,7 +75,7 @@ void MergeSortTest::TestDataStructures() {
void MergeSortTest::TestFunctionPointers() {
using embb::algorithms::MergeSortAllocate;
using embb::tasks::ExecutionPolicy;
using embb::mtapi::ExecutionPolicy;
std::vector<int> vector(kCountSize);
for (size_t i = kCountSize - 1; i > 0; i--) {
......@@ -158,7 +158,7 @@ void MergeSortTest::TestRanges() {
void MergeSortTest::TestBlockSizes() {
using embb::algorithms::MergeSortAllocate;
using embb::tasks::ExecutionPolicy;
using embb::mtapi::ExecutionPolicy;
size_t count = 4;
std::vector<int> init(count);
std::vector<int> vector(count);
......@@ -181,7 +181,7 @@ void MergeSortTest::TestBlockSizes() {
void MergeSortTest::TestPolicy() {
using embb::algorithms::MergeSortAllocate;
using embb::tasks::ExecutionPolicy;
using embb::mtapi::ExecutionPolicy;
size_t count = 4;
std::vector<int> init(count);
std::vector<int> vector(count);
......@@ -242,7 +242,7 @@ void MergeSortTest::TestPolicy() {
void MergeSortTest::StressTest() {
using embb::algorithms::MergeSortAllocate;
size_t count = embb::tasks::Node::GetInstance().GetCoreCount() * 10;
size_t count = embb::mtapi::Node::GetInstance().GetCoreCount() * 10;
std::vector<int> large_vector(count);
std::vector<int> vector_copy(count);
for (size_t i = count - 1; i > 0; i--) {
......
......@@ -26,7 +26,7 @@
#include <quick_sort_test.h>
#include <embb/algorithms/quick_sort.h>
#include <embb/tasks/execution_policy.h>
#include <embb/mtapi/execution_policy.h>
#include <vector>
#include <deque>
#include <sstream>
......@@ -54,7 +54,7 @@ QuickSortTest::QuickSortTest() {
void QuickSortTest::TestDataStructures() {
using embb::algorithms::QuickSort;
using embb::tasks::ExecutionPolicy;
using embb::mtapi::ExecutionPolicy;
int array[kCountSize];
std::vector<int> vector(kCountSize);
......@@ -163,7 +163,7 @@ void QuickSortTest::TestRanges() {
void QuickSortTest::TestBlockSizes() {
using embb::algorithms::QuickSort;
using embb::tasks::ExecutionPolicy;
using embb::mtapi::ExecutionPolicy;
size_t count = 4;
std::vector<int> init(count);
......@@ -187,7 +187,7 @@ void QuickSortTest::TestBlockSizes() {
void QuickSortTest::TestPolicy() {
using embb::algorithms::QuickSort;
using embb::tasks::ExecutionPolicy;
using embb::mtapi::ExecutionPolicy;
size_t count = 4;
std::vector<int> init(count);
std::vector<int> vector(count);
......@@ -248,7 +248,7 @@ void QuickSortTest::TestPolicy() {
void QuickSortTest::StressTest() {
using embb::algorithms::QuickSort;
size_t count = embb::tasks::Node::GetInstance().GetCoreCount() * 10;
size_t count = embb::mtapi::Node::GetInstance().GetCoreCount() * 10;
std::vector<int> large_vector(count);
std::vector<int> vector_copy(count);
for (size_t i = 0; i < count; i++) {
......
......@@ -26,7 +26,7 @@
#include <reduce_test.h>
#include <embb/algorithms/reduce.h>
#include <embb/tasks/execution_policy.h>
#include <embb/mtapi/execution_policy.h>
#include <deque>
#include <vector>
#include <functional>
......@@ -163,7 +163,7 @@ void ReduceTest::TestBlockSizes() {
void ReduceTest::TestPolicy() {
using embb::algorithms::Reduce;
using embb::tasks::ExecutionPolicy;
using embb::mtapi::ExecutionPolicy;
using embb::algorithms::Identity;
size_t count = 4;
int sum = 0;
......@@ -210,9 +210,9 @@ void ReduceTest::TestPolicy() {
void ReduceTest::StressTest() {
using embb::algorithms::Reduce;
using embb::tasks::ExecutionPolicy;
using embb::mtapi::ExecutionPolicy;
using embb::algorithms::Identity;
size_t count = embb::tasks::Node::GetInstance().GetCoreCount() * 10;
size_t count = embb::mtapi::Node::GetInstance().GetCoreCount() * 10;
std::vector<int> large_vector(count);
mtapi_int32_t expected = 0;
for (size_t i = 0; i < count; i++) {
......
......@@ -228,7 +228,7 @@ void ScanTest::TestRanges() {
void ScanTest::TestBlockSizes() {
using embb::algorithms::Scan;
using embb::tasks::ExecutionPolicy;
using embb::mtapi::ExecutionPolicy;
using embb::algorithms::Identity;
size_t count = 4;
std::vector<int> init(count);
......@@ -253,7 +253,7 @@ void ScanTest::TestBlockSizes() {
void ScanTest::TestPolicy() {
using embb::algorithms::Scan;
using embb::tasks::ExecutionPolicy;
using embb::mtapi::ExecutionPolicy;
using embb::algorithms::Identity;
size_t count = 4;
std::vector<int> init(count);
......@@ -324,8 +324,8 @@ void ScanTest::TestPolicy() {
void ScanTest::StressTest() {
using embb::algorithms::Scan;
using embb::algorithms::Identity;
using embb::tasks::ExecutionPolicy;
size_t count = embb::tasks::Node::GetInstance().GetCoreCount() *10;
using embb::mtapi::ExecutionPolicy;
size_t count = embb::mtapi::Node::GetInstance().GetCoreCount() *10;
std::vector<int> large_vector(count);
std::vector<int> large_vector_output(count);
for (size_t i = 0; i < count; i++) {
......
......@@ -136,7 +136,7 @@ void ZipIteratorTest::TestZipScan() {
Scan(embb::algorithms::Zip(vectorA.begin(), vectorB.begin()),
embb::algorithms::Zip(vectorA.end(), vectorB.end()),
vectorOut.begin(), 0, std::plus<int>(), DotProductFunctor(),
embb::tasks::ExecutionPolicy(), 0);
embb::mtapi::ExecutionPolicy(), 0);
long sum = 0;
for (size_t i = 0; i < kCountSize; i++) {
......
......@@ -122,3 +122,8 @@ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/embb
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/embb
DESTINATION include FILES_MATCHING PATTERN "*.h")
install(TARGETS embb_base_c DESTINATION lib)
if (MSVC)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/embb_base_c.pdb
DESTINATION lib
CONFIGURATIONS Debug)
endif()
......@@ -110,6 +110,9 @@ int embb_condition_notify_all(
* \threadsafe
* \see embb_condition_notify_one(), embb_condition_notify_all(),
* embb_condition_wait_until(), embb_condition_wait_for()
* \note It is strongly recommended checking the condition in a loop in order
* to deal with spurious wakeups and situations where another thread has
* locked the mutex between notification and wakeup.
*/
int embb_condition_wait(
embb_condition_t* condition_var,
......@@ -131,6 +134,9 @@ int embb_condition_wait(
* \threadsafe
* \see embb_condition_notify_one(), embb_condition_notify_all(),
* embb_condition_wait(), embb_condition_wait_for()
* \note It is strongly recommended checking the condition in a loop in order
* to deal with spurious wakeups and situations where another thread has
* locked the mutex between notification and wakeup.
*/
int embb_condition_wait_until(
embb_condition_t* condition_var,
......@@ -154,6 +160,9 @@ int embb_condition_wait_until(
* \threadsafe
* \see embb_condition_notify_one(), embb_condition_notify_all(),
* embb_condition_wait(), embb_condition_wait_until()
* \note It is strongly recommended checking the condition in a loop in order
* to deal with spurious wakeups and situations where another thread has
* locked the mutex between notification and wakeup.
*/
int embb_condition_wait_for(
embb_condition_t* condition_var,
......
......@@ -46,3 +46,8 @@ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/embb
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/embb
DESTINATION include FILES_MATCHING PATTERN "*.h")
install(TARGETS embb_base_cpp DESTINATION lib)
if (MSVC)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/embb_base_cpp.pdb
DESTINATION lib
CONFIGURATIONS Debug)
endif()
......@@ -99,6 +99,10 @@ class ConditionVariable {
* \threadsafe
*
* \see NotifyOne(), NotifyAll()
*
* \note It is strongly recommended checking the condition in a loop in order
* to deal with spurious wakeups and situations where another thread has
* locked the mutex between notification and wakeup.
*/
void Wait(
UniqueLock<Mutex>& lock
......@@ -118,6 +122,10 @@ class ConditionVariable {
* \throws embb::base::ErrorException if an error occurred
*
* \threadsafe
*
* \note It is strongly recommended checking the condition in a loop in order
* to deal with spurious wakeups and situations where another thread has
* locked the mutex between notification and wakeup.
*/
bool WaitUntil(
UniqueLock<Mutex>& lock,
......@@ -141,6 +149,10 @@ class ConditionVariable {
* \threadsafe
*
* \tparam Tick Type of tick of the duration. See Duration.
*
* \note It is strongly recommended checking the condition in a loop in order
* to deal with spurious wakeups and situations where another thread has
* locked the mutex between notification and wakeup.
*/
template<typename Tick>
bool WaitFor(
......
......@@ -31,3 +31,8 @@ endif()
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/embb
DESTINATION include FILES_MATCHING PATTERN "*.h")
install(TARGETS embb_containers_cpp DESTINATION lib)
if (MSVC)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/embb_containers_cpp.pdb
DESTINATION lib
CONFIGURATIONS Debug)
endif()
......@@ -74,7 +74,7 @@ int* IntObjectTestPool::Allocate() {
}
void IntObjectTestPool::Release(int* object_pointer) {
int cell = object_pointer - simplePoolObjects;
int cell = static_cast<int>(object_pointer - simplePoolObjects);
simplePool[cell].Store(FREE_MARKER);
}
......
......@@ -24,6 +24,15 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <embb/base/c/memory_allocation.h>
#ifdef EMBB_PLATFORM_COMPILER_MSVC
// Suppress warning generated by malloc.h(160): expression before comma
// has no effect: expected expression with side effect
#pragma warning(push)
#pragma warning(disable : 4548)
#endif
#include <embb/containers/lock_free_tree_value_pool.h>
#include <embb/containers/wait_free_array_value_pool.h>
#include <embb/containers/wait_free_spsc_queue.h>
......@@ -33,6 +42,10 @@
#include <embb/base/c/memory_allocation.h>
#include <embb/base/c/atomic.h>
#ifdef EMBB_PLATFORM_COMPILER_MSVC
#pragma warning(pop) // Reset warning 4548
#endif
#include <partest/partest.h>
#include <embb/base/thread.h>
......
......@@ -17,16 +17,16 @@ include_directories(${EMBB_DATAFLOW_CPP_INCLUDE_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/../base_cpp/include
${CMAKE_CURRENT_BINARY_DIR}/../base_cpp/include
${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_c/include
${CMAKE_CURRENT_SOURCE_DIR}/../tasks_cpp/include
${CMAKE_CURRENT_BINARY_DIR}/../tasks_cpp/include)
${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_cpp/include
${CMAKE_CURRENT_BINARY_DIR}/../mtapi_cpp/include)
add_library (embb_dataflow_cpp ${EMBB_DATAFLOW_CPP_SOURCES} ${EMBB_DATAFLOW_CPP_HEADERS})
target_link_libraries(embb_dataflow_cpp embb_tasks_cpp embb_base_cpp embb_mtapi_c embb_base_c)
target_link_libraries(embb_dataflow_cpp embb_mtapi_cpp embb_base_cpp embb_mtapi_c embb_base_c)
if (BUILD_TESTS STREQUAL ON)
include_directories(${CMAKE_CURRENT_BINARY_DIR}/../partest/include)
add_executable (embb_dataflow_cpp_test ${EMBB_DATAFLOW_CPP_TEST_SOURCES})
target_link_libraries(embb_dataflow_cpp_test embb_dataflow_cpp embb_tasks_cpp embb_mtapi_c partest
target_link_libraries(embb_dataflow_cpp_test embb_dataflow_cpp embb_mtapi_cpp embb_mtapi_c partest
embb_base_cpp embb_base_c ${compiler_libs})
CopyBin(BIN embb_dataflow_cpp_test DEST ${local_install_dir})
endif()
......@@ -34,3 +34,8 @@ endif()
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/
DESTINATION include FILES_MATCHING PATTERN "*.h")
install(TARGETS embb_dataflow_cpp DESTINATION lib)
if (MSVC)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/embb_dataflow_cpp.pdb
DESTINATION lib
CONFIGURATIONS Debug)
endif()
......@@ -29,7 +29,7 @@
#include <cstddef>
#include <embb/tasks/task_context.h>
#include <embb/mtapi/task_context.h>
#include <embb/dataflow/internal/node.h>
......@@ -46,7 +46,7 @@ class Action {
node_->Run(clock_);
}
void RunMTAPI(embb::tasks::TaskContext & /*context*/) {
void RunMTAPI(embb::mtapi::TaskContext & /*context*/) {
node_->Run(clock_);
}
......
......@@ -158,7 +158,7 @@ class Process< Serial, Inputs<I1, I2, I3, I4, I5>,
} else {
const int idx = clock % slices_;
action_[idx] = Action(this, clock);
sched_->Spawn(action_[idx]);
sched_->Start(action_[idx]);
}
}
......
......@@ -37,7 +37,7 @@ class Scheduler {
public:
Scheduler() {}
virtual ~Scheduler() {}
virtual void Spawn(Action & action) = 0;
virtual void Start(Action & action) = 0;
virtual void Enqueue(int process_id, Action & action) = 0;
virtual void WaitForSlice(int slice) = 0;
virtual int GetSlices() = 0;
......
......@@ -29,7 +29,7 @@
#include <embb/dataflow/internal/action.h>
#include <embb/dataflow/internal/scheduler.h>
#include <embb/tasks/node.h>
#include <embb/mtapi/mtapi.h>
#include <embb/base/function.h>
#include <algorithm>
......@@ -38,11 +38,13 @@ namespace embb {
namespace dataflow {
namespace internal {
#define EMBB_DATAFLOW_JOB_ID 1
class SchedulerMTAPI : public Scheduler {
public:
explicit SchedulerMTAPI(int slices)
: slices_(slices) {
embb::tasks::Node & node = embb::tasks::Node::GetInstance();
embb::mtapi::Node & node = embb::mtapi::Node::GetInstance();
int tl = std::min(
static_cast<int>(node.GetTaskLimit()),
......@@ -51,60 +53,85 @@ class SchedulerMTAPI : public Scheduler {
slices_ = tl;
}
group_ = reinterpret_cast<embb::tasks::Group**>(
job_ = node.GetJob(EMBB_DATAFLOW_JOB_ID);
action_ = node.CreateAction(EMBB_DATAFLOW_JOB_ID,
SchedulerMTAPI::action_func);
group_ = reinterpret_cast<embb::mtapi::Group*>(
embb::base::Allocation::Allocate(
sizeof(embb::tasks::Group*)*slices_));
sizeof(embb::mtapi::Group)*slices_));
for (int ii = 0; ii < slices_; ii++) {
embb::tasks::Group & group = node.CreateGroup();
group_[ii] = &group;
group_[ii] = node.CreateGroup();
}
queue_count_ = std::min(
static_cast<int>(node.GetQueueCount()),
static_cast<int>(node.GetWorkerThreadCount()) );
queue_ = reinterpret_cast<embb::tasks::Queue**>(
queue_ = reinterpret_cast<embb::mtapi::Queue*>(
embb::base::Allocation::Allocate(
sizeof(embb::tasks::Queue*)*queue_count_));
sizeof(embb::mtapi::Queue)*queue_count_));
embb::mtapi::QueueAttributes queue_attr;
queue_attr
.SetPriority(0)
.SetOrdered(true);
for (int ii = 0; ii < queue_count_; ii++) {
embb::tasks::Queue & queue = node.CreateQueue(0, true);
queue_[ii] = &queue;
queue_[ii] = node.CreateQueue(job_, queue_attr);
}
}
virtual ~SchedulerMTAPI() {
if (embb::tasks::Node::IsInitialized()) {
if (embb::mtapi::Node::IsInitialized()) {
// only destroy groups and queues if there still is an instance
embb::tasks::Node & node = embb::tasks::Node::GetInstance();
for (int ii = 0; ii < slices_; ii++) {
group_[ii]->WaitAll(MTAPI_INFINITE);
node.DestroyGroup(*group_[ii]);
group_[ii].WaitAll(MTAPI_INFINITE);
group_[ii].Delete();
}
for (int ii = 0; ii < queue_count_; ii++) {
node.DestroyQueue(*queue_[ii]);
queue_[ii].Delete();
}
// delete action as well
action_.Delete();
}
embb::base::Allocation::Free(group_);
embb::base::Allocation::Free(queue_);
}
virtual void Spawn(Action & action) {
virtual void Start(Action & action) {
const int idx = action.GetClock() % slices_;
group_[idx]->Spawn(embb::base::MakeFunction(action, &Action::RunMTAPI));
group_[idx].Start(job_, &action, static_cast<void*>(NULL));
}
virtual void Enqueue(int process_id, Action & action) {
const int idx = action.GetClock() % slices_;
const int queue_id = process_id % queue_count_;
queue_[queue_id]->Spawn(group_[idx],
embb::base::MakeFunction(action, &Action::RunMTAPI));
queue_[queue_id].Enqueue(&action, static_cast<void*>(NULL), group_[idx]);
}
virtual void WaitForSlice(int slice) {
group_[slice]->WaitAll(MTAPI_INFINITE);
group_[slice].WaitAll(MTAPI_INFINITE);
// group is invalid now, recreate
embb::mtapi::Node & node = embb::mtapi::Node::GetInstance();
group_[slice] = node.CreateGroup();
}
virtual int GetSlices() { return slices_; }
private:
embb::tasks::Group ** group_;
embb::tasks::Queue ** queue_;
static void action_func(
const void* args,
mtapi_size_t /*args_size*/,
void* /*result_buffer*/,
mtapi_size_t /*result_buffer_size*/,
const void* /*node_local_data*/,
mtapi_size_t /*node_local_data_size*/,
mtapi_task_context_t * context) {
Action * action =
reinterpret_cast<Action*>(const_cast<void*>(args));
embb::mtapi::TaskContext task_context(context);
action->RunMTAPI(task_context);
}
embb::mtapi::Action action_;
embb::mtapi::Job job_;
embb::mtapi::Group * group_;
embb::mtapi::Queue * queue_;
int queue_count_;
int slices_;
};
......
......@@ -38,7 +38,7 @@ class SchedulerSequential : public Scheduler {
public:
SchedulerSequential() {}
virtual ~SchedulerSequential() {}
virtual void Spawn(Action & action) {
virtual void Start(Action & action) {
action.RunSequential();
}
virtual void Enqueue(int, Action & action) {
......
......@@ -29,7 +29,7 @@
#include <iostream>
#include <sstream>
#include <embb/tasks/tasks.h>
#include <embb/mtapi/mtapi.h>
#include <embb/base/function.h>
#include <embb/base/c/memory_allocation.h>
......@@ -153,15 +153,14 @@ SimpleTest::SimpleTest() {
void SimpleTest::TestBasic() {
// All available cores
embb::base::CoreSet core_set(true);
embb::tasks::Node::Initialize(
embb::mtapi::NodeAttributes node_attr;
node_attr
.SetCoreAffinity(core_set)
.SetMaxQueues(2);
embb::mtapi::Node::Initialize(
MTAPI_DOMAIN_ID,
MTAPI_NODE_ID,
core_set,
1024, // max tasks (default: 1024)
128, // max groups (default: 128)
2, // max queues (default: 16)
1024, // queue capacity (default: 1024)
4); // num priorities (default: 4)
node_attr);
for (int ii = 0; ii < 10000; ii++) {
ArraySink<TEST_COUNT> asink;
......@@ -221,7 +220,7 @@ void SimpleTest::TestBasic() {
PT_EXPECT(asink.Check());
}
embb::tasks::Node::Finalize();
embb::mtapi::Node::Finalize();
PT_EXPECT(embb_get_bytes_allocated() == 0);
}
......
......@@ -14,8 +14,7 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/../../mtapi_c/src
${CMAKE_CURRENT_SOURCE_DIR}/../../mtapi_plugins_c/mtapi_network_c/include
${CMAKE_CURRENT_SOURCE_DIR}/../../mtapi_cpp/include
${CMAKE_CURRENT_SOURCE_DIR}/../../tasks_cpp/include
${CMAKE_CURRENT_BINARY_DIR}/../../tasks_cpp/include
${CMAKE_CURRENT_BINARY_DIR}/../../mtapi_cpp/include
${CMAKE_CURRENT_SOURCE_DIR}/../../containers_cpp/include
${CMAKE_CURRENT_SOURCE_DIR}/../../algorithms_cpp/include
${CMAKE_CURRENT_SOURCE_DIR}/../../dataflow_cpp/include
......@@ -46,7 +45,7 @@ IF(MSVC)
ENDIF()
add_executable(examples ${EXAMPLES_SOURCES})
target_link_libraries(examples embb_dataflow_cpp embb_algorithms_cpp embb_tasks_cpp embb_mtapi_cpp
target_link_libraries(examples embb_dataflow_cpp embb_algorithms_cpp embb_mtapi_cpp
embb_mtapi_network_c ${EMBB_MTAPI_OPENCL_C_CONDITIONAL} embb_mtapi_c
embb_base_cpp embb_base_c embb_containers_cpp
${EXTRA_LIBS} ${compiler_libs})
......
......@@ -34,7 +34,6 @@ void RunMTAPI_C_Network();
void RunMTAPI_C_OpenCL();
#endif
void RunMTAPI_CPP();
void RunTasks();
void RunDataflowLinear();
void RunDataflowNonLinear();
void RunSTLForEach();
......@@ -78,10 +77,6 @@ int main() {
RunMTAPI_CPP();
std::cout << "RunMTAPI_CPP() ... done" << std::endl;
std::cout << "RunTasks() ..." << std::endl;
RunTasks();
std::cout << "RunTasks() ... done" << std::endl;
std::cout << "RunDataflowLinear() ..." << std::endl;
RunDataflowLinear();
std::cout << "RunDataflowLinear() ... done" << std::endl;
......
......@@ -51,8 +51,8 @@ static
static
int fibonacci(int n) {
#include "mtapi/mtapi_cpp_initialize-snippet.h"
#include "mtapi/mtapi_cpp_register_action-snippet.h"
#include "mtapi/mtapi_cpp_get_node-snippet.h"
#include "mtapi/mtapi_cpp_register_action-snippet.h"
/* start calculation */
#include "mtapi/mtapi_cpp_start_task-snippet.h"
/* wait for task completion */
......
/* create action */
embb::mtapi::Action fibonacciAction(
embb::mtapi::Action fibonacciAction = node.CreateAction(
FIBONACCI_JOB, /* action ID, defined by the
application */
(fibonacciActionFunction) /* action function */
);
/* get job */
fibonacciJob = embb::mtapi::Job(FIBONACCI_JOB, THIS_DOMAIN_ID);
fibonacciJob = node.GetJob(FIBONACCI_JOB, THIS_DOMAIN_ID);
void simpleActionFunction(
TaskContext & task_context
) {
// something useful
}
int result;
embb::mtapi::Task task = node.Start(simpleActionFunction);
mtapi_status_t status = task.Wait(MTAPI_INFINITE);
if (status != MTAPI_SUCCESS) {
printf("task failed with error: %d\n\n", status);
exit(status);
mtapi_status_t task_status = task.Wait(MTAPI_INFINITE);
if (task_status != MTAPI_SUCCESS) {
printf("task failed with error: %d\n\n", task_status);
exit(task_status);
}
/*
* 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 <iostream>
#include <embb/tasks/tasks.h>
#include "mtapi/mtapi_check_status-snippet.h"
static
#include "tasks/tasks_cpp_action_signature-snippet.h"
/* get the node instance */
#include "tasks/tasks_cpp_get_node-snippet.h"
/* calculate */
#include "mtapi/mtapi_terminating_condition-snippet.h"
/* first recursive call spawned as task (x = fib(n - 1);) */
#include "tasks/tasks_cpp_calc_task-snippet.h"
/* second recursive call can be called directly (y = fib(n - 2);) */
#include "tasks/tasks_cpp_calc_direct-snippet.h"
/* wait for completion */
#include "tasks/tasks_cpp_wait_task-snippet.h"
/* add the two preceeding numbers */
#include "mtapi/mtapi_write_back-snippet.h"
static
int fibonacci(int n) {
/* get the node instance, the node is initialized automatically */
embb::tasks::Node& node = embb::tasks::Node::GetInstance();
/* start calculation */
#include "tasks/tasks_cpp_start_task-snippet.h"
/* wait for task completion */
mtapi_status_t status = task.Wait(MTAPI_INFINITE);
MTAPI_CHECK_STATUS(status);
return result;
}
void RunTasks() {
int result = fibonacci(6);
std::cout << "result: " << result << std::endl;
}
void fibonacciActionFunction(
int n,
int* result,
embb::tasks::TaskContext & task_context
) {
int b = n - 2;
int y;
fibonacciActionFunction(
b,
&y,
task_context);
int a = n - 1;
int x;
embb::tasks::Task task = node.Spawn(
embb::base::Bind(
embb::base::MakeFunction(fibonacciActionFunction),
a, /* argument */
&x, /* result */
embb::base::Placeholder::_1
)
);
embb::tasks::Node& node = embb::tasks::Node::GetInstance();
int result;
embb::tasks::Task task = node.Spawn(
embb::base::Bind(
embb::base::MakeFunction(fibonacciActionFunction),
n,
&result,
embb::base::Placeholder::_1
)
);
mtapi_status_t status = task.Wait(MTAPI_INFINITE);
MTAPI_CHECK_STATUS(status);
......@@ -148,7 +148,6 @@ INPUT = "@CMAKE_SOURCE_DIR@/doc/reference/embb.dox" \
"@CMAKE_SOURCE_DIR@/containers_cpp/include" \
"@CMAKE_SOURCE_DIR@/dataflow_cpp/include" \
"@CMAKE_SOURCE_DIR@/algorithms_cpp/include" \
"@CMAKE_SOURCE_DIR@/tasks_cpp/include" \
"@CMAKE_SOURCE_DIR@/mtapi_cpp/include" \
"@CMAKE_SOURCE_DIR@/base_cpp/include" \
"@CMAKE_SOURCE_DIR@/mtapi_c/include" \
......
......@@ -152,7 +152,11 @@ After everything is done, the action is deleted (\lstinline|mtapi_action_delete(
\section{C++ Interface}
\label{sec:mtapi_cpp_interface}
\embb provides C++ wrappers for the MTAPI C interface. The signature of the action function for the C++ interface is the same as in the C interface:
\embb provides C++ wrappers for the MTAPI C interface. The full interface provides functions for all MTAPI releated tasks and supports heterogeneous systems. For ease of use a simpler version for SMP systems is provided.
\subsection{Full Interface}
The signature of the action function for the C++ interface is the same as in the C interface:
%
\\\inputlisting{../examples/mtapi/mtapi_c_action_signature-snippet.h}
%
......@@ -193,7 +197,7 @@ After that, the action function needs to be associated to a job. By instancing a
%
\\\inputlisting{../examples/mtapi/mtapi_cpp_register_action-snippet.h}
%
Not that the action is registered and the job is initialized, the root task can be started:
Now that the action is registered and the job is initialized, the root task can be started:
%
\\\inputlisting{../examples/mtapi/mtapi_cpp_start_task-snippet.h}
%
......@@ -203,6 +207,19 @@ The registered action will be unregistered when it goes out of scope.
The runtime needs to be shut down by calling:
\\\inputlisting{../examples/mtapi/mtapi_cpp_finalize-snippet.h}
\subsection{Simplified Interface for SMP actions}
MTAPI CPP provides a simpler version of the MTAPI interface for SMP actions. The signature of the
action function for the simplified API looks like this:
%
\\\inputlisting{../examples/mtapi/mtapi_cpp_simple_action_signature-snippet.h}
%
The action function does not need to be registered with a job. Instead a preregistered job is used that expects a \lstinline|embb::base::Function<void, embb::mtapi::TaskContext &>| object. Therefore a task can be scheduled directly using only the function above:
%
\\\inputlisting{../examples/mtapi/mtapi_cpp_simple_start_task-snippet.h}
%
\section{Plugins}
The \embb implementation of MTAPI provides an extension to allow for custom actions that are not executed by the scheduler for software actions as detailed in the previous sections.
......
\chapter{Tasks}
\label{cha:tasks}
\embb provides a simple task management wrapper for the MTAPI interface. Using the example from the previous section, the signature of the action function for the tasks interface looks like this:
%
\\\inputlisting{../examples/tasks/tasks_cpp_action_signature-snippet.h}
%
First, the node instance needs to be obtained. If the node is not initialized yet, this function will do it.
%
\\\inputlisting{../examples/tasks/tasks_cpp_get_node-snippet.h}
%
\emph{\textbf{Note:} Automatic initialization allows for easy usage of the \emph{Algorithms} and \emph{Dataflow} building blocks. For performance measurements however, explicit initialization by calling \lstinline|embb::tasks::Node::Initialize| is imperative since the measurements will otherwise include the initialization time of MTAPI.}
Checking the arguments and the result buffer is not necessary, since everything is safely typed. However, the terminating condition of the recursion still needs to be checked:
%
\\\inputlisting{../examples/mtapi/mtapi_terminating_condition-snippet.h}
%
After that, the first part of the computation is launched as an MTAPI task using \lstinline|embb::tasks::Node::Spawn()| (registering an action function with a job is done automatically):
%
\\\inputlisting{../examples/tasks/tasks_cpp_calc_task-snippet.h}
%
The second part can be executed directly:
%
\\\inputlisting{../examples/tasks/tasks_cpp_calc_direct-snippet.h}
%
Then, completion of the MTAPI task has to be waited for using \lstinline|embb::tasks::Task::Wait()|:
%
\\\inputlisting{../examples/tasks/tasks_cpp_wait_task-snippet.h}
%
Finally, the two parts can be added and written into the result buffer:
%
\\\inputlisting{../examples/mtapi/mtapi_write_back-snippet.h}
%
The \lstinline|fibonacci()| function also gets simpler compared to the C version. The MTAPI runtime is initialized automatically, only the node instance has to be fetched:
%
\\\inputlisting{../examples/tasks/tasks_cpp_get_node-snippet.h}
%
The root task can be started using \lstinline|embb::tasks::Node::Spawn()| directly, registering with a job is done automatically:
%
\\\inputlisting{../examples/tasks/tasks_cpp_start_task-snippet.h}
%
Again, the started task has to be waited for (using \lstinline|embb::tasks::Task::Wait()|) before the result can be returned. The runtime is shut down automatically in an \lstinline|atexit()| handler.
\emph{\textbf{Note:} If the node was initialized explicitly by calling \lstinline|embb::tasks::Node::Initialize|, the runtime must also be shut down explicitly by calling \lstinline|embb::tasks::Node::Finalize|.}
......@@ -114,7 +114,6 @@
% \input{content/preface}
\input{content/introduction}
\input{content/mtapi}
\input{content/tasks}
\input{content/algorithms}
\input{content/dataflow}
\input{content/containers}
......
......@@ -39,3 +39,8 @@ endif()
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/
DESTINATION include FILES_MATCHING PATTERN "*.h")
install(TARGETS embb_mtapi_c DESTINATION lib)
if (MSVC)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/embb_mtapi_c.pdb
DESTINATION lib
CONFIGURATIONS Debug)
endif()
......@@ -289,10 +289,12 @@ void mtapi_action_delete(
embb_mtapi_thread_context_t * context = NULL;
embb_duration_t wait_duration;
embb_time_t start_time;
embb_time_t end_time;
if (MTAPI_INFINITE < timeout) {
embb_duration_set_milliseconds(
&wait_duration, (unsigned long long)timeout);
embb_time_now(&start_time);
embb_time_in(&end_time, &wait_duration);
}
......@@ -309,6 +311,12 @@ void mtapi_action_delete(
if (MTAPI_INFINITE < timeout) {
embb_time_t current_time;
embb_time_now(&current_time);
if (embb_time_compare(&current_time, &start_time) < 0) {
/* time has moved backwards, maybe a wraparound or jitter
move end_time backward to avoid endeless loop */
start_time = current_time;
embb_time_in(&end_time, &wait_duration);
}
if (embb_time_compare(&current_time, &end_time) > 0) {
/* timeout! */
local_status = MTAPI_TIMEOUT;
......@@ -362,10 +370,12 @@ void mtapi_action_disable(
embb_mtapi_thread_context_t * context = NULL;
embb_duration_t wait_duration;
embb_time_t start_time;
embb_time_t end_time;
if (MTAPI_INFINITE < timeout) {
embb_duration_set_milliseconds(
&wait_duration, (unsigned long long)timeout);
embb_time_now(&start_time);
embb_time_in(&end_time, &wait_duration);
}
......@@ -382,6 +392,12 @@ void mtapi_action_disable(
if (MTAPI_INFINITE < timeout) {
embb_time_t current_time;
embb_time_now(&current_time);
if (embb_time_compare(&current_time, &start_time) < 0) {
/* time has moved backwards, maybe a wraparound or jitter
move end_time backward to avoid endeless loop */
start_time = current_time;
embb_time_in(&end_time, &wait_duration);
}
if (embb_time_compare(&current_time, &end_time) > 0) {
/* timeout! */
local_status = MTAPI_TIMEOUT;
......
......@@ -213,10 +213,12 @@ void mtapi_group_wait_all(
node->group_pool, group);
embb_duration_t wait_duration;
embb_time_t start_time;
embb_time_t end_time;
if (MTAPI_INFINITE < timeout) {
embb_duration_set_milliseconds(
&wait_duration, (unsigned long long)timeout);
embb_time_now(&start_time);
embb_time_in(&end_time, &wait_duration);
}
......@@ -232,6 +234,12 @@ void mtapi_group_wait_all(
if (MTAPI_INFINITE < timeout) {
embb_time_t current_time;
embb_time_now(&current_time);
if (embb_time_compare(&current_time, &start_time) < 0) {
/* time has moved backwards, maybe a wraparound or jitter
move end_time backward to avoid endeless loop */
start_time = current_time;
embb_time_in(&end_time, &wait_duration);
}
if (embb_time_compare(&current_time, &end_time) > 0) {
/* timeout! */
local_status = MTAPI_TIMEOUT;
......@@ -300,10 +308,12 @@ void mtapi_group_wait_any(
embb_mtapi_thread_context_t * context = NULL;
embb_duration_t wait_duration;
embb_time_t start_time;
embb_time_t end_time;
if (MTAPI_INFINITE < timeout) {
embb_duration_set_milliseconds(
&wait_duration, (unsigned long long)timeout);
embb_time_now(&start_time);
embb_time_in(&end_time, &wait_duration);
}
......@@ -318,6 +328,12 @@ void mtapi_group_wait_any(
if (MTAPI_INFINITE < timeout) {
embb_time_t current_time;
embb_time_now(&current_time);
if (embb_time_compare(&current_time, &start_time) < 0) {
/* time has moved backwards, maybe a wraparound or jitter
move end_time backward to avoid endeless loop */
start_time = current_time;
embb_time_in(&end_time, &wait_duration);
}
if (embb_time_compare(&current_time, &end_time) > 0) {
/* timeout! */
local_status = MTAPI_TIMEOUT;
......
......@@ -360,10 +360,12 @@ void mtapi_queue_delete(
embb_mtapi_thread_context_t * context = NULL;
embb_duration_t wait_duration;
embb_time_t start_time;
embb_time_t end_time;
if (MTAPI_INFINITE < timeout) {
embb_duration_set_milliseconds(
&wait_duration, (unsigned long long)timeout);
embb_time_now(&start_time);
embb_time_in(&end_time, &wait_duration);
}
......@@ -381,6 +383,12 @@ void mtapi_queue_delete(
if (MTAPI_INFINITE < timeout) {
embb_time_t current_time;
embb_time_now(&current_time);
if (embb_time_compare(&current_time, &start_time) < 0) {
/* time has moved backwards, maybe a wraparound or jitter
move end_time backward to avoid endeless loop */
start_time = current_time;
embb_time_in(&end_time, &wait_duration);
}
if (embb_time_compare(&current_time, &end_time) > 0) {
/* timeout! */
local_status = MTAPI_TIMEOUT;
......@@ -435,10 +443,12 @@ void mtapi_queue_disable(
embb_mtapi_scheduler_get_current_thread_context(node->scheduler);
embb_duration_t wait_duration;
embb_time_t start_time;
embb_time_t end_time;
if (MTAPI_INFINITE < timeout) {
embb_duration_set_milliseconds(
&wait_duration, (unsigned long long)timeout);
embb_time_now(&start_time);
embb_time_in(&end_time, &wait_duration);
}
......@@ -448,6 +458,12 @@ void mtapi_queue_disable(
if (MTAPI_INFINITE < timeout) {
embb_time_t current_time;
embb_time_now(&current_time);
if (embb_time_compare(&current_time, &start_time) < 0) {
/* time has moved backwards, maybe a wraparound or jitter
move end_time backward to avoid endeless loop */
start_time = current_time;
embb_time_in(&end_time, &wait_duration);
}
if (embb_time_compare(&current_time, &end_time) > 0) {
/* timeout! */
local_status = MTAPI_TIMEOUT;
......
......@@ -407,6 +407,7 @@ mtapi_boolean_t embb_mtapi_scheduler_wait_for_task(
embb_mtapi_node_t* node = embb_mtapi_node_get_instance();
embb_mtapi_thread_context_t * context = NULL;
embb_duration_t wait_duration;
embb_time_t start_time;
embb_time_t end_time;
assert(MTAPI_NULL != node);
......@@ -414,6 +415,7 @@ mtapi_boolean_t embb_mtapi_scheduler_wait_for_task(
if (MTAPI_INFINITE < timeout) {
embb_duration_set_milliseconds(&wait_duration, (unsigned long long)timeout);
embb_time_now(&start_time);
embb_time_in(&end_time, &wait_duration);
}
......@@ -431,6 +433,12 @@ mtapi_boolean_t embb_mtapi_scheduler_wait_for_task(
if (MTAPI_INFINITE < timeout) {
embb_time_t current_time;
embb_time_now(&current_time);
if (embb_time_compare(&current_time, &start_time) < 0) {
/* time has moved backwards, maybe a wraparound or jitter
move end_time backward to avoid endeless loop */
start_time = current_time;
embb_time_in(&end_time, &wait_duration);
}
if (embb_time_compare(&current_time, &end_time) > 0) {
/* timeout! */
return MTAPI_FALSE;
......
......@@ -54,7 +54,8 @@ mtapi_boolean_t embb_mtapi_thread_context_initialize_with_node_worker_and_core(
that->core_num = core_num;
that->priorities = node->attributes.max_priorities;
that->is_initialized = MTAPI_FALSE;
that->is_main_thread = (worker_index == 0) ? node->attributes.reuse_main_thread : MTAPI_FALSE;
that->is_main_thread = (worker_index == 0) ?
node->attributes.reuse_main_thread : MTAPI_FALSE;
embb_atomic_store_int(&that->run, 0);
that->queue = (embb_mtapi_task_queue_t**)embb_mtapi_alloc_allocate(
......
......@@ -10,6 +10,9 @@ else()
set(MTAPI_CPP_AUTOMATIC_INITIALIZE 0)
endif()
configure_file("include/embb/mtapi/internal/cmake_config.h.in"
"include/embb/mtapi/internal/cmake_config.h")
# Execute the GroupSources macro
include(${CMAKE_SOURCE_DIR}/CMakeCommon/GroupSourcesMSVC.cmake)
GroupSourcesMSVC(include)
......@@ -18,6 +21,7 @@ GroupSourcesMSVC(test)
set (EMBB_MTAPI_CPP_INCLUDE_DIRS "include" "src" "test")
include_directories(${EMBB_MTAPI_CPP_INCLUDE_DIRS}
${CMAKE_CURRENT_BINARY_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/../base_c/include
${CMAKE_CURRENT_BINARY_DIR}/../base_c/include
${CMAKE_CURRENT_SOURCE_DIR}/../base_cpp/include
......@@ -38,3 +42,8 @@ endif()
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/
DESTINATION include FILES_MATCHING PATTERN "*.h")
install(TARGETS embb_mtapi_cpp DESTINATION lib)
if (MSVC)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/embb_mtapi_cpp.pdb
DESTINATION lib
CONFIGURATIONS Debug)
endif()
......@@ -43,60 +43,26 @@ class Action {
public:
/**
* Constructs an Action.
* The Action object will be invalid.
*/
Action(
mtapi_job_id_t job_id, /**< Job ID the Action belongs to */
mtapi_action_function_t func, /**< The action function */
const void * node_local_data, /**< Node local data available to all
Tasks using this Action */
mtapi_size_t node_local_data_size, /**< Size of node local data */
ActionAttributes const & attributes
/**< Attributes of the Action */
) {
Create(job_id, func, node_local_data, node_local_data_size,
&attributes.GetInternal());
Action() {
handle_.id = 0;
handle_.tag = 0;
}
/**
* Constructs an Action.
*/
Action(
mtapi_job_id_t job_id, /**< Job ID the Action belongs to */
mtapi_action_function_t func, /**< The action function */
const void * node_local_data, /**< Node local data available to all
Tasks using this Action */
mtapi_size_t node_local_data_size /**< Size of node local data */
) {
Create(job_id, func, node_local_data, node_local_data_size,
MTAPI_DEFAULT_ACTION_ATTRIBUTES);
}
/**
* Constructs an Action.
*/
Action(
mtapi_job_id_t job_id, /**< Job ID the Action belongs to */
mtapi_action_function_t func, /**< The action function */
ActionAttributes const & attributes
/**< Attributes of the Action */
) {
Create(job_id, func, MTAPI_NULL, 0, &attributes.GetInternal());
Action(Action const & other) : handle_(other.handle_) {
// empty
}
/**
* Constructs an Action.
*/
Action(
mtapi_job_id_t job_id, /**< Job ID the Action belongs to */
mtapi_action_function_t func /**< The action function */
) {
Create(job_id, func, MTAPI_NULL, 0, MTAPI_DEFAULT_ACTION_ATTRIBUTES);
Action & operator=(Action const & other) {
handle_ = other.handle_;
return *this;
}
/**
* Destroys an Action.
* Deletes an Action.
*/
~Action() {
void Delete() {
mtapi_action_delete(handle_, MTAPI_INFINITE, MTAPI_NULL);
}
......@@ -111,20 +77,20 @@ class Action {
return handle_;
}
private:
// no default constructor
Action();
// not copyable
Action(Action const & other);
void operator=(Action const & other);
friend class Node;
void Create(
mtapi_job_id_t job_id,
mtapi_action_function_t func,
const void * node_local_data,
mtapi_size_t node_local_data_size,
private:
/**
* Constructs an Action.
*/
Action(
mtapi_job_id_t job_id, /**< Job ID the Action belongs to */
mtapi_action_function_t func, /**< The action function */
const void * node_local_data, /**< Node local data available to all
Tasks using this Action */
mtapi_size_t node_local_data_size, /**< Size of node local data */
mtapi_action_attributes_t const * attributes
/**< Attributes of the Action */
) {
mtapi_status_t status;
handle_ = mtapi_action_create(job_id, func,
......
......@@ -24,13 +24,14 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef EMBB_TASKS_EXECUTION_POLICY_H_
#define EMBB_TASKS_EXECUTION_POLICY_H_
#ifndef EMBB_MTAPI_EXECUTION_POLICY_H_
#define EMBB_MTAPI_EXECUTION_POLICY_H_
#include <embb/mtapi/c/mtapi.h>
#include <embb/mtapi/internal/cmake_config.h>
namespace embb {
namespace tasks {
namespace mtapi {
/**
* Describes the execution policy of a parallel algorithm.
......@@ -42,7 +43,7 @@ namespace tasks {
* max_priorities - 1 as given during initialization using Node::Initialize().
* The default value of max_priorities is 4.
*
* \ingroup CPP_TASKS
* \ingroup CPP_MTAPI
*/
class ExecutionPolicy{
public:
......@@ -118,7 +119,7 @@ class ExecutionPolicy{
*
* \return the affinity
*/
const mtapi_affinity_t &GetAffinity() const;
mtapi_affinity_t GetAffinity() const;
/** Returns the priority
*
......@@ -147,7 +148,7 @@ class ExecutionPolicy{
mtapi_uint_t priority_;
};
} // namespace tasks
} // namespace mtapi
} // namespace embb
#endif // EMBB_TASKS_EXECUTION_POLICY_H_
#endif // EMBB_MTAPI_EXECUTION_POLICY_H_
......@@ -51,49 +51,19 @@ namespace mtapi {
*/
class Group {
public:
/**
* Constructs a Group object with default attributes.
* Requires an initialized Node.
*/
Group() {
Create(MTAPI_GROUP_ID_NONE, MTAPI_DEFAULT_GROUP_ATTRIBUTES);
Group(Group const & other) : handle_(other.handle_) {
// empty
}
/**
* Constructs a Group object using the given Attributes.
* Requires an initialized Node.
*/
Group(
GroupAttributes const & attr /**< The GroupAttributes to use. */
) {
Create(MTAPI_GROUP_ID_NONE, &attr.GetInternal());
Group & operator=(Group const & other) {
handle_ = other.handle_;
return *this;
}
/**
* Constructs a Group object with default attributes and the given ID.
* Requires an initialized Node.
* Deletes a Group object.
*/
Group(
mtapi_group_id_t id /**< A user defined ID of the Group. */
) {
Create(id, MTAPI_DEFAULT_GROUP_ATTRIBUTES);
}
/**
* Constructs a Group object with given attributes and ID.
* Requires an initialized Node.
*/
Group(
mtapi_group_id_t id, /**< A user defined ID of the Group. */
GroupAttributes const & attr /**< The GroupAttributes to use. */
) {
Create(id, &attr.GetInternal());
}
/**
* Destroys a Group object.
*/
~Group() {
void Delete() {
// delete the group, ignore status
mtapi_group_delete(handle_, MTAPI_NULL);
}
......@@ -194,7 +164,6 @@ class Group {
) {
mtapi_status_t status;
mtapi_group_wait_any(handle_, result, timeout, &status);
needs_delete_ = status != MTAPI_GROUP_COMPLETED;
return status;
}
......@@ -245,7 +214,6 @@ class Group {
) {
mtapi_status_t status;
mtapi_group_wait_all(handle_, timeout, &status);
needs_delete_ = status != MTAPI_SUCCESS;
return status;
}
......@@ -271,21 +239,21 @@ class Group {
}
friend class embb::base::Allocation;
friend class Node;
private:
// not copyable
Group(Group const & other);
void operator=(Group const & other);
void Create(
mtapi_group_id_t group_id,
/**
* Constructs a Group object with given attributes and ID.
* Requires an initialized Node.
*/
Group(
mtapi_group_id_t id, /**< A user defined ID of the Group. */
mtapi_group_attributes_t const * attributes
/**< The GroupAttributes to use. */
) {
needs_delete_ = false;
mtapi_status_t status;
handle_ = mtapi_group_create(group_id, attributes, &status);
handle_ = mtapi_group_create(id, attributes, &status);
internal::CheckStatus(status);
needs_delete_ = true;
}
Task Start(
......@@ -307,7 +275,6 @@ class Group {
}
mtapi_group_hndl_t handle_;
bool needs_delete_;
};
} // namespace mtapi
......
......@@ -24,8 +24,8 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef EMBB_TASKS_INTERNAL_CMAKE_CONFIG_H_
#define EMBB_TASKS_INTERNAL_CMAKE_CONFIG_H_
#ifndef EMBB_MTAPI_INTERNAL_CMAKE_CONFIG_H_
#define EMBB_MTAPI_INTERNAL_CMAKE_CONFIG_H_
/* This file is used as input for CMake. CMake creates a file cmake_config.h in
its current build directory under the path builddir/embb/tasks/internal/. From
......@@ -36,6 +36,6 @@
/**
* Is used to enable automatic initialization of the MTAPI node
*/
#define TASKS_CPP_AUTOMATIC_INITIALIZE ${TASKS_CPP_AUTOMATIC_INITIALIZE}
#define MTAPI_CPP_AUTOMATIC_INITIALIZE ${MTAPI_CPP_AUTOMATIC_INITIALIZE}
#endif // EMBB_TASKS_INTERNAL_CMAKE_CONFIG_H_
#endif // EMBB_MTAPI_INTERNAL_CMAKE_CONFIG_H_
......@@ -50,19 +50,6 @@ class Job {
}
/**
* Constructs a Job with the given \c job_id and \c domain_id.
* Requires an initialized Node.
*/
Job(
mtapi_job_id_t job_id, /**< Job ID to use. */
mtapi_domain_t domain_id /**< Domain ID to use. */
) {
mtapi_status_t status;
handle_ = mtapi_job_get(job_id, domain_id, &status);
internal::CheckStatus(status);
}
/**
* Copies a Job object.
*/
Job(
......@@ -91,7 +78,22 @@ class Job {
return handle_;
}
friend class Node;
private:
/**
* Constructs a Job with the given \c job_id and \c domain_id.
* Requires an initialized Node.
*/
Job(
mtapi_job_id_t job_id, /**< Job ID to use. */
mtapi_domain_t domain_id /**< Domain ID to use. */
) {
mtapi_status_t status;
handle_ = mtapi_job_get(job_id, domain_id, &status);
internal::CheckStatus(status);
}
mtapi_job_hndl_t handle_;
};
......
......@@ -35,6 +35,7 @@
* \ingroup CPP
*/
#include <embb/mtapi/execution_policy.h>
#include <embb/mtapi/job.h>
#include <embb/mtapi/action.h>
#include <embb/mtapi/group.h>
......
......@@ -28,12 +28,28 @@
#define EMBB_MTAPI_NODE_H_
#include <embb/base/memory_allocation.h>
#include <embb/base/function.h>
#include <embb/mtapi/c/mtapi.h>
#include <embb/mtapi/execution_policy.h>
#include <embb/mtapi/status_exception.h>
#include <embb/mtapi/node_attributes.h>
#include <embb/mtapi/group.h>
#include <embb/mtapi/queue.h>
#include <embb/mtapi/task.h>
#include <embb/mtapi/task_attributes.h>
#include <embb/mtapi/job.h>
#include <embb/mtapi/action.h>
#include <embb/mtapi/task_context.h>
#ifdef GetJob
#undef GetJob
#endif
#ifdef MTAPI_CPP_AUTOMATIC_INITIALIZE
#define MTAPI_CPP_AUTOMATIC_DOMAIN_ID 1
#define MTAPI_CPP_AUTOMATIC_NODE_ID 1
#endif
#define EMBB_MTAPI_FUNCTION_JOB_ID 2
namespace embb {
......@@ -52,6 +68,8 @@ namespace mtapi {
*/
class Node {
public:
typedef embb::base::Function<void, TaskContext &> SMPFunction;
/**
* Initializes the runtime singleton using default values:
* - all available cores will be used
......@@ -69,16 +87,7 @@ class Node {
static void Initialize(
mtapi_domain_t domain_id, /**< [in] The domain id to use */
mtapi_node_t node_id /**< [in] The node id to use */
) {
if (IsInitialized()) {
EMBB_THROW(StatusException,
"MTAPI: node was already initialized.");
} else {
NodeAttributes attributes; // default attributes
node_instance_ = embb::base::Allocation::New<Node>(
domain_id, node_id, attributes);
}
}
);
/**
* Initializes the runtime singleton.
......@@ -91,15 +100,7 @@ class Node {
mtapi_domain_t domain_id, /**< [in] The domain id to use */
mtapi_node_t node_id, /**< [in] The node id to use */
NodeAttributes const & attributes /**< [in] Attributes to use */
) {
if (IsInitialized()) {
EMBB_THROW(StatusException,
"MTAPI: node was already initialized.");
} else {
node_instance_ = embb::base::Allocation::New<Node>(
domain_id, node_id, attributes);
}
}
);
/**
* Checks if runtime is initialized.
......@@ -116,29 +117,14 @@ class Node {
* \return Reference to the Node singleton
* \threadsafe
*/
static Node & GetInstance() {
if (IsInitialized()) {
return *node_instance_;
} else {
EMBB_THROW(StatusException,
"MTAPI: node is not initialized.");
}
}
static Node & GetInstance();
/**
* Shuts the runtime system down.
* \throws ErrorException if the singleton is not initialized.
* \notthreadsafe
*/
static void Finalize() {
if (IsInitialized()) {
embb::base::Allocation::Delete(node_instance_);
node_instance_ = NULL;
} else {
EMBB_THROW(StatusException,
"MTAPI: node is not initialized.");
}
}
static void Finalize();
/**
* Returns the number of available cores.
......@@ -159,6 +145,67 @@ class Node {
}
/**
* Returns the number of available queues.
* \return The number of available queues
* \waitfree
*/
mtapi_uint_t GetQueueCount() const {
return queue_count_;
}
/**
* Returns the number of available groups.
* \return The number of available groups
* \waitfree
*/
mtapi_uint_t GetGroupCount() const {
return group_count_;
}
/**
* Returns the number of available tasks.
* \return The number of available tasks
* \waitfree
*/
mtapi_uint_t GetTaskLimit() const {
return task_limit_;
}
/**
* Starts a new Task.
*
* \returns The handle to the started Task.
* \threadsafe
*/
Task Start(
SMPFunction const & func /**< Function to use for the task. */
) {
Job job = GetJob(EMBB_MTAPI_FUNCTION_JOB_ID);
void * res = NULL;
return Start(
job, embb::base::Allocation::New<SMPFunction>(func), res);
}
/**
* Starts a new Task with a given affinity and priority.
*
* \returns The handle to the started Task.
* \threadsafe
*/
Task Start(
SMPFunction const & func, /**< Function to use for the task. */
ExecutionPolicy const & policy /**< Affinity and priority of the
task. */
) {
Job job = GetJob(EMBB_MTAPI_FUNCTION_JOB_ID);
void * res = NULL;
TaskAttributes task_attr;
task_attr.SetPolicy(policy);
return Start(
job, embb::base::Allocation::New<SMPFunction>(func), res, task_attr);
}
/**
* Starts a new Task.
*
* \returns The handle to the started Task.
......@@ -238,6 +285,119 @@ class Node {
MTAPI_DEFAULT_TASK_ATTRIBUTES);
}
Job GetJob(mtapi_job_id_t job_id) {
return Job(job_id, domain_id_);
}
Job GetJob(mtapi_job_id_t job_id, mtapi_domain_t domain_id) {
return Job(job_id, domain_id);
}
/**
* Constructs an Action.
*/
Action CreateAction(
mtapi_job_id_t job_id, /**< Job ID the Action belongs to */
mtapi_action_function_t func, /**< The action function */
const void * node_local_data, /**< Node local data available to all
Tasks using this Action */
mtapi_size_t node_local_data_size, /**< Size of node local data */
ActionAttributes const & attributes
/**< Attributes of the Action */
) {
return Action(job_id, func, node_local_data, node_local_data_size,
&attributes.GetInternal());
}
/**
* Constructs an Action.
*/
Action CreateAction(
mtapi_job_id_t job_id, /**< Job ID the Action belongs to */
mtapi_action_function_t func, /**< The action function */
const void * node_local_data, /**< Node local data available to all
Tasks using this Action */
mtapi_size_t node_local_data_size /**< Size of node local data */
) {
return Action(job_id, func, node_local_data, node_local_data_size,
MTAPI_DEFAULT_ACTION_ATTRIBUTES);
}
/**
* Constructs an Action.
*/
Action CreateAction(
mtapi_job_id_t job_id, /**< Job ID the Action belongs to */
mtapi_action_function_t func, /**< The action function */
ActionAttributes const & attributes
/**< Attributes of the Action */
) {
return Action(job_id, func, MTAPI_NULL, 0, &attributes.GetInternal());
}
/**
* Constructs an Action.
*/
Action CreateAction(
mtapi_job_id_t job_id, /**< Job ID the Action belongs to */
mtapi_action_function_t func /**< The action function */
) {
return Action(job_id, func, MTAPI_NULL, 0, MTAPI_DEFAULT_ACTION_ATTRIBUTES);
}
/**
* Constructs a Group object with default attributes.
*/
Group CreateGroup() {
return Group(MTAPI_GROUP_ID_NONE, MTAPI_DEFAULT_GROUP_ATTRIBUTES);
}
/**
* Constructs a Group object with default attributes and the given ID.
*/
Group CreateGroup(
mtapi_group_id_t id /**< A user defined ID of the Group. */
) {
return Group(id, MTAPI_DEFAULT_GROUP_ATTRIBUTES);
}
/**
* Constructs a Group object using the given Attributes.
*/
Group CreateGroup(
GroupAttributes const & group_attr) {
return Group(MTAPI_GROUP_ID_NONE, &group_attr.GetInternal());
}
/**
* Constructs a Group object with given attributes and ID.
*/
Group CreateGroup(
mtapi_group_id_t id, /**< A user defined ID of the Group. */
GroupAttributes const & group_attr /**< The GroupAttributes to use. */
) {
return Group(id, &group_attr.GetInternal());
}
/**
* Constructs a Queue with the given Job and default attributes.
*/
Queue CreateQueue(
Job & job /**< The Job to use for the Queue. */
) {
return Queue(MTAPI_QUEUE_ID_NONE, job, MTAPI_DEFAULT_QUEUE_ATTRIBUTES);
}
/**
* Constructs a Queue with the given Job and QueueAttributes.
*/
Queue CreateQueue(
Job const & job, /**< The Job to use for the Queue. */
QueueAttributes const & attr /**< The attributes to use. */
) {
return Queue(MTAPI_QUEUE_ID_NONE, job, &attr.GetInternal());
}
friend class embb::base::Allocation;
private:
......@@ -251,21 +411,17 @@ class Node {
NodeAttributes const & attr) {
mtapi_status_t status;
mtapi_info_t info;
queue_count_ = attr.GetInternal().max_queues;
group_count_ = attr.GetInternal().max_groups;
task_limit_ = attr.GetInternal().max_tasks;
mtapi_initialize(domain_id, node_id, &attr.GetInternal(), &info, &status);
needs_finalize_ = status == MTAPI_SUCCESS;
internal::CheckStatus(status);
core_count_ = info.hardware_concurrency;
worker_thread_count_ = embb_core_set_count(
&attr.GetInternal().core_affinity);
}
~Node() {
if (needs_finalize_) {
mtapi_status_t status;
mtapi_finalize(&status);
internal::CheckStatus(status);
}
domain_id_ = domain_id;
}
Task Start(
......@@ -286,11 +442,31 @@ class Node {
return Task(task_hndl);
}
static void ActionFunction(
const void* args,
mtapi_size_t /*args_size*/,
void* /*result_buffer*/,
mtapi_size_t /*result_buffer_size*/,
const void* /*node_local_data*/,
mtapi_size_t /*node_local_data_size*/,
mtapi_task_context_t * context) {
TaskContext task_context(context);
embb::base::Function<void, TaskContext &> * func =
reinterpret_cast<embb::base::Function<void, TaskContext &>*>(
const_cast<void*>(args));
(*func)(task_context);
embb::base::Allocation::Delete(func);
}
static embb::mtapi::Node * node_instance_;
mtapi_domain_t domain_id_;
mtapi_uint_t core_count_;
mtapi_uint_t worker_thread_count_;
bool needs_finalize_;
mtapi_uint_t queue_count_;
mtapi_uint_t group_count_;
mtapi_uint_t task_limit_;
Action function_action_;
};
} // namespace mtapi
......
......@@ -51,31 +51,19 @@ namespace mtapi {
*/
class Queue {
public:
/**
* Constructs a Queue with the given Job and default attributes.
* Requires an initialized Node.
*/
Queue(
Job const & job /**< The Job to use for the Queue. */
) {
Create(MTAPI_QUEUE_ID_NONE, job, MTAPI_DEFAULT_QUEUE_ATTRIBUTES);
Queue(Queue const & other) : handle_(other.handle_) {
// empty
}
/**
* Constructs a Queue with the given Job and QueueAttributes.
* Requires an initialized Node.
*/
Queue(
Job const & job, /**< The Job to use for the Queue. */
QueueAttributes const & attr /**< The attributes to use. */
) {
Create(MTAPI_QUEUE_ID_NONE, job, &attr.GetInternal());
Queue & operator=(Queue const & other) {
handle_ = other.handle_;
return *this;
}
/**
* Destroys a Queue object.
* Deletes a Queue object.
*/
~Queue() {
void Delete() {
mtapi_queue_delete(handle_, MTAPI_INFINITE, MTAPI_NULL);
}
......@@ -272,16 +260,13 @@ class Queue {
}
friend class embb::base::Allocation;
friend class Node;
private:
// no default constructor
Queue();
// not copyable
Queue(Queue const & other);
void operator=(Queue const & other);
void Create(
Queue(
mtapi_queue_id_t queue_id,
Job const & job,
mtapi_queue_attributes_t const * attributes
......
......@@ -29,6 +29,7 @@
#include <embb/mtapi/c/mtapi.h>
#include <embb/mtapi/internal/check_status.h>
#include <embb/mtapi/execution_policy.h>
namespace embb {
namespace mtapi {
......@@ -86,6 +87,31 @@ class TaskAttributes {
}
/**
* Sets the affinity of a Task.
* The affinity influences on which worker the Task will be executed.
*
* \returns Reference to this object.
* \notthreadsafe
*/
TaskAttributes & SetAffinity(
mtapi_affinity_t affinity /**< The affinity to set. */
) {
mtapi_status_t status;
mtapi_taskattr_set(&attributes_, MTAPI_TASK_AFFINITY,
&affinity, sizeof(affinity), &status);
internal::CheckStatus(status);
return *this;
}
TaskAttributes & SetPolicy(
ExecutionPolicy const & policy
) {
SetPriority(policy.GetPriority());
SetAffinity(policy.GetAffinity());
return *this;
}
/**
* Sets the number of instances in a Task.
* The Task will be launched \c instances times. In the action function,
* the number of instances and the current instance can be queried from
......
......@@ -24,18 +24,18 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <embb/tasks/execution_policy.h>
#include <embb/tasks/tasks.h>
#include <embb/mtapi/execution_policy.h>
#include <embb/mtapi/node.h>
#include <embb/base/exceptions.h>
#include <embb/base/c/internal/bitset.h>
#include <cassert>
namespace embb {
namespace tasks {
namespace mtapi {
ExecutionPolicy::ExecutionPolicy() :
priority_(DefaultPriority) {
#if TASKS_CPP_AUTOMATIC_INITIALIZE
#if MTAPI_CPP_AUTOMATIC_INITIALIZE
Node::GetInstance(); // MTAPI has to be initialized
#endif
mtapi_status_t status;
......@@ -48,7 +48,7 @@ ExecutionPolicy::ExecutionPolicy() :
ExecutionPolicy::ExecutionPolicy(bool initial_affinity, mtapi_uint_t priority)
:priority_(priority) {
#if TASKS_CPP_AUTOMATIC_INITIALIZE
#if MTAPI_CPP_AUTOMATIC_INITIALIZE
Node::GetInstance(); // MTAPI has to be initialized
#endif
mtapi_status_t status;
......@@ -62,7 +62,7 @@ ExecutionPolicy::ExecutionPolicy(bool initial_affinity, mtapi_uint_t priority)
ExecutionPolicy::ExecutionPolicy(mtapi_uint_t priority)
:priority_(priority) {
#if TASKS_CPP_AUTOMATIC_INITIALIZE
#if MTAPI_CPP_AUTOMATIC_INITIALIZE
Node::GetInstance(); // MTAPI has to be initialized
#endif
mtapi_status_t status;
......@@ -75,7 +75,7 @@ ExecutionPolicy::ExecutionPolicy(mtapi_uint_t priority)
ExecutionPolicy::ExecutionPolicy(bool initial_affinity)
:priority_(DefaultPriority) {
#if TASKS_CPP_AUTOMATIC_INITIALIZE
#if MTAPI_CPP_AUTOMATIC_INITIALIZE
Node::GetInstance(); // MTAPI has to be initialized
#endif
mtapi_status_t status;
......@@ -110,7 +110,7 @@ unsigned int ExecutionPolicy::GetCoreCount() const {
return embb_bitset_count(&affinity_);
}
const mtapi_affinity_t &ExecutionPolicy::GetAffinity() const {
mtapi_affinity_t ExecutionPolicy::GetAffinity() const {
return affinity_;
}
......@@ -120,5 +120,5 @@ mtapi_uint_t ExecutionPolicy::GetPriority() const {
const mtapi_uint_t ExecutionPolicy::DefaultPriority = 0;
} // namespace tasks
} // namespace mtapi
} // namespace embb
......@@ -25,11 +25,79 @@
*/
#include <embb/mtapi/node.h>
#include <embb/base/c/mutex.h>
namespace embb {
namespace mtapi {
embb::mtapi::Node * embb::mtapi::Node::node_instance_ = NULL;
#if MTAPI_CPP_AUTOMATIC_INITIALIZE
static embb_spinlock_t init_mutex = { { 0 } };
#endif
void Node::Initialize(
mtapi_domain_t domain_id,
mtapi_node_t node_id
) {
if (IsInitialized()) {
EMBB_THROW(StatusException,
"MTAPI: node was already initialized.");
} else {
NodeAttributes attributes; // default attributes
node_instance_ = embb::base::Allocation::New<Node>(
domain_id, node_id, attributes);
node_instance_->function_action_ =
node_instance_->CreateAction(EMBB_MTAPI_FUNCTION_JOB_ID, ActionFunction);
}
}
void Node::Initialize(
mtapi_domain_t domain_id,
mtapi_node_t node_id,
NodeAttributes const & attributes
) {
if (IsInitialized()) {
EMBB_THROW(StatusException,
"MTAPI: node was already initialized.");
} else {
node_instance_ = embb::base::Allocation::New<Node>(
domain_id, node_id, attributes);
}
}
Node & Node::GetInstance() {
#if MTAPI_CPP_AUTOMATIC_INITIALIZE
if (!IsInitialized()) {
embb_spin_lock(&init_mutex);
if (!IsInitialized()) {
Node::Initialize(
MTAPI_CPP_AUTOMATIC_DOMAIN_ID, MTAPI_CPP_AUTOMATIC_NODE_ID);
atexit(Node::Finalize);
}
embb_spin_unlock(&init_mutex);
}
return *node_instance_;
#else
if (IsInitialized()) {
return *node_instance_;
} else {
EMBB_THROW(StatusException,
"MTAPI: node is not initialized.");
}
#endif
}
void Node::Finalize() {
if (IsInitialized()) {
node_instance_->function_action_.Delete();
mtapi_finalize(MTAPI_NULL);
embb::base::Allocation::Delete(node_instance_);
node_instance_ = NULL;
} else {
EMBB_THROW(StatusException,
"MTAPI: node is not initialized.");
}
}
} // namespace mtapi
} // namespace embb
......@@ -61,12 +61,14 @@ GroupTest::GroupTest() {
void GroupTest::TestBasic() {
embb::mtapi::Node::Initialize(THIS_DOMAIN_ID, THIS_NODE_ID);
embb::mtapi::Node & node = embb::mtapi::Node::GetInstance();
embb::mtapi::Job job(JOB_TEST_GROUP, THIS_DOMAIN_ID);
embb::mtapi::Action action(JOB_TEST_GROUP, testGroupAction);
embb::mtapi::Job job = node.GetJob(JOB_TEST_GROUP);
embb::mtapi::Action action =
node.CreateAction(JOB_TEST_GROUP, testGroupAction);
{
embb::mtapi::Group group;
embb::mtapi::Group group = node.CreateGroup();
result_example_t buffer[TASK_COUNT];
for (int ii = 0; ii < TASK_COUNT; ii++) {
......@@ -86,7 +88,7 @@ void GroupTest::TestBasic() {
}
{
embb::mtapi::Group group;
embb::mtapi::Group group = node.CreateGroup();
result_example_t buffer[TASK_COUNT];
for (int ii = 0; ii < 4; ii++) {
......@@ -107,6 +109,7 @@ void GroupTest::TestBasic() {
PT_EXPECT_EQ(status, MTAPI_GROUP_COMPLETED);
}
action.Delete();
embb::mtapi::Node::Finalize();
PT_EXPECT_EQ(embb_get_bytes_allocated(), 0u);
......
......@@ -54,13 +54,14 @@ QueueTest::QueueTest() {
void QueueTest::TestBasic() {
embb::mtapi::Node::Initialize(THIS_DOMAIN_ID, THIS_NODE_ID);
embb::mtapi::Node & node = embb::mtapi::Node::GetInstance();
embb::mtapi::Job job(JOB_TEST_QUEUE, THIS_DOMAIN_ID);
embb::mtapi::Action action(JOB_TEST_QUEUE, testQueueAction,
MTAPI_NULL, 0);
embb::mtapi::Job job = node.GetJob(JOB_TEST_QUEUE);
embb::mtapi::Action action = node.CreateAction(
JOB_TEST_QUEUE, testQueueAction, MTAPI_NULL, 0);
{
embb::mtapi::Queue queue(job);
embb::mtapi::Queue queue = node.CreateQueue(job);
int result = 0;
embb::mtapi::Task task = queue.Enqueue<void, int>(MTAPI_NULL, &result);
......@@ -72,6 +73,7 @@ void QueueTest::TestBasic() {
PT_EXPECT_EQ(result, 1);
}
action.Delete();
embb::mtapi::Node::Finalize();
PT_EXPECT_EQ(embb_get_bytes_allocated(), 0u);
......
......@@ -96,9 +96,10 @@ void TaskTest::TestBasic() {
}
{
embb::mtapi::Job job_task(JOB_TEST_TASK, THIS_DOMAIN_ID);
embb::mtapi::Job job_task = node.GetJob(JOB_TEST_TASK);
embb::mtapi::Action action_task(JOB_TEST_TASK, testTaskAction);
embb::mtapi::Action action_task =
node.CreateAction(JOB_TEST_TASK, testTaskAction);
std::string test;
embb::mtapi::Task task = node.Start(job_task, "simple", &test);
......@@ -106,19 +107,23 @@ void TaskTest::TestBasic() {
mtapi_status_t status = task.Wait();
PT_EXPECT_EQ(status, MTAPI_SUCCESS);
PT_EXPECT(test == "simple");
action_task.Delete();
}
{
embb::mtapi::Job job_error(JOB_TEST_ERROR, THIS_DOMAIN_ID);
embb::mtapi::Job job_error = node.GetJob(JOB_TEST_ERROR);
embb::mtapi::Action action_error(JOB_TEST_ERROR, testErrorAction,
embb::mtapi::ActionAttributes());
embb::mtapi::Action action_error =
node.CreateAction(JOB_TEST_ERROR, testErrorAction);
std::string test;
embb::mtapi::Task task = node.Start(job_error, "simple", &test);
testDoSomethingElse();
mtapi_status_t status = task.Wait();
PT_EXPECT_EQ(status, MTAPI_ERR_ACTION_FAILED);
action_error.Delete();
}
embb::mtapi::Node::Finalize();
......
......@@ -45,3 +45,8 @@ endif()
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/
DESTINATION include FILES_MATCHING PATTERN "*.h")
install(TARGETS embb_mtapi_network_c DESTINATION lib)
if (MSVC)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/embb_mtapi_network_c.pdb
DESTINATION lib
CONFIGURATIONS Debug)
endif()
......@@ -45,3 +45,8 @@ endif()
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/
DESTINATION include FILES_MATCHING PATTERN "*.h")
install(TARGETS embb_mtapi_opencl_c DESTINATION lib)
if (MSVC)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/embb_mtapi_opencl_c.pdb
DESTINATION lib
CONFIGURATIONS Debug)
endif()
......@@ -79,7 +79,7 @@ retval=0
##Excluded files
RAND_FILES=( embb_mtapi_test_group.cc embb_mtapi_test_queue.cc embb_mtapi_test_task.cc queue_test-inl.h )
for project in base_c mtapi_c mtapi_plugins_c/mtapi_network_c mtapi_plugins_c/mtapi_opencl_c base_cpp mtapi_cpp tasks_cpp algorithms_cpp containers_cpp dataflow_cpp
for project in base_c mtapi_c mtapi_plugins_c/mtapi_network_c mtapi_plugins_c/mtapi_opencl_c base_cpp mtapi_cpp algorithms_cpp containers_cpp dataflow_cpp
do
echo "-> Doing project: $project"
dir=$d/$project
......
project (project_tasks_cpp)
file(GLOB_RECURSE EMBB_TASKS_CPP_SOURCES "src/*.cc" "src/*.h")
file(GLOB_RECURSE EMBB_TASKS_CPP_HEADERS "include/*.h")
file(GLOB_RECURSE EMBB_TASKS_CPP_TEST_SOURCES "test/*.cc" "test/*.h")
if (USE_AUTOMATIC_INITIALIZATION STREQUAL ON)
set(TASKS_CPP_AUTOMATIC_INITIALIZE 1)
else()
set(TASKS_CPP_AUTOMATIC_INITIALIZE 0)
endif()
configure_file("include/embb/tasks/internal/cmake_config.h.in"
"include/embb/tasks/internal/cmake_config.h")
# Execute the GroupSources macro
include(${CMAKE_SOURCE_DIR}/CMakeCommon/GroupSourcesMSVC.cmake)
GroupSourcesMSVC(include)
GroupSourcesMSVC(src)
GroupSourcesMSVC(test)
set (EMBB_TASKS_CPP_INCLUDE_DIRS "include" "src" "test")
include_directories(${EMBB_TASKS_CPP_INCLUDE_DIRS}
${CMAKE_CURRENT_BINARY_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/../base_c/include
${CMAKE_CURRENT_BINARY_DIR}/../base_c/include
${CMAKE_CURRENT_SOURCE_DIR}/../base_cpp/include
${CMAKE_CURRENT_BINARY_DIR}/../base_cpp/include
${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_c/include)
add_library (embb_tasks_cpp ${EMBB_TASKS_CPP_SOURCES} ${EMBB_TASKS_CPP_HEADERS})
target_link_libraries(embb_tasks_cpp embb_mtapi_c)
if (BUILD_TESTS STREQUAL ON)
include_directories(${CMAKE_CURRENT_BINARY_DIR}/../partest/include)
add_executable (embb_tasks_cpp_test ${EMBB_TASKS_CPP_TEST_SOURCES})
target_link_libraries(embb_tasks_cpp_test embb_tasks_cpp embb_mtapi_c partest
embb_base_cpp embb_base_c ${compiler_libs})
CopyBin(BIN embb_tasks_cpp_test DEST ${local_install_dir})
endif()
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/
DESTINATION include FILES_MATCHING PATTERN "*.h")
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/
DESTINATION include FILES_MATCHING PATTERN "*.h")
install(TARGETS embb_tasks_cpp DESTINATION lib)
/*
* 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_TASKS_ACTION_H_
#define EMBB_TASKS_ACTION_H_
#include <embb/base/function.h>
#include <embb/tasks/task_context.h>
#include <embb/tasks/execution_policy.h>
namespace embb {
namespace tasks {
/**
* A function to be spawned as a Task.
*
* \ingroup CPP_TASKS
*/
class Action {
public:
/**
* Constructs an empty Action.
*/
Action()
: function_()
, execution_policy_() {
// empty
}
/**
* Constructs an Action from a function object.
*
* \tparam Function Function object
*/
template <typename Function>
Action(
Function func /**< [in] Function object */
)
: function_(func)
, execution_policy_() {
// empty
}
/**
* Constructs an Action from a function object and an Affinity.
*
* \tparam Function Function object
*/
template <typename Function>
Action(
Function func, /**< [in] Function object */
ExecutionPolicy execution_policy /**< [in] Execution policy */
)
: function_(func)
, execution_policy_(execution_policy) {
// empty
}
/**
* Executes the Action in a given TaskContext.
*/
void operator() (
TaskContext & context /**< [in, out] Context the operator
is executed in */
) {
function_(context);
}
/**
* Returns the ExecutionPolicy specified during creation.
* \return The ExecutionPolicy of the Action
* \waitfree
*/
ExecutionPolicy GetExecutionPolicy() const {
return execution_policy_;
}
private:
embb::base::Function<void, TaskContext &> function_;
ExecutionPolicy execution_policy_;
};
} // namespace tasks
} // namespace embb
#endif // EMBB_TASKS_ACTION_H_
/*
* 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_TASKS_CONTINUATION_H_
#define EMBB_TASKS_CONTINUATION_H_
#include <embb/mtapi/c/mtapi.h>
#include <embb/tasks/task_context.h>
#include <embb/tasks/action.h>
#include <embb/tasks/task.h>
namespace embb {
namespace tasks {
/**
* Helper struct for Continuation.
*
* \ingroup CPP_TASKS
*/
struct ContinuationStage;
/**
* A Continuation encapsulates a chain of \link Action Actions \endlink to be
* executed consecutively.
*
* \ingroup CPP_TASKS
*/
class Continuation {
public:
/**
* Copies a Continuation.
*/
Continuation(
Continuation const & cont /**< [in] The Continuation to copy. */
);
/**
* Destroys a Continuation.
*/
~Continuation();
/**
* Appends an Action to the Continuation chain.
* \returns A reference to this Continuation chain.
* \notthreadsafe
*/
Continuation & Then(
Action action /**< [in] The Action to append to the
continuation */
);
/**
* Runs the Continuation chain.
* \returns The Task representing the Continuation chain.
* \notthreadsafe
*/
Task Spawn();
/**
* Runs the Continuation chain with the specified execution_policy.
* \returns The Task representing the Continuation chain.
* \notthreadsafe
*/
Task Spawn(
ExecutionPolicy execution_policy /**< [in] The execution policy to use */
);
friend class Node;
private:
explicit Continuation(Action action);
void ExecuteContinuation(TaskContext & context);
ContinuationStage * first_;
ContinuationStage * last_;
};
} // namespace tasks
} // namespace embb
#endif // EMBB_TASKS_CONTINUATION_H_
/*
* 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_TASKS_GROUP_H_
#define EMBB_TASKS_GROUP_H_
#include <embb/mtapi/c/mtapi.h>
#include <embb/tasks/action.h>
#include <embb/tasks/task.h>
namespace embb {
namespace base {
class Allocation;
} // namespace base
namespace tasks {
/**
* Represents a facility to wait for multiple related
* \link Task Tasks\endlink.
*
* \ingroup CPP_TASKS
*/
class Group {
public:
/**
* Runs an Action within the Group.
* \return A Task identifying the Action to run
* \throws ErrorException if the Task object could not be constructed.
* \threadsafe
*/
Task Spawn(
Action action /**< [in] The Action to run */
);
/**
* Runs an Action within the Group. The \c id is returned by WaitAny().
* \return A Task identifying the Action to run
* \throws ErrorException if the Task object could not be constructed.
* \threadsafe
*/
Task Spawn(
mtapi_task_id_t id, /**< [in] The id to return by
WaitAny() */
Action action /**< [in] The Action to run */
);
/**
* Waits for any Task in the Group to finish for \c timeout milliseconds.
* \return The status of the Task that finished execution
* \threadsafe
*/
mtapi_status_t WaitAny(
mtapi_timeout_t timeout /**< [in] Timeout duration in
milliseconds */
);
/**
* Waits for any Task in the Group to finish for \c timeout milliseconds and
* retrieves the id given in Spawn().
* \return The status of the Task that finished execution, \c MTAPI_TIMEOUT
* or \c MTAPI_ERR_*
* \threadsafe
*/
mtapi_status_t WaitAny(
mtapi_timeout_t timeout, /**< [in] Timeout duration in
milliseconds */
mtapi_task_id_t & id /**< [out] The id given to Spawn() */
);
/**
* Waits for all Task in the Group to finish for \c timeout milliseconds.
* \return \c MTAPI_SUCCESS, \c MTAPI_TIMEOUT, \c MTAPI_ERR_* or the status
* of any failed Task
* \threadsafe
*/
mtapi_status_t WaitAll(
mtapi_timeout_t timeout /**< [in] Timeout duration in
milliseconds */
);
friend class embb::base::Allocation;
friend class Node;
friend class Queue;
private:
Group(Group const & group);
Group();
~Group();
void Create();
mtapi_group_hndl_t handle_;
};
} // namespace tasks
} // namespace embb
#endif // EMBB_TASKS_GROUP_H_
/*
* 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_TASKS_NODE_H_
#define EMBB_TASKS_NODE_H_
#include <list>
#include <embb/base/core_set.h>
#include <embb/base/mutex.h>
#include <embb/mtapi/c/mtapi.h>
#include <embb/tasks/action.h>
#include <embb/tasks/task.h>
#include <embb/tasks/continuation.h>
#include <embb/tasks/group.h>
#include <embb/tasks/queue.h>
namespace embb {
namespace base {
class Allocation;
} // namespace base
namespace tasks {
/**
* A singleton representing the MTAPI runtime.
*
* \ingroup CPP_TASKS
*/
class Node {
public:
/**
* Initializes the runtime singleton using default values:
* - all available cores will be used
* - maximum number of tasks is 1024
* - maximum number of groups is 128
* - maximum number of queues is 16
* - maximum queue capacity is 1024
* - maximum number of priorities is 4.
*
* \notthreadsafe
* \throws ErrorException if the singleton was already initialized or the
* Node could not be initialized.
* \memory Allocates about 200kb of memory.
*/
static void Initialize(
mtapi_domain_t domain_id, /**< [in] The domain id to use */
mtapi_node_t node_id /**< [in] The node id to use */
);
/**
* Initializes the runtime singleton.
* \notthreadsafe
* \throws ErrorException if the singleton was already initialized or the
* Node could not be initialized.
* \memory Allocates some memory depending on the values given.
*/
static void Initialize(
mtapi_domain_t domain_id, /**< [in] The domain id to use */
mtapi_node_t node_id, /**< [in] The node id to use */
embb::base::CoreSet const & core_set,
/**< [in] A set of cores MTAPI should
use for its worker threads */
mtapi_uint_t max_tasks, /**< [in] Maximum number of concurrent
\link Task Tasks \endlink */
mtapi_uint_t max_groups, /**< [in] Maximum number of concurrent
\link Group Groups \endlink */
mtapi_uint_t max_queues, /**< [in] Maximum number of concurrent
\link Queue Queues \endlink */
mtapi_uint_t queue_limit, /**< [in] Maximum Queue capacity */
mtapi_uint_t max_priorities /**< [in] Maximum number of priorities,
priorities will be between 0 and
max_priorities-1 */
);
/**
* Checks if runtime is initialized.
* \return \c true if the Node singleton is already initialized, false
* otherwise
* \waitfree
*/
static bool IsInitialized();
/**
* Gets the instance of the runtime system.
* \return Reference to the Node singleton
* \threadsafe
*/
static Node & GetInstance();
/**
* Shuts the runtime system down.
* \throws ErrorException if the singleton is not initialized.
* \notthreadsafe
*/
static void Finalize();
/**
* Returns the number of available queues.
* \return The number of available queues
* \waitfree
*/
mtapi_uint_t GetQueueCount() const {
return queue_count_;
}
/**
* Returns the number of available groups.
* \return The number of available groups
* \waitfree
*/
mtapi_uint_t GetGroupCount() const {
return group_count_;
}
/**
* Returns the number of available tasks.
* \return The number of available tasks
* \waitfree
*/
mtapi_uint_t GetTaskLimit() const {
return task_limit_;
}
/**
* Returns the number of available cores.
* \return The number of available cores
* \waitfree
*/
mtapi_uint_t GetCoreCount() const {
return core_count_;
}
/**
* Returns the number of worker threads.
* \return The number of worker threads.
* \waitfree
*/
mtapi_uint_t GetWorkerThreadCount() const {
return worker_thread_count_;
}
/**
* Creates a Group to launch \link Task Tasks \endlink in.
* \return A reference to the created Group
* \throws ErrorException if the Group object could not be constructed.
* \threadsafe
* \memory Allocates some memory depending on the configuration of the
* runtime.
*/
Group & CreateGroup();
/**
* Destroys a Group. \link Task Tasks \endlink running in the Group will
* finish execution.
* \threadsafe
*/
void DestroyGroup(
Group & group /**< [in,out] The Group to destroy */
);
/**
* Creates a Queue for stream processing. The queue might execute its
* \link Task Tasks \endlink either in order or unordered.
* \return A reference to the new Queue
* \throws ErrorException if the Queue object could not be constructed.
* \threadsafe
* \memory Allocates some memory depending on the configuration of the
* runtime.
*/
Queue & CreateQueue(
mtapi_uint_t priority, /**< [in] Priority of the Queue */
bool ordered /**< [in] \c true if the Queue should be
ordered, otherwise \c false */
);
/**
* Destroys a Queue. Running \link Task Tasks \endlink will be canceled.
* \threadsafe
*/
void DestroyQueue(
Queue & queue /**< [in,out] The Queue to destroy */
);
/**
* Runs an Action.
* \return A Task identifying the Action to run
* \throws ErrorException if the Task object could not be constructed.
* \threadsafe
*/
Task Spawn(
Action action /**< [in] The Action to execute */
);
/**
* Creates a Continuation.
* \return A Continuation chain
* \threadsafe
*/
Continuation First(
Action action /**< [in] The first Action of the
Continuation chain */
);
friend class embb::base::Allocation;
private:
Node(Node const & node);
Node(
mtapi_domain_t domain_id,
mtapi_node_t node_id,
mtapi_node_attributes_t * attr);
~Node();
static void action_func(
const void* args,
mtapi_size_t args_size,
void* result_buffer,
mtapi_size_t result_buffer_size,
const void* node_local_data,
mtapi_size_t node_local_data_size,
mtapi_task_context_t * context);
mtapi_uint_t queue_count_;
mtapi_uint_t group_count_;
mtapi_uint_t task_limit_;
mtapi_uint_t core_count_;
mtapi_uint_t worker_thread_count_;
mtapi_action_hndl_t action_handle_;
std::list<Queue*> queues_;
std::list<Group*> groups_;
embb::base::Spinlock queue_lock_;
embb::base::Spinlock group_lock_;
};
} // namespace tasks
} // namespace embb
#endif // EMBB_TASKS_NODE_H_
/*
* 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_TASKS_QUEUE_H_
#define EMBB_TASKS_QUEUE_H_
#include <embb/mtapi/c/mtapi.h>
#include <embb/tasks/action.h>
#include <embb/tasks/task.h>
#include <embb/tasks/group.h>
namespace embb {
namespace base {
class Allocation;
} // namespace base
namespace tasks {
/**
* Allows for stream processing, either ordered or unordered.
*
* \ingroup CPP_TASKS
*/
class Queue {
public:
/**
* Enables the Queue. \link Task Tasks \endlink enqueued while the Queue was
* disabled are executed.
* \waitfree
*/
void Enable();
/**
* Disables the Queue. Running \link Task Tasks \endlink are canceled.
* \waitfree
*/
void Disable();
/**
* Runs an Action.
* \return A Task identifying the Action to run
* \throws ErrorException if the Task object could not be constructed.
* \threadsafe
*/
Task Spawn(
Action action /**< [in] The Action to run */
);
/**
* Runs an Action in the specified Group
* \return A Task identifying the Action to run
* \throws ErrorException if the Task object could not be constructed.
* \threadsafe
*/
Task Spawn(
Group const * group, /**< [in] The Group to run the Action
in */
Action action /**< [in] The Action to run */
);
/**
* Runs an Action in the specified Group. The \c id is returned by
* Group::WaitAny().
* \return A Task identifying the Action to run
* \throws ErrorException if the Task object could not be constructed.
* \threadsafe
*/
Task Spawn(
mtapi_task_id_t id, /**< [in] The id to return in
Group::WaitAny() */
Group const * group, /**< [in] The Group to run the Action
in */
Action action /**< [in] The Action to run */
);
friend class embb::base::Allocation;
friend class Node;
private:
Queue(Queue const & taskqueue);
Queue(mtapi_uint_t priority, bool ordered);
~Queue();
mtapi_queue_hndl_t handle_;
};
} // namespace tasks
} // namespace embb
#endif // EMBB_TASKS_QUEUE_H_
/*
* 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_TASKS_TASK_H_
#define EMBB_TASKS_TASK_H_
#include <embb/mtapi/c/mtapi.h>
#include <embb/tasks/action.h>
namespace embb {
namespace tasks {
/**
* A Task represents a running Action.
*
* \ingroup CPP_TASKS
*/
class Task {
public:
/**
* Constructs an empty Task
*/
Task();
/**
* Copies a Task
*/
Task(
Task const & task /**< The task to copy. */
);
/**
* Destroys a Task
*/
~Task();
/**
* Waits for Task to finish for \c timeout milliseconds.
* \return The status of the finished Task, \c MTAPI_TIMEOUT or
* \c MTAPI_ERR_*
* \threadsafe
*/
mtapi_status_t Wait(
mtapi_timeout_t timeout /**< [in] Timeout duration in
milliseconds */
);
/**
* Signals the Task to cancel computation.
* \waitfree
*/
void Cancel();
friend class Group;
friend class Queue;
friend class Node;
private:
Task(
Action action);
Task(
Action action,
mtapi_group_hndl_t group);
Task(
mtapi_task_id_t id,
Action action,
mtapi_group_hndl_t group);
Task(
Action action,
mtapi_queue_hndl_t queue);
Task(
Action action,
mtapi_queue_hndl_t queue,
mtapi_group_hndl_t group);
Task(
mtapi_task_id_t id,
Action action,
mtapi_queue_hndl_t queue,
mtapi_group_hndl_t group);
mtapi_task_hndl_t handle_;
};
} // namespace tasks
} // namespace embb
#endif // EMBB_TASKS_TASK_H_
/*
* 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_TASKS_TASK_CONTEXT_H_
#define EMBB_TASKS_TASK_CONTEXT_H_
#include <embb/mtapi/c/mtapi.h>
namespace embb {
namespace tasks {
/**
* Provides information about the status of the currently running Task.
*
* \ingroup CPP_TASKS
*/
class TaskContext {
public:
/**
* Queries whether the Task running in the TaskContext should finish.
* \return \c true if the Task should finish, otherwise \c false
* \notthreadsafe
*/
bool ShouldCancel();
/**
* Queries the index of the worker thread the Task is running on.
* \return The worker thread index the Task is running on
* \notthreadsafe
*/
mtapi_uint_t GetCurrentCoreNumber();
/**
* Sets the return status of the running Task. This will be returned by
* Task::Wait() and is set to \c MTAPI_SUCCESS by default.
* \notthreadsafe
*/
void SetStatus(
mtapi_status_t error_code /**< [in] The status to return by
Task::Wait(), Group::WaitAny(),
Group::WaitAll() */
);
friend class Node;
private:
explicit TaskContext(mtapi_task_context_t * task_context);
mtapi_task_context_t * context_;
};
} // namespace tasks
} // namespace embb
#endif // EMBB_TASKS_TASK_CONTEXT_H_
/*
* 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_TASKS_TASKS_H_
#define EMBB_TASKS_TASKS_H_
/**
* \defgroup CPP_TASKS Tasks
* Simple task management based on MTAPI.
* \ingroup CPP
*/
#include <embb/tasks/internal/cmake_config.h>
#define TASKS_CPP_JOB 1
#if TASKS_CPP_AUTOMATIC_INITIALIZE
#define TASKS_CPP_AUTOMATIC_DOMAIN_ID 1
#define TASKS_CPP_AUTOMATIC_NODE_ID 1
#endif
#include <embb/tasks/execution_policy.h>
#include <embb/tasks/action.h>
#include <embb/tasks/continuation.h>
#include <embb/tasks/group.h>
#include <embb/tasks/node.h>
#include <embb/tasks/queue.h>
#include <embb/tasks/task.h>
#include <embb/tasks/task_context.h>
#endif // EMBB_TASKS_TASKS_H_
/*
* 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 <cstddef>
#include <embb/base/memory_allocation.h>
#include <embb/base/function.h>
#include <embb/tasks/tasks.h>
#include <continuationstage.h>
namespace embb {
namespace tasks {
Continuation::Continuation(Action action) {
first_ = last_ = embb::base::Allocation::New<ContinuationStage>();
first_->action = action;
first_->next = NULL;
}
Continuation::Continuation(Continuation const & cont)
: first_(cont.first_)
, last_(cont.last_) {
}
Continuation::~Continuation() {
}
void Continuation::ExecuteContinuation(TaskContext &) {
ContinuationStage * stage = first_;
Node & node = Node::GetInstance();
while (NULL != stage) {
Task task = node.Spawn(stage->action);
task.Wait(MTAPI_INFINITE);
stage = stage->next;
}
// delete stages
stage = first_;
while (NULL != stage) {
ContinuationStage * next = stage->next;
embb::base::Allocation::Delete(stage);
stage = next;
}
}
Continuation & Continuation::Then(Action action) {
ContinuationStage * cur = embb::base::Allocation::New<ContinuationStage>();
cur->action = action;
cur->next = NULL;
last_->next = cur;
last_ = cur;
return *this;
}
Task Continuation::Spawn() {
return Spawn(ExecutionPolicy());
}
Task Continuation::Spawn(ExecutionPolicy execution_policy) {
Node & node = Node::GetInstance();
return node.Spawn(
Action(
embb::base::MakeFunction(*this, &Continuation::ExecuteContinuation),
ExecutionPolicy(execution_policy)));
}
} // namespace tasks
} // namespace embb
/*
* 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 TASKS_CPP_SRC_CONTINUATIONSTAGE_H_
#define TASKS_CPP_SRC_CONTINUATIONSTAGE_H_
#include <embb/tasks/tasks.h>
namespace embb {
namespace tasks {
struct ContinuationStage {
Action action;
ContinuationStage * next;
};
} // namespace tasks
} // namespace embb
#endif // TASKS_CPP_SRC_CONTINUATIONSTAGE_H_
/*
* 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 <cstring>
#include <cassert>
#include <embb/base/exceptions.h>
#include <embb/tasks/tasks.h>
namespace embb {
namespace tasks {
Group::Group() {
Create();
}
Group::~Group() {
mtapi_status_t status;
mtapi_group_delete(handle_, &status);
assert(MTAPI_SUCCESS == status);
}
void Group::Create() {
mtapi_status_t status;
handle_ = mtapi_group_create(MTAPI_GROUP_ID_NONE, MTAPI_NULL, &status);
if (MTAPI_SUCCESS != status) {
EMBB_THROW(embb::base::ErrorException,
"mtapi::Group could not be constructed");
}
}
Task Group::Spawn(Action action) {
return Task(action, handle_);
}
Task Group::Spawn(mtapi_task_id_t id, Action action) {
return Task(id, action, handle_);
}
mtapi_status_t Group::WaitAny(mtapi_timeout_t timeout) {
mtapi_status_t status;
mtapi_group_wait_any(handle_, MTAPI_NULL, timeout, &status);
if (MTAPI_GROUP_COMPLETED == status) {
// group has been deleted, so recreate it for simplicity
Create();
}
return status;
}
mtapi_status_t Group::WaitAny(
mtapi_timeout_t timeout,
mtapi_task_id_t & result) {
mtapi_status_t status;
void * res;
mtapi_group_wait_any(handle_, &res, timeout, &status);
memcpy(&result, &res, sizeof(result));
if (MTAPI_GROUP_COMPLETED == status) {
// group has been deleted, so recreate it for simplicity
Create();
}
return status;
}
mtapi_status_t Group::WaitAll(mtapi_timeout_t timeout) {
mtapi_status_t status;
mtapi_group_wait_all(handle_, timeout, &status);
// group has been deleted, so recreate it for simplicity
Create();
return status;
}
} // namespace tasks
} // namespace embb
/*
* 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 <algorithm>
#include <cstddef>
#include <cstdlib>
#include <cassert>
#include <embb/base/memory_allocation.h>
#include <embb/base/exceptions.h>
#include <embb/base/thread.h>
#include <embb/tasks/tasks.h>
#if TASKS_CPP_AUTOMATIC_INITIALIZE
#include <embb/base/mutex.h>
#endif
namespace {
static embb::tasks::Node * node_instance = NULL;
#if TASKS_CPP_AUTOMATIC_INITIALIZE
static embb_spinlock_t init_mutex = { { 0 } };
#endif
}
namespace embb {
namespace tasks {
void Node::action_func(
const void* args,
mtapi_size_t /*args_size*/,
void* /*result_buffer*/,
mtapi_size_t /*result_buffer_size*/,
const void* /*node_local_data*/,
mtapi_size_t /*node_local_data_size*/,
mtapi_task_context_t * context) {
Action * action =
reinterpret_cast<Action*>(const_cast<void*>(args));
TaskContext task_context(context);
(*action)(task_context);
embb::base::Allocation::Delete(action);
}
Node::Node(
mtapi_domain_t domain_id,
mtapi_node_t node_id,
mtapi_node_attributes_t * attr) {
mtapi_status_t status;
mtapi_info_t info;
mtapi_initialize(domain_id, node_id, attr, &info, &status);
if (MTAPI_SUCCESS != status) {
EMBB_THROW(embb::base::ErrorException,
"mtapi::Node could not initialize mtapi");
}
mtapi_node_get_attribute(node_id, MTAPI_NODE_MAX_QUEUES, &queue_count_,
sizeof(queue_count_), &status);
assert(MTAPI_SUCCESS == status);
mtapi_node_get_attribute(node_id, MTAPI_NODE_MAX_GROUPS, &group_count_,
sizeof(group_count_), &status);
assert(MTAPI_SUCCESS == status);
mtapi_node_get_attribute(node_id, MTAPI_NODE_MAX_TASKS, &task_limit_,
sizeof(queue_count_), &status);
assert(MTAPI_SUCCESS == status);
core_count_ = info.hardware_concurrency;
worker_thread_count_ = embb_core_set_count(&attr->core_affinity);
action_handle_ = mtapi_action_create(TASKS_CPP_JOB, action_func,
MTAPI_NULL, 0, MTAPI_NULL, &status);
if (MTAPI_SUCCESS != status) {
EMBB_THROW(embb::base::ErrorException,
"mtapi::Node could not create an action");
}
}
Node::~Node() {
for (std::list<Queue*>::iterator ii = queues_.begin();
ii != queues_.end();
++ii) {
embb::base::Allocation::Delete(*ii);
}
queues_.clear();
for (std::list<Group*>::iterator ii = groups_.begin();
ii != groups_.end();
++ii) {
embb::base::Allocation::Delete(*ii);
}
groups_.clear();
mtapi_status_t status;
mtapi_action_delete(action_handle_, MTAPI_INFINITE, &status);
assert(MTAPI_SUCCESS == status);
mtapi_finalize(&status);
assert(MTAPI_SUCCESS == status);
}
void Node::Initialize(
mtapi_domain_t domain_id,
mtapi_node_t node_id) {
if (IsInitialized()) {
EMBB_THROW(embb::base::ErrorException,
"mtapi::Node was already initialized");
} else {
mtapi_status_t status;
mtapi_node_attributes_t attr;
mtapi_uint_t tmp;
mtapi_nodeattr_init(&attr, &status);
assert(MTAPI_SUCCESS == status);
tmp = 4;
mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_ACTIONS,
&tmp, sizeof(tmp), &status);
assert(MTAPI_SUCCESS == status);
// tmp = 4;
mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_JOBS,
&tmp, sizeof(tmp), &status);
assert(MTAPI_SUCCESS == status);
tmp = 1;
mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_ACTIONS_PER_JOB,
&tmp, sizeof(tmp), &status);
assert(MTAPI_SUCCESS == status);
node_instance = embb::base::Allocation::New<Node>(
domain_id, node_id, &attr);
}
}
void Node::Initialize(
mtapi_domain_t domain_id,
mtapi_node_t node_id,
embb::base::CoreSet const & core_set,
mtapi_uint_t max_tasks,
mtapi_uint_t max_groups,
mtapi_uint_t max_queues,
mtapi_uint_t queue_limit,
mtapi_uint_t max_priorities) {
if (IsInitialized()) {
EMBB_THROW(embb::base::ErrorException,
"mtapi::Node was already initialized");
} else {
mtapi_status_t status;
mtapi_node_attributes_t attr;
mtapi_uint_t tmp;
mtapi_nodeattr_init(&attr, &status);
assert(MTAPI_SUCCESS == status);
embb_core_set_t cs;
embb_core_set_init(&cs, 0);
for (unsigned int ii = 0; embb_core_set_count(&cs) < core_set.Count();
ii++) {
if (core_set.IsContained(ii)) {
embb_core_set_add(&cs, ii);
}
}
mtapi_nodeattr_set(&attr, MTAPI_NODE_CORE_AFFINITY,
&cs, sizeof(cs), &status);
assert(MTAPI_SUCCESS == status);
mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_TASKS,
&max_tasks, sizeof(max_tasks), &status);
assert(MTAPI_SUCCESS == status);
tmp = 4;
mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_ACTIONS,
&tmp, sizeof(tmp), &status);
assert(MTAPI_SUCCESS == status);
mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_GROUPS,
&max_groups, sizeof(max_groups), &status);
assert(MTAPI_SUCCESS == status);
mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_QUEUES,
&max_queues, sizeof(max_queues), &status);
assert(MTAPI_SUCCESS == status);
mtapi_nodeattr_set(&attr, MTAPI_NODE_QUEUE_LIMIT,
&queue_limit, sizeof(queue_limit), &status);
assert(MTAPI_SUCCESS == status);
tmp = 4;
mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_JOBS,
&tmp, sizeof(tmp), &status);
assert(MTAPI_SUCCESS == status);
tmp = 1;
mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_ACTIONS_PER_JOB,
&tmp, sizeof(tmp), &status);
assert(MTAPI_SUCCESS == status);
mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_PRIORITIES,
&max_priorities, sizeof(max_priorities), &status);
assert(MTAPI_SUCCESS == status);
node_instance = embb::base::Allocation::New<Node>(
domain_id, node_id, &attr);
}
}
bool Node::IsInitialized() {
return NULL != node_instance;
}
Node & Node::GetInstance() {
#if TASKS_CPP_AUTOMATIC_INITIALIZE
if (!IsInitialized()) {
embb_spin_lock(&init_mutex);
if (!IsInitialized()) {
Node::Initialize(
TASKS_CPP_AUTOMATIC_DOMAIN_ID, TASKS_CPP_AUTOMATIC_NODE_ID);
atexit(Node::Finalize);
}
embb_spin_unlock(&init_mutex);
}
return *node_instance;
#else
if (IsInitialized()) {
return *node_instance;
} else {
EMBB_THROW(embb::base::ErrorException,
"embb::tasks::Node is not initialized");
}
#endif
}
void Node::Finalize() {
if (IsInitialized()) {
embb::base::Allocation::Delete(node_instance);
node_instance = NULL;
} else {
EMBB_THROW(embb::base::ErrorException,
"embb::tasks::Node is not initialized");
}
}
Group & Node::CreateGroup() {
Group * group = embb::base::Allocation::New<Group>();
while (!group_lock_.TryLock(1024)) {
embb::base::Thread::CurrentYield();
}
groups_.push_back(group);
group_lock_.Unlock();
return *group;
}
void Node::DestroyGroup(Group & group) {
std::list<Group*>::iterator ii =
std::find(groups_.begin(), groups_.end(), &group);
if (ii != groups_.end()) {
embb::base::Allocation::Delete(*ii);
groups_.erase(ii);
}
}
Queue & Node::CreateQueue(mtapi_uint_t priority, bool ordered) {
Queue * queue = embb::base::Allocation::New<Queue>(priority, ordered);
while (!queue_lock_.TryLock(1024)) {
embb::base::Thread::CurrentYield();
}
queues_.push_back(queue);
queue_lock_.Unlock();
return *queue;
}
void Node::DestroyQueue(Queue & queue) {
std::list<Queue*>::iterator ii =
std::find(queues_.begin(), queues_.end(), &queue);
if (ii != queues_.end()) {
embb::base::Allocation::Delete(*ii);
queues_.erase(ii);
}
}
Task Node::Spawn(Action action) {
return Task(action);
}
Continuation Node::First(Action action) {
return Continuation(action);
}
} // namespace tasks
} // namespace embb
/*
* 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 <cassert>
#include <embb/base/exceptions.h>
#include <embb/tasks/tasks.h>
namespace embb {
namespace tasks {
Queue::Queue(mtapi_uint_t priority, bool ordered) {
mtapi_status_t status;
mtapi_queue_attributes_t attr;
mtapi_boolean_t bb;
mtapi_queueattr_init(&attr, &status);
assert(MTAPI_SUCCESS == status);
mtapi_queueattr_set(&attr, MTAPI_QUEUE_PRIORITY,
&priority, sizeof(priority), &status);
assert(MTAPI_SUCCESS == status);
bb = ordered ? MTAPI_TRUE : MTAPI_FALSE;
mtapi_queueattr_set(&attr, MTAPI_QUEUE_ORDERED,
&bb, sizeof(bb), &status);
assert(MTAPI_SUCCESS == status);
bb = MTAPI_TRUE;
mtapi_queueattr_set(&attr, MTAPI_QUEUE_RETAIN,
&bb, sizeof(bb), &status);
assert(MTAPI_SUCCESS == status);
mtapi_domain_t domain_id = mtapi_domain_id_get(&status);
assert(MTAPI_SUCCESS == status);
mtapi_job_hndl_t job = mtapi_job_get(TASKS_CPP_JOB, domain_id, &status);
assert(MTAPI_SUCCESS == status);
handle_ = mtapi_queue_create(MTAPI_QUEUE_ID_NONE, job, &attr, &status);
// Handle MTAPI error status in appropriate exceptions
if (status == MTAPI_SUCCESS) {
return;
} else if (status == MTAPI_ERR_QUEUE_LIMIT) {
EMBB_THROW(embb::base::ErrorException,
"mtapi::Queue could not be constructed, "
"maximum number of queues exceeded");
} else if (status == MTAPI_ERR_JOB_INVALID) {
EMBB_THROW(embb::base::ErrorException,
"mtapi::Queue could not be constructed, "
"invalid job");
} else {
EMBB_THROW(embb::base::ErrorException,
"mtapi::Queue could not be constructed");
}
}
Queue::~Queue() {
mtapi_status_t status;
mtapi_queue_delete(handle_, MTAPI_INFINITE, &status);
assert(MTAPI_SUCCESS == status);
}
void Queue::Enable() {
mtapi_status_t status;
mtapi_queue_enable(handle_, &status);
assert(MTAPI_SUCCESS == status);
}
void Queue::Disable() {
mtapi_status_t status;
mtapi_queue_disable(handle_, MTAPI_INFINITE, &status);
assert(MTAPI_SUCCESS == status);
}
Task Queue::Spawn(Action action) {
return Task(action, handle_);
}
Task Queue::Spawn(Group const * group, Action action) {
return Task(action, handle_, group->handle_);
}
} // namespace tasks
} // namespace embb
/*
* 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 <cstring>
#include <cassert>
#include <embb/base/memory_allocation.h>
#include <embb/base/exceptions.h>
#include <embb/tasks/tasks.h>
namespace embb {
namespace tasks {
Task::Task() {
handle_.id = 0;
handle_.tag = 0;
}
Task::Task(Task const & task)
: handle_(task.handle_) {
// empty
}
Task::Task(
Action action) {
mtapi_status_t status;
mtapi_task_attributes_t attr;
ExecutionPolicy policy = action.GetExecutionPolicy();
mtapi_taskattr_init(&attr, &status);
assert(MTAPI_SUCCESS == status);
mtapi_taskattr_set(&attr, MTAPI_TASK_PRIORITY,
&policy.priority_, sizeof(policy.priority_), &status);
assert(MTAPI_SUCCESS == status);
mtapi_taskattr_set(&attr, MTAPI_TASK_AFFINITY,
&policy.affinity_, sizeof(policy.affinity_), &status);
assert(MTAPI_SUCCESS == status);
mtapi_domain_t domain_id = mtapi_domain_id_get(&status);
assert(MTAPI_SUCCESS == status);
mtapi_job_hndl_t job = mtapi_job_get(TASKS_CPP_JOB, domain_id, &status);
assert(MTAPI_SUCCESS == status);
Action* holder = embb::base::Allocation::New<Action>(action);
handle_ = mtapi_task_start(MTAPI_TASK_ID_NONE, job,
holder, sizeof(Action), MTAPI_NULL, 0, &attr, MTAPI_GROUP_NONE, &status);
if (MTAPI_SUCCESS != status) {
EMBB_THROW(embb::base::ErrorException,
"mtapi::Task could not be started");
}
}
Task::Task(
Action action,
mtapi_group_hndl_t group) {
mtapi_status_t status;
mtapi_task_attributes_t attr;
ExecutionPolicy policy = action.GetExecutionPolicy();
mtapi_taskattr_init(&attr, &status);
assert(MTAPI_SUCCESS == status);
mtapi_taskattr_set(&attr, MTAPI_TASK_PRIORITY,
&policy.priority_, sizeof(policy.priority_), &status);
assert(MTAPI_SUCCESS == status);
mtapi_taskattr_set(&attr, MTAPI_TASK_AFFINITY,
&policy.affinity_, sizeof(policy.affinity_), &status);
assert(MTAPI_SUCCESS == status);
mtapi_domain_t domain_id = mtapi_domain_id_get(&status);
assert(MTAPI_SUCCESS == status);
mtapi_job_hndl_t job = mtapi_job_get(TASKS_CPP_JOB, domain_id, &status);
assert(MTAPI_SUCCESS == status);
Action* holder = embb::base::Allocation::New<Action>(action);
handle_ = mtapi_task_start(MTAPI_TASK_ID_NONE, job,
holder, sizeof(Action), MTAPI_NULL, 0, &attr, group, &status);
if (MTAPI_SUCCESS != status) {
EMBB_THROW(embb::base::ErrorException,
"mtapi::Task could not be started");
}
}
Task::Task(
mtapi_task_id_t id,
Action action,
mtapi_group_hndl_t group) {
mtapi_status_t status;
mtapi_task_attributes_t attr;
ExecutionPolicy policy = action.GetExecutionPolicy();
mtapi_taskattr_init(&attr, &status);
assert(MTAPI_SUCCESS == status);
mtapi_taskattr_set(&attr, MTAPI_TASK_PRIORITY,
&policy.priority_, sizeof(policy.priority_), &status);
assert(MTAPI_SUCCESS == status);
mtapi_taskattr_set(&attr, MTAPI_TASK_AFFINITY,
&policy.affinity_, sizeof(policy.affinity_), &status);
assert(MTAPI_SUCCESS == status);
mtapi_domain_t domain_id = mtapi_domain_id_get(&status);
assert(MTAPI_SUCCESS == status);
mtapi_job_hndl_t job = mtapi_job_get(TASKS_CPP_JOB, domain_id, &status);
assert(MTAPI_SUCCESS == status);
Action* holder = embb::base::Allocation::New<Action>(action);
void * idptr = MTAPI_NULL;
memcpy(&idptr, &id, sizeof(id));
handle_ = mtapi_task_start(id, job,
holder, sizeof(Action), idptr, 0, &attr, group, &status);
if (MTAPI_SUCCESS != status) {
EMBB_THROW(embb::base::ErrorException,
"mtapi::Task could not be started");
}
}
Task::Task(
Action action,
mtapi_queue_hndl_t queue) {
mtapi_status_t status;
mtapi_task_attributes_t attr;
ExecutionPolicy policy = action.GetExecutionPolicy();
mtapi_taskattr_init(&attr, &status);
assert(MTAPI_SUCCESS == status);
mtapi_taskattr_set(&attr, MTAPI_TASK_PRIORITY,
&policy.priority_, sizeof(policy.priority_), &status);
assert(MTAPI_SUCCESS == status);
mtapi_taskattr_set(&attr, MTAPI_TASK_AFFINITY,
&policy.affinity_, sizeof(policy.affinity_), &status);
assert(MTAPI_SUCCESS == status);
Action* holder = embb::base::Allocation::New<Action>(action);
handle_ = mtapi_task_enqueue(MTAPI_TASK_ID_NONE, queue,
holder, sizeof(Action), MTAPI_NULL, 0, &attr, MTAPI_GROUP_NONE, &status);
if (MTAPI_SUCCESS != status) {
EMBB_THROW(embb::base::ErrorException,
"mtapi::Task could not be started");
}
}
Task::Task(
Action action,
mtapi_queue_hndl_t queue,
mtapi_group_hndl_t group) {
mtapi_status_t status;
mtapi_task_attributes_t attr;
ExecutionPolicy policy = action.GetExecutionPolicy();
mtapi_taskattr_init(&attr, &status);
assert(MTAPI_SUCCESS == status);
mtapi_taskattr_set(&attr, MTAPI_TASK_PRIORITY,
&policy.priority_, sizeof(policy.priority_), &status);
assert(MTAPI_SUCCESS == status);
mtapi_taskattr_set(&attr, MTAPI_TASK_AFFINITY,
&policy.affinity_, sizeof(policy.affinity_), &status);
assert(MTAPI_SUCCESS == status);
Action* holder = embb::base::Allocation::New<Action>(action);
handle_ = mtapi_task_enqueue(MTAPI_TASK_ID_NONE, queue,
holder, sizeof(Action), MTAPI_NULL, 0, &attr, group, &status);
if (MTAPI_SUCCESS != status) {
EMBB_THROW(embb::base::ErrorException,
"mtapi::Task could not be started");
}
}
Task::Task(
mtapi_task_id_t id,
Action action,
mtapi_queue_hndl_t queue,
mtapi_group_hndl_t group) {
mtapi_status_t status;
mtapi_task_attributes_t attr;
ExecutionPolicy policy = action.GetExecutionPolicy();
mtapi_taskattr_init(&attr, &status);
assert(MTAPI_SUCCESS == status);
mtapi_taskattr_set(&attr, MTAPI_TASK_PRIORITY,
&policy.priority_, sizeof(policy.priority_), &status);
assert(MTAPI_SUCCESS == status);
mtapi_taskattr_set(&attr, MTAPI_TASK_AFFINITY,
&policy.affinity_, sizeof(policy.affinity_), &status);
assert(MTAPI_SUCCESS == status);
Action* holder = embb::base::Allocation::New<Action>(action);
void * idptr = MTAPI_NULL;
memcpy(&idptr, &id, sizeof(id));
handle_ = mtapi_task_enqueue(id, queue,
holder, sizeof(Action), idptr, 0, &attr, group, &status);
if (MTAPI_SUCCESS != status) {
EMBB_THROW(embb::base::ErrorException,
"mtapi::Task could not be started");
}
}
Task::~Task() {
}
mtapi_status_t Task::Wait(mtapi_timeout_t timeout) {
mtapi_status_t status;
mtapi_task_wait(handle_, timeout, &status);
return status;
}
void Task::Cancel() {
mtapi_status_t status;
mtapi_task_cancel(handle_, &status);
assert(MTAPI_SUCCESS == status);
}
} // namespace tasks
} // namespace embb
/*
* 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 <cassert>
#include <embb/tasks/tasks.h>
namespace embb {
namespace tasks {
TaskContext::TaskContext(mtapi_task_context_t * task_context)
: context_(task_context) {
}
bool TaskContext::ShouldCancel() {
mtapi_status_t status;
bool result =
MTAPI_TASK_CANCELLED == mtapi_context_taskstate_get(context_, &status);
assert(MTAPI_SUCCESS == status);
return result;
}
mtapi_uint_t TaskContext::GetCurrentCoreNumber() {
mtapi_status_t status;
mtapi_uint_t result =
mtapi_context_corenum_get(context_, &status);
assert(MTAPI_SUCCESS == status);
return result;
}
void TaskContext::SetStatus(mtapi_status_t error_code) {
mtapi_status_t status;
mtapi_context_status_set(context_, error_code, &status);
assert(MTAPI_SUCCESS == status);
}
} // namespace tasks
} // namespace embb
/*
* 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 <partest/partest.h>
#include <iostream>
#include <tasks_cpp_test_task.h>
#include <tasks_cpp_test_group.h>
#include <tasks_cpp_test_queue.h>
#include <embb/base/c/atomic.h>
PT_MAIN("TASKS") {
embb_atomic_initialize();
PT_RUN(TaskTest);
PT_RUN(GroupTest);
PT_RUN(QueueTest);
embb_atomic_finalize();
}
/*
* 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 TASKS_CPP_TEST_TASKS_CPP_TEST_CONFIG_H_
#define TASKS_CPP_TEST_TASKS_CPP_TEST_CONFIG_H_
#include <partest/partest.h>
#include <embb/tasks/tasks.h>
#define THIS_DOMAIN_ID 1
#define THIS_NODE_ID 1
#endif // TASKS_CPP_TEST_TASKS_CPP_TEST_CONFIG_H_
/*
* 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 <iostream>
#include <tasks_cpp_test_config.h>
#include <tasks_cpp_test_group.h>
#include <embb/base/c/memory_allocation.h>
struct result_example_struct {
mtapi_uint_t value1;
mtapi_uint_t value2;
};
typedef struct result_example_struct result_example_t;
static void testGroupAction(embb::tasks::TaskContext & /*context*/) {
// emtpy
}
static void testDoSomethingElse() {
}
GroupTest::GroupTest() {
CreateUnit("tasks_cpp group test").Add(&GroupTest::TestBasic, this);
}
void GroupTest::TestBasic() {
embb::tasks::Node::Initialize(THIS_DOMAIN_ID, THIS_NODE_ID);
embb::tasks::Node & node = embb::tasks::Node::GetInstance();
embb::tasks::Group & group = node.CreateGroup();
embb::tasks::Task task;
for (int ii = 0; ii < 4; ii++) {
task = group.Spawn(testGroupAction);
}
testDoSomethingElse();
group.WaitAll(MTAPI_INFINITE);
for (int ii = 0; ii < 4; ii++) {
task = group.Spawn(mtapi_task_id_t(ii + 1), testGroupAction);
}
testDoSomethingElse();
mtapi_status_t status;
mtapi_task_id_t result;
while (MTAPI_SUCCESS == (status = group.WaitAny(MTAPI_INFINITE, result))) {
// empty
}
node.DestroyGroup(group);
embb::tasks::Node::Finalize();
PT_EXPECT_EQ(embb_get_bytes_allocated(), 0u);
}
/*
* 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 TASKS_CPP_TEST_TASKS_CPP_TEST_GROUP_H_
#define TASKS_CPP_TEST_TASKS_CPP_TEST_GROUP_H_
#include <partest/partest.h>
class GroupTest : public partest::TestCase {
public:
GroupTest();
private:
void TestBasic();
};
#endif // TASKS_CPP_TEST_TASKS_CPP_TEST_GROUP_H_
/*
* 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 <cstdlib>
#include <tasks_cpp_test_config.h>
#include <tasks_cpp_test_queue.h>
#include <embb/base/c/memory_allocation.h>
#define JOB_TEST_TASK 42
#define TASK_TEST_ID 23
#define QUEUE_TEST_ID 17
static void testQueueAction(embb::tasks::TaskContext & /*context*/) {
// empty
}
static void testDoSomethingElse() {
}
QueueTest::QueueTest() {
CreateUnit("tasks_cpp queue test").Add(&QueueTest::TestBasic, this);
}
void QueueTest::TestBasic() {
embb::tasks::Node::Initialize(THIS_DOMAIN_ID, THIS_NODE_ID);
embb::tasks::Node & node = embb::tasks::Node::GetInstance();
embb::tasks::Queue & queue = node.CreateQueue(0, false);
embb::tasks::Task task = queue.Spawn(testQueueAction);
testDoSomethingElse();
task.Wait(MTAPI_INFINITE);
node.DestroyQueue(queue);
embb::tasks::Node::Finalize();
PT_EXPECT_EQ(embb_get_bytes_allocated(), 0u);
}
/*
* 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 TASKS_CPP_TEST_TASKS_CPP_TEST_QUEUE_H_
#define TASKS_CPP_TEST_TASKS_CPP_TEST_QUEUE_H_
#include <partest/partest.h>
class QueueTest : public partest::TestCase {
public:
QueueTest();
private:
void TestBasic();
};
#endif // TASKS_CPP_TEST_TASKS_CPP_TEST_QUEUE_H_
/*
* 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 <iostream>
#include <string>
#include <cassert>
#include <tasks_cpp_test_config.h>
#include <tasks_cpp_test_task.h>
#include <embb/base/c/memory_allocation.h>
#define JOB_TEST_TASK 42
#define TASK_TEST_ID 23
static void testTaskAction(
char const * msg,
std::string * output,
embb::tasks::TaskContext & /*context*/) {
*output = msg;
}
static void testRecursiveTaskAction(
int * value,
embb::tasks::TaskContext & /*context*/) {
embb::tasks::Node & node = embb::tasks::Node::GetInstance();
*value = *value + 1;
if (*value < 1000) {
embb::tasks::Task task = node.Spawn(
embb::base::Bind(
testRecursiveTaskAction, value, embb::base::Placeholder::_1));
task.Wait(MTAPI_INFINITE);
}
PT_EXPECT(*value == 1000);
}
static void testErrorTaskAction(embb::tasks::TaskContext & context) {
context.SetStatus(MTAPI_ERR_ACTION_FAILED);
}
static void testDoSomethingElse() {
}
TaskTest::TaskTest() {
CreateUnit("tasks_cpp task test").Add(&TaskTest::TestBasic, this);
}
void TaskTest::TestBasic() {
embb::tasks::Node::Initialize(THIS_DOMAIN_ID, THIS_NODE_ID);
embb::tasks::Node & node = embb::tasks::Node::GetInstance();
embb::tasks::ExecutionPolicy policy(false);
PT_EXPECT_EQ(policy.GetAffinity(), 0u);
PT_EXPECT_EQ(policy.GetPriority(), 0u);
policy.AddWorker(0u);
PT_EXPECT_EQ(policy.GetAffinity(), 1u);
if (policy.GetCoreCount() > 1) {
policy.AddWorker(1u);
PT_EXPECT_EQ(policy.GetAffinity(), 3u);
}
policy.RemoveWorker(0u);
PT_EXPECT_EQ(policy.IsSetWorker(0), false);
if (policy.GetCoreCount() > 1) {
PT_EXPECT_EQ(policy.GetAffinity(), 2u);
PT_EXPECT_EQ(policy.IsSetWorker(1), true);
}
std::string test;
embb::tasks::Task task = node.Spawn(
embb::base::Bind(
testTaskAction, "simple", &test, embb::base::Placeholder::_1));
testDoSomethingElse();
task.Wait(MTAPI_INFINITE);
PT_EXPECT(test == "simple");
std::string test1, test2, test3;
task = node.First(
embb::base::Bind(
testTaskAction, "first", &test1, embb::base::Placeholder::_1)).
Then(embb::base::Bind(
testTaskAction, "second", &test2, embb::base::Placeholder::_1)).
Then(embb::base::Bind(
testTaskAction, "third", &test3, embb::base::Placeholder::_1)).
Spawn();
testDoSomethingElse();
task.Wait(MTAPI_INFINITE);
PT_EXPECT(test1 == "first");
PT_EXPECT(test2 == "second");
PT_EXPECT(test3 == "third");
int value = 0;
task = node.Spawn(
embb::base::Bind(
testRecursiveTaskAction, &value, embb::base::Placeholder::_1));
task.Wait(MTAPI_INFINITE);
PT_EXPECT(value == 1000);
mtapi_status_t status;
task = node.Spawn(testErrorTaskAction);
testDoSomethingElse();
status = task.Wait(MTAPI_INFINITE);
PT_EXPECT(MTAPI_ERR_ACTION_FAILED == status);
embb::tasks::Node::Finalize();
PT_EXPECT(embb_get_bytes_allocated() == 0);
}
/*
* 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 TASKS_CPP_TEST_TASKS_CPP_TEST_TASK_H_
#define TASKS_CPP_TEST_TASKS_CPP_TEST_TASK_H_
#include <partest/partest.h>
class TaskTest : public partest::TestCase {
public:
TaskTest();
private:
void TestBasic();
};
#endif // TASKS_CPP_TEST_TASKS_CPP_TEST_TASK_H_
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