aboutsummaryrefslogtreecommitdiffstats
path: root/src/osmo-bsc/penalty_timers.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/osmo-bsc/penalty_timers.c')
-rw-r--r--src/osmo-bsc/penalty_timers.c121
1 files changed, 75 insertions, 46 deletions
diff --git a/src/osmo-bsc/penalty_timers.c b/src/osmo-bsc/penalty_timers.c
index 02cf2468a..124a36255 100644
--- a/src/osmo-bsc/penalty_timers.c
+++ b/src/osmo-bsc/penalty_timers.c
@@ -28,34 +28,22 @@
#include <osmocom/bsc/penalty_timers.h>
#include <osmocom/bsc/gsm_data.h>
-struct penalty_timers {
- struct llist_head timers;
-};
-
-struct penalty_timer {
- struct llist_head entry;
- const void *for_object;
- unsigned int timeout;
-};
-
static unsigned int time_now(void)
{
- time_t now;
- time(&now);
- /* FIXME: use monotonic clock */
- return (unsigned int)now;
-}
-
-struct penalty_timers *penalty_timers_init(void *ctx)
-{
- struct penalty_timers *pt = talloc_zero(ctx, struct penalty_timers);
- if (!pt)
- return NULL;
- INIT_LLIST_HEAD(&pt->timers);
- return pt;
+ struct timespec tp;
+ if (osmo_clock_gettime(CLOCK_MONOTONIC, &tp))
+ return 0;
+ return (unsigned int)tp.tv_sec;
}
-void penalty_timers_add(struct penalty_timers *pt, const void *for_object, int timeout)
+/* Add a penalty timer for a target cell ID.
+ * \param ctx talloc context to allocate new struct penalty_timer from.
+ * \param penalty_timers llist head to add penalty timer to.
+ * \param for_target_cell Which handover target to penalize.
+ * \param timeout Penalty time in seconds.
+ */
+void penalty_timers_add(void *ctx, struct llist_head *penalty_timers,
+ const struct gsm0808_cell_id *for_target_cell, int timeout)
{
struct penalty_timer *timer;
unsigned int now;
@@ -67,9 +55,9 @@ void penalty_timers_add(struct penalty_timers *pt, const void *for_object, int t
then = now + timeout;
- /* timer already running for that BTS? */
- llist_for_each_entry(timer, &pt->timers, entry) {
- if (timer->for_object != for_object)
+ /* timer already running for that target cell? */
+ llist_for_each_entry(timer, penalty_timers, entry) {
+ if (!gsm0808_cell_ids_match(&timer->for_target_cell, for_target_cell, true))
continue;
/* raise, if running timer will timeout earlier or has timed
* out already, otherwise keep later timeout */
@@ -79,24 +67,49 @@ void penalty_timers_add(struct penalty_timers *pt, const void *for_object, int t
}
/* add new timer */
- timer = talloc_zero(pt, struct penalty_timer);
+ timer = talloc_zero(ctx, struct penalty_timer);
if (!timer)
return;
- timer->for_object = for_object;
+ timer->for_target_cell = *for_target_cell;
timer->timeout = then;
- llist_add_tail(&timer->entry, &pt->timers);
+ llist_add_tail(&timer->entry, penalty_timers);
}
-unsigned int penalty_timers_remaining(struct penalty_timers *pt, const void *for_object)
+/* Add a penalty timer for each target cell ID in the given list.
+ * \param ctx talloc context to allocate new struct penalty_timer from.
+ * \param penalty_timers llist head to add penalty timer to.
+ * \param for_target_cells Which handover targets to penalize.
+ * \param timeout Penalty time in seconds.
+ */
+void penalty_timers_add_list(void *ctx, struct llist_head *penalty_timers,
+ const struct gsm0808_cell_id_list2 *for_target_cells, int timeout)
+{
+ int i;
+ for (i = 0; i < for_target_cells->id_list_len; i++) {
+ struct gsm0808_cell_id add = {
+ .id_discr = for_target_cells->id_discr,
+ .id = for_target_cells->id_list[i],
+ };
+ penalty_timers_add(ctx, penalty_timers, &add, timeout);
+ }
+}
+
+/* Return the amount of penalty time in seconds remaining for a target cell.
+ * \param penalty_timers llist head to look up penalty time in.
+ * \param for_target_cell Which handover target to query.
+ * \returns seconds remaining until all penalty time has expired.
+ */
+unsigned int penalty_timers_remaining(struct llist_head *penalty_timers,
+ const struct gsm0808_cell_id *for_target_cell)
{
struct penalty_timer *timer;
unsigned int now = time_now();
unsigned int max_remaining = 0;
- llist_for_each_entry(timer, &pt->timers, entry) {
+ llist_for_each_entry(timer, penalty_timers, entry) {
unsigned int remaining;
- if (timer->for_object != for_object)
+ if (!gsm0808_cell_ids_match(&timer->for_target_cell, for_target_cell, true))
continue;
if (now >= timer->timeout)
continue;
@@ -107,23 +120,39 @@ unsigned int penalty_timers_remaining(struct penalty_timers *pt, const void *for
return max_remaining;
}
-void penalty_timers_clear(struct penalty_timers *pt, const void *for_object)
+/* Return the largest amount of penalty time in seconds remaining for any one of the given target cells.
+ * Call penalty_timers_remaining() for each entry of for_target_cells and return the largest value encountered.
+ * \param penalty_timers llist head to look up penalty time in.
+ * \param for_target_cells Which handover targets to query.
+ * \returns seconds remaining until all penalty time has expired.
+ */
+unsigned int penalty_timers_remaining_list(struct llist_head *penalty_timers,
+ const struct gsm0808_cell_id_list2 *for_target_cells)
+{
+ int i;
+ unsigned int max_remaining = 0;
+ for (i = 0; i < for_target_cells->id_list_len; i++) {
+ unsigned int remaining;
+ struct gsm0808_cell_id query = {
+ .id_discr = for_target_cells->id_discr,
+ .id = for_target_cells->id_list[i],
+ };
+ remaining = penalty_timers_remaining(penalty_timers, &query);
+ max_remaining = OSMO_MAX(max_remaining, remaining);
+ }
+ return max_remaining;
+}
+
+/* Clear penalty timers for one target cell, or completely clear the entire list.
+ * \param penalty_timers llist head to add penalty timer to.
+ * \param for_target_cell Which handover target to clear timers for, or NULL to clear all timers. */
+void penalty_timers_clear(struct llist_head *penalty_timers, const struct gsm0808_cell_id *for_target_cell)
{
struct penalty_timer *timer, *timer2;
- llist_for_each_entry_safe(timer, timer2, &pt->timers, entry) {
- if (for_object && timer->for_object != for_object)
+ llist_for_each_entry_safe(timer, timer2, penalty_timers, entry) {
+ if (for_target_cell && !gsm0808_cell_ids_match(&timer->for_target_cell, for_target_cell, true))
continue;
llist_del(&timer->entry);
talloc_free(timer);
}
}
-
-void penalty_timers_free(struct penalty_timers **pt_p)
-{
- struct penalty_timers *pt = *pt_p;
- if (!pt)
- return;
- penalty_timers_clear(pt, NULL);
- talloc_free(pt);
- *pt_p = NULL;
-}