wqueue: Reject messges if queue is considered full

The write queue was always meant to not queue more than the
max_length messages but the implementation never rejected a
message.

Begin to log and enforce the queue size limit, add a testcase
to verify the code and initialize except_cb as part of a fix
for that new test case.

Real applications might now run into the queue limit and drop
messages where they just queued them before. It is unfortunate
but I still think it is good to implement the routine as it was
intended. We need to review osmo_wqueue_enqueue once more to
see that no msgb is leaked.

Change-Id: I1e6aef30f3e73d4bcf2967bc49f0783aa65395ae
This commit is contained in:
Holger Hans Peter Freyther 2016-11-12 21:25:21 +01:00
parent d7c0a373ff
commit c7f52c4c84
6 changed files with 103 additions and 5 deletions

1
.gitignore vendored
View File

@ -95,6 +95,7 @@ tests/sim/sim_test
tests/gsup/gsup_test
tests/tlv/tlv_test
tests/fsm/fsm_test
tests/write_queue/wqueue_test
utils/osmo-arfcn
utils/osmo-auc-gen

View File

@ -1,6 +1,6 @@
/* Generic write queue implementation */
/*
* (C) 2010 by Holger Hans Peter Freyther
* (C) 2010-2016 by Holger Hans Peter Freyther
* (C) 2010 by On-Waves
*
* All Rights Reserved
@ -23,6 +23,7 @@
#include <errno.h>
#include <osmocom/core/write_queue.h>
#include <osmocom/core/logging.h>
/*! \addtogroup write_queue
* @{
@ -93,6 +94,7 @@ void osmo_wqueue_init(struct osmo_wqueue *queue, int max_length)
queue->current_length = 0;
queue->read_cb = NULL;
queue->write_cb = NULL;
queue->except_cb = NULL;
queue->bfd.cb = osmo_wqueue_bfd_cb;
INIT_LLIST_HEAD(&queue->msg_queue);
}
@ -104,8 +106,11 @@ void osmo_wqueue_init(struct osmo_wqueue *queue, int max_length)
*/
int osmo_wqueue_enqueue(struct osmo_wqueue *queue, struct msgb *data)
{
// if (queue->current_length + 1 >= queue->max_length)
// LOGP(DMSC, LOGL_ERROR, "The queue is full. Dropping not yet implemented.\n");
if (queue->current_length >= queue->max_length) {
LOGP(DLGLOBAL, LOGL_ERROR,
"wqueue(%p) is full. Rejecting msgb\n", queue);
return -ENOSPC;
}
++queue->current_length;
msgb_enqueue(&queue->msg_queue, data);

View File

@ -13,7 +13,8 @@ check_PROGRAMS = timer/timer_test sms/sms_test ussd/ussd_test \
vty/vty_test comp128/comp128_test utils/utils_test \
smscb/gsm0341_test stats/stats_test \
bitvec/bitvec_test msgb/msgb_test bits/bitcomp_test \
tlv/tlv_test gsup/gsup_test fsm/fsm_test
tlv/tlv_test gsup/gsup_test fsm/fsm_test \
write_queue/wqueue_test
if ENABLE_MSGFILE
check_PROGRAMS += msgfile/msgfile_test
@ -133,6 +134,9 @@ gsup_gsup_test_LDADD = $(top_builddir)/src/gsm/libosmogsm.la $(top_builddir)/src
fsm_fsm_test_SOURCES = fsm/fsm_test.c
fsm_fsm_test_LDADD = $(top_builddir)/src/libosmocore.la
write_queue_wqueue_test_SOURCES = write_queue/wqueue_test.c
write_queue_wqueue_test_LDADD = $(top_builddir)/src/libosmocore.la
# The `:;' works around a Bash 3.2 bug when the output is not writeable.
$(srcdir)/package.m4: $(top_srcdir)/configure.ac
:;{ \
@ -168,7 +172,7 @@ EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE) \
utils/utils_test.ok stats/stats_test.ok \
bitvec/bitvec_test.ok msgb/msgb_test.ok bits/bitcomp_test.ok \
sim/sim_test.ok tlv/tlv_test.ok gsup/gsup_test.ok \
fsm/fsm_test.ok fsm/fsm_test.err
fsm/fsm_test.ok fsm/fsm_test.err write_queue/wqueue_test.ok
DISTCLEANFILES = atconfig atlocal

View File

@ -177,6 +177,12 @@ cat $abs_srcdir/stats/stats_test.ok > expout
AT_CHECK([$abs_top_builddir/tests/stats/stats_test], [0], [expout], [ignore])
AT_CLEANUP
AT_SETUP([write_queue])
AT_KEYWORDS([write_queue])
cat $abs_srcdir/write_queue/wqueue_test.ok > expout
AT_CHECK([$abs_top_builddir/tests/write_queue/wqueue_test], [0], [expout], [ignore])
AT_CLEANUP
AT_SETUP([bssgp-fc])
AT_KEYWORDS([bssgp-fc])
cat $abs_srcdir/gb/bssgp_fc_tests.ok > expout

View File

@ -0,0 +1,81 @@
#include <osmocom/core/logging.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/write_queue.h>
static const struct log_info_cat default_categories[] = {
};
static const struct log_info log_info = {
.cat = default_categories,
.num_cat = ARRAY_SIZE(default_categories),
};
static void test_wqueue_limit(void)
{
struct msgb *msg;
struct osmo_wqueue wqueue;
int rc;
osmo_wqueue_init(&wqueue, 0);
OSMO_ASSERT(wqueue.max_length == 0);
OSMO_ASSERT(wqueue.current_length == 0);
OSMO_ASSERT(wqueue.read_cb == NULL);
OSMO_ASSERT(wqueue.write_cb == NULL);
OSMO_ASSERT(wqueue.except_cb == NULL);
/* try to add and fail */
msg = msgb_alloc(4096, "msg1");
rc = osmo_wqueue_enqueue(&wqueue, msg);
OSMO_ASSERT(rc < 0);
/* add one and fail on the second */
wqueue.max_length = 1;
rc = osmo_wqueue_enqueue(&wqueue, msg);
OSMO_ASSERT(rc == 0);
OSMO_ASSERT(wqueue.current_length == 1);
msg = msgb_alloc(4096, "msg2");
rc = osmo_wqueue_enqueue(&wqueue, msg);
OSMO_ASSERT(rc < 0);
/* add one more */
wqueue.max_length = 2;
rc = osmo_wqueue_enqueue(&wqueue, msg);
OSMO_ASSERT(rc == 0);
OSMO_ASSERT(wqueue.current_length == 2);
/* release everything */
osmo_wqueue_clear(&wqueue);
OSMO_ASSERT(wqueue.current_length == 0);
OSMO_ASSERT(wqueue.max_length == 2);
/* Add two, fail on the third, free it and the queue */
msg = msgb_alloc(4096, "msg3");
rc = osmo_wqueue_enqueue(&wqueue, msg);
OSMO_ASSERT(rc == 0);
OSMO_ASSERT(wqueue.current_length == 1);
msg = msgb_alloc(4096, "msg4");
rc = osmo_wqueue_enqueue(&wqueue, msg);
OSMO_ASSERT(rc == 0);
OSMO_ASSERT(wqueue.current_length == 2);
msg = msgb_alloc(4096, "msg5");
rc = osmo_wqueue_enqueue(&wqueue, msg);
OSMO_ASSERT(rc < 0);
OSMO_ASSERT(wqueue.current_length == 2);
msgb_free(msg);
osmo_wqueue_clear(&wqueue);
}
int main(int argc, char **argv)
{
struct log_target *stderr_target;
log_init(&log_info, NULL);
stderr_target = log_target_create_stderr();
log_add_target(stderr_target);
log_set_print_filename(stderr_target, 0);
test_wqueue_limit();
printf("Done\n");
return 0;
}

View File

@ -0,0 +1 @@
Done