test_alarmset.c revision 9a690580
1/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc.  See LICENSE. */
2#include <assert.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6#include <sys/queue.h>
7
8#include "lsquic.h"
9
10#include "lsquic_packet_common.h"
11#include "lsquic_alarmset.h"
12
13
14static lsquic_time_t global_now;
15
16static struct cb_ctx {
17    lsquic_time_t   last_expiry;
18    unsigned        n_calls;
19} global_ctx;
20
21
22static void
23alarm_cb (enum alarm_id al_id, void *ctx, lsquic_time_t expiry,
24                                                            lsquic_time_t now)
25{
26    struct cb_ctx *cb_ctx = ctx;
27    assert(cb_ctx == &global_ctx);
28    assert(cb_ctx->last_expiry <= expiry);  /* This checks sortedness */
29    assert(global_now == now);
30    ++cb_ctx->n_calls;
31    cb_ctx->last_expiry = expiry;
32}
33
34
35#if __GNUC__
36#   define popcount __builtin_popcount
37#else
38static int
39popcount (unsigned v)
40{
41    int count, i;
42    for (i = 0, count = 0; i < sizeof(v) * 8; ++i)
43        if (v & (1 << i))
44            ++count;
45    return count;
46}
47#endif
48
49
50int
51main (void)
52{
53    unsigned i;
54    lsquic_alarmset_t alset;
55
56    lsquic_alarmset_init(&alset, 0);
57
58    for (i = 0; i < MAX_LSQUIC_ALARMS; ++i)
59        lsquic_alarmset_init_alarm(&alset, i, alarm_cb, &global_ctx);
60
61    lsquic_alarmset_set(&alset, 0, 20);
62    lsquic_alarmset_set(&alset, 1,  5);
63    lsquic_alarmset_set(&alset, 2, 11);
64    lsquic_alarmset_set(&alset, 3, 15);
65
66    assert(lsquic_alarmset_is_set(&alset, 3));
67    lsquic_alarmset_unset(&alset, 3);
68    assert(!lsquic_alarmset_is_set(&alset, 3));
69    lsquic_alarmset_set(&alset, 3, 15);
70
71    global_ctx.last_expiry = 0;
72    global_ctx.n_calls     = 0;
73
74    lsquic_alarmset_ring_expired(&alset, global_now = 1);
75
76    assert(0 == global_ctx.n_calls);
77
78    assert(lsquic_alarmset_is_set(&alset, 1));
79    lsquic_alarmset_ring_expired(&alset, global_now = 10);
80    assert(!lsquic_alarmset_is_set(&alset, 1));
81
82    assert(1 == global_ctx.n_calls);
83    assert(5 == global_ctx.last_expiry);
84
85    lsquic_alarmset_ring_expired(&alset, global_now = 12);
86
87    assert(2 == global_ctx.n_calls);
88    assert(11 == global_ctx.last_expiry);
89
90    lsquic_alarmset_ring_expired(&alset, global_now = 20);
91
92    /* expiry must be strictly smaller than current time */
93    assert(3 == global_ctx.n_calls);
94    assert(15 == global_ctx.last_expiry);
95
96    lsquic_alarmset_ring_expired(&alset, global_now = 21);
97
98    assert(4 == global_ctx.n_calls);
99    assert(20 == global_ctx.last_expiry);
100
101    unsigned t = 1;
102    for (i = 1; i < (1u << MAX_LSQUIC_ALARMS); ++i)
103    {
104        alset.as_armed_set = 0;     /* Unset all */
105        unsigned const count = popcount(i);
106        unsigned const min_n = i % count;
107        unsigned const min_t = t++;
108        unsigned j, n, ids[2];
109        for (j = 0, n = 0; j < MAX_LSQUIC_ALARMS; ++j)
110        {
111            if ((1u << j) & i)
112            {
113                if (n == min_n)
114                {
115                    ids[0] = j;
116                    lsquic_alarmset_set(&alset, j, min_t);
117                }
118                else
119                    lsquic_alarmset_set(&alset, j, t++);
120                ++n;
121            }
122        }
123        lsquic_time_t found_min_t = lsquic_alarmset_mintime(&alset, &ids[1]);
124        assert(min_t == found_min_t);
125        assert(ids[0] == ids[1]);
126    }
127
128    return 0;
129}
130