paging: Store list of gsm_paging_request in bsc_subscr
This allows havily decreasing the algorithmic cost of removing all pending active paging requests for a given subscriber once it answers on a given BTS. Beforehand, the whole paging queue of all BTS were iterated. Now, only the active requests for that subscriber are iterated. Related: SYS#6200 Change-Id: I831d0fe01d7812c34500362b90f47cd65645b666
This commit is contained in:
parent
2709614011
commit
70a1d60a83
|
@ -10,6 +10,7 @@
|
|||
#include <osmocom/gsm/gsm48.h>
|
||||
|
||||
struct log_target;
|
||||
struct gsm_bts;
|
||||
|
||||
struct bsc_subscr {
|
||||
struct llist_head entry;
|
||||
|
@ -18,7 +19,8 @@ struct bsc_subscr {
|
|||
char imsi[GSM23003_IMSI_MAX_DIGITS+1];
|
||||
uint32_t tmsi;
|
||||
|
||||
uint32_t active_paging_requests;
|
||||
uint32_t active_paging_requests_len;
|
||||
struct llist_head active_paging_requests;
|
||||
};
|
||||
|
||||
const char *bsc_subscr_name(struct bsc_subscr *bsub);
|
||||
|
@ -51,3 +53,9 @@ void bsc_subscr_set_imsi(struct bsc_subscr *bsub, const char *imsi);
|
|||
|
||||
void log_set_filter_bsc_subscr(struct log_target *target,
|
||||
struct bsc_subscr *bsub);
|
||||
|
||||
struct gsm_paging_request;
|
||||
void bsc_subscr_add_active_paging_request(struct bsc_subscr *bsub, struct gsm_paging_request *req);
|
||||
void bsc_subscr_remove_active_paging_request(struct bsc_subscr *bsub, struct gsm_paging_request *req);
|
||||
void bsc_subscr_remove_active_paging_request_all(struct bsc_subscr *bsub);
|
||||
struct gsm_paging_request *bsc_subscr_find_req_by_bts(struct bsc_subscr *bsub, const struct gsm_bts *bts);
|
||||
|
|
|
@ -69,9 +69,10 @@ struct bsc_paging_params {
|
|||
struct gsm_paging_request {
|
||||
/* list_head for list of all paging requests */
|
||||
struct llist_head entry;
|
||||
/* the subscriber which we're paging. Later gsm_paging_request
|
||||
* should probably become a part of the bsc_subsrc struct? */
|
||||
/* the subscriber which we're paging. This struct is included using
|
||||
* bsub_entry field in list bsub->active_paging_requests */
|
||||
struct bsc_subscr *bsub;
|
||||
struct llist_head bsub_entry;
|
||||
/* back-pointer to the BTS on which we are paging */
|
||||
struct gsm_bts *bts;
|
||||
/* what kind of channel type do we ask the MS to establish */
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <osmocom/core/logging.h>
|
||||
|
||||
#include <osmocom/bsc/bsc_subscriber.h>
|
||||
#include <osmocom/bsc/paging.h>
|
||||
#include <osmocom/bsc/debug.h>
|
||||
|
||||
static void bsc_subscr_free(struct bsc_subscr *bsub);
|
||||
|
@ -77,6 +78,7 @@ static struct bsc_subscr *bsc_subscr_alloc(struct llist_head *list)
|
|||
.talloc_object = bsub,
|
||||
.use_cb = bsub_use_cb,
|
||||
};
|
||||
INIT_LLIST_HEAD(&bsub->active_paging_requests);
|
||||
|
||||
llist_add_tail(&bsub->entry, list);
|
||||
|
||||
|
@ -222,6 +224,7 @@ const char *bsc_subscr_id(struct bsc_subscr *bsub)
|
|||
|
||||
static void bsc_subscr_free(struct bsc_subscr *bsub)
|
||||
{
|
||||
OSMO_ASSERT(llist_empty(&bsub->active_paging_requests));
|
||||
llist_del(&bsub->entry);
|
||||
talloc_free(bsub);
|
||||
}
|
||||
|
@ -246,3 +249,41 @@ void log_set_filter_bsc_subscr(struct log_target *target,
|
|||
} else
|
||||
target->filter_map &= ~(1 << LOG_FLT_BSC_SUBSCR);
|
||||
}
|
||||
|
||||
void bsc_subscr_add_active_paging_request(struct bsc_subscr *bsub, struct gsm_paging_request *req)
|
||||
{
|
||||
bsub->active_paging_requests_len++;
|
||||
bsc_subscr_get(bsub, BSUB_USE_PAGING_REQUEST);
|
||||
llist_add_tail(&req->bsub_entry, &bsub->active_paging_requests);
|
||||
}
|
||||
|
||||
void bsc_subscr_remove_active_paging_request(struct bsc_subscr *bsub, struct gsm_paging_request *req)
|
||||
{
|
||||
llist_del(&req->bsub_entry);
|
||||
bsub->active_paging_requests_len--;
|
||||
bsc_subscr_put(bsub, BSUB_USE_PAGING_REQUEST);
|
||||
}
|
||||
|
||||
void bsc_subscr_remove_active_paging_request_all(struct bsc_subscr *bsub)
|
||||
{
|
||||
/* Avoid accessing bsub after reaching 0 active_paging_request_len,
|
||||
* since it could be freed during put(): */
|
||||
unsigned remaining = bsub->active_paging_requests_len;
|
||||
while (remaining > 0) {
|
||||
struct gsm_paging_request *req;
|
||||
req = llist_first_entry(&bsub->active_paging_requests,
|
||||
struct gsm_paging_request, bsub_entry);
|
||||
bsc_subscr_remove_active_paging_request(bsub, req);
|
||||
remaining--;
|
||||
}
|
||||
}
|
||||
|
||||
struct gsm_paging_request *bsc_subscr_find_req_by_bts(struct bsc_subscr *bsub, const struct gsm_bts *bts)
|
||||
{
|
||||
struct gsm_paging_request *req;
|
||||
llist_for_each_entry(req, &bsub->active_paging_requests, bsub_entry) {
|
||||
if (req->bts == bts)
|
||||
return req;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -86,11 +86,10 @@ static const struct timespec retrans_period = {
|
|||
static void paging_remove_request(struct gsm_bts_paging_state *paging_bts,
|
||||
struct gsm_paging_request *to_be_deleted)
|
||||
{
|
||||
to_be_deleted->bsub->active_paging_requests--;
|
||||
osmo_timer_del(&to_be_deleted->T3113);
|
||||
llist_del(&to_be_deleted->entry);
|
||||
paging_bts->pending_requests_len--;
|
||||
bsc_subscr_put(to_be_deleted->bsub, BSUB_USE_PAGING_REQUEST);
|
||||
bsc_subscr_remove_active_paging_request(to_be_deleted->bsub, to_be_deleted);
|
||||
talloc_free(to_be_deleted);
|
||||
if (llist_empty(&paging_bts->pending_requests))
|
||||
osmo_timer_del(&paging_bts->work_timer);
|
||||
|
@ -331,7 +330,7 @@ static void paging_T3113_expired(void *data)
|
|||
|
||||
/* If last BTS paging times out (active_paging_requests will be
|
||||
* decremented in paging_remove_request below): */
|
||||
if (req->bsub->active_paging_requests == 1)
|
||||
if (req->bsub->active_paging_requests_len == 1)
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->bsc_ctrs, BSC_CTR_PAGING_EXPIRED));
|
||||
|
||||
/* destroy it now. Do not access req afterwards */
|
||||
|
@ -444,17 +443,16 @@ static int _paging_request(const struct bsc_paging_params *params, struct gsm_bt
|
|||
}
|
||||
|
||||
LOG_PAGING_BTS(params, bts, DPAG, LOGL_DEBUG, "Start paging\n");
|
||||
params->bsub->active_paging_requests++;
|
||||
req = talloc_zero(tall_paging_ctx, struct gsm_paging_request);
|
||||
OSMO_ASSERT(req);
|
||||
req->reason = params->reason;
|
||||
req->bsub = params->bsub;
|
||||
bsc_subscr_get(req->bsub, BSUB_USE_PAGING_REQUEST);
|
||||
req->bts = bts;
|
||||
req->chan_type = params->chan_needed;
|
||||
req->pgroup = pgroup;
|
||||
req->msc = params->msc;
|
||||
osmo_timer_setup(&req->T3113, paging_T3113_expired, req);
|
||||
bsc_subscr_add_active_paging_request(req->bsub, req);
|
||||
|
||||
bts_entry->pending_requests_len++;
|
||||
/* there's no initial req (attempts==0), add to the start of the list */
|
||||
|
@ -517,36 +515,6 @@ int paging_request_bts(const struct bsc_paging_params *params, struct gsm_bts *b
|
|||
return 1;
|
||||
}
|
||||
|
||||
/*! Stop paging a given subscriber on a given BTS.
|
||||
* \param[out] returns the MSC that paged the subscriber, if any.
|
||||
* \param[out] returns the reason for a pending paging, if any.
|
||||
* \param[in] bts BTS which has received a paging response.
|
||||
* \param[in] bsub subscriber.
|
||||
* \returns whether active request for the subscriber on bts was found
|
||||
*/
|
||||
static bool paging_request_stop_bts(struct bsc_msc_data **msc_p, enum bsc_paging_reason *reason_p,
|
||||
struct gsm_bts *bts, struct bsc_subscr *bsub)
|
||||
{
|
||||
struct gsm_bts_paging_state *bts_entry = &bts->paging;
|
||||
struct gsm_paging_request *req, *req2;
|
||||
|
||||
*msc_p = NULL;
|
||||
*reason_p = BSC_PAGING_NONE;
|
||||
|
||||
llist_for_each_entry_safe(req, req2, &bts_entry->pending_requests,
|
||||
entry) {
|
||||
if (req->bsub != bsub)
|
||||
continue;
|
||||
*msc_p = req->msc;
|
||||
*reason_p = req->reason;
|
||||
LOG_PAGING_BTS(req, bts, DPAG, LOGL_DEBUG, "Stop paging\n");
|
||||
paging_remove_request(&bts->paging, req);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*! Stop paging on all cells and return the MSC that paged (if any) and all pending paging reasons.
|
||||
* \param[out] returns the MSC that paged the subscriber, if there was a pending request.
|
||||
* \param[out] returns the ORed bitmask of all reasons of pending pagings.
|
||||
|
@ -556,34 +524,39 @@ static bool paging_request_stop_bts(struct bsc_msc_data **msc_p, enum bsc_paging
|
|||
void paging_request_stop(struct bsc_msc_data **msc_p, enum bsc_paging_reason *reasons_p,
|
||||
struct gsm_bts *bts, struct bsc_subscr *bsub)
|
||||
{
|
||||
struct gsm_bts *bts_i;
|
||||
struct bsc_msc_data *paged_from_msc;
|
||||
enum bsc_paging_reason reasons;
|
||||
struct bsc_msc_data *paged_from_msc = NULL;
|
||||
enum bsc_paging_reason reasons = BSC_PAGING_NONE;
|
||||
OSMO_ASSERT(bts);
|
||||
struct gsm_paging_request *req = bsc_subscr_find_req_by_bts(bsub, bts);
|
||||
|
||||
paging_request_stop_bts(&paged_from_msc, &reasons, bts, bsub);
|
||||
if (paged_from_msc) {
|
||||
/* Avoid accessing bsub after reaching 0 active_paging_request_len,
|
||||
* since it could be freed during put(): */
|
||||
unsigned remaining = bsub->active_paging_requests_len;
|
||||
|
||||
if (req) {
|
||||
paged_from_msc = req->msc;
|
||||
reasons = req->reason;
|
||||
LOG_PAGING_BTS(req, bts, DPAG, LOGL_DEBUG, "Stop paging\n");
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_PAGING_RESPONDED));
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(bts->network->bsc_ctrs, BSC_CTR_PAGING_RESPONDED));
|
||||
paging_remove_request(&bts->paging, req);
|
||||
remaining--;
|
||||
}
|
||||
|
||||
llist_for_each_entry(bts_i, &bsc_gsmnet->bts_list, list) {
|
||||
struct bsc_msc_data *paged_from_msc2;
|
||||
enum bsc_paging_reason reason2;
|
||||
|
||||
if (bts_i == bts)
|
||||
continue; /* Already handled above, avoid repeated lookup */
|
||||
|
||||
paging_request_stop_bts(&paged_from_msc2, &reason2, bts_i, bsub);
|
||||
if (paged_from_msc2) {
|
||||
reasons |= reason2;
|
||||
if (!paged_from_msc) {
|
||||
/* If this happened, it would be a bit weird: it means there was no Paging Request
|
||||
* pending on the BTS that sent the Paging Reponse, but there *is* a Paging Request
|
||||
* pending on a different BTS. But why not return an MSC when we found one. */
|
||||
paged_from_msc = paged_from_msc2;
|
||||
}
|
||||
while (remaining > 0) {
|
||||
struct gsm_paging_request *req;
|
||||
req = llist_first_entry(&bsub->active_paging_requests,
|
||||
struct gsm_paging_request, bsub_entry);
|
||||
LOG_PAGING_BTS(req, bts, DPAG, LOGL_DEBUG, "Stop paging\n");
|
||||
reasons |= req->reason;
|
||||
if (!paged_from_msc) {
|
||||
/* If this happened, it would be a bit weird: it means there was no Paging Request
|
||||
* pending on the BTS that sent the Paging Response, but there *is* a Paging Request
|
||||
* pending on a different BTS. But why not return an MSC when we found one. */
|
||||
paged_from_msc = req->msc;
|
||||
}
|
||||
paging_remove_request(&bts->paging, req);
|
||||
remaining--;
|
||||
}
|
||||
|
||||
*msc_p = paged_from_msc;
|
||||
|
|
Loading…
Reference in New Issue