Implement an emergency cleanup handler registration mechanism to allow modules to clean themselves before application gets killed.

Flush PCAP contents just before killing the application.
master
faluco 3 years ago committed by Andre Puschmann
parent 0507d9df2b
commit 2c1e9c0c55

@ -0,0 +1,25 @@
/**
*
* \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_EMERGENCY_HANDLERS_H
#define SRSRAN_EMERGENCY_HANDLERS_H
using emergency_cleanup_callback = void (*)(void*);
// Add a cleanup function to be called when a kill signal is about to be delivered to the process. The handler may
// optionally pass a pointer to identify what instance of the handler is being called.
void add_emergency_cleanup_handler(emergency_cleanup_callback callback, void* data);
// Executes all registered emergency cleanup handlers.
void execute_emergency_cleanup_handlers();
#endif // SRSRAN_EMERGENCY_HANDLERS_H

@ -28,6 +28,10 @@ class mac_pcap_base : protected srsran::thread
{
public:
mac_pcap_base();
mac_pcap_base(const mac_pcap_base& other) = delete;
mac_pcap_base& operator=(const mac_pcap_base& other) = delete;
~mac_pcap_base();
void enable(bool enable);
virtual uint32_t close() = 0;
@ -36,7 +40,7 @@ public:
// EUTRA
void
write_ul_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t crnti, uint32_t reTX, uint32_t tti, uint8_t cc_idx);
write_ul_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t crnti, uint32_t reTX, uint32_t tti, uint8_t cc_idx);
void write_dl_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t crnti, bool crc_ok, uint32_t tti, uint8_t cc_idx);
void write_dl_ranti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t ranti, bool crc_ok, uint32_t tti, uint8_t cc_idx);

@ -21,7 +21,10 @@ namespace srsran {
class s1ap_pcap
{
public:
s1ap_pcap() = default;
s1ap_pcap();
s1ap_pcap(const s1ap_pcap& other) = delete;
s1ap_pcap& operator=(const s1ap_pcap& other) = delete;
void enable();
void open(const char* filename_);
void close();

@ -18,6 +18,7 @@
#ifndef SRSRAN_SIGNAL_HANDLER_H
#define SRSRAN_SIGNAL_HANDLER_H
#include "srsran/common/emergency_handlers.h"
#include "srsran/srslog/sink.h"
#include "srsran/srslog/srslog.h"
#include <signal.h>
@ -30,7 +31,7 @@ extern "C" {
#define SRSRAN_TERM_TIMEOUT_S (5)
// static vars required by signal handling
static srslog::sink* log_sink = nullptr;
static srslog::sink* log_sink = nullptr;
static std::atomic<bool> running = {true};
void srsran_dft_exit();
@ -41,11 +42,12 @@ static void srsran_signal_handler(int signal)
case SIGALRM:
fprintf(stderr, "Couldn't stop after %ds. Forcing exit.\n", SRSRAN_TERM_TIMEOUT_S);
srslog::flush();
//:TODO: refactor the sighandler, should not depend on log utilities
//: TODO: refactor the sighandler, should not depend on log utilities
if (log_sink) {
log_sink->flush();
}
srsran_dft_exit();
execute_emergency_cleanup_handlers();
raise(SIGKILL);
default:
// all other registered signals try to stop the app gracefully

@ -28,6 +28,7 @@ set(SOURCES arch_select.cc
rlc_pcap.cc
s1ap_pcap.cc
security.cc
emergency_handlers.cc
standard_streams.cc
thread_pool.cc
threads.c

@ -0,0 +1,59 @@
/**
*
* \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.
*
*/
#include "srsran/common/emergency_handlers.h"
#include "srsran/support/srsran_assert.h"
namespace {
/// Holds the callback function pointer and the associated user provided data pointer.
struct handler_instance {
std::atomic<void*> data{};
std::atomic<emergency_cleanup_callback> callback{};
};
} // namespace
// Handlers are added in a thread safe manner without using locks to avoid possible issues if a signal is emitted while
// modifying the callback array.
static constexpr unsigned max_handlers = 12;
static handler_instance registered_handlers[max_handlers];
static std::atomic<unsigned> num_handlers;
void add_emergency_cleanup_handler(emergency_cleanup_callback callback, void* data)
{
// Reserve a slot in the array.
auto pos = num_handlers.fetch_add(1);
// Check if we have space in the array.
if (pos >= max_handlers) {
srsran_assert(0, "Exceeded the emergency cleanup handler registered limit");
return;
}
// Order is important here: write last the callback member as it is used to signal that the handler is valid when
// reading the array.
registered_handlers[pos].data.store(data);
registered_handlers[pos].callback.store(callback);
}
void execute_emergency_cleanup_handlers()
{
for (unsigned i = 0, e = num_handlers; i != e; ++i) {
auto callback = registered_handlers[i].callback.load();
// Test the validity of the callback as it may have not been written yet into the array even if num_callbacks has
// been updated.
if (callback) {
callback(registered_handlers[i].data.load());
}
}
}

@ -11,13 +11,23 @@
*/
#include "srsran/common/mac_pcap_base.h"
#include "srsran/common/emergency_handlers.h"
#include "srsran/config.h"
#include "srsran/phy/common/phy_common.h"
#include <stdint.h>
namespace srsran {
mac_pcap_base::mac_pcap_base() : logger(srslog::fetch_basic_logger("MAC")), thread("PCAP_WRITER_MAC") {}
/// Try to flush the contents of the pcap class before the application is killed.
static void emergency_cleanup_handler(void* data)
{
reinterpret_cast<mac_pcap_base*>(data)->close();
}
mac_pcap_base::mac_pcap_base() : logger(srslog::fetch_basic_logger("MAC")), thread("PCAP_WRITER_MAC")
{
add_emergency_cleanup_handler(emergency_cleanup_handler, this);
}
mac_pcap_base::~mac_pcap_base() {}
@ -45,7 +55,7 @@ void mac_pcap_base::run_thread()
}
// write remainder of queue
pcap_pdu_t pdu = {};
pcap_pdu_t pdu = {};
while (queue.try_pop(pdu)) {
std::lock_guard<std::mutex> lock(mutex);
write_pdu(pdu);

@ -11,12 +11,24 @@
*/
#include "srsran/common/s1ap_pcap.h"
#include "srsran/common/emergency_handlers.h"
#include "srsran/common/pcap.h"
#include "srsran/srsran.h"
#include <stdint.h>
namespace srsran {
/// Try to flush the contents of the pcap class before the application is killed.
static void emergency_cleanup_handler(void* data)
{
reinterpret_cast<s1ap_pcap*>(data)->close();
}
s1ap_pcap::s1ap_pcap()
{
add_emergency_cleanup_handler(emergency_cleanup_handler, this);
}
void s1ap_pcap::enable()
{
enable_write = true;
@ -29,6 +41,9 @@ void s1ap_pcap::open(const char* filename_)
}
void s1ap_pcap::close()
{
if (!enable_write) {
return;
}
fprintf(stdout, "Saving S1AP PCAP file (DLT=%d) to %s\n", S1AP_LTE_DLT, filename.c_str());
DLT_PCAP_Close(pcap_file);
}

Loading…
Cancel
Save