Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/cond.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,14 @@ int ABT_cond_wait(ABT_cond cond, ABT_mutex mutex)
* Unlike other implementations of condition variables, a spurious wakeup never
* occurs.
*
* @note
* This function exhibits significantly higher CPU utilization than
* ABT_cond_wait() when blocking, even with the BASIC_WAIT scheduler. This
* is because Argobots lacks a user-space timeout mechanism, requiring
* continuous rescheduling of the caller to poll for `abstime`. The
* `--enable-sched-sleep` option can mitigate this, but it introduces a
* latency penalty for some workloads.
*
* @contexts
* \DOC_CONTEXT_ANY \DOC_CONTEXT_CTXSWITCH
*
Expand Down
104 changes: 104 additions & 0 deletions src/eventual.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,110 @@ int ABT_eventual_wait(ABT_eventual eventual, void **value)
return ABT_SUCCESS;
}

static inline double convert_timespec_to_sec(const struct timespec *p_ts)
{
double secs;
secs = ((double)p_ts->tv_sec) + 1.0e-9 * ((double)p_ts->tv_nsec);
return secs;
}

/**
* @ingroup EVENTUAL
* @brief Wait on an eventual with a timeout.
*
* \c ABT_eventual_timedwait() blocks the caller until the eventual \c eventual
* is signaled by \c ABT_eventual_set() or until the absolute timeout specified
* by \c abstime is reached. If the eventual is already ready when this function
* is called, the caller will not be blocked and the value will be returned
* immediately.
*
* If \c value is not \c NULL, \c value is set to the memory buffer of
* \c eventual. If \c value is not \c NULL but the size of the memory buffer of
* \c eventual (i.e., \c nbytes passed to \c ABT_eventual_create()) is zero,
* \c value is set to \c NULL.
*
* The memory buffer pointed to by \c value is deallocated when \c eventual is
* freed by \c ABT_eventual_free(). The memory buffer is properly aligned for
* storage of any type of object that has the given size. If the data written
* by \c ABT_eventual_set() is smaller than the size of the memory buffer of
* \c eventual, the contents of the memory buffer that was not written by
* \c ABT_eventual_set() are undefined. The contents of the memory buffer get
* undefined if either \c ABT_eventual_set() or \c ABT_eventual_reset() is
* called for \c eventual. The memory buffer is read-only, so rewriting the
* contents of the obtained memory buffer causes undefined behavior.
*
* \DOC_DESC_ATOMICITY_EVENTUAL_READINESS
*
* @changev20
* \DOC_DESC_V1X_NOTASK{\c ABT_ERR_EVENTUAL}
* @endchangev20
*
* @contexts
* \DOC_V1X \DOC_CONTEXT_INIT_NOTASK \DOC_CONTEXT_CTXSWITCH_CONDITIONAL{
* \c eventual is not ready}\n
* \DOC_V20 \DOC_CONTEXT_INIT \DOC_CONTEXT_CTXSWITCH_CONDITIONAL{\c eventual is
* not ready}
*
* @errors
* \DOC_ERROR_SUCCESS
* \DOC_ERROR_INV_EVENTUAL_HANDLE{\c eventual}
* \DOC_ERROR_COND_TIMEDOUT
* \DOC_V1X \DOC_ERROR_TASK{\c ABT_ERR_EVENTUAL}
*
* @undefined
* \DOC_UNDEFINED_UNINIT
* \DOC_UNDEFINED_NULL_PTR{\c abstime}
* \DOC_UNDEFINED_EVENTUAL_BUFFER{\c eventual, \c value}
*
* @param[in] eventual eventual handle
* @param[out] value memory buffer of the eventual
* @param[in] abstime absolute timeout
* @return Error code
*/
int ABT_eventual_timedwait(ABT_eventual eventual, void **value,
const struct timespec *abstime)
{
ABTI_UB_ASSERT(ABTI_initialized());
ABTI_UB_ASSERT(abstime);

ABTI_local *p_local = ABTI_local_get_local();
ABTI_eventual *p_eventual = ABTI_eventual_get_ptr(eventual);
ABTI_CHECK_NULL_EVENTUAL_PTR(p_eventual);

#ifndef ABT_CONFIG_ENABLE_VER_20_API
/* This routine cannot be called by a tasklet. */
if (ABTI_IS_ERROR_CHECK_ENABLED && p_local) {
ABTI_xstream *p_local_xstream = ABTI_local_get_xstream(p_local);
ABTI_CHECK_TRUE(p_local_xstream->p_thread->type &
ABTI_THREAD_TYPE_YIELDABLE,
ABT_ERR_EVENTUAL);
}
#endif

double tar_time = convert_timespec_to_sec(abstime);

ABTD_spinlock_acquire(&p_eventual->lock);
if (p_eventual->ready == ABT_FALSE) {
ABT_bool is_timedout =
ABTI_waitlist_wait_timedout_and_unlock(&p_local,
&p_eventual->waitlist,
&p_eventual->lock, tar_time,
ABT_SYNC_EVENT_TYPE_EVENTUAL,
(void *)p_eventual);
if (is_timedout) {
return ABT_ERR_COND_TIMEDOUT;
}
} else {
ABTD_spinlock_release(&p_eventual->lock);
}
/* This value is updated outside the critical section, but it is okay since
* the "pointer" to the memory buffer is constant and there is no way to
* avoid updating this memory buffer by ABT_eventual_set() etc. */
if (value)
*value = p_eventual->value;
return ABT_SUCCESS;
}

/**
* @ingroup EVENTUAL
* @brief Check if an eventual is ready.
Expand Down
7 changes: 5 additions & 2 deletions src/include/abt.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -333,9 +333,10 @@ extern "C" {
#define ABT_ERR_COND 41
/**
* @ingroup ERROR_CODE
* @brief Error code: a return value when a condition variable is timed out.
* @brief Error code: a return value when a timed wait operation times out.
*
* This error code is used by \c ABT_cond_timedwait().
* This error code is used by \c ABT_cond_timedwait() and
* \c ABT_eventual_timedwait().
*/
#define ABT_ERR_COND_TIMEDOUT 42
/**
Expand Down Expand Up @@ -2635,6 +2636,8 @@ int ABT_rwlock_unlock(ABT_rwlock rwlock) ABT_API_PUBLIC;
int ABT_eventual_create(int nbytes, ABT_eventual *neweventual) ABT_API_PUBLIC;
int ABT_eventual_free(ABT_eventual *eventual) ABT_API_PUBLIC;
int ABT_eventual_wait(ABT_eventual eventual, void **value) ABT_API_PUBLIC;
int ABT_eventual_timedwait(ABT_eventual eventual, void **value,
const struct timespec *abstime) ABT_API_PUBLIC;
int ABT_eventual_test(ABT_eventual eventual, void **value, ABT_bool *is_ready) ABT_API_PUBLIC;
int ABT_eventual_set(ABT_eventual eventual, void *value, int nbytes) ABT_API_PUBLIC;
int ABT_eventual_reset(ABT_eventual eventual) ABT_API_PUBLIC;
Expand Down
2 changes: 1 addition & 1 deletion src/include/abti_error.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

#define ABTI_STATIC_ASSERT(cond) \
do { \
((void)sizeof(char[2 * !!(cond)-1])); \
((void)sizeof(char[2 * !!(cond) - 1])); \
} while (0)

#ifdef ABT_CONFIG_PRINT_ABT_ERRNO
Expand Down
2 changes: 2 additions & 0 deletions test/basic/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ TESTS = \
eventual_create \
eventual_static \
eventual_test \
eventual_timedwait \
barrier \
self_exit_to \
self_rank_id \
Expand Down Expand Up @@ -177,6 +178,7 @@ future_create_SOURCES = future_create.c
eventual_create_SOURCES = eventual_create.c
eventual_static_SOURCES = eventual_static.c
eventual_test_SOURCES = eventual_test.c
eventual_timedwait_SOURCES = eventual_timedwait.c
barrier_SOURCES = barrier.c
self_exit_to_SOURCES = self_exit_to.c
self_rank_id_SOURCES = self_rank_id.c
Expand Down
Loading