Coverage Report

Created: 2025-07-23 07:05

/src/open5gs/lib/core/ogs-timer.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
3
 *
4
 * This file is part of Open5GS.
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU Affero General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
18
 */
19
20
#include "ogs-core.h"
21
22
#undef OGS_LOG_DOMAIN
23
0
#define OGS_LOG_DOMAIN __ogs_event_domain
24
25
typedef struct ogs_timer_mgr_s {
26
    OGS_POOL(pool, ogs_timer_t);
27
    ogs_rbtree_t tree;
28
} ogs_timer_mgr_t;
29
30
static void add_timer_node(
31
        ogs_rbtree_t *tree, ogs_timer_t *timer, ogs_time_t duration)
32
0
{
33
0
    ogs_rbnode_t **new = NULL;
34
0
    ogs_rbnode_t *parent = NULL;
35
0
    ogs_assert(tree);
36
0
    ogs_assert(timer);
37
38
0
    timer->timeout = ogs_get_monotonic_time() + duration;
39
40
0
    new = &tree->root;
41
0
    while (*new) {
42
0
        ogs_timer_t *this = ogs_rb_entry(*new, ogs_timer_t, rbnode);
43
44
0
        parent = *new;
45
0
        if (timer->timeout < this->timeout)
46
0
            new = &(*new)->left;
47
0
        else
48
0
            new = &(*new)->right;
49
0
    }
50
51
0
    ogs_rbtree_link_node(timer, parent, new);
52
0
    ogs_rbtree_insert_color(tree, timer);
53
0
}
54
55
ogs_timer_mgr_t *ogs_timer_mgr_create(unsigned int capacity)
56
0
{
57
0
    ogs_timer_mgr_t *manager = ogs_calloc(1, sizeof *manager);
58
0
    if (!manager) {
59
0
        ogs_error("ogs_calloc() failed");
60
0
        return NULL;
61
0
    }
62
63
0
    ogs_pool_init(&manager->pool, capacity);
64
65
0
    return manager;
66
0
}
67
68
void ogs_timer_mgr_destroy(ogs_timer_mgr_t *manager)
69
0
{
70
0
    ogs_assert(manager);
71
72
0
    ogs_pool_final(&manager->pool);
73
0
    ogs_free(manager);
74
0
}
75
76
ogs_timer_t *ogs_timer_add(
77
        ogs_timer_mgr_t *manager, void (*cb)(void *data), void *data)
78
0
{
79
0
    ogs_timer_t *timer = NULL;
80
0
    ogs_assert(manager);
81
82
0
    ogs_pool_alloc(&manager->pool, &timer);
83
0
    if (!timer) {
84
0
        ogs_fatal("ogs_pool_alloc() failed");
85
0
        return NULL;
86
0
    }
87
88
0
    memset(timer, 0, sizeof *timer);
89
0
    timer->cb = cb;
90
0
    timer->data = data;
91
92
0
    timer->manager = manager;
93
94
0
    return timer;
95
0
}
96
97
void ogs_timer_delete_debug(ogs_timer_t *timer, const char *file_line)
98
0
{
99
0
    ogs_timer_mgr_t *manager;
100
0
    ogs_assert(timer);
101
0
    manager = timer->manager;
102
0
    ogs_assert(manager);
103
104
0
    ogs_timer_stop(timer);
105
106
0
    ogs_pool_free(&manager->pool, timer);
107
0
}
108
109
void ogs_timer_start_debug(
110
        ogs_timer_t *timer, ogs_time_t duration, const char *file_line)
111
0
{
112
0
    ogs_timer_mgr_t *manager = NULL;
113
0
    ogs_assert(timer);
114
0
    ogs_assert(duration);
115
116
0
    manager = timer->manager;
117
0
    ogs_assert(manager);
118
119
0
    if (timer->running == true)
120
0
        ogs_rbtree_delete(&manager->tree, timer);
121
122
0
    timer->running = true;
123
0
    add_timer_node(&manager->tree, timer, duration);
124
0
}
125
126
void ogs_timer_stop_debug(ogs_timer_t *timer, const char *file_line)
127
0
{
128
0
    ogs_timer_mgr_t *manager = NULL;
129
0
    ogs_assert(timer);
130
0
    manager = timer->manager;
131
0
    ogs_assert(manager);
132
133
0
    if (timer->running == false)
134
0
        return;
135
136
0
    timer->running = false;
137
0
    ogs_rbtree_delete(&manager->tree, timer);
138
0
}
139
140
ogs_time_t ogs_timer_mgr_next(ogs_timer_mgr_t *manager)
141
0
{
142
0
    ogs_time_t current;
143
0
    ogs_rbnode_t *rbnode = NULL;
144
0
    ogs_assert(manager);
145
146
0
    current = ogs_get_monotonic_time();
147
0
    rbnode = ogs_rbtree_first(&manager->tree);
148
0
    if (rbnode) {
149
0
        ogs_timer_t *this = ogs_rb_entry(rbnode, ogs_timer_t, rbnode);
150
0
        if (this->timeout > current) {
151
0
            return (this->timeout - current);
152
0
        } else {
153
0
            return OGS_NO_WAIT_TIME;
154
0
        }
155
0
    }
156
157
0
    return OGS_INFINITE_TIME;
158
0
}
159
160
void ogs_timer_mgr_expire(ogs_timer_mgr_t *manager)
161
0
{
162
0
    OGS_LIST(list);
163
0
    ogs_lnode_t *lnode;
164
165
0
    ogs_time_t current;
166
0
    ogs_rbnode_t *rbnode;
167
0
    ogs_timer_t *this;
168
0
    ogs_assert(manager);
169
170
0
    current = ogs_get_monotonic_time();
171
172
0
    ogs_rbtree_for_each(&manager->tree, rbnode) {
173
0
        this = ogs_rb_entry(rbnode, ogs_timer_t, rbnode);
174
175
0
        if (this->timeout > current)
176
0
            break;
177
178
0
        ogs_list_add(&list, &this->lnode);
179
0
    }
180
181
    /* You should not perform a delete on a timer using ogs_timer_delete()
182
     * in a callback function this->cb(). */
183
0
    ogs_list_for_each(&list, lnode) {
184
0
        this = ogs_rb_entry(lnode, ogs_timer_t, lnode);
185
0
        ogs_timer_stop(this);
186
0
        if (this->cb)
187
0
            this->cb(this->data);
188
0
    }
189
0
}