# vim: set ft=c:

MPI_T_category_changed:
    .desc: Get the timestamp indicating the last change to the categories
{
    *update_number = cat_stamp;
}

MPI_T_category_get_categories:
    .desc: Get sub-categories in a category
{ -- error_check -- indices
    if (len != 0) {
        MPIT_ERRTEST_ARGNULL(indices);
    }
}
{ -- early_return --
    if (len == 0) {
        goto fn_exit;
    }
}

MPI_T_category_get_cvars:
    .desc: Get control variables in a category
{ -- error_check -- indices
    if (len != 0) {
        MPIT_ERRTEST_ARGNULL(indices);
    }
}
{ -- early_return --
    if (len == 0) {
        goto fn_exit;
    }
}

MPI_T_category_get_index:
    .desc: Get the index of a category
    .error: MPI_T_ERR_INVALID_NAME
{
    name2index_hash_t *hash_entry;

    /* Do hash lookup by the name */
    HASH_FIND_STR(cat_hash, name, hash_entry);
    if (hash_entry != NULL) {
        *cat_index = hash_entry->idx;
    } else {
        mpi_errno = MPI_T_ERR_INVALID_NAME;
        goto fn_fail;
    }
}

MPI_T_category_get_info:
    .desc: Get the information about a category
    .skip: validate-ANY
    .error: MPI_T_ERR_INVALID_INDEX
{ -- error_check --
    MPIT_ERRTEST_CAT_INDEX(cat_index);
}
{
    cat_table_entry_t *cat;
    cat = (cat_table_entry_t *) utarray_eltptr(cat_table, cat_index);
    MPIR_T_strncpy(name, cat->name, name_len);
    MPIR_T_strncpy(desc, cat->desc, desc_len);

    if (num_cvars != NULL)
        *num_cvars = utarray_len(cat->cvar_indices);

    if (num_pvars != NULL)
        *num_pvars = utarray_len(cat->pvar_indices);

    if (num_categories != NULL)
        *num_categories = utarray_len(cat->subcat_indices);
}

MPI_T_category_get_num:
    .desc: Get the number of categories
{
    *num_cat = utarray_len(cat_table);
}

MPI_T_category_get_pvars:
    .desc: Get performance variables in a category
    .error: MPI_T_ERR_INVALID
{ -- error_check -- indices
    if (len != 0) {
        MPIT_ERRTEST_ARGNULL(indices);
    }
}
{ -- early_return --
    if (len == 0) {
        goto fn_exit;
    }
}

MPI_T_cvar_get_index:
    .desc: Get the index of a control variable
    .error: MPI_T_ERR_INVALID_NAME
{
    name2index_hash_t *hash_entry;

    /* Do hash lookup by the name */
    HASH_FIND_STR(cvar_hash, name, hash_entry);
    if (hash_entry != NULL) {
        *cvar_index = hash_entry->idx;
    } else {
        mpi_errno = MPI_T_ERR_INVALID_NAME;
        goto fn_fail;
    }
}

MPI_T_cvar_get_info:
    .desc: Get the information about a control variable
    .skip: validate-ANY
    .error: MPI_T_ERR_INVALID_INDEX
{ -- error_check --
    MPIT_ERRTEST_CVAR_INDEX(cvar_index);
}
{
    cvar_table_entry_t *cvar;
    cvar = (cvar_table_entry_t *) utarray_eltptr(cvar_table, cvar_index);

    MPIR_T_strncpy(name, cvar->name, name_len);
    MPIR_T_strncpy(desc, cvar->desc, desc_len);

    if (verbosity != NULL)
        *verbosity = cvar->verbosity;

    if (datatype != NULL)
        *datatype = cvar->datatype;

    if (enumtype != NULL)
        *enumtype = cvar->enumtype;

    if (bind!= NULL)
        *bind= cvar->bind;

    if (scope != NULL)
        *scope = cvar->scope;
}

MPI_T_cvar_get_num:
    .desc: Get the number of control variables
{
    *num_cvar = utarray_len(cvar_table);
}

MPI_T_cvar_handle_alloc:
    .desc: Allocate a handle for a control variable
    .skip: validate-TOOL_MPI_OBJ
    .error: MPI_T_ERR_OUT_OF_HANDLES

MPI_T_cvar_handle_free:
    .desc: Free an existing handle for a control variable
{
    MPIR_T_cvar_handle_t *hnd;
    hnd = *handle;
    MPL_free(hnd);
    *handle = MPI_T_CVAR_HANDLE_NULL;
}

MPI_T_cvar_read:
    .desc: Read the value of a control variable

MPI_T_cvar_write:
    .desc: Write a control variable
    .error: MPI_T_ERR_CVAR_SET_NEVER, MPI_T_ERR_CVAR_SET_NOT_NOW
{ -- error_check --
    MPIR_T_cvar_handle_t *hnd = handle;

    if (hnd->scope == MPI_T_SCOPE_CONSTANT) {
        mpi_errno = MPI_T_ERR_CVAR_SET_NEVER;
        goto fn_fail;
    } else if (hnd->scope == MPI_T_SCOPE_READONLY) {
        mpi_errno = MPI_T_ERR_CVAR_SET_NOT_NOW;
        goto fn_fail;
    }
}

MPI_T_enum_get_info:
    .desc: Get the information about an enumeration
    .skip: validate-STRING, validate-STRING_LENGTH
{
    *num = utarray_len(enumtype->items);
    MPIR_T_strncpy(name, enumtype->name, name_len);
}

MPI_T_enum_get_item:
    .desc: Get the information about an item in an enumeration
{
    enum_item_t *item;
    item = (enum_item_t *) utarray_eltptr(enumtype->items, indx);
    *value = item->value;
    MPIR_T_strncpy(name, item->name, name_len);
}

MPI_T_finalize:
    .desc: Finalize the MPI tool information interface
    .skip: global_cs
    .seealso: MPI_T_init_thread
    .error: MPI_T_ERR_NOT_INITIALIZED
{
    --MPIR_T_init_balance;
    if (MPIR_T_init_balance < 0) {
        mpi_errno = MPI_T_ERR_NOT_INITIALIZED;
        goto fn_fail;
    }

    if (MPIR_T_init_balance == 0) {
        MPIR_T_env_finalize();
    }
}

MPI_T_init_thread:
    .desc: Initialize the MPI_T execution environment
    .skip: global_cs, initcheck
    .seealso: MPI_T_finalize
{ -- error_check -- required
    CHECKENUM: required, thread_level, MPI_THREAD_SINGLE MPI_THREAD_FUNNELED MPI_THREAD_SERIALIZED MPI_THREAD_MULTIPLE
}
{
#if defined MPICH_IS_THREADED
    MPIR_T_is_threaded = (required == MPI_THREAD_MULTIPLE);
#endif /* MPICH_IS_THREADED */

    if (provided != NULL) {
        /* This must be min(required,MPICH_THREAD_LEVEL) if runtime
         * control of thread level is available */
        *provided = (MPICH_THREAD_LEVEL < required) ? MPICH_THREAD_LEVEL : required;
    }

    ++MPIR_T_init_balance;
    if (MPIR_T_init_balance == 1) {
        mpi_errno = MPIR_T_env_init();
        if (mpi_errno) {
            goto fn_fail;
        }
    }
}

MPI_T_pvar_get_index:
    .desc: Get the index of a performance variable
    .error: MPI_T_ERR_INVALID_NAME
{
    int seq = var_class - MPIR_T_PVAR_CLASS_FIRST;
    name2index_hash_t *hash_entry;

    /* Do hash lookup by the name */
    HASH_FIND_STR(pvar_hashs[seq], name, hash_entry);
    if (hash_entry != NULL) {
        *pvar_index = hash_entry->idx;
    } else {
        mpi_errno = MPI_T_ERR_INVALID_NAME;
        goto fn_fail;
    }
}

MPI_T_pvar_get_info:
    .desc: Get the information about a performance variable
    .skip: validate-ANY
    .error: MPI_T_ERR_INVALID_INDEX
{ -- error_check --
    MPIT_ERRTEST_CVAR_INDEX(pvar_index);
}
{
    pvar_table_entry_t *entry;
    entry = (pvar_table_entry_t *) utarray_eltptr(pvar_table, pvar_index);
    if (!entry->active) {
        mpi_errno = MPI_T_ERR_INVALID_INDEX;
        goto fn_fail;
    }

    pvar_table_entry_t *info;
    info = (pvar_table_entry_t *) utarray_eltptr(pvar_table, pvar_index);

    MPIR_T_strncpy(name, info->name, name_len);
    MPIR_T_strncpy(desc, info->desc, desc_len);

    if (verbosity != NULL)
        *verbosity = info->verbosity;

    if (var_class != NULL)
        *var_class = info->varclass;

    if (datatype != NULL)
        *datatype = info->datatype;

    if (enumtype != NULL)
        *enumtype = info->enumtype;

    if (bind != NULL)
        *bind = info->bind;

    if (readonly != NULL)
        *readonly = info->flags & MPIR_T_PVAR_FLAG_READONLY;

    if (continuous != NULL)
        *continuous = info->flags & MPIR_T_PVAR_FLAG_CONTINUOUS;

    if (atomic != NULL)
        *atomic = info->flags & MPIR_T_PVAR_FLAG_ATOMIC;
}

MPI_T_pvar_get_num:
    .desc: Get the number of performance variables
{
    *num_pvar = utarray_len(pvar_table);
}

MPI_T_pvar_handle_alloc:
    .desc: Allocate a handle for a performance variable
    .skip: validate-TOOL_MPI_OBJ
    .error: MPI_T_ERR_INVALID_INDEX, MPI_T_ERR_OUT_OF_HANDLES
{ -- error_check -- pvar_index
    pvar_table_entry_t *entry;
    entry = (pvar_table_entry_t *) utarray_eltptr(pvar_table, pvar_index);
    if (!entry->active) {
        mpi_errno = MPI_T_ERR_INVALID_INDEX;
        goto fn_fail;
    }
}

MPI_T_pvar_handle_free:
    .desc: Free an existing handle for a performance variable

MPI_T_pvar_read:
    .desc: Read the value of a performance variable

MPI_T_pvar_readreset:
    .desc: Read the value of a performance variable and then reset it
    .error: MPI_T_ERR_INVALID_HANDLE, MPI_T_ERR_PVAR_NO_ATOMIC
{ -- error_check --
     if (handle == MPI_T_PVAR_ALL_HANDLES || session != handle->session
	|| !MPIR_T_pvar_is_oncestarted(handle)) {
	mpi_errno = MPI_T_ERR_INVALID_HANDLE;
	goto fn_fail;
    }

    if (!MPIR_T_pvar_is_atomic(handle)) {
	mpi_errno = MPI_T_ERR_PVAR_NO_ATOMIC;
	goto fn_fail;
    }
}

MPI_T_pvar_reset:
    .desc: Reset a performance variable
    .error: MPI_T_ERR_INVALID_HANDLE, MPI_T_ERR_PVAR_NO_WRITE
{
    MPIR_T_pvar_handle_t *hnd;
    /* If handle is MPI_T_PVAR_ALL_HANDLES, dispatch the call.
     * Otherwise, do correctness check, then go to impl.
     */
    if (handle == MPI_T_PVAR_ALL_HANDLES) {
        DL_FOREACH(session->hlist, hnd) {
            if (!MPIR_T_pvar_is_readonly(hnd)) {
                mpi_errno = MPIR_T_pvar_reset_impl(session, hnd);
                if (mpi_errno != MPI_SUCCESS)
                    goto fn_fail;
            }
        }
    } else {
        if (handle->session != session) {
            mpi_errno = MPI_T_ERR_INVALID_HANDLE;
            goto fn_fail;
        }

        if (MPIR_T_pvar_is_readonly(handle)) {
            mpi_errno = MPI_T_ERR_PVAR_NO_WRITE;
            goto fn_fail;
        }

        mpi_errno = MPIR_T_pvar_reset_impl(session, handle);
        if (mpi_errno != MPI_SUCCESS)
            goto fn_fail;
    }
}

MPI_T_pvar_session_create:
    .desc: Create a new session for accessing performance variables
    .error: MPI_T_ERR_OUT_OF_SESSIONS

MPI_T_pvar_session_free:
    .desc: Free an existing performance variable session

MPI_T_pvar_start:
    .desc: Start a performance variable
    .error: MPI_T_ERR_INVALID_HANDLE, MPI_T_ERR_PVAR_NO_STARTSTOP
{
    if (handle == MPI_T_PVAR_ALL_HANDLES) {
        MPIR_T_pvar_handle_t *hnd;
        DL_FOREACH(session->hlist, hnd) {
            if (!MPIR_T_pvar_is_continuous(hnd) && !MPIR_T_pvar_is_started(hnd))
                mpi_errno = MPIR_T_pvar_start_impl(session, hnd);
        }
    } else {
        if (handle->session != session) {
            mpi_errno = MPI_T_ERR_INVALID_HANDLE;
            goto fn_fail;
        }
        if (MPIR_T_pvar_is_continuous(handle)) {
            mpi_errno = MPI_T_ERR_PVAR_NO_STARTSTOP;
            goto fn_fail;
        }

        if (!MPIR_T_pvar_is_started(handle)) {
            mpi_errno = MPIR_T_pvar_start_impl(session, handle);
            if (mpi_errno != MPI_SUCCESS)
                goto fn_fail;
        }
    }
}

MPI_T_pvar_stop:
    .desc: Stop a performance variable
    .error: MPI_T_ERR_INVALID_HANDLE, MPI_T_ERR_PVAR_NO_STARTSTOP
{
    /* If handle is MPI_T_PVAR_ALL_HANDLES, dispatch the call.
     * Otherwise, do correctness check, then go to impl.
     */
    if (handle == MPI_T_PVAR_ALL_HANDLES) {
        MPIR_T_pvar_handle_t *hnd;
        DL_FOREACH(session->hlist, hnd) {
            if (!MPIR_T_pvar_is_continuous(hnd) && MPIR_T_pvar_is_started(hnd)) {
                mpi_errno = MPIR_T_pvar_stop_impl(session, hnd);
                if (mpi_errno != MPI_SUCCESS)
                    goto fn_fail;
            }
        }
    } else {
        if (handle->session != session) {
            mpi_errno = MPI_T_ERR_INVALID_HANDLE;
            goto fn_fail;
        }
        if (MPIR_T_pvar_is_continuous(handle)) {
            mpi_errno = MPI_T_ERR_PVAR_NO_STARTSTOP;
            goto fn_fail;
        }

        if (MPIR_T_pvar_is_started(handle)) {
            mpi_errno = MPIR_T_pvar_stop_impl(session, handle);
            if (mpi_errno != MPI_SUCCESS)
                goto fn_fail;
        }
    }
}

MPI_T_pvar_write:
    .desc: Write a performance variable
    .error: MPI_T_ERR_PVAR_NO_WRITE
{ -- error_check --
    if (MPIR_T_pvar_is_readonly(handle)) {
        mpi_errno = MPI_T_ERR_PVAR_NO_WRITE;
        goto fn_fail;
    }
}

MPI_T_category_get_num_events:
    .desc: Returns the number of event types contained in the queried category.
    .error: MPI_T_ERR_INVALID_INDEX

MPI_T_category_get_events:
    .desc: Query which event types are contained in a particular category.
    .error: MPI_T_ERR_INVALID_INDEX

MPI_T_source_get_num:
    .desc: Query the number of event sources

MPI_T_source_get_info:
    .desc: Returns additional information on the source identified by the source_index argument
    .skip: validate-INFO, validate-SOURCE_INDEX
    .error: MPI_T_ERR_INVALID_INDEX

MPI_T_source_get_timestamp:
    .desc: Returns a current timestamp from the source identified by the source_index argument
    .skip: validate-SOURCE_INDEX
    .error: MPI_T_ERR_INVALID_INDEX, MPI_T_ERR_NOT_SUPPORTED

MPI_T_event_get_num:
    .desc: Query the number of event types

MPI_T_event_get_info:
    .desc: Returns additional information about a specific event type
    .skip: validate-STRING, validate-DATATYPE, validate-DISPLACEMENT_NNI, validate-ARRAY_LENGTH_NNI, validate-INFO, validate-EVENT_INDEX
    .error: MPI_T_ERR_INVALID_INDEX

MPI_T_event_get_index:
    .desc: Returns the index of an event type identified by a known event type name
    .error: MPI_T_ERR_INVALID_NAME

MPI_T_event_handle_alloc:
    .desc: Creates a registration handle for the event type identified by event_index
    .skip: validate-TOOL_MPI_OBJ, validate-EVENT_INDEX
    .error: MPI_T_ERR_INVALID_INDEX

MPI_T_event_handle_set_info:
    .desc: Updates the hints of the event-registration handle associated with event_registration

MPI_T_event_handle_get_info:
    .desc: Returns a new info object containing the hints of the event-registration handle associated with event_registration

MPI_T_event_register_callback:
    .desc: Associates a user-defined function with an allocated event-registration handle
    .skip: validate-CALLBACK_SAFETY, validate-EVENT_CB_FUNCTION

MPI_T_event_callback_set_info:
    .desc: Updates the hints of the callback function registered for the callback safety level specified by cb_safety of the event-registration handle associated with event_registration
    .skip: validate-CALLBACK_SAFETY

MPI_T_event_callback_get_info:
    .desc: Returns a new info object containing the hints of the callback function registered for the callback safety level specified by cb_safety of the event-registration handle associated with event_registration.
    .skip: validate-CALLBACK_SAFETY

MPI_T_event_handle_free:
    .desc: Initiates deallocation of the event-registration handle specified by event_registration
    .skip: validate-EVENT_FREE_CB_FUNCTION

MPI_T_event_set_dropped_handler:
    .desc: Registers a function to be called when event information is dropped for the registration handle specified in event_registration
    .skip: validate-EVENT_DROP_CB_FUNCTION

MPI_T_event_read:
    .desc: Copy one element of event data to a user-specified buffer

MPI_T_event_copy:
    .desc: Copy event data as a whole into a user-specified buffer

MPI_T_event_get_timestamp:
    .desc: Returns the timestamp of when the event was initially observed by the implementation

MPI_T_event_get_source:
    .desc: Returns the index of the source of the event instance
