Beispiel #1
0
/**
 * @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;
}
Beispiel #2
0
/* 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;
}
Beispiel #3
0
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;
}
Beispiel #4
0
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;
}
Beispiel #5
0
/**
 * @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;
}
Beispiel #6
0
/**
 * @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;
}
Beispiel #7
0
/**
 * @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;
}