LIBFEBUG++(3) | Library Functions Manual | LIBFEBUG++(3) |
febug::controlled_socket
,
febug::wrapper
,
febug::formatters
,
febug::debug_handler()
—
#include
<libfebug.hpp>
c++
-l
febug++
…
#define FEBUG_DONT 0
#define FEBUG_SOCKET "/var/run/febug.sock"
#define FEBUG_SIGNUM SIGUSR2
getenv
("FEBUG_DONT"
);
getenv
("FEBUG_SOCKET"
);
struct febug::controlled_socket;
const febug::controlled_socket
febug::global_controlled_socket;
struct febug::wrapper;
febug::wrapper::wrapper
(const
T & data, const char
* name, ...);
febug::wrapper::wrapper
(const
T & data, uint8_t
signal, const char *
name, ...);
febug::wrapper::wrapper
(const
T & data, uint8_t
signal, const char *
name, va_list
ap);
std::map<size_t, void (*)(int, size_t)> febug::formatters;
void
febug::debug_handler
(int);
There are three compile-time macros that allow customising
libfebug++
behaviour:
FEBUG_DONT
FEBUG_SIGNUM
febug_wrap
(). Defaults to
SIGUSR2
.FEBUG_SOCKET
There are two environment variables that allow a user to customise its behaviour:
FEBUG_DONT
FEBUG_SOCKET
FEBUG_SOCKET
to connect to
febug(8).The febug::controlled_socket structure is defined as follows:
struct febug::controlled_socket { int fd = -1; inline operator int() const noexcept { return this->fd; } controlled_socket(const char * path = FEBUG_SOCKET) noexcept; ~controlled_socket() noexcept; };
There is a global instance at
febug::global_controlled_socket which, if
path (FEBUG_SOCKET
) isn't the
null pointer, attempts to connect to
febug(8) and will set
fd, if successful. Similarly, destroying it will hang
up and reset fd.
The program needs to install
febug::debug_handler
() (or a wrapper around it) as
the signal handler for FEBUG_SIGNUM
(and any other
signals, if different ones are explicitly requested); if notifications are
disabled (by requesting SIGKILL
), some event loop
that answers on febug::global_controlled_socket must
be in place. It's a no-op if
febug::global_controlled_socket is
-1.
The program should register handlers for types of variables it
wishes to handle by adding entries to
febug::formatters — the key is
typeid(std::decay_t<T>).hash_code()
, so if
this yields different results for two types that should have the same
handler, multiple entries need to be registered. If no handler was
registered for a type, febug::debug_handler
() will
instead return a generic "not found" message. The handler takes
the write end of the pipe as the first argument, and the variable ID as the
second; it shouldn't close the pipe, as that is done by
febug::debug_handler
() regardless, and the program
would then run the risk of closing another file with the same descriptor
simultaneously opened by another thread.
The febug::wrapper structure is defined as follows:
template <class T> struct febug::wrapper { const T * data; wrapper(const T & data, const char * name, ...) noexcept; wrapper(const T & data, uint8_t signal, const char * name, ...) noexcept; wrapper(const T & data, uint8_t signal, const char * name, va_list ap) noexcept; ~wrapper() noexcept; };
If the program wishes to debug a variable, it should construct a
febug::wrapper referencing it; the constructor will
send a febug_message
with the type corresponding to
typeid(std::decay_t<T>).hash_code()
, ID
corresponding to the pointer to data, signal being
either specified or defaulting to FEBUG_SIGNUM
, and
name formatted according to
printf(3).
The destructor will send a stop_febug_message. Both become
no-ops if febug::global_controlled_socket is
-1.
std::sort
() but waits a second between each
comparison; the vector and the amount of comparisons can be inspected via a
febug(8) mount:
// SPDX-License-Identifier: MIT #include <libfebug.hpp> #include <algorithm> #include <cstring> #include <errno.h> #include <unistd.h> #include <vector> int main() { if(febug::global_controlled_socket != -1) { febug::formatters.emplace( typeid(std::vector<int>).hash_code(), [](int retpipe, std::size_t vid) { const std::vector<int> & data = *(const std::vector<int> *)vid; for(auto num : data) dprintf(retpipe, "%d ", num); write(retpipe, "\n", 1); }); febug::formatters.emplace( typeid(std::size_t).hash_code(), [](int retpipe, std::size_t vid) { const std::size_t & data = *(const std::size_t *)vid; dprintf(retpipe, "%zu\n", data); }); } struct sigaction handler {}; handler.sa_handler = febug::debug_handler; if(sigaction(FEBUG_SIGNUM, &handler, nullptr) == -1) std::fprintf(stderr, "sigaction: %s\n", std::strerror(errno)); { std::vector<int> data{-1, -2, -3, 0, 1, 2, 3, -1, -2, -3, 0, 1, 2, 3, -1, -2, -3, 0, 1, 2, 3, -1, -2, -3, 0, 1, 2, 3, -1, -2, -3, 0, 1, 2, 3, -1, -2, -3, 0, 1, 2, 3}; std::size_t comparisons_done{}; febug::wrapper data_w{data, "cool_data"}; febug::wrapper comparisons_done_w{comparisons_done, "comparisons"}; std::sort(data.begin(), data.end(), [&](auto lhs, auto rhs) { sleep(1); ++comparisons_done; return lhs < rhs; }); } sleep(2); }
febug mailing list: <~nabijaczleweli/febug@lists.sr.ht>, archived at https://lists.sr.ht/~nabijaczleweli/febug
June 12, 2023 | febug 0.2.1 |