blob: b80fec94600beeeb857aff7dcfe9a038632c3988 [file] [log] [blame]
Neels Hofmeyrcbdfb782018-02-12 16:45:39 +01001/* (C) 2018 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
2 *
3 * All Rights Reserved
4 *
5 * Author: Neels Hofmeyr <nhofmeyr@sysmocom.de>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include <talloc.h>
23#include <time.h>
24#include <stdint.h>
25
26#include <osmocom/core/linuxlist.h>
27
28#include <osmocom/bsc/penalty_timers.h>
29#include <osmocom/bsc/gsm_data.h>
30
31struct penalty_timers {
32 struct llist_head timers;
33};
34
35struct penalty_timer {
36 struct llist_head entry;
37 void *for_object;
38 unsigned int timeout;
39};
40
41static unsigned int time_now(void)
42{
43 time_t now;
44 time(&now);
45 /* FIXME: use monotonic clock */
46 return (unsigned int)now;
47}
48
49struct penalty_timers *penalty_timers_init(void *ctx)
50{
51 struct penalty_timers *pt = talloc_zero(ctx, struct penalty_timers);
52 if (!pt)
53 return NULL;
54 INIT_LLIST_HEAD(&pt->timers);
55 return pt;
56}
57
58void penalty_timers_add(struct penalty_timers *pt, void *for_object, int timeout)
59{
60 struct penalty_timer *timer;
61 unsigned int now;
62 unsigned int then;
63 now = time_now();
64
65 if (timeout <= 0)
66 return;
67
68 then = now + timeout;
69
70 /* timer already running for that BTS? */
71 llist_for_each_entry(timer, &pt->timers, entry) {
72 if (timer->for_object != for_object)
73 continue;
74 /* raise, if running timer will timeout earlier or has timed
75 * out already, otherwise keep later timeout */
76 if (timer->timeout < then)
77 timer->timeout = then;
78 return;
79 }
80
81 /* add new timer */
82 timer = talloc_zero(pt, struct penalty_timer);
83 if (!timer)
84 return;
85
86 timer->for_object = for_object;
87 timer->timeout = then;
88
89 llist_add_tail(&timer->entry, &pt->timers);
90}
91
92unsigned int penalty_timers_remaining(struct penalty_timers *pt, void *for_object)
93{
94 struct penalty_timer *timer;
95 unsigned int now = time_now();
96 unsigned int max_remaining = 0;
97 llist_for_each_entry(timer, &pt->timers, entry) {
98 unsigned int remaining;
99 if (timer->for_object != for_object)
100 continue;
101 if (now >= timer->timeout)
102 continue;
103 remaining = timer->timeout - now;
104 if (remaining > max_remaining)
105 max_remaining = remaining;
106 }
107 return max_remaining;
108}
109
110void penalty_timers_clear(struct penalty_timers *pt, void *for_object)
111{
112 struct penalty_timer *timer, *timer2;
113 llist_for_each_entry_safe(timer, timer2, &pt->timers, entry) {
114 if (for_object && timer->for_object != for_object)
115 continue;
116 llist_del(&timer->entry);
117 talloc_free(timer);
118 }
119}
120
121void penalty_timers_free(struct penalty_timers **pt_p)
122{
123 struct penalty_timers *pt = *pt_p;
124 if (!pt)
125 return;
126 penalty_timers_clear(pt, NULL);
127 talloc_free(pt);
128 *pt_p = NULL;
129}