tbf: Use C++/talloc magic to support TBF constructors/destructors

The TBF object are currently created by using talloc_zero/talloc_free
directly from plain functions. Therefore C++ constructors and destructors
are not called. So the only initialisation that is done is setting
every member to 0. Non POD members do not have their constructors
called either, which makes it impossible to use the current LListHead
class for real members when the LListHead::m_back member has to be set.

This commit changes the TBF allocation functions to call the
corresponding C++ constructor after the call to talloc_zero and to
register the C++ destructor with the talloc context, so that is is
called before talloc_free actually frees the memory.

With this change, non-POD members and custom
constructors/desctructors can be used with gprs_rlcmac_tbf,
gprs_rlcmac_dl_tbf, and gprs_rlcmac_ul_tbf.

Note that this change is only a single step of the plan to turn the
TBF classes into real C++ classes.

Sponsored-by: On-Waves ehf
diff --git a/src/tbf.cpp b/src/tbf.cpp
index 2e6da02..9d4363f 100644
--- a/src/tbf.cpp
+++ b/src/tbf.cpp
@@ -41,6 +41,11 @@
 
 static void tbf_timer_cb(void *_tbf);
 
+gprs_rlcmac_tbf::gprs_rlcmac_tbf(gprs_rlcmac_tbf_direction dir) :
+	direction(dir)
+{
+}
+
 gprs_rlcmac_bts *gprs_rlcmac_tbf::bts_data() const
 {
 	return bts->bts_data();
@@ -523,6 +528,17 @@
 	return 0;
 }
 
+gprs_rlcmac_ul_tbf::gprs_rlcmac_ul_tbf() :
+	gprs_rlcmac_tbf(GPRS_RLCMAC_UL_TBF)
+{
+};
+
+static int ul_tbf_dtor(struct gprs_rlcmac_ul_tbf *tbf)
+{
+	tbf->~gprs_rlcmac_ul_tbf();
+	return 0;
+}
+
 
 struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts,
 	GprsMs *ms, int8_t use_trx,
@@ -540,7 +556,8 @@
 	if (!tbf)
 		return NULL;
 
-	tbf->direction = GPRS_RLCMAC_UL_TBF;
+	talloc_set_destructor(tbf, ul_tbf_dtor);
+	new (tbf) gprs_rlcmac_ul_tbf();
 
 	if (!ms)
 		ms = bts->bts->ms_alloc(ms_class);
@@ -558,6 +575,17 @@
 	return tbf;
 }
 
+gprs_rlcmac_dl_tbf::gprs_rlcmac_dl_tbf() :
+	gprs_rlcmac_tbf(GPRS_RLCMAC_DL_TBF)
+{
+};
+
+static int dl_tbf_dtor(struct gprs_rlcmac_dl_tbf *tbf)
+{
+	tbf->~gprs_rlcmac_dl_tbf();
+	return 0;
+}
+
 struct gprs_rlcmac_dl_tbf *tbf_alloc_dl_tbf(struct gprs_rlcmac_bts *bts,
 	GprsMs *ms, int8_t use_trx,
 	uint8_t ms_class, uint8_t single_slot)
@@ -574,7 +602,8 @@
 	if (!tbf)
 		return NULL;
 
-	tbf->direction = GPRS_RLCMAC_DL_TBF;
+	talloc_set_destructor(tbf, dl_tbf_dtor);
+	new (tbf) gprs_rlcmac_dl_tbf();
 
 	if (!ms)
 		ms = bts->bts->ms_alloc(ms_class);
diff --git a/src/tbf.h b/src/tbf.h
index a596ad7..f1484f0 100644
--- a/src/tbf.h
+++ b/src/tbf.h
@@ -110,6 +110,7 @@
 		     prefetch(pos->member.list.next))
 
 struct gprs_rlcmac_tbf {
+	gprs_rlcmac_tbf(gprs_rlcmac_tbf_direction dir);
 
 	static void free_all(struct gprs_rlcmac_trx *trx);
 	static void free_all(struct gprs_rlcmac_pdch *pdch);
@@ -306,6 +307,8 @@
 }
 
 struct gprs_rlcmac_dl_tbf : public gprs_rlcmac_tbf {
+	gprs_rlcmac_dl_tbf();
+
 	void cleanup();
 
 	/* dispatch Unitdata.DL messages */
@@ -371,6 +374,8 @@
 };
 
 struct gprs_rlcmac_ul_tbf : public gprs_rlcmac_tbf {
+	gprs_rlcmac_ul_tbf();
+
 	struct msgb *create_ul_ack(uint32_t fn);
 
 	/* blocks were acked */
diff --git a/tests/ms/MsTest.cpp b/tests/ms/MsTest.cpp
index 5a25d76..7255da3 100644
--- a/tests/ms/MsTest.cpp
+++ b/tests/ms/MsTest.cpp
@@ -55,9 +55,9 @@
 	OSMO_ASSERT(ms->is_idle());
 
 	dl_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf);
-	dl_tbf->direction = GPRS_RLCMAC_DL_TBF;
+	new (dl_tbf) gprs_rlcmac_dl_tbf();
 	ul_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_ul_tbf);
-	ul_tbf->direction = GPRS_RLCMAC_UL_TBF;
+	new (ul_tbf) gprs_rlcmac_ul_tbf();
 
 	ms->attach_tbf(ul_tbf);
 	OSMO_ASSERT(!ms->is_idle());
@@ -116,9 +116,9 @@
 	OSMO_ASSERT(ms->is_idle());
 
 	dl_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf);
-	dl_tbf->direction = GPRS_RLCMAC_DL_TBF;
+	new (dl_tbf) gprs_rlcmac_dl_tbf();
 	ul_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_ul_tbf);
-	ul_tbf->direction = GPRS_RLCMAC_UL_TBF;
+	new (ul_tbf) gprs_rlcmac_ul_tbf();
 
 	OSMO_ASSERT(last_cb == UNKNOWN);
 
@@ -186,11 +186,11 @@
 	was_idle = false;
 
 	dl_tbf[0] = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf);
-	dl_tbf[0]->direction = GPRS_RLCMAC_DL_TBF;
+	new (dl_tbf[0]) gprs_rlcmac_dl_tbf();
 	dl_tbf[1] = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf);
-	dl_tbf[1]->direction = GPRS_RLCMAC_DL_TBF;
+	new (dl_tbf[1]) gprs_rlcmac_dl_tbf();
 	ul_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_ul_tbf);
-	ul_tbf->direction = GPRS_RLCMAC_UL_TBF;
+	new (ul_tbf) gprs_rlcmac_ul_tbf();
 
 	ms->attach_tbf(dl_tbf[0]);
 	OSMO_ASSERT(!ms->is_idle());
@@ -343,7 +343,7 @@
 	printf("=== start %s ===\n", __func__);
 
 	ul_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_ul_tbf);
-	ul_tbf->direction = GPRS_RLCMAC_UL_TBF;
+	new (ul_tbf) gprs_rlcmac_ul_tbf();
 
 	ms = store.get_ms(tlli + 0);
 	OSMO_ASSERT(ms == NULL);
@@ -434,9 +434,9 @@
 	OSMO_ASSERT(ms->is_idle());
 
 	dl_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf);
-	dl_tbf->direction = GPRS_RLCMAC_DL_TBF;
+	new (dl_tbf) gprs_rlcmac_dl_tbf();
 	ul_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_ul_tbf);
-	ul_tbf->direction = GPRS_RLCMAC_UL_TBF;
+	new (ul_tbf) gprs_rlcmac_ul_tbf();
 
 	OSMO_ASSERT(last_cb == UNKNOWN);
 
@@ -492,7 +492,7 @@
 	OSMO_ASSERT(ms->is_idle());
 
 	dl_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf);
-	dl_tbf->direction = GPRS_RLCMAC_DL_TBF;
+	new (dl_tbf) gprs_rlcmac_dl_tbf();
 
 	dl_tbf->set_ms(ms);
 	OSMO_ASSERT(!ms->is_idle());