int ABTI_sched_free(ABTI_sched *p_sched) { int abt_errno = ABT_SUCCESS; int p; /* If sched is currently used, free is not allowed. */ if (p_sched->used != ABTI_SCHED_NOT_USED) { abt_errno = ABT_ERR_SCHED; goto fn_fail; } /* If sched is a default provided one, it should free its pool here. * Otherwise, freeing the pool is the user's reponsibility. */ for (p = 0; p < p_sched->num_pools; p++) { ABTI_pool *p_pool = ABTI_pool_get_ptr(p_sched->pools[p]); int32_t num_scheds = ABTI_pool_release(p_pool); if (p_pool->automatic == ABT_TRUE && num_scheds == 0) { abt_errno = ABT_pool_free(p_sched->pools+p); ABTI_CHECK_ERROR(abt_errno); } } ABTU_free(p_sched->pools); /* Free the associated work unit */ if (p_sched->type == ABT_SCHED_TYPE_ULT) { if (p_sched->p_thread) { if (p_sched->p_thread->type == ABTI_THREAD_TYPE_MAIN_SCHED) { ABTI_thread_free_main_sched(p_sched->p_thread); } else { ABTI_thread_free(p_sched->p_thread); } } } else if (p_sched->type == ABT_SCHED_TYPE_TASK) { if (p_sched->p_task) { ABTI_task_free(p_sched->p_task); } } LOG_EVENT("[S%" PRIu64 "] freed\n", p_sched->id); p_sched->free(ABTI_sched_get_handle(p_sched)); p_sched->data = NULL; ABTU_free(p_sched); fn_exit: return abt_errno; fn_fail: HANDLE_ERROR_FUNC_WITH_CODE(abt_errno); goto fn_exit; }
/** * @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; }
static void sched_run(ABT_sched sched) { uint32_t work_count = 0; sched_data *p_data; int num_pools; ABT_pool *p_pools; ABT_unit unit; int target; unsigned seed = time(NULL); CNT_DECL(run_cnt); ABTI_xstream *p_xstream = ABTI_local_get_xstream(); ABTI_sched *p_sched = ABTI_sched_get_ptr(sched); ABT_sched_get_data(sched, (void **)&p_data); ABT_sched_get_num_pools(sched, &num_pools); p_pools = (ABT_pool *)ABTU_malloc(num_pools * sizeof(ABT_pool)); ABT_sched_get_pools(sched, num_pools, 0, p_pools); while (1) { CNT_INIT(run_cnt, 0); /* Execute one work unit from the scheduler's pool */ ABT_pool pool = p_pools[0]; ABTI_pool *p_pool = ABTI_pool_get_ptr(pool); size_t size = ABTI_pool_get_size(p_pool); if (size > 0) { unit = ABTI_pool_pop(p_pool); if (unit != ABT_UNIT_NULL) { ABTI_xstream_run_unit(p_xstream, unit, p_pool); CNT_INC(run_cnt); } } else if (num_pools > 1) { /* Steal a work unit from other pools */ target = (num_pools == 2) ? 1 : (rand_r(&seed) % (num_pools-1) + 1); pool = p_pools[target]; p_pool = ABTI_pool_get_ptr(pool); size = ABTI_pool_get_size(p_pool); if (size > 0) { unit = ABTI_pool_pop(p_pool); LOG_EVENT_POOL_POP(p_pool, unit); if (unit != ABT_UNIT_NULL) { ABT_unit_set_associated_pool(unit, pool); ABTI_xstream_run_unit(p_xstream, unit, p_pool); CNT_INC(run_cnt); } } } if (++work_count >= p_data->event_freq) { ABT_bool stop = ABTI_sched_has_to_stop(p_sched, p_xstream); if (stop == ABT_TRUE) break; work_count = 0; ABTI_xstream_check_events(p_xstream, sched); SCHED_SLEEP(run_cnt, p_data->sleep_time); } } ABTU_free(p_pools); }
static int sched_free(ABT_sched sched) { sched_data *p_data; ABT_sched_get_data(sched, (void **)&p_data); ABTU_free(p_data); return ABT_SUCCESS; }
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; }
void ABTI_log_debug(FILE *fh, char *path, int line, const char *format, ...) { if (gp_ABTI_global->use_logging == ABT_FALSE) return; int line_len; size_t newfmt_len; char *newfmt; line_len = ABTU_get_int_len(line); newfmt_len = strlen(path) + line_len + 4 + strlen(format); newfmt = (char *)ABTU_malloc(newfmt_len + 1); sprintf(newfmt, "[%s:%d] %s", path, line, format); va_list list; va_start(list, format); vfprintf(fh, newfmt, list); va_end(list); fflush(fh); ABTU_free(newfmt); }
void ABTI_log_event(FILE *fh, const char *format, ...) { if (gp_ABTI_global->use_logging == ABT_FALSE) return; ABT_unit_type type; ABTI_xstream *p_xstream = NULL; ABTI_thread *p_thread = NULL; ABTI_task *p_task = NULL; char *prefix_fmt = NULL, *prefix = NULL; char *newfmt; size_t tid, rank; int tid_len = 0, rank_len = 0; size_t newfmt_len; ABT_self_get_type(&type); switch (type) { case ABT_UNIT_TYPE_THREAD: p_xstream = ABTI_local_get_xstream(); p_thread = ABTI_local_get_thread(); if (p_thread == NULL) { if (p_xstream && p_xstream->type != ABTI_XSTREAM_TYPE_PRIMARY) { prefix_fmt = "<U%" PRIu64 ":E%" PRIu64 "> %s"; rank = p_xstream->rank; tid = 0; } else { prefix = "<U0:E0> "; prefix_fmt = "%s%s"; } } else { rank = p_xstream->rank; if (lp_ABTI_log->p_sched) { prefix_fmt = "<S%" PRIu64 ":E%" PRIu64 "> %s"; tid = lp_ABTI_log->p_sched->id; } else { prefix_fmt = "<U%" PRIu64 ":E%" PRIu64 "> %s"; tid = ABTI_thread_get_id(p_thread); } } break; case ABT_UNIT_TYPE_TASK: p_xstream = ABTI_local_get_xstream(); rank = p_xstream->rank; p_task = ABTI_local_get_task(); if (lp_ABTI_log->p_sched) { prefix_fmt = "<S%" PRIu64 ":E%" PRIu64 "> %s"; tid = lp_ABTI_log->p_sched->id; } else { prefix_fmt = "<T%" PRIu64 ":E%" PRIu64 "> %s"; tid = ABTI_task_get_id(p_task); } break; case ABT_UNIT_TYPE_EXT: prefix = "<EXT> "; prefix_fmt = "%s%s"; break; default: prefix = "<UNKNOWN> "; prefix_fmt = "%s%s"; break; } if (prefix == NULL) { tid_len = ABTU_get_int_len(tid); rank_len = ABTU_get_int_len(rank); newfmt_len = 6 + tid_len + rank_len + strlen(format); newfmt = (char *)ABTU_malloc(newfmt_len + 1); sprintf(newfmt, prefix_fmt, tid, rank, format); } else { newfmt_len = strlen(prefix) + strlen(format); newfmt = (char *)ABTU_malloc(newfmt_len + 1); sprintf(newfmt, prefix_fmt, prefix, format); } va_list list; va_start(list, format); vfprintf(fh, newfmt, list); va_end(list); fflush(fh); ABTU_free(newfmt); }
void ABTI_log_finalize(void) { ABTU_free(lp_ABTI_log); lp_ABTI_log = NULL; }
void ABTI_sched_print(ABTI_sched *p_sched, FILE *p_os, int indent, ABT_bool print_sub) { char *prefix = ABTU_get_indent_str(indent); if (p_sched == NULL) { fprintf(p_os, "%s== NULL SCHED ==\n", prefix); goto fn_exit; } ABTI_sched_kind kind; char *kind_str, *type, *state, *used; char *pools_str; int i; size_t size, pos; kind = p_sched->kind; if (kind == ABTI_sched_get_kind(ABTI_sched_get_basic_def())) { kind_str = "BASIC"; } else if (kind == ABTI_sched_get_kind(ABTI_sched_get_prio_def())) { kind_str = "PRIO"; } else { kind_str = "USER"; } switch (p_sched->type) { case ABT_SCHED_TYPE_ULT: type = "ULT"; break; case ABT_SCHED_TYPE_TASK: type = "TASKLET"; break; default: type = "UNKNOWN"; break; } switch (p_sched->state) { case ABT_SCHED_STATE_READY: state = "READY"; break; case ABT_SCHED_STATE_RUNNING: state = "RUNNING"; break; case ABT_SCHED_STATE_STOPPED: state = "STOPPED"; break; case ABT_SCHED_STATE_TERMINATED: state = "TERMINATED"; break; default: state = "UNKNOWN"; break; } switch (p_sched->used) { case ABTI_SCHED_NOT_USED: used = "NOT_USED"; break; case ABTI_SCHED_MAIN: used = "MAIN"; break; case ABTI_SCHED_IN_POOL: used = "IN_POOL"; break; default: type = "UNKNOWN"; break; } size = sizeof(char) * (p_sched->num_pools * 20 + 4); pools_str = (char *)ABTU_calloc(size, 1); pools_str[0] = '['; pools_str[1] = ' '; pos = 2; for (i = 0; i < p_sched->num_pools; i++) { ABTI_pool *p_pool = ABTI_pool_get_ptr(p_sched->pools[i]); sprintf(&pools_str[pos], "%p ", p_pool); pos = strlen(pools_str); } pools_str[pos] = ']'; fprintf(p_os, "%s== SCHED (%p) ==\n" #ifdef ABT_CONFIG_USE_DEBUG_LOG "%sid : %" PRIu64 "\n" #endif "%skind : %" PRIu64 " (%s)\n" "%stype : %s\n" "%sstate : %s\n" "%sused : %s\n" "%sautomatic: %s\n" "%srequest : 0x%x\n" "%snum_pools: %d\n" "%spools : %s\n" "%ssize : %zu\n" "%stot_size : %zu\n" "%sdata : %p\n", prefix, p_sched, #ifdef ABT_CONFIG_USE_DEBUG_LOG prefix, p_sched->id, #endif prefix, p_sched->kind, kind_str, prefix, type, prefix, state, prefix, used, prefix, (p_sched->automatic == ABT_TRUE) ? "TRUE" : "FALSE", prefix, p_sched->request, prefix, p_sched->num_pools, prefix, pools_str, prefix, ABTI_sched_get_size(p_sched), prefix, ABTI_sched_get_total_size(p_sched), prefix, p_sched->data ); ABTU_free(pools_str); if (print_sub == ABT_TRUE) { for (i = 0; i < p_sched->num_pools; i++) { ABTI_pool *p_pool = ABTI_pool_get_ptr(p_sched->pools[i]); ABTI_pool_print(p_pool, p_os, indent + 2); } } fn_exit: fflush(p_os); ABTU_free(prefix); }
/** * @ingroup SCHED * @brief Create a predefined scheduler. * * \c ABT_sched_create_basic() creates a predefined scheduler and returns its * handle through \c 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 \c ABT_POOL_NULL, the corresponding pool is * automatically created. The pool array can be \c NULL. In this case, all * the pools will be created automatically. The config must have been created * by \c ABT_sched_config_create(), and will be used as argument in the * initialization. If no specific configuration is required, the parameter can * be \c ABT_CONFIG_NULL. * * NOTE: The new scheduler will be automatically freed when it is not used * anymore or its associated ES is terminated. Accordingly, the pools * associated with the new scheduler will be automatically freed if they are * exclusive to the scheduler and are not user-defined ones (i.e., created by * \c ABT_pool_create_basic() or implicitly created because \c pools is \c NULL * or a pool in the \c pools array is \c ABT_POOL_NULL). If the pools were * created using \c ABT_pool_create() by the user, they have to be freed * explicitly with \c ABT_pool_free(). * * @param[in] predef predefined scheduler * @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_basic(ABT_sched_predef predef, int num_pools, ABT_pool *pools, ABT_sched_config config, ABT_sched *newsched) { int abt_errno = ABT_SUCCESS; ABT_pool_access access; ABT_bool automatic; int p; /* We set the access to the default one */ access = ABT_POOL_ACCESS_MPSC; automatic = ABT_TRUE;; /* We read the config and set the configured parameters */ abt_errno = ABTI_sched_config_read_global(config, &access, &automatic); ABTI_CHECK_ERROR(abt_errno); /* A pool array is provided, predef has to be compatible */ if (pools != NULL) { /* 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, access, ABT_TRUE, &pool_list[p]); ABTI_CHECK_ERROR(abt_errno); } else { pool_list[p] = pools[p]; } } /* Creation of the scheduler */ switch (predef) { case ABT_SCHED_DEFAULT: case ABT_SCHED_BASIC: abt_errno = ABT_sched_create(ABTI_sched_get_basic_def(), num_pools, pool_list, ABT_SCHED_CONFIG_NULL, newsched); break; case ABT_SCHED_PRIO: abt_errno = ABT_sched_create(ABTI_sched_get_prio_def(), num_pools, pool_list, ABT_SCHED_CONFIG_NULL, newsched); break; case ABT_SCHED_RANDWS: abt_errno = ABT_sched_create(ABTI_sched_get_randws_def(), num_pools, pool_list, ABT_SCHED_CONFIG_NULL, newsched); break; default: abt_errno = ABT_ERR_INV_SCHED_PREDEF; break; } ABTI_CHECK_ERROR(abt_errno); ABTU_free(pool_list); } /* No pool array is provided, predef has to be compatible */ else { /* Set the number of pools */ switch (predef) { case ABT_SCHED_DEFAULT: case ABT_SCHED_BASIC: num_pools = 1; break; case ABT_SCHED_PRIO: num_pools = ABTI_SCHED_NUM_PRIO; break; case ABT_SCHED_RANDWS: num_pools = 1; break; default: abt_errno = ABT_ERR_INV_SCHED_PREDEF; ABTI_CHECK_ERROR(abt_errno); break; } /* Creation of the pools */ /* To avoid the malloc overhead, we use a stack array. */ ABT_pool pool_list[ABTI_SCHED_NUM_PRIO]; int p; for (p = 0; p < num_pools; p++) { abt_errno = ABT_pool_create_basic(ABT_POOL_FIFO, access, ABT_TRUE, pool_list+p); ABTI_CHECK_ERROR(abt_errno); } /* Creation of the scheduler */ switch (predef) { case ABT_SCHED_DEFAULT: case ABT_SCHED_BASIC: abt_errno = ABT_sched_create(ABTI_sched_get_basic_def(), num_pools, pool_list, config, newsched); break; case ABT_SCHED_PRIO: abt_errno = ABT_sched_create(ABTI_sched_get_prio_def(), num_pools, pool_list, config, newsched); break; case ABT_SCHED_RANDWS: abt_errno = ABT_sched_create(ABTI_sched_get_randws_def(), num_pools, pool_list, config, newsched); break; default: abt_errno = ABT_ERR_INV_SCHED_PREDEF; ABTI_CHECK_ERROR(abt_errno); break; } } ABTI_CHECK_ERROR(abt_errno); ABTI_sched *p_sched = ABTI_sched_get_ptr(*newsched); p_sched->automatic = automatic; fn_exit: return abt_errno; fn_fail: HANDLE_ERROR_FUNC_WITH_CODE(abt_errno); *newsched = ABT_SCHED_NULL; goto fn_exit; }
/** * @ingroup COND * @brief Wait on the condition. * * The ULT calling \c ABT_cond_timedwait() waits on the condition variable * until it is signaled or the absolute time specified by \c abstime passes. * If system time equals or exceeds \c abstime before \c cond is signaled, * the error code \c ABT_ERR_COND_TIMEDOUT is returned. * * 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 * @param[in] abstime absolute time for timeout * @return Error code * @retval ABT_SUCCESS on success * @retval ABT_ERR_COND_TIMEDOUT timeout */ int ABT_cond_timedwait(ABT_cond cond, ABT_mutex mutex, const struct timespec *abstime) { 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); double tar_time = convert_timespec_to_sec(abstime); ABTI_unit *p_unit; volatile int ext_signal = 0; p_unit = (ABTI_unit *)ABTU_calloc(1, sizeof(ABTI_unit)); p_unit->pool = (ABT_pool)&ext_signal; p_unit->type = ABT_UNIT_TYPE_EXT; 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++; ABTI_mutex_unlock(&p_cond->mutex); /* Unlock the mutex that the calling ULT is holding */ ABTI_mutex_unlock(p_mutex); while (!ext_signal) { double cur_time = get_cur_time(); if (cur_time >= tar_time) { remove_unit(p_cond, p_unit); abt_errno = ABT_ERR_COND_TIMEDOUT; break; } ABT_thread_yield(); } 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; }
/** * @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; }