/* * Copyright (c) 2014, 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 #include #include #include #include mtapi_group_hndl_t MTAPI_GROUP_NONE = { 0, EMBB_MTAPI_IDPOOL_INVALID_ID }; /* ---- POOL STORAGE FUNCTIONS --------------------------------------------- */ embb_mtapi_pool_implementation(group) /* ---- CLASS MEMBERS ------------------------------------------------------ */ void embb_mtapi_group_initialize(embb_mtapi_group_t * that) { assert(MTAPI_NULL != that); that->group_id = MTAPI_GROUP_ID_NONE; that->deleted = MTAPI_FALSE; that->num_tasks.internal_variable = 0; embb_mtapi_task_queue_initialize(&that->queue); } void embb_mtapi_group_initialize_with_node( embb_mtapi_group_t * that, embb_mtapi_node_t * node) { assert(MTAPI_NULL != that); assert(MTAPI_NULL != node); that->group_id = MTAPI_GROUP_ID_NONE; that->deleted = MTAPI_FALSE; that->num_tasks.internal_variable = 0; embb_mtapi_task_queue_initialize_with_capacity( &that->queue, node->attributes.queue_limit); } void embb_mtapi_group_finalize(embb_mtapi_group_t * that) { assert(MTAPI_NULL != that); that->deleted = MTAPI_TRUE; that->num_tasks.internal_variable = 0; embb_mtapi_task_queue_finalize(&that->queue); } /* ---- INTERFACE FUNCTIONS ------------------------------------------------ */ mtapi_group_hndl_t mtapi_group_create( MTAPI_IN mtapi_group_id_t group_id, MTAPI_IN mtapi_group_attributes_t* attributes, MTAPI_OUT mtapi_status_t* status) { mtapi_status_t local_status = MTAPI_ERR_UNKNOWN; embb_mtapi_node_t* node = embb_mtapi_node_get_instance(); mtapi_group_hndl_t group_hndl = { 0, EMBB_MTAPI_IDPOOL_INVALID_ID }; embb_mtapi_group_t* group = NULL; embb_mtapi_log_trace("mtapi_group_create() called\n"); if (embb_mtapi_node_is_initialized()) { group = embb_mtapi_group_pool_allocate(node->group_pool); if (MTAPI_NULL != group) { embb_mtapi_group_initialize_with_node(group, node); group->group_id = group_id; if (MTAPI_NULL != attributes) { group->attributes = *attributes; local_status = MTAPI_SUCCESS; } else { mtapi_groupattr_init(&group->attributes, &local_status); } if (MTAPI_SUCCESS == local_status) { group_hndl = group->handle; } else { embb_mtapi_group_finalize(group); embb_mtapi_group_pool_deallocate(node->group_pool, group); } } else { local_status = MTAPI_ERR_GROUP_LIMIT; } } else { embb_mtapi_log_error("mtapi not initialized\n"); local_status = MTAPI_ERR_NODE_NOTINIT; } mtapi_status_set(status, local_status); return group_hndl; } void mtapi_group_set_attribute( MTAPI_IN mtapi_group_hndl_t group, MTAPI_IN mtapi_uint_t attribute_num, MTAPI_OUT void* attribute, MTAPI_IN mtapi_size_t attribute_size, MTAPI_OUT mtapi_status_t* status) { mtapi_status_t local_status = MTAPI_ERR_UNKNOWN; embb_mtapi_node_t* node = embb_mtapi_node_get_instance(); embb_mtapi_group_t* local_group; embb_mtapi_log_trace("mtapi_group_set_attribute() called\n"); if (embb_mtapi_node_is_initialized()) { if (embb_mtapi_group_pool_is_handle_valid(node->group_pool, group)) { local_group = embb_mtapi_group_pool_get_storage_for_handle( node->group_pool, group); mtapi_groupattr_set(&local_group->attributes, attribute_num, attribute, attribute_size, &local_status); } else { local_status = MTAPI_ERR_GROUP_INVALID; } } else { embb_mtapi_log_error("mtapi not initialized\n"); local_status = MTAPI_ERR_NODE_NOTINIT; } mtapi_status_set(status, local_status); } void mtapi_group_get_attribute( MTAPI_IN mtapi_group_hndl_t group, MTAPI_IN mtapi_uint_t attribute_num, MTAPI_OUT void* attribute, MTAPI_IN mtapi_size_t attribute_size, MTAPI_OUT mtapi_status_t* status ) { mtapi_status_t local_status = MTAPI_ERR_UNKNOWN; EMBB_UNUSED(attribute_num); EMBB_UNUSED(attribute_size); embb_mtapi_log_trace("mtapi_group_get_attribute() called\n"); if (embb_mtapi_node_is_initialized()) { embb_mtapi_node_t* node = embb_mtapi_node_get_instance(); if (embb_mtapi_group_pool_is_handle_valid(node->group_pool, group)) { /* the following is not needed for now, since there are no attributes embb_mtapi_group_t* local_group = embb_mtapi_group_pool_get_storage_for_handle( node->group_pool, group); */ if (MTAPI_NULL == attribute) { local_status = MTAPI_ERR_PARAMETER; } else { /* switch is not needed for now, since there are no attributes switch (attribute_num) { default: */ local_status = MTAPI_ERR_ATTR_NUM; /* break; }*/ } } else { local_status = MTAPI_ERR_GROUP_INVALID; } } else { embb_mtapi_log_error("mtapi not initialized\n"); local_status = MTAPI_ERR_NODE_NOTINIT; } mtapi_status_set(status, local_status); } void mtapi_group_wait_all( MTAPI_IN mtapi_group_hndl_t group, MTAPI_IN mtapi_timeout_t timeout, MTAPI_OUT mtapi_status_t* status) { mtapi_status_t local_status = MTAPI_ERR_UNKNOWN; embb_mtapi_log_trace("mtapi_group_wait_all() called\n"); if (embb_mtapi_node_is_initialized()) { embb_mtapi_node_t* node = embb_mtapi_node_get_instance(); if (embb_mtapi_group_pool_is_handle_valid(node->group_pool, group)) { embb_mtapi_thread_context_t * context = NULL; embb_mtapi_group_t* local_group = embb_mtapi_group_pool_get_storage_for_handle( node->group_pool, group); embb_duration_t wait_duration; embb_time_t end_time; if (MTAPI_INFINITE < timeout) { embb_duration_set_milliseconds( &wait_duration, (unsigned long long)timeout); embb_time_in(&end_time, &wait_duration); } /* find out on which thread we are */ context = embb_mtapi_scheduler_get_current_thread_context( node->scheduler); /* wait for all tasks to arrive in the queue */ local_status = MTAPI_SUCCESS; while (embb_atomic_load_int(&local_group->num_tasks)) { embb_mtapi_task_t* local_task; if (MTAPI_INFINITE < timeout) { embb_time_t current_time; embb_time_now(¤t_time); if (embb_time_compare(¤t_time, &end_time) > 0) { /* timeout! */ local_status = MTAPI_TIMEOUT; break; } } /* fetch and delete all available tasks */ local_task = embb_mtapi_task_queue_pop(&local_group->queue); while (MTAPI_NULL != local_task) { if (MTAPI_SUCCESS != local_task->error_code) { local_status = local_task->error_code; } embb_mtapi_task_delete(local_task, node->task_pool); embb_atomic_fetch_and_add_int(&local_group->num_tasks, -1); local_task = embb_mtapi_task_queue_pop(&local_group->queue); } /* do other work if applicable */ embb_mtapi_scheduler_execute_task_or_yield( node->scheduler, node, context); } if (MTAPI_TIMEOUT != local_status) { /* group becomes invalid, so delete it */ mtapi_group_delete(group, MTAPI_NULL); } } else { local_status = MTAPI_ERR_GROUP_INVALID; } } else { embb_mtapi_log_error("mtapi not initialized\n"); local_status = MTAPI_ERR_NODE_NOTINIT; } mtapi_status_set(status, local_status); embb_mtapi_log_trace("mtapi_group_wait_all() returns\n"); } void mtapi_group_wait_any( MTAPI_IN mtapi_group_hndl_t group, MTAPI_OUT void** result, MTAPI_IN mtapi_timeout_t timeout, MTAPI_OUT mtapi_status_t* status) { mtapi_status_t local_status = MTAPI_ERR_UNKNOWN; embb_mtapi_log_trace("mtapi_group_wait_any() called\n"); if (embb_mtapi_node_is_initialized()) { embb_mtapi_node_t* node = embb_mtapi_node_get_instance(); if (embb_mtapi_group_pool_is_handle_valid(node->group_pool, group)) { embb_mtapi_group_t* local_group = embb_mtapi_group_pool_get_storage_for_handle( node->group_pool, group); embb_mtapi_task_t* local_task; /* are there any tasks left? */ if (0 == embb_atomic_load_int(&local_group->num_tasks)) { /* group becomes invalid, so delete it */ mtapi_group_delete(group, &local_status); local_status = MTAPI_GROUP_COMPLETED; } else { embb_mtapi_thread_context_t * context = NULL; embb_duration_t wait_duration; embb_time_t end_time; if (MTAPI_INFINITE < timeout) { embb_duration_set_milliseconds( &wait_duration, (unsigned long long)timeout); embb_time_in(&end_time, &wait_duration); } /* find out on which thread we are */ context = embb_mtapi_scheduler_get_current_thread_context( node->scheduler); /* wait for any task to arrive */ local_status = MTAPI_SUCCESS; local_task = embb_mtapi_task_queue_pop(&local_group->queue); while (MTAPI_NULL == local_task) { if (MTAPI_INFINITE < timeout) { embb_time_t current_time; embb_time_now(¤t_time); if (embb_time_compare(¤t_time, &end_time) > 0) { /* timeout! */ local_status = MTAPI_TIMEOUT; break; } } /* do other work if applicable */ embb_mtapi_scheduler_execute_task_or_yield( node->scheduler, node, context); /* try to pop a task from the group queue */ local_task = embb_mtapi_task_queue_pop(&local_group->queue); } /* was there a timeout, or is there a result? */ if (MTAPI_NULL != local_task) { /* store result */ if (MTAPI_NULL != result) { *result = local_task->result_buffer; } /* return error code set by the task */ local_status = local_task->error_code; /* delete task */ embb_mtapi_task_delete(local_task, node->task_pool); embb_atomic_fetch_and_add_int(&local_group->num_tasks, -1); } } } else { local_status = MTAPI_ERR_GROUP_INVALID; } } else { embb_mtapi_log_error("mtapi not initialized\n"); local_status = MTAPI_ERR_NODE_NOTINIT; } mtapi_status_set(status, local_status); embb_mtapi_log_trace("mtapi_group_wait_any() returns\n"); } void mtapi_group_delete( MTAPI_IN mtapi_group_hndl_t group, MTAPI_OUT mtapi_status_t* status) { mtapi_status_t local_status = MTAPI_ERR_UNKNOWN; if (embb_mtapi_node_is_initialized()) { embb_mtapi_node_t* node = embb_mtapi_node_get_instance(); if (embb_mtapi_group_pool_is_handle_valid(node->group_pool, group)) { embb_mtapi_group_t* local_group = embb_mtapi_group_pool_get_storage_for_handle( node->group_pool, group); if (local_group->deleted) { local_status = MTAPI_ERR_GROUP_INVALID; } else { embb_mtapi_group_finalize(local_group); embb_mtapi_group_pool_deallocate(node->group_pool, local_group); local_status = MTAPI_SUCCESS; } } else { local_status = MTAPI_ERR_GROUP_INVALID; } } else { local_status = MTAPI_ERR_NODE_NOTINIT; } mtapi_status_set(status, local_status); }