mirror of
https://github.com/logos-messaging/nim-ffi.git
synced 2026-06-21 00:40:16 +00:00
The recycle/async-destroy work changed the Nim `ffiDtor` export from `int destroy(ctx)` to `int destroy(ctx, callback, userData)`, but the C++ and Rust generators still emitted the 1-arg signature. Foreign callers therefore passed only `ctx`; inside Nim, `callback`/`userData` held uninitialised register garbage. `requestRecycle` stored the garbage callback and the recycle handler later invoked it — a jump through a wild pointer that segfaulted in every C++ E2E / ASan / TSan job (the crash surfaced at teardown, after each test's assertions had already passed). Generate the 3-arg ABI and have the destructor/Drop block on the recycle callback via the existing sync-call helper, so the pool slot is fully drained and parked before the handle goes away — otherwise rapid create/destroy churn (StressShortLivedPerThreadContext, ThreadedHammer) could outrun the recycle and exhaust the pool. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
28 lines
1.3 KiB
Smarty
28 lines
1.3 KiB
Smarty
// Special-member policy: this class owns a {{LIB}} context, which in
|
|
// turn owns the library's worker thread(s) and internal state. Moving
|
|
// such an object out from under a caller silently tears that state
|
|
// down and is easy to misuse (e.g. storing in a container that
|
|
// relocates its elements). It also has no clean analogue in the other
|
|
// binding languages we generate. So copies and moves are both
|
|
// deleted; ownership is transferred via {{CTX}}::create returning a
|
|
// std::unique_ptr<{{CTX}}>. The destructor still releases the
|
|
// context.
|
|
~{{CTX}}() {
|
|
if (ptr_) {
|
|
// `{{LIB}}_destroy` is non-blocking at the C ABI: it parks the
|
|
// context for reuse and reports the outcome via the callback. Block
|
|
// here until that callback fires so the pool slot is fully drained
|
|
// and parked before this object goes away — otherwise a rapid
|
|
// create/destroy churn could outrun the recycle and exhaust the pool.
|
|
(void)ffi_call_([this](FFICallback cb, void* ud) {
|
|
return {{LIB}}_destroy(ptr_, cb, ud);
|
|
}, timeout_);
|
|
ptr_ = nullptr;
|
|
}
|
|
}
|
|
|
|
{{CTX}}(const {{CTX}}&) = delete;
|
|
{{CTX}}& operator=(const {{CTX}}&) = delete;
|
|
{{CTX}}({{CTX}}&&) = delete;
|
|
{{CTX}}& operator=({{CTX}}&&) = delete;
|