/** * @ingroup COND * @brief Free the condition variable. * * \c ABT_cond_free() deallocates the memory used for the condition variable * object associated with the handle \c cond. If it is successfully processed, * \c cond is set to \c ABT_COND_NULL. * * @param[in,out] cond handle to the condition variable * @return Error code * @retval ABT_SUCCESS on success */ int ABT_cond_free(ABT_cond *cond) { int abt_errno = ABT_SUCCESS; ABT_cond h_cond = *cond; ABTI_cond *p_cond = ABTI_cond_get_ptr(h_cond); ABTI_CHECK_NULL_COND_PTR(p_cond); ABTI_CHECK_TRUE(p_cond->num_waiters == 0, ABT_ERR_COND); /* The lock needs to be acquired to safely free the condition structure. * However, we do not have to unlock it because the entire structure is * freed here. */ ABTI_mutex_spinlock(&p_cond->mutex); ABTU_free(p_cond); /* Return value */ *cond = ABT_COND_NULL; fn_exit: return abt_errno; fn_fail: HANDLE_ERROR_FUNC_WITH_CODE(abt_errno); goto fn_exit; }
/* Get the pool suitable for receiving a migrating ULT */ int ABTI_sched_get_migration_pool(ABTI_sched *p_sched, ABTI_pool *source_pool, ABTI_pool **pp_pool) { int abt_errno = ABT_SUCCESS; ABT_sched sched = ABTI_sched_get_handle(p_sched); ABTI_pool *p_pool; ABTI_CHECK_TRUE(p_sched->state != ABT_SCHED_STATE_TERMINATED, ABT_ERR_INV_SCHED); /* Find a pool */ /* If get_migr_pool is not defined, we pick the first pool */ if (p_sched->get_migr_pool == NULL) { if (p_sched->num_pools == 0) p_pool = NULL; else p_pool = p_sched->pools[0]; } else p_pool = p_sched->get_migr_pool(sched); /* Check the pool */ if (ABTI_pool_accept_migration(p_pool, source_pool) == ABT_TRUE) { *pp_pool = p_pool; } else { ABTI_CHECK_TRUE(0, ABT_ERR_INV_POOL_ACCESS); } fn_exit: return abt_errno; fn_fail: *pp_pool = NULL; HANDLE_ERROR_FUNC_WITH_CODE(abt_errno); goto fn_exit; }
int ABTI_local_finalize(void) { int abt_errno = ABT_SUCCESS; ABTI_CHECK_TRUE(lp_ABTI_local != NULL, ABT_ERR_OTHER); ABTU_free(lp_ABTI_local); lp_ABTI_local = NULL; ABTI_LOG_FINALIZE(); fn_exit: return abt_errno; fn_fail: HANDLE_ERROR_FUNC_WITH_CODE(abt_errno); goto fn_exit; }
int ABTI_local_init(void) { int abt_errno = ABT_SUCCESS; ABTI_CHECK_TRUE(lp_ABTI_local == NULL, ABT_ERR_OTHER); lp_ABTI_local = (ABTI_local *)ABTU_malloc(sizeof(ABTI_local)); lp_ABTI_local->p_xstream = NULL; lp_ABTI_local->p_thread = NULL; lp_ABTI_local->p_task = NULL; ABTI_LOG_INIT(); fn_exit: return abt_errno; fn_fail: HANDLE_ERROR_FUNC_WITH_CODE(abt_errno); goto fn_exit; }
/** * @ingroup SCHED * @brief Get the pools of the scheduler \c sched. * * @param[in] sched handle to the target scheduler * @param[in] max_pools maximum number of pools to get * @param[in] idx index of the first pool to get * @param[out] pools array of handles to the pools * @return Error code * @retval ABT_SUCCESS on success */ int ABT_sched_get_pools(ABT_sched sched, int max_pools, int idx, ABT_pool *pools) { int abt_errno = ABT_SUCCESS; ABTI_sched *p_sched = ABTI_sched_get_ptr(sched); ABTI_CHECK_NULL_SCHED_PTR(p_sched); ABTI_CHECK_TRUE(idx+max_pools <= p_sched->num_pools, ABT_ERR_SCHED); int p; for (p = idx; p < idx+max_pools; p++) { pools[p-idx] = p_sched->pools[p]; } fn_exit: return abt_errno; fn_fail: HANDLE_ERROR_FUNC_WITH_CODE(abt_errno); goto fn_exit; }
/** * @ingroup SCHED * @brief Create a new user-defined scheduler and return its handle through * newsched. * * The pools used by the new scheduler are provided by \c pools. The contents * of this array is copied, so it can be freed. If a pool in the array is * ABT_POOL_NULL, the corresponding pool is automatically created. * The config must have been created by ABT_sched_config_create, and will be * used as argument in the initialization. If no specific configuration is * required, the parameter will be ABT_CONFIG_NULL. * * @param[in] def definition required for scheduler creation * @param[in] num_pools number of pools associated with this scheduler * @param[in] pools pools associated with this scheduler * @param[in] config specific config used during the scheduler creation * @param[out] newsched handle to a new scheduler * @return Error code * @retval ABT_SUCCESS on success */ int ABT_sched_create(ABT_sched_def *def, int num_pools, ABT_pool *pools, ABT_sched_config config, ABT_sched *newsched) { int abt_errno = ABT_SUCCESS; ABTI_sched *p_sched; int p; ABTI_CHECK_TRUE(newsched != NULL, ABT_ERR_SCHED); p_sched = (ABTI_sched *)ABTU_malloc(sizeof(ABTI_sched)); /* Copy of the contents of pools */ ABT_pool *pool_list; pool_list = (ABT_pool *)ABTU_malloc(num_pools*sizeof(ABT_pool)); for (p = 0; p < num_pools; p++) { if (pools[p] == ABT_POOL_NULL) { abt_errno = ABT_pool_create_basic(ABT_POOL_FIFO, ABT_POOL_ACCESS_MPSC, ABT_TRUE, &pool_list[p]); ABTI_CHECK_ERROR(abt_errno); } else { pool_list[p] = pools[p]; } } /* Check if the pools are available */ for (p = 0; p < num_pools; p++) { ABTI_pool_retain(ABTI_pool_get_ptr(pool_list[p])); } p_sched->used = ABTI_SCHED_NOT_USED; p_sched->automatic = ABT_FALSE; p_sched->kind = ABTI_sched_get_kind(def); p_sched->state = ABT_SCHED_STATE_READY; p_sched->request = 0; p_sched->pools = pool_list; p_sched->num_pools = num_pools; p_sched->type = def->type; p_sched->p_thread = NULL; p_sched->p_task = NULL; p_sched->p_ctx = NULL; p_sched->init = def->init; p_sched->run = def->run; p_sched->free = def->free; p_sched->get_migr_pool = def->get_migr_pool; #ifdef ABT_CONFIG_USE_DEBUG_LOG p_sched->id = ABTI_sched_get_new_id(); #endif LOG_EVENT("[S%" PRIu64 "] created\n", p_sched->id); /* Return value */ *newsched = ABTI_sched_get_handle(p_sched); /* Specific initialization */ p_sched->init(*newsched, config); fn_exit: return abt_errno; fn_fail: *newsched = ABT_SCHED_NULL; HANDLE_ERROR_FUNC_WITH_CODE(abt_errno); goto fn_exit; }
/** * @ingroup COND * @brief Wait on the condition. * * The ULT calling \c ABT_cond_wait() waits on the condition variable until * it is signaled. * The user should call this routine while the mutex specified as \c mutex is * locked. The mutex will be automatically released while waiting. After signal * is received and the waiting ULT is awakened, the mutex will be * automatically locked for use by the ULT. The user is then responsible for * unlocking mutex when the ULT is finished with it. * * @param[in] cond handle to the condition variable * @param[in] mutex handle to the mutex * @return Error code * @retval ABT_SUCCESS on success */ int ABT_cond_wait(ABT_cond cond, ABT_mutex mutex) { int abt_errno = ABT_SUCCESS; ABTI_cond *p_cond = ABTI_cond_get_ptr(cond); ABTI_CHECK_NULL_COND_PTR(p_cond); ABTI_mutex *p_mutex = ABTI_mutex_get_ptr(mutex); ABTI_CHECK_NULL_MUTEX_PTR(p_mutex); ABTI_thread *p_thread; ABTI_unit *p_unit; ABT_unit_type type; volatile int ext_signal = 0; if (lp_ABTI_local != NULL) { p_thread = ABTI_local_get_thread(); ABTI_CHECK_TRUE(p_thread != NULL, ABT_ERR_COND); type = ABT_UNIT_TYPE_THREAD; p_unit = &p_thread->unit_def; p_unit->thread = ABTI_thread_get_handle(p_thread); p_unit->type = type; } else { /* external thread */ type = ABT_UNIT_TYPE_EXT; p_unit = (ABTI_unit *)ABTU_calloc(1, sizeof(ABTI_unit)); p_unit->pool = (ABT_pool)&ext_signal; p_unit->type = type; } ABTI_mutex_spinlock(&p_cond->mutex); if (p_cond->p_waiter_mutex == NULL) { p_cond->p_waiter_mutex = p_mutex; } else { ABT_bool result = ABTI_mutex_equal(p_cond->p_waiter_mutex, p_mutex); if (result == ABT_FALSE) { ABTI_mutex_unlock(&p_cond->mutex); abt_errno = ABT_ERR_INV_MUTEX; goto fn_fail; } } if (p_cond->num_waiters == 0) { p_unit->p_prev = p_unit; p_unit->p_next = p_unit; p_cond->p_head = p_unit; p_cond->p_tail = p_unit; } else { p_cond->p_tail->p_next = p_unit; p_cond->p_head->p_prev = p_unit; p_unit->p_prev = p_cond->p_tail; p_unit->p_next = p_cond->p_head; p_cond->p_tail = p_unit; } p_cond->num_waiters++; if (type == ABT_UNIT_TYPE_THREAD) { /* Change the ULT's state to BLOCKED */ ABTI_thread_set_blocked(p_thread); ABTI_mutex_unlock(&p_cond->mutex); /* Unlock the mutex that the calling ULT is holding */ /* FIXME: should check if mutex was locked by the calling ULT */ ABTI_mutex_unlock(p_mutex); /* Suspend the current ULT */ ABTI_thread_suspend(p_thread); } else { /* TYPE == ABT_UNIT_TYPE_EXT */ ABTI_mutex_unlock(&p_cond->mutex); ABTI_mutex_unlock(p_mutex); /* External thread is waiting here polling ext_signal. */ /* FIXME: need a better implementation */ while (!ext_signal) { } ABTU_free(p_unit); } /* Lock the mutex again */ ABTI_mutex_spinlock(p_mutex); fn_exit: return abt_errno; fn_fail: HANDLE_ERROR_FUNC_WITH_CODE(abt_errno); goto fn_exit; }