From b5692037a286ad098d3ffb5b4711d5a191ac13e4 Mon Sep 17 00:00:00 2001 From: Francisco Date: Mon, 22 Mar 2021 17:37:08 +0000 Subject: [PATCH] created macros for assertions and warnings. The assert macro prints the whole callstack on crash. The warning macro can just log a warning or call an assertion fail depending on the cmake flag STOP_ON_WARNING --- CMakeLists.txt | 10 ++++ lib/include/srsran/adt/circular_map.h | 18 +++---- lib/include/srsran/common/srsran_assert.h | 60 ++++++++++++++++++++++ lib/include/srsran/common/test_common.h | 33 ++++++------ lib/test/adt/circular_map_test.cc | 7 ++- srsenb/test/mac/sched_common_test_suite.cc | 22 ++++---- 6 files changed, 108 insertions(+), 42 deletions(-) create mode 100644 lib/include/srsran/common/srsran_assert.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f7ff1327..9671e961e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,6 +81,8 @@ option(ENABLE_TIMEPROF "Enable time profiling" ON) option(FORCE_32BIT "Add flags to force 32 bit compilation" OFF) option(ENABLE_SRSLOG_TRACING "Enable event tracing using srslog" OFF) +option(ASSERTS_ENABLED "Enable srsRAN asserts" ON) +option(STOP_ON_WARNING "Interrupt application on warning" OFF) # Users that want to try this feature need to make sure the lto plugin is # loaded by bintools (ar, nm, ...). Older versions of bintools will not do @@ -107,6 +109,14 @@ if (ENABLE_SRSLOG_TRACING) add_definitions(-DENABLE_SRSLOG_EVENT_TRACE) endif (ENABLE_SRSLOG_TRACING) +if (ASSERTS_ENABLED) + add_definitions(-DASSERTS_ENABLED) +endif() + +if (STOP_ON_WARNING) + add_definitions(-DSTOP_ON_WARNING) +endif() + ######################################################################## # Find dependencies ######################################################################## diff --git a/lib/include/srsran/adt/circular_map.h b/lib/include/srsran/adt/circular_map.h index 7d78b8970..50ca4b318 100644 --- a/lib/include/srsran/adt/circular_map.h +++ b/lib/include/srsran/adt/circular_map.h @@ -14,15 +14,15 @@ #define SRSRAN_ID_MAP_H #include "expected.h" +#include "srsran/common/srsran_assert.h" #include -#include namespace srsran { template class static_circular_map { - static_assert(std::is_integral::value, "Map key must be an integer"); + static_assert(std::is_integral::value and std::is_unsigned::value, "Map key must be an unsigned integer"); using obj_t = std::pair; using obj_storage_t = typename std::aligned_storage::type; @@ -48,22 +48,22 @@ public: obj_t& operator*() { - assert(idx < ptr->buffer.size() && "Index out-of-bounds"); + srsran_assert(idx < ptr->buffer.size(), "Iterator out-of-bounds (%zd >= %zd)", idx, ptr->buffer.size()); return ptr->get_obj_(idx); } obj_t* operator->() { - assert(idx < ptr->buffer.size() && "Index out-of-bounds"); + srsran_assert(idx < ptr->buffer.size(), "Iterator out-of-bounds (%zd >= %zd)", idx, ptr->buffer.size()); return &ptr->get_obj_(idx); } const obj_t* operator*() const { - assert(idx < ptr->buffer.size() && "Index out-of-bounds"); + srsran_assert(idx < ptr->buffer.size(), "Iterator out-of-bounds (%zd >= %zd)", idx, ptr->buffer.size()); return ptr->buffer[idx]; } const obj_t* operator->() const { - assert(idx < ptr->buffer.size() && "Index out-of-bounds"); + srsran_assert(idx < ptr->buffer.size(), "Iterator out-of-bounds (%zd >= %zd)", idx, ptr->buffer.size()); return ptr->buffer[idx]; } @@ -189,7 +189,7 @@ public: iterator erase(iterator it) { - assert(it.idx < N); + srsran_assert(it.idx < N, "Iterator out-of-bounds (%zd >= %zd)", it.idx, N); iterator next = it; ++next; it->~obj_t(); @@ -207,12 +207,12 @@ public: T& operator[](K id) { - assert(contains(id)); + srsran_assert(contains(id), "Accessing non-existent ID=%zd", (size_t)id); return get_obj_(id % N).second; } const T& operator[](K id) const { - assert(contains(id)); + srsran_assert(contains(id), "Accessing non-existent ID=%zd", (size_t)id); return get_obj_(id % N).second; } diff --git a/lib/include/srsran/common/srsran_assert.h b/lib/include/srsran/common/srsran_assert.h new file mode 100644 index 000000000..f9f3e8646 --- /dev/null +++ b/lib/include/srsran/common/srsran_assert.h @@ -0,0 +1,60 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#ifndef SRSRAN_ASSERT_H +#define SRSRAN_ASSERT_H + +#include "srsran/common/standard_streams.h" +#include "srsran/srslog/srslog.h" + +#ifdef ASSERTS_ENABLED + +#define srsran_unlikely(expr) __builtin_expect(!!(expr), 0) + +#define srsran_assert(condition, fmt, ...) \ + do { \ + if (srsran_unlikely(not(condition))) { \ + srslog::fetch_basic_logger("ALL").error("%s:%d: " fmt, __FILE__, __LINE__, ##__VA_ARGS__); \ + srsran::console_stderr("%s:%d: " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \ + srslog::flush(); \ + std::abort(); \ + } \ + } while (0) + +#ifdef STOP_ON_WARNING + +#define srsran_warning(condition, fmt, ...) srsran_assert(condition, fmt, ##__VA_ARGS__) + +#else // STOP_ON_WARNING + +#define srsran_warning(condition, fmt, ...) \ + do { \ + if (srsran_unlikely(not(condition))) { \ + srslog::fetch_basic_logger("ALL").warning("%s:%d: " fmt, __FILE__, __LINE__, ##__VA_ARGS__); \ + } \ + } while (0) + +#endif // STOP_ON_WARNING + +#else // ASSERTS_ENABLED + +#define srslte_assert(condition, fmt, ...) \ + do { \ + } while (0) + +#define srsran_warning(condition, fmt, ...) \ + do { \ + } while (0) + +#endif + +#endif // SRSRAN_ASSERT_H diff --git a/lib/include/srsran/common/test_common.h b/lib/include/srsran/common/test_common.h index e85632386..8e3785c85 100644 --- a/lib/include/srsran/common/test_common.h +++ b/lib/include/srsran/common/test_common.h @@ -17,6 +17,8 @@ #ifdef __cplusplus +#include "srsran/common/crash_handler.h" +#include "srsran/common/srsran_assert.h" #include "srsran/common/standard_streams.h" #include "srsran/srslog/srslog.h" #include @@ -128,27 +130,24 @@ private: std::vector entries; }; -} // namespace srsran +inline void test_init(int argc, char** argv) +{ + // Setup a backtrace pretty printer + srsran_debug_handle_crash(argc, argv); -#define TESTERROR(fmt, ...) \ - do { \ - srslog::fetch_basic_logger("TEST").error(fmt, ##__VA_ARGS__); \ - return SRSRAN_ERROR; \ - } while (0) + srslog::fetch_basic_logger("ALL").set_level(srslog::basic_levels::info); -#define TESTWARN(fmt, ...) \ - do { \ - srslog::fetch_basic_logger("TEST").warning(fmt, ##__VA_ARGS__); \ - } while (0) + // Start the log backend. + srslog::init(); +} -#define CONDERROR(cond, fmt, ...) \ - do { \ - if (cond) { \ - TESTERROR(fmt, ##__VA_ARGS__); \ - } \ - } while (0) +} // namespace srsran + +#define CONDERROR(cond, fmt, ...) srsran_assert(not(cond), fmt, ##__VA_ARGS__) + +#define TESTERROR(fmt, ...) CONDERROR(true, fmt, ##__VA_ARGS__) -#define TESTASSERT(cond) CONDERROR((not(cond)), "[%s][Line %d] Fail at \"%s\"", __FUNCTION__, __LINE__, (#cond)) +#define TESTASSERT(cond) srsran_assert((cond), "Fail at \"%s\"", (#cond)) #else // if C diff --git a/lib/test/adt/circular_map_test.cc b/lib/test/adt/circular_map_test.cc index 662f65329..a8a79ab0a 100644 --- a/lib/test/adt/circular_map_test.cc +++ b/lib/test/adt/circular_map_test.cc @@ -10,8 +10,8 @@ * */ -#include "srsran/common/test_common.h" #include "srsran/adt/circular_map.h" +#include "srsran/common/test_common.h" namespace srsran { @@ -87,13 +87,12 @@ int test_id_map_wraparound() } // namespace srsran -int main() +int main(int argc, char** argv) { auto& test_log = srslog::fetch_basic_logger("TEST"); test_log.set_level(srslog::basic_levels::info); - // Start the log backend. - srslog::init(); + srsran::test_init(argc, argv); TESTASSERT(srsran::test_id_map() == SRSRAN_SUCCESS); TESTASSERT(srsran::test_id_map_wraparound() == SRSRAN_SUCCESS); diff --git a/srsenb/test/mac/sched_common_test_suite.cc b/srsenb/test/mac/sched_common_test_suite.cc index 3926c5ba2..2d2554f87 100644 --- a/srsenb/test/mac/sched_common_test_suite.cc +++ b/srsenb/test/mac/sched_common_test_suite.cc @@ -28,12 +28,11 @@ int test_pusch_collisions(const sf_output_res_t& sf_out, uint32_t enb_cc_idx, co auto try_ul_fill = [&](prb_interval alloc, const char* ch_str, bool strict = true) { CONDERROR(alloc.stop() > nof_prb, "Allocated RBs %s out-of-bounds", fmt::format("{}", alloc).c_str()); CONDERROR(alloc.empty(), "Allocations must have at least one PRB"); - if (strict and ul_allocs.any(alloc.start(), alloc.stop())) { - TESTERROR("Collision Detected of %s alloc=%s and cumulative_mask=0x%s", - ch_str, - fmt::format("{}", alloc).c_str(), - fmt::format("{:x}", ul_allocs).c_str()); - } + CONDERROR(strict and ul_allocs.any(alloc.start(), alloc.stop()), + "Collision Detected of %s alloc=%s and cumulative_mask=0x%s", + ch_str, + fmt::format("{}", alloc).c_str(), + fmt::format("{:x}", ul_allocs).c_str()); ul_allocs.fill(alloc.start(), alloc.stop(), true); return SRSRAN_SUCCESS; }; @@ -102,12 +101,11 @@ int test_pdsch_collisions(const sf_output_res_t& sf_out, uint32_t enb_cc_idx, co return SRSRAN_ERROR; } CONDERROR(alloc_mask.none(), "DL allocation must occupy at least one RBG."); - if ((dl_allocs & alloc_mask).any()) { - TESTERROR("Detected collision in the DL %s allocation (%s intersects %s)", - channel, - fmt::format("{}", dl_allocs).c_str(), - fmt::format("{}", alloc_mask).c_str()); - } + CONDERROR((dl_allocs & alloc_mask).any(), + "Detected collision in the DL %s allocation (%s intersects %s)", + channel, + fmt::format("{}", dl_allocs).c_str(), + fmt::format("{}", alloc_mask).c_str()); dl_allocs |= alloc_mask; return SRSRAN_SUCCESS; };