static HG_THREAD_RETURN_TYPE thread_cb_cond_all(void *arg) { hg_thread_ret_t thread_ret = (hg_thread_ret_t) 0; (void) arg; hg_thread_mutex_lock(&thread_mutex); while (working) hg_thread_cond_timedwait(&thread_cond, &thread_mutex, 1000); hg_thread_mutex_unlock(&thread_mutex); hg_thread_exit(thread_ret); return thread_ret; }
/*---------------------------------------------------------------------------*/ na_return_t NA_Trigger(na_context_t *context, unsigned int timeout, unsigned int max_count, unsigned int *actual_count) { struct na_private_context *na_private_context = (struct na_private_context *) context; na_return_t ret = NA_SUCCESS; na_bool_t completion_queue_empty = 0; struct na_cb_completion_data *completion_data = NULL; unsigned int count = 0; if (!context) { NA_LOG_ERROR("NULL context"); ret = NA_INVALID_PARAM; goto done; } while (count < max_count) { hg_thread_mutex_lock(&na_private_context->completion_queue_mutex); /* Is completion queue empty */ completion_queue_empty = (na_bool_t) hg_queue_is_empty( na_private_context->completion_queue); while (completion_queue_empty) { /* TODO needed ? */ /* If queue is empty and already triggered something, just leave */ if (count) { hg_thread_mutex_unlock( &na_private_context->completion_queue_mutex); goto done; } if (!timeout) { /* Timeout is 0 so leave */ ret = NA_TIMEOUT; hg_thread_mutex_unlock( &na_private_context->completion_queue_mutex); goto done; } /* Otherwise wait timeout ms */ if (hg_thread_cond_timedwait( &na_private_context->completion_queue_cond, &na_private_context->completion_queue_mutex, timeout) != HG_UTIL_SUCCESS) { /* Timeout occurred so leave */ ret = NA_TIMEOUT; hg_thread_mutex_unlock( &na_private_context->completion_queue_mutex); goto done; } } /* Completion queue should not be empty now */ completion_data = (struct na_cb_completion_data *) hg_queue_pop_tail(na_private_context->completion_queue); if (!completion_data) { NA_LOG_ERROR("NULL completion data"); ret = NA_INVALID_PARAM; hg_thread_mutex_unlock(&na_private_context->completion_queue_mutex); goto done; } /* Unlock now so that other threads can eventually add callbacks * to the queue while callback gets executed */ hg_thread_mutex_unlock(&na_private_context->completion_queue_mutex); /* Execute callback */ if (completion_data->callback) { /* TODO should return error from callback ? */ completion_data->callback(completion_data->callback_info); } /* Execute plugin callback (free resources etc) */ if (completion_data->plugin_callback) completion_data->plugin_callback(completion_data->callback_info, completion_data->plugin_callback_args); free(completion_data); count++; } if (actual_count) *actual_count = count; done: return ret; }
/*---------------------------------------------------------------------------*/ na_return_t NA_Progress(na_class_t *na_class, na_context_t *context, unsigned int timeout) { struct na_private_context *na_private_context = (struct na_private_context *) context; double remaining = timeout / 1000.0; /* Convert timeout in ms into seconds */ na_return_t ret = NA_SUCCESS; if (!na_class) { NA_LOG_ERROR("NULL NA class"); ret = NA_INVALID_PARAM; goto done; } if (!context) { NA_LOG_ERROR("NULL context"); ret = NA_INVALID_PARAM; goto done; } if (!na_class->progress) { NA_LOG_ERROR("progress plugin callback is not defined"); ret = NA_PROTOCOL_ERROR; goto done; } /* TODO option for concurrent progress */ /* Prevent multiple threads from concurrently calling progress on the same * context */ hg_thread_mutex_lock(&na_private_context->progress_mutex); while (na_private_context->progressing) { hg_time_t t1, t2; if (remaining <= 0) { /* Timeout is 0 so leave */ hg_thread_mutex_unlock(&na_private_context->progress_mutex); ret = NA_TIMEOUT; goto done; } hg_time_get_current(&t1); if (hg_thread_cond_timedwait(&na_private_context->progress_cond, &na_private_context->progress_mutex, (unsigned int) (remaining * 1000)) != HG_UTIL_SUCCESS) { /* Timeout occurred so leave */ hg_thread_mutex_unlock(&na_private_context->progress_mutex); ret = NA_TIMEOUT; goto done; } hg_time_get_current(&t2); remaining -= hg_time_to_double(hg_time_subtract(t2, t1)); if (remaining < 0) { /* Give a chance to call progress with timeout of 0 if * progressing is NA_FALSE */ remaining = 0; } } na_private_context->progressing = NA_TRUE; hg_thread_mutex_unlock(&na_private_context->progress_mutex); /* Try to make progress for remaining time */ ret = na_class->progress(na_class, context, (unsigned int) (remaining * 1000)); hg_thread_mutex_lock(&na_private_context->progress_mutex); /* At this point, either progress succeeded or failed with NA_TIMEOUT, * meaning remaining time is now 0, so wake up other threads waiting */ na_private_context->progressing = NA_FALSE; hg_thread_cond_signal(&na_private_context->progress_cond); hg_thread_mutex_unlock(&na_private_context->progress_mutex); done: return ret; }