Skip to content

fix(winrtble): release radio state handlers on final adapter drop - #477

Merged
qdot merged 1 commit into
deviceplug:devfrom
Raphiiko:fix/winrt-radio-cleanup-0.13.1
Sep 20, 2026
Merged

qdot merged 1 commit into
deviceplug:devfrom
Raphiiko:fix/winrt-radio-cleanup-0.13.1

Conversation

@Raphiiko

@Raphiiko Raphiiko commented Sep 20, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This is the proposed fix for the Windows memory growth described in #476.

Astra wrote this patch and analyzed the memory dumps. I can confirm the difference in memory consumption in my tests, but I can't vouch for the implementation or whether this is the right fix.

Changes

The patch saves the Radio::StateChanged registration token and removes the handler when the last adapter clone is dropped. The callback holds a weak reference to the device manager instead of keeping it alive.

It leaves the scan-handler cleanup in btleplug 0.13.1 unchanged.

Testing

I ran my application with unpatched 0.13.1 for about eight hours, then with this patch for two hours, using the same five Bluetooth LE devices.

Unpatched Patched
Private memory at start 53 MiB 53 MiB
Private memory at end 1,477 MiB 56 MiB
Growth over matching periods About 182 MiB/hour About 0.37 MiB/hour

All five devices connected in both runs, with no connection failures logged during measurement. I haven't tested the patched build for eight hours.

Astra's analysis of the matching dumps found radio callbacks increasing from 18 to 3,198 in the unpatched run. With the patch, it found one at both the start and end.

The patch also adds three Windows Bluetooth regression tests covering handler removal, adapter clones, and cleanup after scanning. All three passed, along with the 42 existing library tests. Formatting and library lint checks passed.

Keep radio event registration ownership shared across adapter clones. Use a weak manager reference in the callback and unregister when the last adapter drops. Add Windows hardware regression tests for handler release, adapter clones, and scan cleanup.
@qdot

qdot commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

Fix looks good, thanks!

@qdot
qdot changed the base branch from master to dev September 20, 2026 19:21
@qdot
qdot self-requested a review September 20, 2026 19:21
@qdot
qdot merged commit 69428c0 into deviceplug:dev Sep 20, 2026
5 checks passed
Raphiiko added a commit to Raphiiko/OyasumiVR that referenced this pull request Sep 30, 2026
The btleplug fork carried one commit, which releases the WinRT radio
state handlers on the final adapter drop. Upstream merged it as
deviceplug/btleplug#477 and released it in 0.13.2. The core now uses
btleplug 0.13.3 from crates.io. 0.13.3 also fixes a GATT deadlock, a
scanner crash on truncated service data, and GATT operations failing
after a dropped connection.

minisign-verify goes from 0.2.5 to 0.3.0 in the privileged launcher, and
minisign from 0.7.9 to 0.10.0 in the signing tool and the launcher tests.
Neither changes the signature format, and neither needed code changes.
Newer minisign refuses keys that minisign 0.7.4 to 0.8.0 wrote with an
empty password. The launcher test that loads the real signing key passes.
Raphiiko added a commit to Raphiiko/OyasumiVR that referenced this pull request Sep 30, 2026
* chore(deps): upgrade Angular 22.2, Vitest 5, Sentry 11 and Rust crates

Move Angular from 22.1 to 22.2 with ng update, which made no code
changes. Angular 22.2 accepts Vitest 5, so Vitest moves from 4.1 to 5.0.
TypeScript stays on 6.0, because Angular 22.2 still requires <6.1. Other
npm packages take their in-range patch releases. The @tauri-apps packages
stay on their current versions so they keep matching the Tauri 2.11 crates.

@sentry/angular 11 removes sendDefaultPii, enableLogs and enableMetrics.
Leaving its replacement, dataCollection, unset would collect user info,
cookies, HTTP headers and bodies by default. Error reporting now sets
dataCollection so that none of those are collected, and it drops the two
options that have no replacement.

Rust: base64 0.22 to 0.23 and dirs 6 to 7 in the core, nvml-wrapper 0.12
to 0.13 in the elevated sidecar, base64 0.23 in src-shared-rust and as a
test-only dependency of the privileged launcher, and in-range updates to
sentry 0.49.3 and hyper-util 0.1.21. None of them needed code changes.

* chore(deps): move btleplug to crates.io and upgrade minisign

The btleplug fork carried one commit, which releases the WinRT radio
state handlers on the final adapter drop. Upstream merged it as
deviceplug/btleplug#477 and released it in 0.13.2. The core now uses
btleplug 0.13.3 from crates.io. 0.13.3 also fixes a GATT deadlock, a
scanner crash on truncated service data, and GATT operations failing
after a dropped connection.

minisign-verify goes from 0.2.5 to 0.3.0 in the privileged launcher, and
minisign from 0.7.9 to 0.10.0 in the signing tool and the launcher tests.
Neither changes the signature format, and neither needed code changes.
Newer minisign refuses keys that minisign 0.7.4 to 0.8.0 wrote with an
empty password. The launcher test that loads the real signing key passes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants