diff options
Diffstat (limited to 'src/osmo-bsc/penalty_timers.c')
-rw-r--r-- | src/osmo-bsc/penalty_timers.c | 121 |
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; -} |