/* -*- c++ -*- */ /* * Copyright 2004,2018 Free Software Foundation, Inc. * * This file is part of GNU Radio * * SPDX-License-Identifier: GPL-3.0-or-later * */ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <gnuradio/buffer.h> #include <gnuradio/random.h> #include <stdlib.h> #include <boost/test/unit_test.hpp> static void leak_check(void f()) { long buffer_count = gr::buffer_ncurrently_allocated(); long buffer_reader_count = gr::buffer_reader_ncurrently_allocated(); f(); BOOST_CHECK_EQUAL(buffer_reader_count, gr::buffer_reader_ncurrently_allocated()); BOOST_CHECK_EQUAL(buffer_count, gr::buffer_ncurrently_allocated()); } // ---------------------------------------------------------------------------- // test single writer, no readers... // static void t0_body() { int nitems = 4000 / sizeof(int); int counter = 0; gr::buffer_sptr buf(gr::make_buffer(nitems, sizeof(int), gr::block_sptr())); int last_sa; int sa; sa = buf->space_available(); BOOST_CHECK(sa > 0); last_sa = sa; for (int i = 0; i < 5; i++) { sa = buf->space_available(); BOOST_CHECK_EQUAL(last_sa, sa); last_sa = sa; int* p = (int*)buf->write_pointer(); BOOST_CHECK(p != 0); for (int j = 0; j < sa; j++) *p++ = counter++; buf->update_write_pointer(sa); } } // ---------------------------------------------------------------------------- // test single writer, single reader // static void t1_body() { int nitems = 4000 / sizeof(int); int write_counter = 0; int read_counter = 0; gr::buffer_sptr buf(gr::make_buffer(nitems, sizeof(int), gr::block_sptr())); gr::buffer_reader_sptr r1(gr::buffer_add_reader(buf, 0, gr::block_sptr())); int sa; // write 1/3 of buffer sa = buf->space_available(); BOOST_CHECK(sa > 0); int* p = (int*)buf->write_pointer(); BOOST_CHECK(p != 0); for (int j = 0; j < sa / 3; j++) { *p++ = write_counter++; } buf->update_write_pointer(sa / 3); // write the next 1/3 (1/2 of what's left) sa = buf->space_available(); BOOST_CHECK(sa > 0); p = (int*)buf->write_pointer(); BOOST_CHECK(p != 0); for (int j = 0; j < sa / 2; j++) { *p++ = write_counter++; } buf->update_write_pointer(sa / 2); // check that we can read it OK int ia = r1->items_available(); BOOST_CHECK_EQUAL(write_counter, ia); int* rp = (int*)r1->read_pointer(); BOOST_CHECK(rp != 0); for (int i = 0; i < ia / 2; i++) { BOOST_CHECK_EQUAL(read_counter, *rp); read_counter++; rp++; } r1->update_read_pointer(ia / 2); // read the rest ia = r1->items_available(); rp = (int*)r1->read_pointer(); BOOST_CHECK(rp != 0); for (int i = 0; i < ia; i++) { BOOST_CHECK_EQUAL(read_counter, *rp); read_counter++; rp++; } r1->update_read_pointer(ia); } // ---------------------------------------------------------------------------- // single writer, single reader: check wrap-around // static void t2_body() { // 64K is the largest granularity we've seen so far (MS windows file mapping). // This allows a bit of "white box testing" int nitems = (64 * (1L << 10)) / sizeof(int); // 64K worth of ints gr::buffer_sptr buf(gr::make_buffer(nitems, sizeof(int), gr::block_sptr())); gr::buffer_reader_sptr r1(gr::buffer_add_reader(buf, 0, gr::block_sptr())); int read_counter = 0; int write_counter = 0; int n; int* wp = 0; int* rp = 0; // Write 3/4 of buffer n = (int)(buf->space_available() * 0.75); wp = (int*)buf->write_pointer(); for (int i = 0; i < n; i++) *wp++ = write_counter++; buf->update_write_pointer(n); // Now read it all int m = r1->items_available(); BOOST_CHECK_EQUAL(n, m); rp = (int*)r1->read_pointer(); for (int i = 0; i < m; i++) { BOOST_CHECK_EQUAL(read_counter, *rp); read_counter++; rp++; } r1->update_read_pointer(m); // Now write as much as we can. // This will wrap around the buffer n = buf->space_available(); BOOST_CHECK_EQUAL(nitems - 1, n); // white box test wp = (int*)buf->write_pointer(); for (int i = 0; i < n; i++) *wp++ = write_counter++; buf->update_write_pointer(n); // now read it all m = r1->items_available(); BOOST_CHECK_EQUAL(n, m); rp = (int*)r1->read_pointer(); for (int i = 0; i < m; i++) { BOOST_CHECK_EQUAL(read_counter, *rp); read_counter++; rp++; } r1->update_read_pointer(m); } // ---------------------------------------------------------------------------- // single writer, N readers, randomized order and lengths // ---------------------------------------------------------------------------- static void t3_body() { int nitems = (64 * (1L << 10)) / sizeof(int); static const int N = 5; gr::buffer_sptr buf(gr::make_buffer(nitems, sizeof(int), gr::block_sptr())); gr::buffer_reader_sptr reader[N]; int read_counter[N]; int write_counter = 0; gr::random random; for (int i = 0; i < N; i++) { read_counter[i] = 0; reader[i] = buffer_add_reader(buf, 0, gr::block_sptr()); } for (int lc = 0; lc < 1000; lc++) { // write some int n = (int)(buf->space_available() * random.ran1()); int* wp = (int*)buf->write_pointer(); for (int i = 0; i < n; i++) *wp++ = write_counter++; buf->update_write_pointer(n); // pick a random reader and read some int r = (int)(N * random.ran1()); int m = reader[r]->items_available(); int* rp = (int*)reader[r]->read_pointer(); for (int i = 0; i < m; i++) { BOOST_CHECK_EQUAL(read_counter[r], *rp); read_counter[r]++; rp++; } reader[r]->update_read_pointer(m); } } // ---------------------------------------------------------------------------- BOOST_AUTO_TEST_CASE(t0) { leak_check(t0_body); } BOOST_AUTO_TEST_CASE(t1) { leak_check(t1_body); } BOOST_AUTO_TEST_CASE(t2) { leak_check(t2_body); } BOOST_AUTO_TEST_CASE(t3) { leak_check(t3_body); }