/** * * \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 SRSLOG_BACKEND_WORKER_H #define SRSLOG_BACKEND_WORKER_H #include "srsran/srslog/detail/log_entry.h" #include "srsran/srslog/detail/support/dyn_arg_store_pool.h" #include "srsran/srslog/detail/support/work_queue.h" #include "srsran/srslog/shared_types.h" #include #include namespace srslog { /// The backend worker runs in a secondary thread a routine that endlessly pops /// log entries from a work queue and dispatches them to the selected sinks. class backend_worker { public: backend_worker(detail::work_queue& queue, detail::dyn_arg_store_pool& arg_pool) : queue(queue), arg_pool(arg_pool), running_flag(false) {} backend_worker(const backend_worker&) = delete; backend_worker& operator=(const backend_worker&) = delete; ~backend_worker() { stop(); } /// Starts the backend worker thread. After returning from this function the /// secondary thread is ensured to be running. Calling this function more than /// once has no effect. void start(backend_priority priority); /// Stops the backend worker thread if it is running, otherwise the call has /// no effect. After returning from this function the secondary thread is /// ensured to have terminated. Calling this function more than once has no /// effect. void stop(); /// Returns true if the worker thread is currently running, otherwise /// returns false. bool is_running() const { return running_flag; } /// Uses the specified error handler to receive error notifications. Calls to /// this method when the worker is running will get ignored. void set_error_handler(error_handler new_err_handler) { // Ignore new handlers when the worker is running. if (is_running()) { return; } // Install a dummy callback if the input one is empty. This avoids having to // check for null at each call site. if (!new_err_handler) { err_handler = [](const std::string&) {}; return; } err_handler = std::move(new_err_handler); } private: /// Creates the worker thread. /// NOTE: This function should be only called once. void create_worker(backend_priority priority); /// Entry function used by the secondary thread. void do_work(); /// Processes the log entry. void process_log_entry(detail::log_entry&& entry); /// Processes outstanding entries in the queue until it gets empty. void process_outstanding_entries(); /// Checks the current size of the queue reporting an error message if it is /// about to reach its maximum capacity. /// Error message is only reported once to avoid spamming. void report_queue_on_full_once() { if (queue.is_almost_full()) { err_handler(fmt::format("The backend queue size is about to reach its maximum " "capacity of {} elements, new log entries will get " "discarded.\nConsider increasing the queue capacity.", queue.get_capacity())); err_handler = [](const std::string&) {}; } } /// Establishes the specified thread priority for the calling thread. void set_thread_priority(backend_priority priority) const; private: detail::work_queue& queue; detail::dyn_arg_store_pool& arg_pool; detail::shared_variable running_flag; error_handler err_handler = [](const std::string& error) { fmt::print(stderr, "srsLog error - {}\n", error); }; std::once_flag start_once_flag; std::thread worker_thread; fmt::memory_buffer fmt_buffer; }; } // namespace srslog #endif // SRSLOG_BACKEND_WORKER_H