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

This commit is contained in:
Francisco 2021-03-22 17:37:08 +00:00 committed by Francisco Paisana
parent 9d8d897d3e
commit b5692037a2
6 changed files with 108 additions and 42 deletions

View File

@ -81,6 +81,8 @@ option(ENABLE_TIMEPROF "Enable time profiling" ON)
option(FORCE_32BIT "Add flags to force 32 bit compilation" OFF) option(FORCE_32BIT "Add flags to force 32 bit compilation" OFF)
option(ENABLE_SRSLOG_TRACING "Enable event tracing using srslog" 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 # 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 # 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) add_definitions(-DENABLE_SRSLOG_EVENT_TRACE)
endif (ENABLE_SRSLOG_TRACING) endif (ENABLE_SRSLOG_TRACING)
if (ASSERTS_ENABLED)
add_definitions(-DASSERTS_ENABLED)
endif()
if (STOP_ON_WARNING)
add_definitions(-DSTOP_ON_WARNING)
endif()
######################################################################## ########################################################################
# Find dependencies # Find dependencies
######################################################################## ########################################################################

View File

@ -14,15 +14,15 @@
#define SRSRAN_ID_MAP_H #define SRSRAN_ID_MAP_H
#include "expected.h" #include "expected.h"
#include "srsran/common/srsran_assert.h"
#include <array> #include <array>
#include <cassert>
namespace srsran { namespace srsran {
template <typename K, typename T, size_t N> template <typename K, typename T, size_t N>
class static_circular_map class static_circular_map
{ {
static_assert(std::is_integral<K>::value, "Map key must be an integer"); static_assert(std::is_integral<K>::value and std::is_unsigned<K>::value, "Map key must be an unsigned integer");
using obj_t = std::pair<K, T>; using obj_t = std::pair<K, T>;
using obj_storage_t = typename std::aligned_storage<sizeof(obj_t), alignof(obj_t)>::type; using obj_storage_t = typename std::aligned_storage<sizeof(obj_t), alignof(obj_t)>::type;
@ -48,22 +48,22 @@ public:
obj_t& operator*() 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); return ptr->get_obj_(idx);
} }
obj_t* operator->() 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); return &ptr->get_obj_(idx);
} }
const obj_t* operator*() const 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]; return ptr->buffer[idx];
} }
const obj_t* operator->() const 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]; return ptr->buffer[idx];
} }
@ -189,7 +189,7 @@ public:
iterator erase(iterator it) 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; iterator next = it;
++next; ++next;
it->~obj_t(); it->~obj_t();
@ -207,12 +207,12 @@ public:
T& operator[](K id) 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; return get_obj_(id % N).second;
} }
const T& operator[](K id) const 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; return get_obj_(id % N).second;
} }

View File

@ -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

View File

@ -17,6 +17,8 @@
#ifdef __cplusplus #ifdef __cplusplus
#include "srsran/common/crash_handler.h"
#include "srsran/common/srsran_assert.h"
#include "srsran/common/standard_streams.h" #include "srsran/common/standard_streams.h"
#include "srsran/srslog/srslog.h" #include "srsran/srslog/srslog.h"
#include <atomic> #include <atomic>
@ -128,27 +130,24 @@ private:
std::vector<std::string> entries; std::vector<std::string> entries;
}; };
inline void test_init(int argc, char** argv)
{
// Setup a backtrace pretty printer
srsran_debug_handle_crash(argc, argv);
srslog::fetch_basic_logger("ALL").set_level(srslog::basic_levels::info);
// Start the log backend.
srslog::init();
}
} // namespace srsran } // namespace srsran
#define TESTERROR(fmt, ...) \ #define CONDERROR(cond, fmt, ...) srsran_assert(not(cond), fmt, ##__VA_ARGS__)
do { \
srslog::fetch_basic_logger("TEST").error(fmt, ##__VA_ARGS__); \
return SRSRAN_ERROR; \
} while (0)
#define TESTWARN(fmt, ...) \ #define TESTERROR(fmt, ...) CONDERROR(true, fmt, ##__VA_ARGS__)
do { \
srslog::fetch_basic_logger("TEST").warning(fmt, ##__VA_ARGS__); \
} while (0)
#define CONDERROR(cond, fmt, ...) \ #define TESTASSERT(cond) srsran_assert((cond), "Fail at \"%s\"", (#cond))
do { \
if (cond) { \
TESTERROR(fmt, ##__VA_ARGS__); \
} \
} while (0)
#define TESTASSERT(cond) CONDERROR((not(cond)), "[%s][Line %d] Fail at \"%s\"", __FUNCTION__, __LINE__, (#cond))
#else // if C #else // if C

View File

@ -10,8 +10,8 @@
* *
*/ */
#include "srsran/common/test_common.h"
#include "srsran/adt/circular_map.h" #include "srsran/adt/circular_map.h"
#include "srsran/common/test_common.h"
namespace srsran { namespace srsran {
@ -87,13 +87,12 @@ int test_id_map_wraparound()
} // namespace srsran } // namespace srsran
int main() int main(int argc, char** argv)
{ {
auto& test_log = srslog::fetch_basic_logger("TEST"); auto& test_log = srslog::fetch_basic_logger("TEST");
test_log.set_level(srslog::basic_levels::info); test_log.set_level(srslog::basic_levels::info);
// Start the log backend. srsran::test_init(argc, argv);
srslog::init();
TESTASSERT(srsran::test_id_map() == SRSRAN_SUCCESS); TESTASSERT(srsran::test_id_map() == SRSRAN_SUCCESS);
TESTASSERT(srsran::test_id_map_wraparound() == SRSRAN_SUCCESS); TESTASSERT(srsran::test_id_map_wraparound() == SRSRAN_SUCCESS);

View File

@ -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) { 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.stop() > nof_prb, "Allocated RBs %s out-of-bounds", fmt::format("{}", alloc).c_str());
CONDERROR(alloc.empty(), "Allocations must have at least one PRB"); CONDERROR(alloc.empty(), "Allocations must have at least one PRB");
if (strict and ul_allocs.any(alloc.start(), alloc.stop())) { CONDERROR(strict and ul_allocs.any(alloc.start(), alloc.stop()),
TESTERROR("Collision Detected of %s alloc=%s and cumulative_mask=0x%s", "Collision Detected of %s alloc=%s and cumulative_mask=0x%s",
ch_str, ch_str,
fmt::format("{}", alloc).c_str(), fmt::format("{}", alloc).c_str(),
fmt::format("{:x}", ul_allocs).c_str()); fmt::format("{:x}", ul_allocs).c_str());
}
ul_allocs.fill(alloc.start(), alloc.stop(), true); ul_allocs.fill(alloc.start(), alloc.stop(), true);
return SRSRAN_SUCCESS; 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; return SRSRAN_ERROR;
} }
CONDERROR(alloc_mask.none(), "DL allocation must occupy at least one RBG."); CONDERROR(alloc_mask.none(), "DL allocation must occupy at least one RBG.");
if ((dl_allocs & alloc_mask).any()) { CONDERROR((dl_allocs & alloc_mask).any(),
TESTERROR("Detected collision in the DL %s allocation (%s intersects %s)", "Detected collision in the DL %s allocation (%s intersects %s)",
channel, channel,
fmt::format("{}", dl_allocs).c_str(), fmt::format("{}", dl_allocs).c_str(),
fmt::format("{}", alloc_mask).c_str()); fmt::format("{}", alloc_mask).c_str());
}
dl_allocs |= alloc_mask; dl_allocs |= alloc_mask;
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
}; };