aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJacob Erlbeck <jerlbeck@sysmocom.de>2015-07-14 11:35:21 +0200
committerJacob Erlbeck <jerlbeck@sysmocom.de>2015-07-16 19:24:13 +0200
commit5a2b8be3f5c9659cedb56855d2741accfdaeab3d (patch)
treeb52de4a174e185c8a372e8ff558e1c3a32f5da6f /src
parent2b558857dd720ea0a743d2656873a8c472ecd6b9 (diff)
alloc: Refactor alloc algorithms to only apply changes on success
Currently these algorithms modify other objects (MS, TBF, PDCH) even if the allocation will fail later on. To implement an algorithm that dynamically tries another algorithm on failure (e.g. A after B), the first (failing) algorithm should not change or damage anything. This commit refactors algorithm A and B to delay the actual allocation until it is known that the allocation will not fail. Ticket: #1934 Sponsored-by: On-Waves ehf
Diffstat (limited to 'src')
-rw-r--r--src/gprs_rlcmac_ts_alloc.cpp234
1 files changed, 150 insertions, 84 deletions
diff --git a/src/gprs_rlcmac_ts_alloc.cpp b/src/gprs_rlcmac_ts_alloc.cpp
index 22e03754..e1e00555 100644
--- a/src/gprs_rlcmac_ts_alloc.cpp
+++ b/src/gprs_rlcmac_ts_alloc.cpp
@@ -313,7 +313,7 @@ static void assign_dlink_tbf(
attach_tbf_to_pdch(pdch, tbf);
}
-static int find_trx(BTS *bts, GprsMs *ms, int use_trx)
+static int find_trx(BTS *bts, const GprsMs *ms, int use_trx)
{
unsigned trx_no;
unsigned ts;
@@ -347,8 +347,8 @@ static int find_trx(BTS *bts, GprsMs *ms, int use_trx)
return -EBUSY;
}
-static int tfi_find_free(BTS *bts, GprsMs *ms, enum gprs_rlcmac_tbf_direction dir,
- int use_trx, int *trx_no_)
+static int tfi_find_free(BTS *bts, const GprsMs *ms,
+ enum gprs_rlcmac_tbf_direction dir, int use_trx, int *trx_no_)
{
int tfi;
uint8_t trx_no;
@@ -371,8 +371,8 @@ static int tfi_find_free(BTS *bts, GprsMs *ms, enum gprs_rlcmac_tbf_direction di
* Assign single slot for uplink and downlink
*/
int alloc_algorithm_a(struct gprs_rlcmac_bts *bts,
- GprsMs *ms,
- struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single,
+ GprsMs *ms_,
+ struct gprs_rlcmac_tbf *tbf_, uint32_t cust, uint8_t single,
int use_trx)
{
struct gprs_rlcmac_pdch *pdch;
@@ -383,6 +383,9 @@ int alloc_algorithm_a(struct gprs_rlcmac_bts *bts,
int usf = -1;
int mask = 0xff;
const char *mask_reason = NULL;
+ const GprsMs *ms = ms_;
+ const gprs_rlcmac_tbf *tbf = tbf_;
+ gprs_rlcmac_trx *trx = ms->current_trx();
LOGP(DRLCMAC, LOGL_DEBUG, "Slot Allocation (Algorithm A) for class "
"%d\n", tbf->ms_class());
@@ -393,7 +396,8 @@ int alloc_algorithm_a(struct gprs_rlcmac_bts *bts,
"- Failed to find a usable TRX (TFI exhausted)\n");
return trx_no;
}
- tbf->trx = &bts->trx[trx_no];
+ if (!trx)
+ trx = &bts->trx[trx_no];
dl_slots = ms->reserved_dl_slots();
ul_slots = ms->reserved_ul_slots();
@@ -408,53 +412,56 @@ int alloc_algorithm_a(struct gprs_rlcmac_bts *bts,
mask = dl_slots & ul_slots;
}
- mask = find_possible_pdchs(tbf->trx, 1, mask, mask_reason);
+ mask = find_possible_pdchs(trx, 1, mask, mask_reason);
if (!mask)
return -EINVAL;
- ts = find_least_busy_pdch(tbf->trx, tbf->direction, mask,
+ ts = find_least_busy_pdch(trx, tbf->direction, mask,
compute_usage_by_reservation,
&tfi, &usf);
- if (ts < 0) {
+ if (tbf->direction == GPRS_RLCMAC_UL_TBF && usf < 0) {
LOGP(DRLCMAC, LOGL_NOTICE, "- Failed "
- "to allocate a TS, no TFI or USF available\n");
+ "to allocate a TS, no USF available\n");
return -EBUSY;
}
- pdch = &tbf->trx->pdch[ts];
- if (tbf->direction == GPRS_RLCMAC_UL_TBF) {
- struct gprs_rlcmac_ul_tbf *ul_tbf = static_cast<gprs_rlcmac_ul_tbf *>(tbf);
-
- if (usf < 0)
- usf = find_free_usf(pdch);
+ if (ts < 0) {
+ LOGP(DRLCMAC, LOGL_NOTICE, "- Failed "
+ "to allocate a TS, no TFI available\n");
+ return -EBUSY;
+ }
- if (usf < 0) {
- LOGP(DRLCMAC, LOGL_NOTICE, "- Failed "
- "allocating TS=%d, no USF available\n", ts);
- return -EBUSY;
- }
+ pdch = &trx->pdch[ts];
+ /* The allocation will be successful, so the system state and tbf_/ms_
+ * may be modified from now on. */
+ if (tbf->direction == GPRS_RLCMAC_UL_TBF) {
+ struct gprs_rlcmac_ul_tbf *ul_tbf =
+ static_cast<gprs_rlcmac_ul_tbf *>(tbf_);
LOGP(DRLCMAC, LOGL_DEBUG, "- Assign uplink TS=%d TFI=%d USF=%d\n",
ts, tfi, usf);
assign_uplink_tbf_usf(pdch, ul_tbf, tfi, usf);
} else {
- struct gprs_rlcmac_dl_tbf *dl_tbf = static_cast<gprs_rlcmac_dl_tbf *>(tbf);
+ struct gprs_rlcmac_dl_tbf *dl_tbf =
+ static_cast<gprs_rlcmac_dl_tbf *>(tbf_);
LOGP(DRLCMAC, LOGL_DEBUG, "- Assign downlink TS=%d TFI=%d\n",
ts, tfi);
assign_dlink_tbf(pdch, dl_tbf, tfi);
}
+
+ tbf_->trx = trx;
/* the only one TS is the common TS */
- tbf->first_ts = tbf->first_common_ts = ts;
- ms->set_reserved_slots(tbf->trx, 1 << ts, 1 << ts);
+ tbf_->first_ts = tbf_->first_common_ts = ts;
+ ms_->set_reserved_slots(trx, 1 << ts, 1 << ts);
- tbf->upgrade_to_multislot = 0;
+ tbf_->upgrade_to_multislot = 0;
return 0;
}
static int find_multi_slots(struct gprs_rlcmac_bts *bts,
struct gprs_rlcmac_trx *trx,
- GprsMs *ms, uint8_t *ul_slots, uint8_t *dl_slots)
+ const GprsMs *ms, uint8_t *ul_slots, uint8_t *dl_slots)
{
const struct gprs_ms_multislot_class *ms_class;
uint8_t Tx, Sum; /* Maximum Number of Slots: RX, Tx, Sum Rx+Tx */
@@ -768,52 +775,70 @@ static int find_multi_slots(struct gprs_rlcmac_bts *bts,
*
*/
int alloc_algorithm_b(struct gprs_rlcmac_bts *bts,
- GprsMs *ms,
- struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single, int use_trx)
+ GprsMs *ms_, struct gprs_rlcmac_tbf *tbf_,
+ uint32_t cust, uint8_t single, int use_trx)
{
- uint8_t dl_slots = 0;
- uint8_t ul_slots = 0;
+ uint8_t dl_slots;
+ uint8_t ul_slots;
+ uint8_t reserved_dl_slots;
+ uint8_t reserved_ul_slots;
int8_t first_common_ts;
uint8_t slotcount = 0;
uint8_t avail_count = 0;
char slot_info[9] = {0};
int ts;
+ int first_ts = -1;
+ int usf[8] = {-1, -1, -1, -1, -1, -1, -1, -1};
int rc;
+ int tfi;
int trx_no;
+ const GprsMs *ms = ms_;
+ const gprs_rlcmac_tbf *tbf = tbf_;
+ gprs_rlcmac_trx *trx;
- rc = tfi_find_free(bts->bts, ms, tbf->direction, use_trx, &trx_no);
- if (rc < 0) {
- LOGP(DRLCMAC, LOGL_NOTICE, "- Failed to allocate a TFI\n");
- return rc;
- }
- tbf->m_tfi = rc;
- tbf->trx = &bts->trx[trx_no];
+ /* Step 1: Get current state from the MS object */
if (!ms) {
LOGP(DRLCMAC, LOGL_ERROR, "MS not set\n");
return -EINVAL;
}
- dl_slots = ms->reserved_dl_slots();
- ul_slots = ms->reserved_ul_slots();
+ reserved_dl_slots = dl_slots = ms->reserved_dl_slots();
+ reserved_ul_slots = ul_slots = ms->reserved_ul_slots();
+ first_common_ts = ms->first_common_ts();
+ trx = ms->current_trx();
+
+ if (trx) {
+ if (use_trx >= 0 && use_trx != trx->trx_no) {
+ LOGP(DRLCMAC, LOGL_ERROR,
+ "- Requested incompatible TRX %d (current is %d)\n",
+ use_trx, trx->trx_no);
+ return -EINVAL;
+ }
+ use_trx = trx->trx_no;
+ }
+
+ /* Step 2a: Find usable TRX and TFI */
+ tfi = tfi_find_free(bts->bts, ms, tbf->direction, use_trx, &trx_no);
+ if (tfi < 0) {
+ LOGP(DRLCMAC, LOGL_NOTICE, "- Failed to allocate a TFI\n");
+ return tfi;
+ }
+
+ /* Step 2b: Reserve slots on the TRX for the MS */
+ if (!trx)
+ trx = &bts->trx[trx_no];
if (!dl_slots || !ul_slots) {
- rc = find_multi_slots(bts, tbf->trx, ms, &ul_slots, &dl_slots);
+ rc = find_multi_slots(bts, trx, ms, &ul_slots, &dl_slots);
if (rc < 0)
return rc;
- ms->set_reserved_slots(tbf->trx, ul_slots, dl_slots);
-
- LOGP(DRLCMAC, LOGL_DEBUG,
- "- Reserved DL/UL slots: (TS=0)\"%s\"(TS=7)\n",
- set_flag_chars(set_flag_chars(set_flag_chars(slot_info,
- dl_slots, 'D', '.'),
- ul_slots, 'U'),
- ul_slots & dl_slots, 'C'));
+ reserved_dl_slots = dl_slots;
+ reserved_ul_slots = ul_slots;
}
- first_common_ts = ms->first_common_ts();
-
+ /* Step 3: Derive the slot set for the current TBF */
if (single) {
/* Make sure to consider the first common slot only */
ul_slots = dl_slots = dl_slots & ul_slots;
@@ -821,7 +846,7 @@ int alloc_algorithm_b(struct gprs_rlcmac_bts *bts,
ts = first_common_ts;
if (ts < 0)
- ts = find_least_busy_pdch(tbf->trx, tbf->direction,
+ ts = find_least_busy_pdch(trx, tbf->direction,
dl_slots & ul_slots, compute_usage_by_num_tbfs,
NULL, NULL);
if (ts < 0)
@@ -841,12 +866,10 @@ int alloc_algorithm_b(struct gprs_rlcmac_bts *bts,
}
if (tbf->direction == GPRS_RLCMAC_DL_TBF) {
- struct gprs_rlcmac_dl_tbf *dl_tbf = static_cast<gprs_rlcmac_dl_tbf *>(tbf);
-
LOGP(DRLCMAC, LOGL_DEBUG,
"- Selected DL slots: (TS=0)\"%s\"(TS=7)%s\n",
set_flag_chars(set_flag_chars(slot_info,
- ms->reserved_dl_slots(), 'd', '.'),
+ reserved_dl_slots, 'd', '.'),
dl_slots, 'D'),
single ? ", single" : "");
@@ -856,21 +879,11 @@ int alloc_algorithm_b(struct gprs_rlcmac_bts *bts,
"available\n");
return -EINVAL;
}
- for (ts = 0; ts < 8; ts++) {
- if (!(dl_slots & (1 << ts)))
- continue;
-
- LOGP(DRLCMAC, LOGL_DEBUG, "- Assigning DL TS "
- "%d\n", ts);
- assign_dlink_tbf(&tbf->trx->pdch[ts], dl_tbf, tbf->tfi());
- slotcount++;
- if (slotcount == 1)
- dl_tbf->first_ts = ts;
- }
- avail_count = bitcount(ms->reserved_dl_slots());
+ slotcount = bitcount(dl_slots);
+ first_ts = ffs(dl_slots) - 1;
+ avail_count = bitcount(reserved_dl_slots);
} else {
- struct gprs_rlcmac_ul_tbf *ul_tbf = static_cast<gprs_rlcmac_ul_tbf *>(tbf);
int free_usf = -1;
if (first_common_ts >= 0)
@@ -878,7 +891,7 @@ int alloc_algorithm_b(struct gprs_rlcmac_bts *bts,
else
ul_slots = ul_slots & dl_slots;
- ts = find_least_busy_pdch(tbf->trx, GPRS_RLCMAC_UL_TBF,
+ ts = find_least_busy_pdch(trx, GPRS_RLCMAC_UL_TBF,
ul_slots, compute_usage_by_num_tbfs,
NULL, &free_usf);
@@ -886,26 +899,25 @@ int alloc_algorithm_b(struct gprs_rlcmac_bts *bts,
LOGP(DRLCMAC, LOGL_NOTICE, "No USF available\n");
return -EBUSY;
}
+ OSMO_ASSERT(ts >= 0 && ts <= 8);
+
ul_slots = 1 << ts;
+ usf[ts] = free_usf;
LOGP(DRLCMAC, LOGL_DEBUG,
"- Selected UL slots: (TS=0)\"%s\"(TS=7)%s\n",
set_flag_chars(set_flag_chars(slot_info,
- ms->reserved_ul_slots(), 'u', '.'),
+ reserved_ul_slots, 'u', '.'),
ul_slots, 'U'),
single ? ", single" : "");
- assign_uplink_tbf_usf(&tbf->trx->pdch[ts], ul_tbf,
- tbf->tfi(), free_usf);
slotcount++;
- ul_tbf->first_ts = ts;
+ first_ts = ts;
/* We will stick to that single UL slot, unreserve the others */
- if (ul_slots != ms->reserved_ul_slots())
- ms->set_reserved_slots(tbf->trx,
- ul_slots, ms->reserved_dl_slots());
+ reserved_ul_slots = ul_slots;
- avail_count = bitcount(ms->reserved_ul_slots());
+ avail_count = bitcount(reserved_ul_slots);
#if 0 /* This code assigns multiple slots for UL (and wastes USFs that way) */
for (ts = 0; ts < 8; ts++) {
if (!(ul_slots & (1 << ts)))
@@ -929,25 +941,79 @@ int alloc_algorithm_b(struct gprs_rlcmac_bts *bts,
#endif
}
+ first_common_ts = ffs(dl_slots & ul_slots) - 1;
+
+ if (first_common_ts < 0) {
+ LOGP(DRLCMAC, LOGL_NOTICE, "No first common slots available\n");
+ return -EINVAL;
+ }
+ if (first_ts < 0) {
+ LOGP(DRLCMAC, LOGL_NOTICE, "No first slot available\n");
+ return -EINVAL;
+ }
+
if (single && slotcount) {
- tbf->upgrade_to_multislot = (avail_count > slotcount);
+ tbf_->upgrade_to_multislot = (avail_count > slotcount);
LOGP(DRLCMAC, LOGL_INFO, "Using single slot at TS %d for %s\n",
- tbf->first_ts,
+ first_ts,
(tbf->direction == GPRS_RLCMAC_DL_TBF) ? "DL" : "UL");
} else {
- tbf->upgrade_to_multislot = 0;
+ tbf_->upgrade_to_multislot = 0;
LOGP(DRLCMAC, LOGL_INFO, "Using %d slots for %s\n", slotcount,
(tbf->direction == GPRS_RLCMAC_DL_TBF) ? "DL" : "UL");
}
- first_common_ts = ffs(dl_slots & ul_slots) - 1;
+ /* The allocation will be successful, so the system state and tbf_/ms_
+ * may be modified from now on. */
- if (first_common_ts < 0) {
- LOGP(DRLCMAC, LOGL_NOTICE, "No first common slots available\n");
- return -EINVAL;
+ /* Step 4: Update MS and TBF and really allocate the resources */
+
+ /* The reserved slots have changed, update the MS */
+ if (reserved_ul_slots != ms->reserved_ul_slots() ||
+ reserved_dl_slots != ms->reserved_dl_slots())
+ {
+ ms_->set_reserved_slots(trx,
+ reserved_ul_slots, reserved_dl_slots);
+
+ LOGP(DRLCMAC, LOGL_DEBUG,
+ "- Reserved DL/UL slots: (TS=0)\"%s\"(TS=7)\n",
+ set_flag_chars(set_flag_chars(set_flag_chars(slot_info,
+ dl_slots, 'D', '.'),
+ ul_slots, 'U'),
+ ul_slots & dl_slots, 'C'));
}
- tbf->first_common_ts = first_common_ts;
+ tbf_->trx = trx;
+ tbf_->first_common_ts = first_common_ts;
+ tbf_->first_ts = first_ts;
+
+ if (tbf->direction == GPRS_RLCMAC_DL_TBF) {
+ struct gprs_rlcmac_dl_tbf *dl_tbf =
+ static_cast<gprs_rlcmac_dl_tbf *>(tbf_);
+ for (ts = 0; ts < 8; ts++) {
+ if (!(dl_slots & (1 << ts)))
+ continue;
+
+ LOGP(DRLCMAC, LOGL_DEBUG, "- Assigning DL TS "
+ "%d\n", ts);
+ assign_dlink_tbf(&trx->pdch[ts], dl_tbf, tfi);
+ }
+ } else {
+ struct gprs_rlcmac_ul_tbf *ul_tbf =
+ static_cast<gprs_rlcmac_ul_tbf *>(tbf_);
+
+ for (ts = 0; ts < 8; ts++) {
+ if (!(ul_slots & (1 << ts)))
+ continue;
+
+ OSMO_ASSERT(usf[ts] >= 0);
+
+ LOGP(DRLCMAC, LOGL_DEBUG, "- Assigning UL TS "
+ "%d\n", ts);
+ assign_uplink_tbf_usf(&trx->pdch[ts], ul_tbf,
+ tfi, usf[ts]);
+ }
+ }
return 0;
}