fixeria submitted this change.
libosmo-trx/ep: flush pending TRXC messages on endpoint teardown
osmo_trx_ep_close() used to drop any still-queued ctrl socket Tx data
via osmo_iofd_free(), including a 'goodbye' TRXC message (i.e. "CMD
POWEROFF") that may have just been enqueued right before teardown.
Track bytes still pending on each channel's ctrl_iofd (ctrl_wr_pending)
and, if any remain at close() time, swap the iofd's write_cb instead of
freeing it right away: keep waiting until every enqueued byte has
actually completed (or a write fails), then finally free it. Data
sockets and pending Tx data batches (TRXDv2 batching) are still
dropped immediately, as before.
Expose the "still flushing" state via the new osmo_trx_ep_is_closing(),
so a caller can tell it apart from fully closed: re-opening the same
ports while a flush is still in flight would otherwise risk a confusing
EADDRINUSE, so osmo_trx_ep_open() and osmo_trx_ep_set_num_chans() now
return -EBUSY in that case. osmo_trx_ep_free() called while still
closing reparents the whole endpoint to OTC_GLOBAL and defers the
actual free until the last flush completes, instead of dropping
the still-in-flight state.
This follows the async-flush pattern used by osmo-pcap's
osmo_pcap_wr_file_flush()/_is_flushing(), adapted to the osmo_io API
(there is no osmo_iofd_flush()).
Change-Id: I69e6a3bcf49afc3cfca4a72afdf459625cb91e56
---
M libosmo-trx/include/osmocom/trx/ep.h
M libosmo-trx/src/trx_ep.c
M tests/libosmo-trx/trx_ep_test.c
M tests/libosmo-trx/trx_ep_test.err
M tests/libosmo-trx/trx_ep_test.ok
5 files changed, 297 insertions(+), 10 deletions(-)
diff --git a/libosmo-trx/include/osmocom/trx/ep.h b/libosmo-trx/include/osmocom/trx/ep.h
index e3c855c..af2c7be 100644
--- a/libosmo-trx/include/osmocom/trx/ep.h
+++ b/libosmo-trx/include/osmocom/trx/ep.h
@@ -69,6 +69,13 @@
void osmo_trx_ep_close(struct osmo_trx_ep *ep);
void osmo_trx_ep_free(struct osmo_trx_ep *ep);
bool osmo_trx_ep_is_open(const struct osmo_trx_ep *ep);
+bool osmo_trx_ep_is_closing(const struct osmo_trx_ep *ep);
+
+/*! Called once osmo_trx_ep_close() has fully completed (see
+ * osmo_trx_ep_set_closed_cb()) */
+typedef void (*osmo_trx_ep_closed_cb_t)(struct osmo_trx_ep *ep);
+void osmo_trx_ep_set_closed_cb(struct osmo_trx_ep *ep, osmo_trx_ep_closed_cb_t closed_cb);
+
void osmo_trx_ep_set_priv(struct osmo_trx_ep *ep, void *priv);
void *osmo_trx_ep_get_priv(const struct osmo_trx_ep *ep);
int osmo_trx_ep_set_name(struct osmo_trx_ep *ep, const char *fmt, ...);
diff --git a/libosmo-trx/src/trx_ep.c b/libosmo-trx/src/trx_ep.c
index e12fff9..35cabbd 100644
--- a/libosmo-trx/src/trx_ep.c
+++ b/libosmo-trx/src/trx_ep.c
@@ -59,12 +59,22 @@
struct osmo_io_fd *data_iofd;
uint8_t pdu_ver; /* TRXD PDU version in use */
struct msgb *tx_msg; /* pending TRXDv2 Tx batch */
+ /* Bytes handed to osmo_iofd_write_msgb() on ctrl_iofd but not yet
+ * completed (per trx_ep_ctrl_write_cb()), used by trx_ep_ctrl_close()
+ * to tell whether a flush is needed on teardown. Non-zero here also
+ * means ctrl_iofd is currently being flushed asynchronously after
+ * osmo_trx_ep_close(); see osmo_trx_ep_is_closing(). */
+ size_t ctrl_wr_pending;
};
/*! Sockets currently bound */
#define OSMO_TRX_EP_F_OPEN (1 << 0)
/*! Enable the clock socket (base_port + 0) */
#define OSMO_TRX_EP_F_CLOCK_SOCKET (1 << 1)
+/*! osmo_trx_ep_free() was called while a chan's ctrl socket was still
+ * flushing: the actual free is deferred to trx_ep_ctrl_close_write_cb(),
+ * once the last one completes. */
+#define OSMO_TRX_EP_F_PENDING_FREE (1 << 2)
struct osmo_trx_ep {
uint32_t flags; /* see OSMO_TRX_EP_F_* */
@@ -78,6 +88,10 @@
struct osmo_io_fd *clck_iofd;
struct osmo_trx_ep_chan *chans; /* array of num_chans channels */
unsigned int num_chans;
+ /* called once osmo_trx_ep_close() has fully completed, i.e. every
+ * ctrl chan is closed (immediately if nothing needed flushing, or
+ * once the last async flush finishes); see osmo_trx_ep_set_closed_cb() */
+ osmo_trx_ep_closed_cb_t closed_cb;
};
/*! Default base UDP port, see osmo_trx_ep_set_base_port() */
@@ -234,10 +248,109 @@
/* nothing to do, but osmo_io requires a write call-back */
}
+/* Track bytes still pending on a channel's ctrl_iofd, so trx_ep_ctrl_close()
+ * can tell whether anything is still in flight at teardown time. */
+static void trx_ep_ctrl_write_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg)
+{
+ struct osmo_trx_ep_chan *chan = osmo_iofd_get_data(iofd);
+
+ if (res > 0) {
+ OSMO_ASSERT((size_t)res <= chan->ctrl_wr_pending);
+ chan->ctrl_wr_pending -= res;
+ } else {
+ /* discard: nothing will complete this write again, so a
+ * stale non-zero count here would wedge trx_ep_ctrl_close()
+ * into (uselessly) waiting for it forever on teardown */
+ LOGEPCH(chan->ep, chan->num, LOGL_ERROR,
+ "%s(): write failed (res=%d), discarding %zu pending byte(s)\n",
+ __func__, res, chan->ctrl_wr_pending);
+ chan->ctrl_wr_pending = 0;
+ }
+}
+
/***********************************************************************
* open/close
***********************************************************************/
+/*! Write call-back for a channel's ctrl_iofd while it is being flushed
+ * asynchronously after osmo_trx_ep_close(): a 'goodbye' TRXC message
+ * (e.g. "CMD POWEROFF") may have been enqueued via
+ * osmo_trx_ep_send_ctrl_msg() right before tearing down the endpoint;
+ * osmo_iofd_free() would otherwise drop it together with the (now
+ * pointless) rest of the Tx queue. Keeps waiting until every byte
+ * enqueued on it has actually completed (or a write fails), then frees
+ * the iofd and, if osmo_trx_ep_free() was called on the (kept alive)
+ * endpoint in the meantime and no other channel is still flushing,
+ * finally frees the endpoint too. */
+static void trx_ep_ctrl_close_write_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg)
+{
+ struct osmo_trx_ep_chan *chan = osmo_iofd_get_data(iofd);
+ struct osmo_trx_ep *ep = chan->ep;
+
+ if (res > 0) {
+ OSMO_ASSERT((size_t)res <= chan->ctrl_wr_pending);
+ chan->ctrl_wr_pending -= res;
+ /* keep waiting until every enqueued byte has actually completed */
+ if (chan->ctrl_wr_pending > 0) {
+ LOGEPCH(ep, chan->num, LOGL_DEBUG,
+ "%s(): wrote %d byte(s), %zu still pending\n",
+ __func__, res, chan->ctrl_wr_pending);
+ return;
+ }
+ LOGEPCH(ep, chan->num, LOGL_DEBUG,
+ "%s(): wrote %d byte(s), flush completed\n",
+ __func__, res);
+ } else {
+ LOGEPCH(ep, chan->num, LOGL_ERROR,
+ "%s(): flush aborted (res=%d), discarding %zu pending byte(s)\n",
+ __func__, res, chan->ctrl_wr_pending);
+ chan->ctrl_wr_pending = 0;
+ }
+
+ osmo_iofd_free(chan->ctrl_iofd);
+ chan->ctrl_iofd = NULL;
+
+ if (osmo_trx_ep_is_closing(ep))
+ return; /* other ctrl chans are still closing */
+
+ if (ep->closed_cb != NULL)
+ ep->closed_cb(ep);
+
+ if (~ep->flags & OSMO_TRX_EP_F_PENDING_FREE)
+ return; /* deferred free() is not pending */
+
+ LOGEP(ep, LOGL_DEBUG, "%s(): last flush completed, free()ing\n", __func__);
+ talloc_free(ep);
+}
+
+static const struct osmo_io_ops trx_ep_ctrl_close_ioops = {
+ .write_cb = &trx_ep_ctrl_close_write_cb,
+};
+
+/* Close a channel's ctrl_iofd, flushing (best-effort) any still-in-flight
+ * Tx data first instead of dropping it immediately. */
+static void trx_ep_ctrl_close(struct osmo_trx_ep_chan *chan)
+{
+ struct osmo_io_fd *iofd = chan->ctrl_iofd;
+
+ if (iofd == NULL)
+ return;
+
+ if (chan->ctrl_wr_pending == 0) {
+ LOGEPCH(chan->ep, chan->num, LOGL_DEBUG,
+ "%s(): nothing pending, closing immediately\n", __func__);
+ osmo_iofd_free(iofd);
+ chan->ctrl_iofd = NULL;
+ return;
+ }
+
+ LOGEPCH(chan->ep, chan->num, LOGL_DEBUG,
+ "%s(): %zu byte(s) still pending, flushing asynchronously\n",
+ __func__, chan->ctrl_wr_pending);
+
+ osmo_iofd_set_ioops(iofd, &trx_ep_ctrl_close_ioops);
+}
+
static const struct osmo_io_ops trx_ep_clck_ioops = {
.read_cb = &trx_ep_clck_read_cb,
.write_cb = &trx_ep_write_cb,
@@ -245,7 +358,7 @@
static const struct osmo_io_ops trx_ep_ctrl_ioops = {
.read_cb = &trx_ep_ctrl_read_cb,
- .write_cb = &trx_ep_write_cb,
+ .write_cb = &trx_ep_ctrl_write_cb,
};
static const struct osmo_io_ops trx_ep_data_ioops = {
@@ -323,8 +436,10 @@
/* Close a channel's ctrl+data sockets and drop its pending Tx batch */
static void trx_ep_chan_close(struct osmo_trx_ep_chan *chan)
{
- osmo_iofd_free(chan->ctrl_iofd);
- chan->ctrl_iofd = NULL;
+ /* trx_ep_ctrl_close() clears chan->ctrl_iofd itself, but only once
+ * it's actually safe to: immediately if nothing was pending, or
+ * later from trx_ep_ctrl_close_write_cb() if a flush is needed. */
+ trx_ep_ctrl_close(chan);
osmo_iofd_free(chan->data_iofd);
chan->data_iofd = NULL;
msgb_free(chan->tx_msg);
@@ -362,13 +477,18 @@
}
/*! Open the clock/ctrl/data sockets of the given endpoint.
- * \returns 0 on success; -EALREADY if already open; other negative
- * values on error (all sockets closed) */
+ * \returns 0 on success; -EALREADY if already open; -EBUSY if a previous
+ * osmo_trx_ep_close() is still flushing a ctrl socket (see
+ * osmo_trx_ep_is_closing()); other negative values on error (all sockets
+ * closed) */
int osmo_trx_ep_open(struct osmo_trx_ep *ep)
{
if (ep->flags & OSMO_TRX_EP_F_OPEN)
return -EALREADY;
+ if (osmo_trx_ep_is_closing(ep))
+ return -EBUSY;
+
if (ep->laddr == NULL || ep->raddr == NULL)
return -EINVAL;
@@ -401,8 +521,11 @@
return -EIO;
}
-/*! Close all sockets of the given endpoint (drops pending Tx batches).
- * No-op if not opened. */
+/*! Close all sockets of the given endpoint. No-op if not opened.
+ * Any TRXC message still queued on a ctrl socket (e.g. a 'goodbye'
+ * "CMD POWEROFF" sent right before teardown) is flushed asynchronously
+ * (best-effort) instead of being dropped; pending Tx data batches are
+ * dropped. */
void osmo_trx_ep_close(struct osmo_trx_ep *ep)
{
if (~ep->flags & OSMO_TRX_EP_F_OPEN)
@@ -419,14 +542,34 @@
trx_ep_chan_close(&ep->chans[i]);
ep->flags &= ~OSMO_TRX_EP_F_OPEN;
+
+ /* if any chan started an async flush, trx_ep_ctrl_close_sendto_cb()
+ * calls closed_cb() once the last one completes instead */
+ if (ep->closed_cb != NULL && !osmo_trx_ep_is_closing(ep))
+ ep->closed_cb(ep);
}
-/*! Free the given endpoint instance (closes all sockets) */
+/*! Free the given endpoint instance (closes all sockets). If a ctrl socket
+ * is still flushing (see osmo_trx_ep_is_closing()), the endpoint itself is
+ * kept alive until the flush completes (see trx_ep_ctrl_close_write_cb()),
+ * which then finishes this deferred free. */
void osmo_trx_ep_free(struct osmo_trx_ep *ep)
{
if (ep == NULL)
return;
+
osmo_trx_ep_close(ep);
+
+ if (osmo_trx_ep_is_closing(ep)) {
+ /* Detach from the caller's (possibly about-to-be-freed)
+ * talloc parent: ep must outlive it until the flush
+ * completes, since the still-flushing iofd is a talloc
+ * child of ep. */
+ talloc_steal(OTC_GLOBAL, ep);
+ ep->flags |= OSMO_TRX_EP_F_PENDING_FREE;
+ return;
+ }
+
talloc_free(ep);
}
@@ -436,6 +579,25 @@
return ep->flags & OSMO_TRX_EP_F_OPEN;
}
+/*! Whether a ctrl socket from a previous osmo_trx_ep_close() is still
+ * flushing a queued TRXC message in the background (see trx_ep_ctrl_close()). */
+bool osmo_trx_ep_is_closing(const struct osmo_trx_ep *ep)
+{
+ for (unsigned int i = 0; i < ep->num_chans; i++) {
+ if (ep->chans[i].ctrl_wr_pending > 0)
+ return true;
+ }
+ return false;
+}
+
+/*! Set the call-back invoked once osmo_trx_ep_close() has fully completed:
+ * immediately if no ctrl chan needed flushing, or once the last async
+ * flush finishes (see osmo_trx_ep_is_closing()) otherwise. */
+void osmo_trx_ep_set_closed_cb(struct osmo_trx_ep *ep, osmo_trx_ep_closed_cb_t closed_cb)
+{
+ ep->closed_cb = closed_cb;
+}
+
/*! Set the application-private data */
void osmo_trx_ep_set_priv(struct osmo_trx_ep *ep, void *priv)
{
@@ -455,13 +617,21 @@
}
/*! Change the number of channels; only valid before osmo_trx_ep_open().
- * \returns 0 on success; -EBUSY if the endpoint is already open; -EINVAL
- * if num_chans is 0; -ENOMEM on allocation failure */
+ * \returns 0 on success; -EBUSY if the endpoint is already open or a ctrl
+ * socket from a previous osmo_trx_ep_close() is still flushing (see
+ * osmo_trx_ep_is_closing()); -EINVAL if num_chans is 0; -ENOMEM on
+ * allocation failure */
int osmo_trx_ep_set_num_chans(struct osmo_trx_ep *ep, unsigned int num_chans)
{
if (ep->flags & OSMO_TRX_EP_F_OPEN)
return -EBUSY;
+ /* re-allocating ep->chans below would leave a still-flushing
+ * channel's ctrl_iofd pointing at freed memory (its write_cb looks
+ * up its struct osmo_trx_ep_chan via osmo_iofd_get_data()) */
+ if (osmo_trx_ep_is_closing(ep))
+ return -EBUSY;
+
if (num_chans == 0)
return -EINVAL;
if (num_chans == ep->num_chans)
@@ -651,6 +821,7 @@
const struct osmo_trxc_msg *tmsg)
{
struct msgb *msg;
+ size_t len;
int rc;
OSMO_ASSERT(chan < ep->num_chans);
@@ -662,10 +833,13 @@
return rc;
}
msgb_put(msg, rc);
+ len = msgb_length(msg);
rc = osmo_iofd_write_msgb(ep->chans[chan].ctrl_iofd, msg);
if (rc < 0)
msgb_free(msg);
+ else
+ ep->chans[chan].ctrl_wr_pending += len;
return rc;
}
diff --git a/tests/libosmo-trx/trx_ep_test.c b/tests/libosmo-trx/trx_ep_test.c
index a6f3d9c..7f96540 100644
--- a/tests/libosmo-trx/trx_ep_test.c
+++ b/tests/libosmo-trx/trx_ep_test.c
@@ -91,6 +91,11 @@
ep_label(ep), chan, osmo_trxd_burst_req_name(br));
}
+static void ep_closed_cb(struct osmo_trx_ep *ep)
+{
+ printf("%s: closed_cb()\n", ep_label(ep));
+}
+
static void fill_burst_req(struct osmo_trxd_burst_req *br, uint32_t fn)
{
*br = (struct osmo_trxd_burst_req){
@@ -171,6 +176,7 @@
{
osmo_trx_ep_close(ep);
OSMO_ASSERT(osmo_trx_ep_is_open(ep) == false);
+ OSMO_ASSERT(osmo_trx_ep_is_closing(ep) == false);
osmo_trx_ep_free(ep);
}
@@ -287,6 +293,61 @@
ep_close_free(ep_bts);
}
+static void test_ctrl_close_flush(bool do_free)
+{
+ struct osmo_trx_ep *ep_trx = ep_alloc("trx", OSMO_TRX_EP_MODE_TRX);
+ struct osmo_trx_ep *ep_bts = ep_alloc("bts", OSMO_TRX_EP_MODE_L1);
+
+ printf("=== %s(do_free=%d): starting testcase ===\n", __func__, (int)do_free);
+
+ ep_set_num_chans(ep_trx, 3);
+ ep_set_num_chans(ep_bts, 3);
+
+ ep_open(ep_trx);
+ ep_open(ep_bts);
+
+ static const struct osmo_trxc_msg cmd_rfmute = {
+ .type = OSMO_TRXC_MT_CMD,
+ .cmd = OSMO_TRXC_CMD_RFMUTE,
+ .params = "1",
+ };
+
+ static const struct osmo_trxc_msg cmd_poweroff = {
+ .type = OSMO_TRXC_MT_CMD,
+ .cmd = OSMO_TRXC_CMD_POWEROFF,
+ };
+
+ printf("=== %s(): TRXC CMDs sent right before osmo_trx_ep_close() (BTS -> TRX) ===\n", __func__);
+ osmo_trx_ep_send_ctrl_msg(ep_bts, 1, &cmd_rfmute);
+ osmo_trx_ep_send_ctrl_msg(ep_bts, 0, &cmd_poweroff);
+
+ osmo_trx_ep_set_closed_cb(ep_bts, ep_closed_cb);
+ osmo_trx_ep_close(ep_bts);
+ OSMO_ASSERT(osmo_trx_ep_is_open(ep_bts) == false);
+ OSMO_ASSERT(osmo_trx_ep_is_closing(ep_bts) == true);
+
+ /* osmo_trx_ep_open() is expected to fail while closing */
+ OSMO_ASSERT(osmo_trx_ep_open(ep_bts) == -EBUSY);
+ /* osmo_trx_ep_set_num_chans() is expected to fail too */
+ OSMO_ASSERT(osmo_trx_ep_set_num_chans(ep_bts, 16) == -EBUSY);
+
+ if (do_free) {
+ OSMO_ASSERT(talloc_parent(ep_bts) == test_ctx);
+ osmo_trx_ep_free(ep_bts); /* osmo_trx_ep_free() postpones the actual free() */
+ OSMO_ASSERT(talloc_parent(ep_bts) == OTC_GLOBAL);
+ OSMO_ASSERT(osmo_trx_ep_is_closing(ep_bts) == true);
+ OSMO_ASSERT(osmo_trx_ep_is_open(ep_bts) == false);
+ flush_io(); /* after flushing, the ep is finally free()ed! */
+ } else {
+ flush_io();
+ OSMO_ASSERT(osmo_trx_ep_is_closing(ep_bts) == false);
+ OSMO_ASSERT(osmo_trx_ep_is_open(ep_bts) == false);
+ ep_close_free(ep_bts);
+ }
+
+ ep_close_free(ep_trx);
+}
+
int main(int argc, char **argv)
{
test_ctx = talloc_named_const(NULL, 0, "trx_ep_test");
@@ -301,6 +362,8 @@
test_clck_ctrl();
test_burst_req_ind();
+ test_ctrl_close_flush(false);
+ test_ctrl_close_flush(true);
printf("Done\n");
return 0;
diff --git a/tests/libosmo-trx/trx_ep_test.err b/tests/libosmo-trx/trx_ep_test.err
index f8e32d3..4f7e5e9 100644
--- a/tests/libosmo-trx/trx_ep_test.err
+++ b/tests/libosmo-trx/trx_ep_test.err
@@ -1,10 +1,43 @@
DLGLOBAL INFO (ep=ep_trx) Opening TRXC/TRXD connections l=127.0.0.1:16700<->r=127.0.0.1:16800
DLGLOBAL INFO (ep=ep_bts) Opening TRXC/TRXD connections l=127.0.0.1:16800<->r=127.0.0.1:16700
DLGLOBAL INFO (ep=ep_trx) Closing TRXC/TRXD connections l=127.0.0.1:16700<->r=127.0.0.1:16800
+DLGLOBAL DEBUG (ep=ep_trx, chan=0) trx_ep_ctrl_close(): nothing pending, closing immediately
+DLGLOBAL DEBUG (ep=ep_trx, chan=1) trx_ep_ctrl_close(): nothing pending, closing immediately
DLGLOBAL INFO (ep=ep_bts) Closing TRXC/TRXD connections l=127.0.0.1:16800<->r=127.0.0.1:16700
+DLGLOBAL DEBUG (ep=ep_bts, chan=0) trx_ep_ctrl_close(): nothing pending, closing immediately
+DLGLOBAL DEBUG (ep=ep_bts, chan=1) trx_ep_ctrl_close(): nothing pending, closing immediately
DLGLOBAL INFO (ep=ep_trx) Opening TRXC/TRXD connections l=127.0.0.1:16700<->r=127.0.0.1:16800
DLGLOBAL INFO (ep=ep_bts) Opening TRXC/TRXD connections l=127.0.0.1:16800<->r=127.0.0.1:16700
DLGLOBAL INFO (ep=ep_bts, chan=0) Using TRXD PDU version 2
DLGLOBAL INFO (ep=ep_trx, chan=0) Using TRXD PDU version 2
DLGLOBAL INFO (ep=ep_trx) Closing TRXC/TRXD connections l=127.0.0.1:16700<->r=127.0.0.1:16800
+DLGLOBAL DEBUG (ep=ep_trx, chan=0) trx_ep_ctrl_close(): nothing pending, closing immediately
+DLGLOBAL DEBUG (ep=ep_trx, chan=1) trx_ep_ctrl_close(): nothing pending, closing immediately
DLGLOBAL INFO (ep=ep_bts) Closing TRXC/TRXD connections l=127.0.0.1:16800<->r=127.0.0.1:16700
+DLGLOBAL DEBUG (ep=ep_bts, chan=0) trx_ep_ctrl_close(): nothing pending, closing immediately
+DLGLOBAL DEBUG (ep=ep_bts, chan=1) trx_ep_ctrl_close(): nothing pending, closing immediately
+DLGLOBAL INFO (ep=ep_trx) Opening TRXC/TRXD connections l=127.0.0.1:16700<->r=127.0.0.1:16800
+DLGLOBAL INFO (ep=ep_bts) Opening TRXC/TRXD connections l=127.0.0.1:16800<->r=127.0.0.1:16700
+DLGLOBAL INFO (ep=ep_bts) Closing TRXC/TRXD connections l=127.0.0.1:16800<->r=127.0.0.1:16700
+DLGLOBAL DEBUG (ep=ep_bts, chan=0) trx_ep_ctrl_close(): 12 byte(s) still pending, flushing asynchronously
+DLGLOBAL DEBUG (ep=ep_bts, chan=1) trx_ep_ctrl_close(): 12 byte(s) still pending, flushing asynchronously
+DLGLOBAL DEBUG (ep=ep_bts, chan=2) trx_ep_ctrl_close(): nothing pending, closing immediately
+DLGLOBAL DEBUG (ep=ep_bts, chan=0) trx_ep_ctrl_close_write_cb(): wrote 12 byte(s), flush completed
+DLGLOBAL DEBUG (ep=ep_bts, chan=1) trx_ep_ctrl_close_write_cb(): wrote 12 byte(s), flush completed
+DLGLOBAL INFO (ep=ep_trx) Closing TRXC/TRXD connections l=127.0.0.1:16700<->r=127.0.0.1:16800
+DLGLOBAL DEBUG (ep=ep_trx, chan=0) trx_ep_ctrl_close(): nothing pending, closing immediately
+DLGLOBAL DEBUG (ep=ep_trx, chan=1) trx_ep_ctrl_close(): nothing pending, closing immediately
+DLGLOBAL DEBUG (ep=ep_trx, chan=2) trx_ep_ctrl_close(): nothing pending, closing immediately
+DLGLOBAL INFO (ep=ep_trx) Opening TRXC/TRXD connections l=127.0.0.1:16700<->r=127.0.0.1:16800
+DLGLOBAL INFO (ep=ep_bts) Opening TRXC/TRXD connections l=127.0.0.1:16800<->r=127.0.0.1:16700
+DLGLOBAL INFO (ep=ep_bts) Closing TRXC/TRXD connections l=127.0.0.1:16800<->r=127.0.0.1:16700
+DLGLOBAL DEBUG (ep=ep_bts, chan=0) trx_ep_ctrl_close(): 12 byte(s) still pending, flushing asynchronously
+DLGLOBAL DEBUG (ep=ep_bts, chan=1) trx_ep_ctrl_close(): 12 byte(s) still pending, flushing asynchronously
+DLGLOBAL DEBUG (ep=ep_bts, chan=2) trx_ep_ctrl_close(): nothing pending, closing immediately
+DLGLOBAL DEBUG (ep=ep_bts, chan=0) trx_ep_ctrl_close_write_cb(): wrote 12 byte(s), flush completed
+DLGLOBAL DEBUG (ep=ep_bts, chan=1) trx_ep_ctrl_close_write_cb(): wrote 12 byte(s), flush completed
+DLGLOBAL DEBUG (ep=ep_bts) trx_ep_ctrl_close_write_cb(): last flush completed, free()ing
+DLGLOBAL INFO (ep=ep_trx) Closing TRXC/TRXD connections l=127.0.0.1:16700<->r=127.0.0.1:16800
+DLGLOBAL DEBUG (ep=ep_trx, chan=0) trx_ep_ctrl_close(): nothing pending, closing immediately
+DLGLOBAL DEBUG (ep=ep_trx, chan=1) trx_ep_ctrl_close(): nothing pending, closing immediately
+DLGLOBAL DEBUG (ep=ep_trx, chan=2) trx_ep_ctrl_close(): nothing pending, closing immediately
diff --git a/tests/libosmo-trx/trx_ep_test.ok b/tests/libosmo-trx/trx_ep_test.ok
index 6b9c322..194e5d5 100644
--- a/tests/libosmo-trx/trx_ep_test.ok
+++ b/tests/libosmo-trx/trx_ep_test.ok
@@ -26,4 +26,14 @@
BURST.ind batch flush
bts: rx_burst_ind(chan=0): NOPE.ind tn=5 fn=200005 trx_num=0 rssi=-63 toa256=-512 C/I=-150 cB
bts: rx_burst_ind(chan=0): BURST.ind tn=6 fn=200005 trx_num=0 rssi=-63 toa256=-512 C/I=-150 cB mod=GMSK set=0 tsc=7 burst_len=148
+=== test_ctrl_close_flush(do_free=0): starting testcase ===
+=== test_ctrl_close_flush(): TRXC CMDs sent right before osmo_trx_ep_close() (BTS -> TRX) ===
+bts: closed_cb()
+trx: rx_ctrl_msg(chan=0): 'CMD POWEROFF'
+trx: rx_ctrl_msg(chan=1): 'CMD RFMUTE 1'
+=== test_ctrl_close_flush(do_free=1): starting testcase ===
+=== test_ctrl_close_flush(): TRXC CMDs sent right before osmo_trx_ep_close() (BTS -> TRX) ===
+bts: closed_cb()
+trx: rx_ctrl_msg(chan=0): 'CMD POWEROFF'
+trx: rx_ctrl_msg(chan=1): 'CMD RFMUTE 1'
Done
To view, visit change 43112. To unsubscribe, or for help writing mail filters, visit settings.