Skip to content

Commit 1ec9d3f

Browse files
committed
teardown for blst.PairingPool
1 parent ebb9def commit 1ec9d3f

File tree

2 files changed

+30
-3
lines changed

2 files changed

+30
-3
lines changed

bindings/napi/blst.zig

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -549,14 +549,15 @@ const VerifyMultiJob = struct {
549549
/// Persistent thread pool with preallocated buffers for parallel pairing verification.
550550
/// Workers park on ResetEvents between jobs. All dispatch buffers are preallocated.
551551
/// Scratch arrays for NAPI callers eliminate per-call allocs for n <= SCRATCH_MAX.
552-
const PairingPool = struct {
552+
pub const PairingPool = struct {
553553
const max_workers = 256;
554554

555555
n_workers: u32,
556556
workers: []std.Thread,
557557
work_items: []?WorkItem,
558558
work_ready: []std.Thread.ResetEvent,
559559
work_done: []std.Thread.ResetEvent,
560+
shutdown: std.atomic.Value(bool),
560561

561562
// Preallocated per-dispatch buffers (safe to reuse: dispatch is synchronous)
562563
pairing_bufs: [][Pairing.sizeOf()]u8,
@@ -568,7 +569,7 @@ const PairingPool = struct {
568569
scratch_sig_ptrs: []*const Signature,
569570
scratch_rands: [][32]u8,
570571

571-
var instance: ?*PairingPool = null;
572+
pub var instance: ?*PairingPool = null;
572573

573574
fn get() *PairingPool {
574575
if (@as(*const ?*PairingPool, &instance).*) |p| return p;
@@ -605,6 +606,7 @@ const PairingPool = struct {
605606
.work_items = work_items,
606607
.work_ready = work_ready,
607608
.work_done = work_done,
609+
.shutdown = std.atomic.Value(bool).init(false),
608610
.pairing_bufs = allocator.alloc([Pairing.sizeOf()]u8, n_workers) catch @panic("PairingPool: OOM"),
609611
.has_work = allocator.alloc(bool, n_workers) catch @panic("PairingPool: OOM"),
610612
.scratch_msg_ptrs = allocator.alloc(*const [32]u8, SCRATCH_MAX) catch @panic("PairingPool: OOM"),
@@ -616,7 +618,6 @@ const PairingPool = struct {
616618
// Workers get IDs 1..n; ID 0 is reserved for the calling (main) thread.
617619
for (0..background_worker_count) |i| {
618620
threads[i] = std.Thread.spawn(.{}, workerLoop, .{ pool, i + 1 }) catch @panic("PairingPool: spawn failed");
619-
threads[i].detach();
620621
}
621622

622623
instance = pool;
@@ -628,6 +629,8 @@ const PairingPool = struct {
628629
pool.work_ready[worker_index].wait();
629630
pool.work_ready[worker_index].reset();
630631

632+
if (pool.shutdown.load(.acquire)) return;
633+
631634
const item = pool.work_items[worker_index] orelse {
632635
pool.work_done[worker_index].set();
633636
continue;
@@ -850,6 +853,29 @@ const PairingPool = struct {
850853

851854
return acc.finalVerify(null);
852855
}
856+
857+
pub fn deinit(pool: *PairingPool) void {
858+
pool.shutdown.store(true, .release);
859+
860+
// Wake all background workers so they observe the shutdown flag and exit.
861+
for (pool.work_ready[1..pool.n_workers]) |*e| e.set();
862+
863+
// Join all background threads.
864+
for (pool.workers) |t| t.join();
865+
866+
allocator.free(pool.workers);
867+
allocator.free(pool.work_items);
868+
allocator.free(pool.work_ready);
869+
allocator.free(pool.work_done);
870+
allocator.free(pool.pairing_bufs);
871+
allocator.free(pool.has_work);
872+
allocator.free(pool.scratch_msg_ptrs);
873+
allocator.free(pool.scratch_pk_ptrs);
874+
allocator.free(pool.scratch_sig_ptrs);
875+
allocator.free(pool.scratch_rands);
876+
allocator.destroy(pool);
877+
instance = null;
878+
}
853879
};
854880

855881
/// Verify an aggregated signature against multiple messages and multiple public keys.

bindings/napi/root.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const EnvCleanup = struct {
2424
config.state.deinit();
2525
pubkeys.state.deinit();
2626
pool.state.deinit();
27+
if (blst.PairingPool.instance) |p| p.deinit();
2728
}
2829
}
2930
};

0 commit comments

Comments
 (0)