/**
* Copyright (C) Mellanox Technologies Ltd. 2001-2014. ALL RIGHTS RESERVED.
*
* See file LICENSE for terms.
*/
#include "timerq.h"
#include <ucs/debug/log.h>
#include <ucs/debug/memtrack.h>
#include <ucs/sys/math.h>
#include <stdlib.h>
ucs_status_t ucs_timerq_init(ucs_timer_queue_t *timerq)
{
ucs_trace_func("timerq=%p", timerq);
ucs_spinlock_init(&timerq->lock);
timerq->timers = NULL;
timerq->num_timers = 0;
/* coverity[missing_lock] */
timerq->min_interval = UCS_TIME_INFINITY;
return UCS_OK;
}
void ucs_timerq_cleanup(ucs_timer_queue_t *timerq)
{
ucs_status_t status;
ucs_trace_func("timerq=%p", timerq);
if (timerq->num_timers > 0) {
ucs_warn("timer queue with %d timers being destroyed", timerq->num_timers);
}
ucs_free(timerq->timers);
status = ucs_spinlock_destroy(&timerq->lock);
if (status != UCS_OK) {
ucs_warn("ucs_spinlock_destroy() failed (%d)", status);
}
}
ucs_status_t ucs_timerq_add(ucs_timer_queue_t *timerq, int timer_id,
ucs_time_t interval)
{
ucs_status_t status;
ucs_timer_t *ptr;
ucs_trace_func("timerq=%p interval=%.2fus timer_id=%d", timerq,
ucs_time_to_usec(interval), timer_id);
ucs_spin_lock(&timerq->lock);
/* Make sure ID is unique */
for (ptr = timerq->timers; ptr < timerq->timers + timerq->num_timers; ++ptr) {
if (ptr->id == timer_id) {
status = UCS_ERR_ALREADY_EXISTS;
goto out_unlock;
}
}
/* Resize timer array */
ptr = ucs_realloc(timerq->timers, (timerq->num_timers + 1) * sizeof(ucs_timer_t),
"timerq");
if (ptr == NULL) {
status = UCS_ERR_NO_MEMORY;
goto out_unlock;
}
timerq->timers = ptr;
++timerq->num_timers;
timerq->min_interval = ucs_min(interval, timerq->min_interval);
ucs_assert(timerq->min_interval != UCS_TIME_INFINITY);
/* Initialize the new timer */
ptr = &timerq->timers[timerq->num_timers - 1];
ptr->expiration = 0; /* will fire the next time sweep is called */
ptr->interval = interval;
ptr->id = timer_id;
status = UCS_OK;
out_unlock:
ucs_spin_unlock(&timerq->lock);
return status;
}
ucs_status_t ucs_timerq_remove(ucs_timer_queue_t *timerq, int timer_id)
{
ucs_status_t status;
ucs_timer_t *ptr;
ucs_trace_func("timerq=%p timer_id=%d", timerq, timer_id);
status = UCS_ERR_NO_ELEM;
ucs_spin_lock(&timerq->lock);
timerq->min_interval = UCS_TIME_INFINITY;
ptr = timerq->timers;
while (ptr < timerq->timers + timerq->num_timers) {
if (ptr->id == timer_id) {
*ptr = timerq->timers[--timerq->num_timers];
status = UCS_OK;
} else {
timerq->min_interval = ucs_min(timerq->min_interval, ptr->interval);
++ptr;
}
}
/* TODO realloc - shrink */
if (timerq->num_timers == 0) {
ucs_assert(timerq->min_interval == UCS_TIME_INFINITY);
free(timerq->timers);
timerq->timers = NULL;
} else {
ucs_assert(timerq->min_interval != UCS_TIME_INFINITY);
}
ucs_spin_unlock(&timerq->lock);
return status;
}