diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a73c46..21d054d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,7 @@ option(BUILD_EXAMPLES "Specify whether examples should be built" OFF) option(USE_EXCEPTIONS "Specify whether exceptions should be activated in C++" ON) option(INSTALL_DOCS "Specify whether Doxygen docs should be installed" ON) option(WARNINGS_ARE_ERRORS "Specify whether warnings should be treated as errors" OFF) +option(USE_AUTOMATIC_INITIALIZATION "Specify whether the MTAPI C++ interface, algorithms and dataflow should automatically intialize the MTAPI node if no explicit initialization is present" ON) ## LOCAL INSTALLATION OF SUBPROJECT BINARIES # diff --git a/README.md b/README.md index 6669a48..f3c8f35 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,10 @@ specified on build file generation. When exceptions are turned off, an error message is emitted and the program aborts in case of an exception within EMBĀ². To disable exceptions, add the option -DUSE_EXCEPTIONS=OFF. +Similarly, automatic initialization of the task scheduler by the MTAPI C++ +interface can be disabled with -DUSE_AUTOMATIC_INITIALIZATION=OFF. This way, +unexpected delays after startup can be avoided, e.g. for timing measurements. + The tutorial of EMBĀ² comes with example source files in doc/examples/. These can be built with the other source files using CMake option -DBUILD_EXAMPLES=ON in the generation step. Note, however, that the examples use C++11 features and @@ -184,6 +188,10 @@ For a Linux Debug build with exception handling, type cmake -G "Unix Makefiles" .. -DCMAKE_BUILD_TYPE=Debug +For a default Linux build without automatic MTAPI C++ initialization, type + + cmake .. -DUSE_AUTOMATIC_INITIALIZATION=OFF + For a Windows build (VS 2013, x86) without exception handling, type cmake -G "Visual Studio 12" .. -DUSE_EXCEPTIONS=OFF @@ -350,6 +358,16 @@ Please use these defines for new platform specific code. If additional defines are needed, they can be defined in the config.h or cmake_config.h.in files. +Important Notes +--------------- + +- The MTAPI C++ interface supports automatic initialization, which allows for + easy usage of the MTAPI C++, Algorithms, and Dataflow components. For + performance measurements, explicit initialization is strongly recommended + since the measurements will otherwise include the initialization time of + MTAPI. + + Links ----- diff --git a/algorithms_cpp/CMakeLists.txt b/algorithms_cpp/CMakeLists.txt index b5ce17f..bf9f799 100644 --- a/algorithms_cpp/CMakeLists.txt +++ b/algorithms_cpp/CMakeLists.txt @@ -17,7 +17,8 @@ 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}/../mtapi_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}) diff --git a/algorithms_cpp/test/main.cc b/algorithms_cpp/test/main.cc index be4167a..4b5bf5e 100644 --- a/algorithms_cpp/test/main.cc +++ b/algorithms_cpp/test/main.cc @@ -67,6 +67,7 @@ int compute1_() { PT_MAIN("Algorithms") { embb::mtapi::Node::Initialize(THIS_DOMAIN_ID, THIS_NODE_ID); + PT_RUN(PartitionerTest); PT_RUN(ForEachTest); PT_RUN(ReduceTest); diff --git a/base_cpp/test/thread_test.cc b/base_cpp/test/thread_test.cc index 34ea2be..f8af461 100644 --- a/base_cpp/test/thread_test.cc +++ b/base_cpp/test/thread_test.cc @@ -61,6 +61,9 @@ void ThreadTest::TestStartingAndJoining() { embb::base::Thread thread2(ThreadTest::StaticThreadStartArg1, arg1); double arg2 = 3.0; embb::base::Thread thread3(ThreadTest::StaticThreadStartArg2, arg1, arg2); + embb::base::Thread::ID thread3id; + thread3id = thread3.GetID(); + PT_EXPECT_EQ(thread3id, thread3.GetID()); // Non-static member start methods with functor MemberStart start4(&ThreadTest::ThreadStart, this); diff --git a/dataflow_cpp/CMakeLists.txt b/dataflow_cpp/CMakeLists.txt index 6c5d4e6..0ad76a0 100644 --- a/dataflow_cpp/CMakeLists.txt +++ b/dataflow_cpp/CMakeLists.txt @@ -17,8 +17,8 @@ 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}/../mtapi_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_mtapi_cpp embb_base_cpp embb_mtapi_c embb_base_c) diff --git a/doc/examples/CMakeLists.txt b/doc/examples/CMakeLists.txt index cff5224..9393c95 100644 --- a/doc/examples/CMakeLists.txt +++ b/doc/examples/CMakeLists.txt @@ -11,6 +11,7 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR}/../../base_cpp/include ${CMAKE_CURRENT_SOURCE_DIR}/../../mtapi_c/include ${CMAKE_CURRENT_SOURCE_DIR}/../../mtapi_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 diff --git a/doc/examples/mtapi/mtapi_check_status-snippet.h b/doc/examples/mtapi/mtapi_check_status-snippet.h index d22c393..bf1d1d3 100644 --- a/doc/examples/mtapi/mtapi_check_status-snippet.h +++ b/doc/examples/mtapi/mtapi_check_status-snippet.h @@ -1,7 +1,8 @@ #include +#include #include #define MTAPI_CHECK_STATUS(status) \ if (MTAPI_SUCCESS != status) { \ - embb_log_error("MTAPI C Example", "...error %d\n\n", status); \ - abort(); \ + printf("...error %d\n\n", status); \ + exit(status); \ } diff --git a/doc/tutorial/content/algorithms.tex b/doc/tutorial/content/algorithms.tex index 9a52973..14bff9f 100644 --- a/doc/tutorial/content/algorithms.tex +++ b/doc/tutorial/content/algorithms.tex @@ -1,7 +1,9 @@ \chapter{Algorithms} \label{cha:algorithms} -The \emph{Algorithms} building block of \embb provides high-level constructs for typical parallelization tasks. They are aligned to the functions provided by the C++ Standard Library, but contain additional functionality typical for embedded systems such as task priorities. Although the algorithms can be used in a black-box way, it is good to have a basic understanding of their implementation: The algorithms split computations to be performed in parallel into tasks which are executed by the MTAPI task scheduler (cf. Chapter~\ref{cha:mtapi}). For that purpose, the tasks are stored in queues and mapped to a fixed number of worker threads at runtime. Since MTAPI allocates the necessary data structures during initialization, the maximum number of tasks in flight is fixed. In case one of the algorithms exceeds this limit, an exception is thrown. +The \emph{Algorithms} building block of \embb provides high-level constructs for typical parallelization tasks. They are aligned to the functions provided by the C++ Standard Library, but contain additional functionality typical for embedded systems such as task priorities. Although the algorithms can be used in a black-box way, it is good to have a basic understanding of their implementation: The algorithms split computations to be performed in parallel into tasks which are executed by the MTAPI task scheduler (cf. Chapter~\ref{cha:mtapi}). For that purpose, the tasks are stored in queues and mapped to a fixed number of worker threads at runtime. Since MTAPI allocates the necessary data structures during initialization, the maximum number of tasks in flight is fixed. In case one of the algorithms exceeds this limit, an exception is thrown. + +\emph{\textbf{Note:} The \emph{Algorithms} building block is implemented using the MTAPI C++ interface. By calling \lstinline|embb::mtapi::Node::Initialize| task and other limits can be customized. Explicit initialization also eliminates unexpected delays when measuring performance. See Section~\ref{sec:mtapi_cpp_interface} for details.} In the following, we look at parallel function invocation (Section~\ref{sec:algorithms_invoke}), sorting (Section~\ref{sec:algorithms_sorting}), counting (Section~\ref{sec:algorithms_counting}), foreach loops (Section~\ref{sec:algorithms_foreach}), reductions (Section~\ref{sec:algorithms_reductions}), and prefix computations (Section~\ref{sec:algorithms_prefix}). diff --git a/doc/tutorial/content/dataflow.tex b/doc/tutorial/content/dataflow.tex index 3274bf8..7d09e6b 100644 --- a/doc/tutorial/content/dataflow.tex +++ b/doc/tutorial/content/dataflow.tex @@ -18,6 +18,8 @@ With the \emph{Dataflow} building block, \embb provides generic skeletons for th % \item dynamic control of data streams (conditional execution) %\end{itemize} +\emph{\textbf{Note:} The \emph{Dataflow} building block is implemented using the MTAPI C++ interface. Since MTAPI does not allocate memory after initialization, the number of tasks and other resources are limited. By calling \lstinline|embb::mtapi::Node::Initialize| these limits can be customized. Explicit initialization also eliminates unexpected delays when measuring performance. See Section~\ref{sec:mtapi_cpp_interface} for details.} + \section{Linear Pipelines} Before we go into detail, we demonstrate the basic concepts of this building block by means of a simple application which finds and replaces strings in a file. Let us start with the sequential implementation. The program shown in Listing~\ref{lst:replace_seq} reads a file line by line and replaces each occurrence of a given string with a new string. The main part consists of the \lstinline|while| loop which performs three steps: @@ -138,7 +140,7 @@ is used to construct the sink: % %In order to avoid that the received string is overwritten accidentally, the parameter \lstinline|str| corresponding to the input port of \lstinline|write| must be constant.\\ -\emph{Note: If you parallelize your own application using \embb and your compiler emits a lengthy error message containing lots of templates, it is very likely that for at least one process, the ports and their directions do not match the signature of the given function.} +\emph{\textbf{Note:} If you parallelize your own application using \embb and your compiler emits a lengthy error message containing lots of templates, it is very likely that for at least one process, the ports and their directions do not match the signature of the given function.} The network needs to know about the processes declared above, so we add them to our network: % diff --git a/doc/tutorial/content/mtapi.tex b/doc/tutorial/content/mtapi.tex index 06ea39e..e0cb5a3 100644 --- a/doc/tutorial/content/mtapi.tex +++ b/doc/tutorial/content/mtapi.tex @@ -160,6 +160,8 @@ First, the node instance needs to be obtained. If the node is not initialized ye % \\\inputlisting{../examples/mtapi/mtapi_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::mtapi::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} @@ -190,3 +192,5 @@ The root task can be started using \lstinline|embb::mtapi::Node::Spawn()| direct \\\inputlisting{../examples/mtapi/mtapi_cpp_start_task-snippet.h} % Again, the started task has to be waited for (using \lstinline|embb::mtapi::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::mtapi::Node::Initialize|, the runtime must also be shut down explicitly by calling \lstinline|embb::mtapi::Node::Finalize|.} diff --git a/mtapi_c/include/embb/mtapi/c/mtapi.h b/mtapi_c/include/embb/mtapi/c/mtapi.h index 38e9341..51460cc 100644 --- a/mtapi_c/include/embb/mtapi/c/mtapi.h +++ b/mtapi_c/include/embb/mtapi/c/mtapi.h @@ -1050,8 +1050,14 @@ void mtapi_nodeattr_set( * * \c attributes is a pointer to a node attributes object that was previously * prepared with mtapi_nodeattr_init() and mtapi_nodeattr_set(). If - * \c attributes is \c MTAPI_NULL, then implementation-defined default - * attributes will be used. + * \c attributes is \c MTAPI_NULL, then the following default + * attributes will be used: + * - 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. * * On success, \c *status is set to \c MTAPI_SUCCESS. On error, \c *status is * set to the appropriate error defined below. diff --git a/mtapi_c/src/embb_mtapi_action_t.c b/mtapi_c/src/embb_mtapi_action_t.c index 6c57c7e..eeeaf83 100644 --- a/mtapi_c/src/embb_mtapi_action_t.c +++ b/mtapi_c/src/embb_mtapi_action_t.c @@ -412,6 +412,7 @@ void mtapi_action_enable( embb_mtapi_action_pool_get_storage_for_handle( node->action_pool, action); local_action->enabled = MTAPI_TRUE; + local_status = MTAPI_SUCCESS; } else { local_status = MTAPI_ERR_ACTION_INVALID; } diff --git a/mtapi_c/src/embb_mtapi_id_pool_t.c b/mtapi_c/src/embb_mtapi_id_pool_t.c index 08869b6..570fa98 100644 --- a/mtapi_c/src/embb_mtapi_id_pool_t.c +++ b/mtapi_c/src/embb_mtapi_id_pool_t.c @@ -37,12 +37,12 @@ void embb_mtapi_id_pool_initialize( that->capacity = capacity; that->id_buffer = (mtapi_uint_t*) - embb_mtapi_alloc_allocate(sizeof(mtapi_uint_t)*(capacity)); + embb_mtapi_alloc_allocate(sizeof(mtapi_uint_t)*(capacity + 1)); that->id_buffer[0] = EMBB_MTAPI_IDPOOL_INVALID_ID; - for (ii = 1; ii < capacity; ii++) { + for (ii = 1; ii <= capacity; ii++) { that->id_buffer[ii] = ii; } - that->ids_available = capacity - 1; + that->ids_available = capacity; that->put_id_position = 0; that->get_id_position = 1; embb_mtapi_spinlock_initialize(&that->lock); diff --git a/mtapi_c/src/embb_mtapi_job_t.c b/mtapi_c/src/embb_mtapi_job_t.c index 6064208..227666e 100644 --- a/mtapi_c/src/embb_mtapi_job_t.c +++ b/mtapi_c/src/embb_mtapi_job_t.c @@ -40,9 +40,9 @@ mtapi_boolean_t embb_mtapi_job_initialize_list(embb_mtapi_node_t * node) { node->job_list = (embb_mtapi_job_t*)embb_mtapi_alloc_allocate( - sizeof(embb_mtapi_job_t)*node->attributes.max_jobs); + sizeof(embb_mtapi_job_t)*(node->attributes.max_jobs + 1)); mtapi_uint_t ii; - for (ii = 0; ii < node->attributes.max_jobs; ii++) { + for (ii = 0; ii <= node->attributes.max_jobs; ii++) { embb_mtapi_job_initialize( &node->job_list[ii], node->attributes.max_actions_per_job); node->job_list[ii].handle.id = ii; @@ -53,7 +53,7 @@ mtapi_boolean_t embb_mtapi_job_initialize_list(embb_mtapi_node_t * node) { void embb_mtapi_job_finalize_list(embb_mtapi_node_t * node) { mtapi_uint_t ii; - for (ii = 0; ii < node->attributes.max_jobs; ii++) { + for (ii = 0; ii <= node->attributes.max_jobs; ii++) { embb_mtapi_job_finalize(&node->job_list[ii]); node->job_list[ii].handle.id = 0; } @@ -69,7 +69,7 @@ mtapi_boolean_t embb_mtapi_job_is_handle_valid( mtapi_job_hndl_t handle) { assert(MTAPI_NULL != node); return ((0 < handle.id) && - (handle.id < node->attributes.max_jobs) && + (handle.id <= node->attributes.max_jobs) && (node->job_list[handle.id].handle.tag == handle.tag)) ? MTAPI_TRUE : MTAPI_FALSE; } @@ -87,7 +87,7 @@ mtapi_boolean_t embb_mtapi_job_is_id_valid( embb_mtapi_node_t * node, mtapi_job_id_t id) { assert(MTAPI_NULL != node); - return ((0 < id) && (id < node->attributes.max_jobs)) ? + return ((0 < id) && (id <= node->attributes.max_jobs)) ? MTAPI_TRUE : MTAPI_FALSE; } diff --git a/mtapi_c/src/embb_mtapi_pool_template-inl.h b/mtapi_c/src/embb_mtapi_pool_template-inl.h index 76860e9..5366972 100644 --- a/mtapi_c/src/embb_mtapi_pool_template-inl.h +++ b/mtapi_c/src/embb_mtapi_pool_template-inl.h @@ -60,8 +60,8 @@ mtapi_boolean_t embb_mtapi_##TYPE##_pool_initialize( \ assert(MTAPI_NULL != that); \ embb_mtapi_id_pool_initialize(&that->id_pool, capacity); \ that->storage = (embb_mtapi_##TYPE##_t*)embb_mtapi_alloc_allocate( \ - sizeof(embb_mtapi_##TYPE##_t)*capacity); \ - for (ii = 0; ii < capacity; ii++) { \ + sizeof(embb_mtapi_##TYPE##_t)*(capacity + 1)); \ + for (ii = 0; ii <= capacity; ii++) { \ that->storage[ii].handle.id = EMBB_MTAPI_IDPOOL_INVALID_ID; \ that->storage[ii].handle.tag = 0; \ } \ @@ -102,7 +102,7 @@ mtapi_boolean_t embb_mtapi_##TYPE##_pool_is_handle_valid( \ mtapi_##TYPE##_hndl_t handle) { \ assert(MTAPI_NULL != that); \ return ((0 < handle.id) && \ - (handle.id < that->id_pool.capacity) && \ + (handle.id <= that->id_pool.capacity) && \ (that->storage[handle.id].handle.tag == handle.tag)) ? \ MTAPI_TRUE : MTAPI_FALSE; \ } \ diff --git a/mtapi_c/src/embb_mtapi_queue_t.c b/mtapi_c/src/embb_mtapi_queue_t.c index 5346046..8288dab 100644 --- a/mtapi_c/src/embb_mtapi_queue_t.c +++ b/mtapi_c/src/embb_mtapi_queue_t.c @@ -200,6 +200,7 @@ mtapi_queue_hndl_t mtapi_queue_create( queue->queue_id = queue_id; queue_hndl = queue->handle; } else { + embb_mtapi_queue_pool_deallocate(node->queue_pool, queue); local_status = MTAPI_ERR_JOB_INVALID; } } else { diff --git a/mtapi_c/test/embb_mtapi_test_error.cc b/mtapi_c/test/embb_mtapi_test_error.cc new file mode 100644 index 0000000..6b3450a --- /dev/null +++ b/mtapi_c/test/embb_mtapi_test_error.cc @@ -0,0 +1,740 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + + +#define JOB_TEST_TASK 42 +#define TASK_TEST_ID 23 +#define INVALID_ATTRIBUTE 255 + +static embb_atomic_int wait; + +static void testErrorAction( + const void* /*args*/, + mtapi_size_t /*arg_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* /*task_context*/) { + while (1 == embb_atomic_load_int(&wait)) + embb_thread_yield(); + embb_atomic_store_int(&wait, 2); +} + +ErrorTest::ErrorTest() { + CreateUnit("mtapi error test").Add(&ErrorTest::TestBasic, this); +} + +static void TestNodeNotInit() { + mtapi_status_t status; + mtapi_affinity_t affinity; + mtapi_job_hndl_t job_hndl; + mtapi_queue_hndl_t queue_hndl; + mtapi_group_hndl_t group_hndl; + mtapi_action_hndl_t action_hndl; + + status = MTAPI_ERR_UNKNOWN; + mtapi_finalize(&status); + PT_EXPECT_EQ(status, MTAPI_ERR_NODE_NOTINIT); + + status = MTAPI_ERR_UNKNOWN; + mtapi_node_id_get(&status); + PT_EXPECT_EQ(status, MTAPI_ERR_NODE_NOTINIT); + + status = MTAPI_ERR_UNKNOWN; + mtapi_node_get_attribute(THIS_NODE_ID, + MTAPI_NODE_MAX_ACTIONS, MTAPI_NULL, 0, + &status); + PT_EXPECT_EQ(status, MTAPI_ERR_NODE_NOTINIT); + + status = MTAPI_ERR_UNKNOWN; + mtapi_domain_id_get(&status); + PT_EXPECT_EQ(status, MTAPI_ERR_NODE_NOTINIT); + + + status = MTAPI_ERR_UNKNOWN; + action_hndl = mtapi_action_create(1, testErrorAction, MTAPI_NULL, 0, + MTAPI_DEFAULT_ACTION_ATTRIBUTES, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_NODE_NOTINIT); + + status = MTAPI_ERR_UNKNOWN; + mtapi_action_set_attribute(action_hndl, + MTAPI_ACTION_GLOBAL, + MTAPI_ATTRIBUTE_VALUE(MTAPI_TRUE), MTAPI_ATTRIBUTE_POINTER_AS_VALUE, + &status); + PT_EXPECT_EQ(status, MTAPI_ERR_NODE_NOTINIT); + + status = MTAPI_ERR_UNKNOWN; + mtapi_action_get_attribute(action_hndl, + MTAPI_ACTION_GLOBAL, MTAPI_NULL, 0, + &status); + PT_EXPECT_EQ(status, MTAPI_ERR_NODE_NOTINIT); + + status = MTAPI_ERR_UNKNOWN; + mtapi_action_enable(action_hndl, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_NODE_NOTINIT); + + status = MTAPI_ERR_UNKNOWN; + mtapi_action_disable(action_hndl, MTAPI_INFINITE, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_NODE_NOTINIT); + + status = MTAPI_ERR_UNKNOWN; + mtapi_action_delete(action_hndl, MTAPI_INFINITE, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_NODE_NOTINIT); + + + status = MTAPI_ERR_UNKNOWN; + job_hndl = mtapi_job_get(1, THIS_DOMAIN_ID, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_NODE_NOTINIT); + + + status = MTAPI_ERR_UNKNOWN; + queue_hndl = mtapi_queue_create(1, job_hndl, + MTAPI_DEFAULT_QUEUE_ATTRIBUTES, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_NODE_NOTINIT); + + status = MTAPI_ERR_UNKNOWN; + mtapi_queue_enable(queue_hndl, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_NODE_NOTINIT); + + status = MTAPI_ERR_UNKNOWN; + mtapi_queue_disable(queue_hndl, MTAPI_INFINITE, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_NODE_NOTINIT); + + status = MTAPI_ERR_UNKNOWN; + mtapi_queue_delete(queue_hndl, MTAPI_INFINITE, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_NODE_NOTINIT); + + status = MTAPI_ERR_UNKNOWN; + mtapi_queue_get_attribute(queue_hndl, + MTAPI_QUEUE_DOMAIN_SHARED, MTAPI_NULL, 0, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_NODE_NOTINIT); + + status = MTAPI_ERR_UNKNOWN; + mtapi_queue_set_attribute(queue_hndl, + MTAPI_QUEUE_DOMAIN_SHARED, MTAPI_NULL, 0, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_NODE_NOTINIT); + + + status = MTAPI_ERR_UNKNOWN; + group_hndl = mtapi_group_create(MTAPI_GROUP_ID_NONE, + MTAPI_DEFAULT_GROUP_ATTRIBUTES, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_NODE_NOTINIT); + + status = MTAPI_ERR_UNKNOWN; + mtapi_group_delete(group_hndl, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_NODE_NOTINIT); + + status = MTAPI_ERR_UNKNOWN; + mtapi_group_get_attribute(group_hndl, + 0, MTAPI_NULL, 0, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_NODE_NOTINIT); + + status = MTAPI_ERR_UNKNOWN; + mtapi_group_set_attribute(group_hndl, + 0, MTAPI_NULL, 0, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_NODE_NOTINIT); + + + status = MTAPI_ERR_UNKNOWN; + mtapi_affinity_init(&affinity, MTAPI_TRUE, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_NODE_NOTINIT); + + status = MTAPI_ERR_UNKNOWN; + mtapi_affinity_set(&affinity, 0, MTAPI_TRUE, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_NODE_NOTINIT); + + status = MTAPI_ERR_UNKNOWN; + mtapi_affinity_get(&affinity, 0, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_NODE_NOTINIT); + + + PT_EXPECT_EQ(embb_get_bytes_allocated(), 0u); +} + +static void TestLimits() { + mtapi_status_t status; + mtapi_node_attributes_t node_attr; + mtapi_action_hndl_t action_hndl, action_hndl_invalid; + mtapi_job_hndl_t job_hndl, job_hndl_invalid; + mtapi_task_hndl_t task_hndl, task_hndl_invalid; + mtapi_group_hndl_t group_hndl, group_hndl_invalid; + mtapi_queue_hndl_t queue_hndl, queue_hndl_invalid; + char buffer[128]; + + /* initialize a node with all limits set to 1 */ + status = MTAPI_ERR_UNKNOWN; + mtapi_nodeattr_init(&node_attr, &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + mtapi_nodeattr_set(&node_attr, + MTAPI_NODE_MAX_ACTIONS, + MTAPI_ATTRIBUTE_VALUE(1), MTAPI_ATTRIBUTE_POINTER_AS_VALUE, + &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + mtapi_nodeattr_set(&node_attr, + MTAPI_NODE_MAX_ACTIONS_PER_JOB, + MTAPI_ATTRIBUTE_VALUE(1), MTAPI_ATTRIBUTE_POINTER_AS_VALUE, + &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + mtapi_nodeattr_set(&node_attr, + MTAPI_NODE_MAX_GROUPS, + MTAPI_ATTRIBUTE_VALUE(1), MTAPI_ATTRIBUTE_POINTER_AS_VALUE, + &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + mtapi_nodeattr_set(&node_attr, + MTAPI_NODE_MAX_QUEUES, + MTAPI_ATTRIBUTE_VALUE(1), MTAPI_ATTRIBUTE_POINTER_AS_VALUE, + &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + mtapi_nodeattr_set(&node_attr, + MTAPI_NODE_MAX_PRIORITIES, + MTAPI_ATTRIBUTE_VALUE(1), MTAPI_ATTRIBUTE_POINTER_AS_VALUE, + &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + mtapi_nodeattr_set(&node_attr, + MTAPI_NODE_MAX_JOBS, + MTAPI_ATTRIBUTE_VALUE(1), MTAPI_ATTRIBUTE_POINTER_AS_VALUE, + &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + mtapi_nodeattr_set(&node_attr, + MTAPI_NODE_MAX_TASKS, + MTAPI_ATTRIBUTE_VALUE(1), MTAPI_ATTRIBUTE_POINTER_AS_VALUE, + &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + mtapi_nodeattr_set(&node_attr, + MTAPI_NODE_QUEUE_LIMIT, + MTAPI_ATTRIBUTE_VALUE(1), MTAPI_ATTRIBUTE_POINTER_AS_VALUE, + &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + mtapi_initialize(THIS_DOMAIN_ID, THIS_NODE_ID, + &node_attr, MTAPI_NULL, &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + + /* try to get an attribute with invalid attribute pointer */ + status = MTAPI_ERR_UNKNOWN; + mtapi_node_get_attribute(THIS_NODE_ID, + MTAPI_NODE_MAX_ACTIONS, MTAPI_NULL, 0, + &status); + PT_EXPECT_EQ(status, MTAPI_ERR_PARAMETER); + + + /* create our test action */ + status = MTAPI_ERR_UNKNOWN; + action_hndl = mtapi_action_create(1, testErrorAction, MTAPI_NULL, 0, + MTAPI_DEFAULT_ACTION_ATTRIBUTES, &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + status = MTAPI_ERR_UNKNOWN; + mtapi_action_disable(action_hndl, MTAPI_INFINITE, &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + status = MTAPI_ERR_UNKNOWN; + mtapi_action_enable(action_hndl, &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + status = MTAPI_ERR_UNKNOWN; + mtapi_action_set_attribute(action_hndl, MTAPI_ACTION_GLOBAL, + MTAPI_ATTRIBUTE_VALUE(MTAPI_TRUE), MTAPI_ATTRIBUTE_POINTER_AS_VALUE, + &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + status = MTAPI_ERR_UNKNOWN; + mtapi_action_get_attribute(action_hndl, + MTAPI_ACTION_GLOBAL, &buffer, MTAPI_ACTION_GLOBAL_SIZE, + &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + /* try to get an attribute of that action with invalid attribute pointer */ + status = MTAPI_ERR_UNKNOWN; + mtapi_action_get_attribute(action_hndl, + MTAPI_ACTION_GLOBAL, MTAPI_NULL, 0, + &status); + PT_EXPECT_EQ(status, MTAPI_ERR_PARAMETER); + + /* try to get an attribute of that action with invalid attribute number */ + status = MTAPI_ERR_UNKNOWN; + mtapi_action_get_attribute(action_hndl, + INVALID_ATTRIBUTE, &buffer, 0, + &status); + PT_EXPECT_EQ(status, MTAPI_ERR_ATTR_NUM); + + /* try to create another action, since the limit is one this will fail */ + status = MTAPI_ERR_UNKNOWN; + action_hndl_invalid = mtapi_action_create(1, testErrorAction, MTAPI_NULL, 0, + MTAPI_DEFAULT_ACTION_ATTRIBUTES, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_ACTION_LIMIT); + + status = MTAPI_ERR_UNKNOWN; + mtapi_action_enable(action_hndl_invalid, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_ACTION_INVALID); + + status = MTAPI_ERR_UNKNOWN; + mtapi_action_disable(action_hndl_invalid, MTAPI_INFINITE, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_ACTION_INVALID); + + status = MTAPI_ERR_UNKNOWN; + mtapi_action_delete(action_hndl_invalid, MTAPI_INFINITE, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_ACTION_INVALID); + + status = MTAPI_ERR_UNKNOWN; + mtapi_action_set_attribute(action_hndl_invalid, MTAPI_ACTION_DOMAIN_SHARED, + MTAPI_ATTRIBUTE_VALUE(MTAPI_TRUE), MTAPI_ATTRIBUTE_POINTER_AS_VALUE, + &status); + PT_EXPECT_EQ(status, MTAPI_ERR_ACTION_INVALID); + + status = MTAPI_ERR_UNKNOWN; + mtapi_action_get_attribute(action_hndl_invalid, MTAPI_ACTION_DOMAIN_SHARED, + MTAPI_NULL, 0, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_ACTION_INVALID); + + + /* get handle for job number 1, associated with our action */ + status = MTAPI_ERR_UNKNOWN; + job_hndl = mtapi_job_get(1, THIS_DOMAIN_ID, &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + /* try to get the invalid job number 2, limit is 1 */ + status = MTAPI_ERR_UNKNOWN; + job_hndl_invalid = mtapi_job_get(2, THIS_DOMAIN_ID, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_JOB_INVALID); + + + /* start a task with the invalid job, this will fail */ + status = MTAPI_ERR_UNKNOWN; + mtapi_task_start(MTAPI_TASK_ID_NONE, job_hndl_invalid, + MTAPI_NULL, 0, MTAPI_NULL, 0, + MTAPI_DEFAULT_TASK_ATTRIBUTES, MTAPI_GROUP_NONE, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_JOB_INVALID); + + + /* test if executing a task works, so do not wait */ + embb_atomic_store_int(&wait, 0); + + status = MTAPI_ERR_UNKNOWN; + task_hndl = mtapi_task_start(MTAPI_TASK_ID_NONE, job_hndl, + MTAPI_NULL, 0, MTAPI_NULL, 0, + MTAPI_DEFAULT_TASK_ATTRIBUTES, MTAPI_GROUP_NONE, &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + status = MTAPI_ERR_UNKNOWN; + mtapi_task_wait(task_hndl, MTAPI_INFINITE, &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + /* task should have executed, wait contains 2 */ + PT_EXPECT_EQ(embb_atomic_load_int(&wait), 2); + + + /* this time wait, so we can test the task limit */ + embb_atomic_store_int(&wait, 1); + + /* this task will wait until wait is set to 0 */ + status = MTAPI_ERR_UNKNOWN; + task_hndl = mtapi_task_start(MTAPI_TASK_ID_NONE, job_hndl, + MTAPI_NULL, 0, MTAPI_NULL, 0, + MTAPI_DEFAULT_TASK_ATTRIBUTES, MTAPI_GROUP_NONE, &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + /* we cannot start another task since the limit is 1 */ + status = MTAPI_ERR_UNKNOWN; + task_hndl_invalid = mtapi_task_start(MTAPI_TASK_ID_NONE, job_hndl, + MTAPI_NULL, 0, MTAPI_NULL, 0, + MTAPI_DEFAULT_TASK_ATTRIBUTES, MTAPI_GROUP_NONE, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_TASK_LIMIT); + + /* let the waiting task do its work */ + embb_atomic_store_int(&wait, 0); + + status = MTAPI_ERR_UNKNOWN; + mtapi_task_wait(task_hndl, MTAPI_INFINITE, &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + /* task should have executed, wait contains 2 */ + PT_EXPECT_EQ(embb_atomic_load_int(&wait), 2); + + + /* create a group */ + status = MTAPI_ERR_UNKNOWN; + group_hndl = mtapi_group_create(MTAPI_GROUP_ID_NONE, + MTAPI_DEFAULT_GROUP_ATTRIBUTES, &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + /* try to create another group, this will fail since the limit is 1 */ + status = MTAPI_ERR_UNKNOWN; + group_hndl_invalid = mtapi_group_create(MTAPI_GROUP_ID_NONE, + MTAPI_DEFAULT_GROUP_ATTRIBUTES, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_GROUP_LIMIT); + + /* try to delete the invalid group, this will fail */ + status = MTAPI_ERR_UNKNOWN; + mtapi_group_delete(group_hndl_invalid, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_GROUP_INVALID); + + /* delete the valid group */ + status = MTAPI_ERR_UNKNOWN; + mtapi_group_delete(group_hndl, &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + /* try to get an attribute of the deleted group */ + status = MTAPI_ERR_UNKNOWN; + mtapi_group_get_attribute(group_hndl, 0, NULL, 0, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_GROUP_INVALID); + + /* try to set an attribute of the deleted group */ + status = MTAPI_ERR_UNKNOWN; + mtapi_group_set_attribute(group_hndl, 0, NULL, 0, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_GROUP_INVALID); + + + /* create a queue with invalid job */ + status = MTAPI_ERR_UNKNOWN; + mtapi_queue_create(MTAPI_QUEUE_ID_NONE, job_hndl_invalid, + MTAPI_DEFAULT_QUEUE_ATTRIBUTES, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_JOB_INVALID); + + /* create a queue */ + status = MTAPI_ERR_UNKNOWN; + queue_hndl = mtapi_queue_create(MTAPI_QUEUE_ID_NONE, job_hndl, + MTAPI_DEFAULT_QUEUE_ATTRIBUTES, &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + status = MTAPI_ERR_UNKNOWN; + mtapi_queue_disable(queue_hndl, MTAPI_INFINITE, &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + status = MTAPI_ERR_UNKNOWN; + mtapi_queue_enable(queue_hndl, &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + /* try to create another queue, this will fail since the limit is 1 */ + status = MTAPI_ERR_UNKNOWN; + queue_hndl_invalid = mtapi_queue_create(MTAPI_QUEUE_ID_NONE, job_hndl, + MTAPI_DEFAULT_QUEUE_ATTRIBUTES, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_QUEUE_LIMIT); + + /* try to enable the invalid queue */ + status = MTAPI_ERR_UNKNOWN; + mtapi_queue_enable(queue_hndl_invalid, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_QUEUE_INVALID); + + /* try to disable the invalid queue */ + status = MTAPI_ERR_UNKNOWN; + mtapi_queue_disable(queue_hndl_invalid, MTAPI_INFINITE, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_QUEUE_INVALID); + + /* try to delete the invalid queue */ + status = MTAPI_ERR_UNKNOWN; + mtapi_queue_delete(queue_hndl_invalid, MTAPI_INFINITE, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_QUEUE_INVALID); + + status = MTAPI_ERR_UNKNOWN; + mtapi_queue_set_attribute(queue_hndl_invalid, MTAPI_QUEUE_DOMAIN_SHARED, + MTAPI_ATTRIBUTE_VALUE(MTAPI_TRUE), MTAPI_ATTRIBUTE_POINTER_AS_VALUE, + &status); + PT_EXPECT_EQ(status, MTAPI_ERR_QUEUE_INVALID); + + status = MTAPI_ERR_UNKNOWN; + mtapi_queue_get_attribute(queue_hndl_invalid, MTAPI_QUEUE_DOMAIN_SHARED, + MTAPI_NULL, 0, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_QUEUE_INVALID); + + + /* now test the task limit via queues, let the first one wait */ + embb_atomic_store_int(&wait, 1); + + /* enqueue the task */ + status = MTAPI_ERR_UNKNOWN; + task_hndl = mtapi_task_enqueue(MTAPI_TASK_ID_NONE, queue_hndl, + MTAPI_NULL, 0, MTAPI_NULL, 0, + MTAPI_DEFAULT_TASK_ATTRIBUTES, MTAPI_GROUP_NONE, &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + /* enqueue another one, this will fail since the limit is one */ + status = MTAPI_ERR_UNKNOWN; + mtapi_task_enqueue(MTAPI_TASK_ID_NONE, queue_hndl, + MTAPI_NULL, 0, MTAPI_NULL, 0, + MTAPI_DEFAULT_TASK_ATTRIBUTES, MTAPI_GROUP_NONE, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_TASK_LIMIT); + + /* let the valid task do its work */ + embb_atomic_store_int(&wait, 0); + + status = MTAPI_ERR_UNKNOWN; + mtapi_task_wait(task_hndl, MTAPI_INFINITE, &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + /* the task has completed, wait should contain 2 */ + PT_EXPECT_EQ(embb_atomic_load_int(&wait), 2); + + + /* disable our queue */ + status = MTAPI_ERR_UNKNOWN; + mtapi_queue_disable(queue_hndl, MTAPI_INFINITE, &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + status = MTAPI_ERR_UNKNOWN; + mtapi_queue_set_attribute(queue_hndl, MTAPI_QUEUE_DOMAIN_SHARED, + MTAPI_ATTRIBUTE_VALUE(MTAPI_TRUE), MTAPI_ATTRIBUTE_POINTER_AS_VALUE, + &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + status = MTAPI_ERR_UNKNOWN; + mtapi_queue_get_attribute(queue_hndl, MTAPI_QUEUE_DOMAIN_SHARED, + MTAPI_NULL, 0, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_PARAMETER); + + status = MTAPI_ERR_UNKNOWN; + mtapi_queue_get_attribute(queue_hndl, INVALID_ATTRIBUTE, + &buffer, 0, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_ATTR_NUM); + + status = MTAPI_ERR_UNKNOWN; + mtapi_queue_get_attribute(queue_hndl, MTAPI_QUEUE_DOMAIN_SHARED, + &buffer, MTAPI_QUEUE_DOMAIN_SHARED_SIZE, &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + /* try to enqueue another task, this will fail since the queue is disabled */ + status = MTAPI_ERR_UNKNOWN; + mtapi_task_enqueue(MTAPI_TASK_ID_NONE, queue_hndl, + MTAPI_NULL, 0, MTAPI_NULL, 0, + MTAPI_DEFAULT_TASK_ATTRIBUTES, MTAPI_GROUP_NONE, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_QUEUE_DISABLED); + + /* disable our queue */ + status = MTAPI_ERR_UNKNOWN; + mtapi_queue_delete(queue_hndl, MTAPI_INFINITE, &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + + /* and we're done */ + mtapi_finalize(&status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + PT_EXPECT_EQ(embb_get_bytes_allocated(), 0u); +} + +static void TestParameter() { + mtapi_status_t status; + mtapi_node_attributes_t node_attr; + mtapi_action_attributes_t action_attr; + mtapi_task_attributes_t task_attr; + mtapi_queue_attributes_t queue_attr; + mtapi_group_attributes_t group_attr; + mtapi_info_t info; + + + status = MTAPI_ERR_UNKNOWN; + mtapi_nodeattr_init(MTAPI_NULL, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_PARAMETER); + + status = MTAPI_ERR_UNKNOWN; + mtapi_nodeattr_init(&node_attr, &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + status = MTAPI_ERR_UNKNOWN; + mtapi_nodeattr_set(&node_attr, INVALID_ATTRIBUTE, NULL, 0, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_ATTR_NUM); + + + status = MTAPI_ERR_UNKNOWN; + mtapi_initialize(THIS_DOMAIN_ID, THIS_NODE_ID, + MTAPI_DEFAULT_NODE_ATTRIBUTES, MTAPI_NULL, &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + /* try second init */ + status = MTAPI_ERR_UNKNOWN; + mtapi_initialize(THIS_DOMAIN_ID, THIS_NODE_ID, + MTAPI_DEFAULT_NODE_ATTRIBUTES, &info, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_NODE_INITIALIZED); + + + status = MTAPI_ERR_UNKNOWN; + mtapi_actionattr_init(MTAPI_NULL, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_PARAMETER); + + status = MTAPI_ERR_UNKNOWN; + mtapi_actionattr_init(&action_attr, &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + status = MTAPI_ERR_UNKNOWN; + mtapi_actionattr_set(&action_attr, INVALID_ATTRIBUTE, NULL, 0, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_ATTR_NUM); + + + status = MTAPI_ERR_UNKNOWN; + mtapi_taskattr_init(MTAPI_NULL, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_PARAMETER); + + status = MTAPI_ERR_UNKNOWN; + mtapi_taskattr_init(&task_attr, &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + status = MTAPI_ERR_UNKNOWN; + mtapi_taskattr_set(&task_attr, INVALID_ATTRIBUTE, NULL, 0, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_ATTR_NUM); + + + status = MTAPI_ERR_UNKNOWN; + mtapi_queueattr_init(MTAPI_NULL, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_PARAMETER); + + status = MTAPI_ERR_UNKNOWN; + mtapi_queueattr_init(&queue_attr, &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + status = MTAPI_ERR_UNKNOWN; + mtapi_queueattr_set(&queue_attr, INVALID_ATTRIBUTE, NULL, 0, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_ATTR_NUM); + + + status = MTAPI_ERR_UNKNOWN; + mtapi_groupattr_init(MTAPI_NULL, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_PARAMETER); + + status = MTAPI_ERR_UNKNOWN; + mtapi_groupattr_init(&group_attr, &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + status = MTAPI_ERR_UNKNOWN; + mtapi_groupattr_set(&group_attr, INVALID_ATTRIBUTE, NULL, 0, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_ATTR_NUM); + + + status = MTAPI_ERR_UNKNOWN; + mtapi_finalize(&status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + PT_EXPECT_EQ(embb_get_bytes_allocated(), 0u); +} + +void TestContext() { + mtapi_status_t status; + mtapi_task_context_t* task_ctx_invalid = MTAPI_NULL; + + /* the following context is considered valid although it is not a real one, + but is checked against the stored pointers and will lead to + MTAPI_ERR_CONTEXT_OUTOFCONTEXT */ + embb_mtapi_thread_context_t thread_ctx_storage; + embb_tss_create(&thread_ctx_storage.tss_id); + embb_mtapi_task_context_t task_ctx_storage; + task_ctx_storage.thread_context = &thread_ctx_storage; + mtapi_task_context_t* task_ctx = &task_ctx_storage; + + status = MTAPI_ERR_UNKNOWN; + mtapi_initialize(THIS_DOMAIN_ID, THIS_NODE_ID, + MTAPI_DEFAULT_NODE_ATTRIBUTES, MTAPI_NULL, &status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + + status = MTAPI_ERR_UNKNOWN; + mtapi_context_corenum_get(task_ctx_invalid, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_CONTEXT_INVALID); + + status = MTAPI_ERR_UNKNOWN; + mtapi_context_instnum_get(task_ctx_invalid, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_CONTEXT_INVALID); + + status = MTAPI_ERR_UNKNOWN; + mtapi_context_numinst_get(task_ctx_invalid, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_CONTEXT_INVALID); + + status = MTAPI_ERR_UNKNOWN; + mtapi_context_status_set(task_ctx_invalid, MTAPI_SUCCESS, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_CONTEXT_INVALID); + + status = MTAPI_ERR_UNKNOWN; + mtapi_context_runtime_notify(task_ctx_invalid, + MTAPI_NOTIF_EXECUTE_NEXT, NULL, 0, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_CONTEXT_INVALID); + + status = MTAPI_ERR_UNKNOWN; + mtapi_context_taskstate_get(task_ctx_invalid, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_CONTEXT_INVALID); + + + status = MTAPI_ERR_UNKNOWN; + mtapi_context_corenum_get(task_ctx, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_CONTEXT_OUTOFCONTEXT); + + status = MTAPI_ERR_UNKNOWN; + mtapi_context_instnum_get(task_ctx, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_CONTEXT_OUTOFCONTEXT); + + status = MTAPI_ERR_UNKNOWN; + mtapi_context_numinst_get(task_ctx, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_CONTEXT_OUTOFCONTEXT); + + status = MTAPI_ERR_UNKNOWN; + mtapi_context_status_set(task_ctx, MTAPI_SUCCESS, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_CONTEXT_OUTOFCONTEXT); + + status = MTAPI_ERR_UNKNOWN; + mtapi_context_runtime_notify(task_ctx, + MTAPI_NOTIF_EXECUTE_NEXT, NULL, 0, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_CONTEXT_OUTOFCONTEXT); + + status = MTAPI_ERR_UNKNOWN; + mtapi_context_taskstate_get(task_ctx, &status); + PT_EXPECT_EQ(status, MTAPI_ERR_CONTEXT_OUTOFCONTEXT); + + + status = MTAPI_ERR_UNKNOWN; + mtapi_finalize(&status); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + + embb_tss_delete(&thread_ctx_storage.tss_id); + + PT_EXPECT_EQ(embb_get_bytes_allocated(), 0u); +} + +void ErrorTest::TestBasic() { + TestNodeNotInit(); + TestParameter(); + TestLimits(); + TestContext(); +} diff --git a/mtapi_c/test/embb_mtapi_test_error.h b/mtapi_c/test/embb_mtapi_test_error.h new file mode 100644 index 0000000..3759bdd --- /dev/null +++ b/mtapi_c/test/embb_mtapi_test_error.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014-2015, 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 MTAPI_C_TEST_EMBB_MTAPI_TEST_ERROR_H_ +#define MTAPI_C_TEST_EMBB_MTAPI_TEST_ERROR_H_ + +#include + +class ErrorTest : public partest::TestCase { + public: + ErrorTest(); + + private: + void TestBasic(); +}; + +#endif // MTAPI_C_TEST_EMBB_MTAPI_TEST_ERROR_H_ diff --git a/mtapi_c/test/embb_mtapi_test_queue.cc b/mtapi_c/test/embb_mtapi_test_queue.cc index 9bedc62..08a0933 100644 --- a/mtapi_c/test/embb_mtapi_test_queue.cc +++ b/mtapi_c/test/embb_mtapi_test_queue.cc @@ -52,7 +52,7 @@ static void testQueueAction( } embb_mtapi_log_info("testQueueAction %d called from worker %d...\n", workload_id, core_num); - EMBB_UNUSED_IN_RELEASE(workload_id); + EMBB_UNUSED(workload_id); } static void testDoSomethingElse() { diff --git a/mtapi_c/test/embb_mtapi_test_task.cc b/mtapi_c/test/embb_mtapi_test_task.cc index da0a42e..4b01445 100644 --- a/mtapi_c/test/embb_mtapi_test_task.cc +++ b/mtapi_c/test/embb_mtapi_test_task.cc @@ -50,7 +50,7 @@ static void testTaskAction( } embb_mtapi_log_info("testTaskAction %d called from worker %d...\n", *reinterpret_cast(args), core_num); - EMBB_UNUSED_IN_RELEASE(args); + EMBB_UNUSED(args); } static void testDoSomethingElse() { diff --git a/mtapi_c/test/main.cc b/mtapi_c/test/main.cc index edd2bd1..6d8b6c2 100644 --- a/mtapi_c/test/main.cc +++ b/mtapi_c/test/main.cc @@ -34,10 +34,12 @@ #include #include #include +#include PT_MAIN("MTAPI C") { embb_log_set_log_level(EMBB_LOG_LEVEL_NONE); + PT_RUN(ErrorTest); PT_RUN(InitFinalizeTest); PT_RUN(TaskTest); PT_RUN(GroupTest); diff --git a/mtapi_cpp/CMakeLists.txt b/mtapi_cpp/CMakeLists.txt index 301766c..19a6353 100644 --- a/mtapi_cpp/CMakeLists.txt +++ b/mtapi_cpp/CMakeLists.txt @@ -4,6 +4,18 @@ file(GLOB_RECURSE EMBB_MTAPI_CPP_SOURCES "src/*.cc" "src/*.h") file(GLOB_RECURSE EMBB_MTAPI_CPP_HEADERS "include/*.h") file(GLOB_RECURSE EMBB_MTAPI_CPP_TEST_SOURCES "test/*.cc" "test/*.h") +if (USE_AUTOMATIC_INITIALIZATION STREQUAL ON) + message("-- Automatic initialization enabled (default)") + set(MTAPI_CPP_AUTOMATIC_INITIALIZE 1) +else() + set(MTAPI_CPP_AUTOMATIC_INITIALIZE 0) + message("-- Automatic initialization disabled") +endif() +message(" (set with command line option -DUSE_AUTOMATIC_INITIALIZATION=ON/OFF)") + +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) @@ -12,12 +24,12 @@ 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 ${CMAKE_CURRENT_BINARY_DIR}/../base_cpp/include - ${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_c/include - ) + ${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_c/include) add_library (embb_mtapi_cpp ${EMBB_MTAPI_CPP_SOURCES} ${EMBB_MTAPI_CPP_HEADERS}) target_link_libraries(embb_mtapi_cpp embb_mtapi_c) @@ -32,4 +44,6 @@ 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_mtapi_cpp DESTINATION lib) diff --git a/mtapi_cpp/include/embb/mtapi/internal/cmake_config.h.in b/mtapi_cpp/include/embb/mtapi/internal/cmake_config.h.in new file mode 100644 index 0000000..32af64c --- /dev/null +++ b/mtapi_cpp/include/embb/mtapi/internal/cmake_config.h.in @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014-2015, 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_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/mtapi/internal/. From + there, the cmake_config.h can be included as usual using + #include + */ + +/** + * Is used to enable automatic initialization of the MTAPI node + */ +#define MTAPI_CPP_AUTOMATIC_INITIALIZE ${MTAPI_CPP_AUTOMATIC_INITIALIZE} + +#endif // EMBB_MTAPI_INTERNAL_CMAKE_CONFIG_H_ diff --git a/mtapi_cpp/include/embb/mtapi/mtapi.h b/mtapi_cpp/include/embb/mtapi/mtapi.h index 2e138bc..4c83834 100644 --- a/mtapi_cpp/include/embb/mtapi/mtapi.h +++ b/mtapi_cpp/include/embb/mtapi/mtapi.h @@ -35,8 +35,9 @@ * \ingroup CPP */ +#include + #define MTAPI_CPP_TASK_JOB 1 -#define MTAPI_CPP_AUTOMATIC_INITIALIZE 1 #if MTAPI_CPP_AUTOMATIC_INITIALIZE #define MTAPI_CPP_AUTOMATIC_DOMAIN_ID 1 #define MTAPI_CPP_AUTOMATIC_NODE_ID 1 diff --git a/mtapi_cpp/include/embb/mtapi/node.h b/mtapi_cpp/include/embb/mtapi/node.h index e6b366f..442ebd0 100644 --- a/mtapi_cpp/include/embb/mtapi/node.h +++ b/mtapi_cpp/include/embb/mtapi/node.h @@ -60,7 +60,7 @@ class Node { * - maximum number of groups is 128 * - maximum number of queues is 16 * - maximum queue capacity is 1024 - * - maximum number of priorites is 4. + * - maximum number of priorities is 4. * * \notthreadsafe * \throws ErrorException if the singleton was already initialized or the diff --git a/mtapi_cpp/src/node.cc b/mtapi_cpp/src/node.cc index e8986e8..0deb322 100644 --- a/mtapi_cpp/src/node.cc +++ b/mtapi_cpp/src/node.cc @@ -39,7 +39,9 @@ namespace { static embb::mtapi::Node * node_instance = NULL; +#if MTAPI_CPP_AUTOMATIC_INITIALIZE static embb::base::Mutex init_mutex; +#endif } diff --git a/mtapi_cpp/test/mtapi_cpp_test_task.cc b/mtapi_cpp/test/mtapi_cpp_test_task.cc index 958df21..88242b3 100644 --- a/mtapi_cpp/test/mtapi_cpp_test_task.cc +++ b/mtapi_cpp/test/mtapi_cpp_test_task.cc @@ -77,6 +77,18 @@ void TaskTest::TestBasic() { embb::mtapi::Node & node = embb::mtapi::Node::GetInstance(); + embb::mtapi::ExecutionPolicy policy(false); + PT_EXPECT_EQ(policy.GetAffinity(), 0u); + PT_EXPECT_EQ(policy.GetPriority(), 0u); + policy.AddWorker(0u); + PT_EXPECT_EQ(policy.GetAffinity(), 1u); + policy.AddWorker(1u); + PT_EXPECT_EQ(policy.GetAffinity(), 3u); + policy.RemoveWorker(0u); + PT_EXPECT_EQ(policy.GetAffinity(), 2u); + PT_EXPECT_EQ(policy.IsSetWorker(0), false); + PT_EXPECT_EQ(policy.IsSetWorker(1), true); + std::string test; embb::mtapi::Task task = node.Spawn( embb::base::Bind(