Add shared library warmup

This commit is contained in:
Jeremy 2023-11-20 22:41:24 -06:00
parent 7c49e64ba6
commit a6a64b5671
No known key found for this signature in database
GPG Key ID: B4C8300FEC395042
3 changed files with 29 additions and 0 deletions

View File

@ -423,6 +423,10 @@ namespace cpptrace {
`safe_generate_raw_trace` will just produce an empty trace and if object information can't be resolved in a signal-safe
way then `get_minimal_object_frame` will not populate fields beyond the `raw_address`.
**Another big note:** Calls to shared objects can be lazy-loaded where the first call to the shared object invokes
non-signal-safe functions such as `malloc()`. To avoid this, call these routines in `main()` ahead of a signal handler
to "warm up" the library.
Because signal-safe tracing is an involved process, I have written up a comprehensive overview of
what is involved at [signal-safe-tracing.md](signal-safe-tracing.md).

View File

@ -80,6 +80,12 @@ Currently the only back-end that can unwind safely is libunwind. Currently, the
information in a signal-safe manner is `_dl_find_object`, which doesn't exist on macos (or windows of course). If anyone
knows ways to do these safely on other platforms, I'd be much appreciative.
# A pitfall to be aware of
Calls to functions in shared objects can be lazy-loaded where the first call to the shared object invokes
non-signal-safe functions such as `malloc()`. To avoid this, call these safe cpptrace routines in `main()` ahead of a
signal handler to "warm up" the library.
# Signal-Safe Tracing With `fork()` + `exec()`
Of the three strategies, `fork()` + `exec()`, is the most technically involved and the only way to resolve while the
@ -96,6 +102,8 @@ The main program handles most of the complexity for tracing from signal handlers
- Resolving raw frame pointers to minimal object frames
- Sending that info to the other process
Also note: A warmup for the library is done in main.
A basic implementation is as follows:
```cpp
@ -155,7 +163,16 @@ void handler(int signo, siginfo_t* info, void* context) {
_exit(1);
}
void warmup_cpptrace() {
// This is done for any dynamic-loading shenanigans
cpptrace::frame_ptr buffer[10];
std::size_t count = cpptrace::safe_generate_raw_trace(buffer, 10);
cpptrace::minimal_object_frame frame;
cpptrace::get_minimal_object_frame(buffer[0], &frame);
}
int main() {
warmup_cpptrace();
// Setup signal handler
struct sigaction action = { 0 };
action.sa_flags = 0;

View File

@ -65,9 +65,17 @@ void handler(int signo, siginfo_t* info, void* context) {
_exit(1);
}
void warmup_cpptrace() {
cpptrace::frame_ptr buffer[10];
std::size_t count = cpptrace::safe_generate_raw_trace(buffer, 10);
cpptrace::minimal_object_frame frame;
cpptrace::get_minimal_object_frame(buffer[0], &frame);
}
int main() {
cpptrace::absorb_trace_exceptions(false);
cpptrace::register_terminate_handler();
warmup_cpptrace();
struct sigaction action = { 0 };
action.sa_flags = 0;