margo-timer.c 3.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

/*
 * (C) 2016 The University of Chicago
 * 
 * See COPYRIGHT in top-level directory.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>

#include <abt.h>
#include "margo-timer.h"
#include "utlist.h"


Shane Snyder's avatar
Shane Snyder committed
19
static void margo_timer_queue(margo_timer_t *timer);
20 21 22


static ABT_mutex timer_mutex = ABT_MUTEX_NULL;
Shane Snyder's avatar
Shane Snyder committed
23
static margo_timer_t *timer_head = NULL;
24

Shane Snyder's avatar
Shane Snyder committed
25
void margo_timer_sys_init()
26 27 28 29 30
{
    ABT_mutex_create(&timer_mutex);
    return;
}

Shane Snyder's avatar
Shane Snyder committed
31
void margo_timer_sys_shutdown()
32
{
Shane Snyder's avatar
Shane Snyder committed
33
    margo_timer_t *cur;
34 35 36 37 38

    if(timer_mutex == ABT_MUTEX_NULL)
        return;

    ABT_mutex_lock(timer_mutex);
Shane Snyder's avatar
Shane Snyder committed
39
    /* delete any remaining timers from the queue */
40 41 42 43 44 45 46 47
    while(timer_head)
    {
        cur = timer_head;
        DL_DELETE(timer_head, cur);
    }
    ABT_mutex_unlock(timer_mutex);
    ABT_mutex_free(&timer_mutex);
    timer_mutex = ABT_MUTEX_NULL;
Shane Snyder's avatar
Shane Snyder committed
48

49 50 51
    return;
}

Shane Snyder's avatar
Shane Snyder committed
52 53
void margo_timer_init(
    margo_timer_t *timer,
54 55
    margo_timer_cb_fn cb_fn,
    void *cb_dat,
Shane Snyder's avatar
Shane Snyder committed
56
    double timeout_ms)
57
{
Shane Snyder's avatar
Shane Snyder committed
58 59
    assert(timer_mutex != ABT_MUTEX_NULL);
    assert(timer);
60

Shane Snyder's avatar
Shane Snyder committed
61 62 63 64 65
    memset(timer, 0, sizeof(*timer));
    timer->cb_fn = cb_fn;
    timer->cb_dat = cb_dat;
    timer->expiration = ABT_get_wtime() + (timeout_ms/1000);
    timer->prev = timer->next = NULL;
66

Shane Snyder's avatar
Shane Snyder committed
67
    margo_timer_queue(timer);
68 69 70 71

    return;
}

Shane Snyder's avatar
Shane Snyder committed
72 73
void margo_timer_destroy(
    margo_timer_t *timer)
74 75
{
    assert(timer_mutex != ABT_MUTEX_NULL);
Shane Snyder's avatar
Shane Snyder committed
76
    assert(timer);
77 78

    ABT_mutex_lock(timer_mutex);
Shane Snyder's avatar
Shane Snyder committed
79 80
    if(timer->prev || timer->next)
        DL_DELETE(timer_head, timer);
81 82
    ABT_mutex_unlock(timer_mutex);

83 84 85 86 87
    return;
}

void margo_check_timers()
{
Shane Snyder's avatar
Shane Snyder committed
88
    margo_timer_t *cur;
89 90 91 92 93 94 95 96 97 98 99 100 101
    double now = ABT_get_wtime();

    assert(timer_mutex != ABT_MUTEX_NULL);

    ABT_mutex_lock(timer_mutex);

    /* iterate through timer list, performing timeout action
     * for all elements which have passed expiration time
     */
    while(timer_head && (timer_head->expiration < now))
    {
        cur = timer_head;
        DL_DELETE(timer_head, cur);
Shane Snyder's avatar
Shane Snyder committed
102
        cur->prev = cur->next = NULL;
103 104 105 106 107 108 109 110 111

        /* execute callback */
        cur->cb_fn(cur->cb_dat);
    }
    ABT_mutex_unlock(timer_mutex);

    return;
}

Shane Snyder's avatar
Shane Snyder committed
112
static void margo_timer_queue(margo_timer_t *timer)
113
{
Shane Snyder's avatar
Shane Snyder committed
114
    margo_timer_t *cur;
115 116 117 118 119 120

    ABT_mutex_lock(timer_mutex);

    /* if list of timers is empty, put ourselves on it */
    if(!timer_head)
    {
Shane Snyder's avatar
Shane Snyder committed
121
        DL_APPEND(timer_head, timer);
122 123 124 125 126 127 128 129 130 131 132 133 134 135
    }
    else
    {
        /* something else already in queue, keep it sorted in ascending order
         * of expiration time
         */
        cur = timer_head;
        do
        {
            /* walk backwards through queue */
            cur = cur->prev;
            /* as soon as we find an element that expires before this one, 
             * then we add ours after it
             */
Shane Snyder's avatar
Shane Snyder committed
136
            if(cur->expiration < timer->expiration)
137
            {
Shane Snyder's avatar
Shane Snyder committed
138
                DL_APPEND_ELEM(timer_head, cur, timer);
139 140 141 142 143 144 145
                break;
            }
        }while(cur != timer_head);

        /* if we never found one with an expiration before this one, then
         * this one is the new head
         */
Shane Snyder's avatar
Shane Snyder committed
146 147
        if(timer->prev == NULL && timer->next == NULL)
            DL_PREPEND(timer_head, timer);
148 149 150 151 152 153
    }
    ABT_mutex_unlock(timer_mutex);

    return;
}