LibGpiodV2EventObserver never disposes edge events: one finalizable SafeHandle per edge causes multi-ms gen0 GC pauses
Maintainers usually reply within 1 day
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 76/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- csharp
- Domain
- embedded-iot, performance
Research direction
Start in LibGpiodV2EventObserver.HandleEdgeEventsOfRequestInLoop and inspect how EdgeEventBuffer.GetEvent creates the event handle. Ensure the event is disposed after its callbacks run, then check the event observer's tests or reproduce with the GPIO setup described in the issue. Done means each edge event is disposed promptly and the finalizer queue no longer grows by one handle per edge.
Written by the indexing model from the issue text.
Description
Description
With LibGpiodV2Driver (also used by RaspberryPi3Driver for interrupts), every edge event leaves an undisposed SafeHandle behind for the finalizer. EdgeEventBuffer.GetEvent returns a copy (gpiod_edge_event_copy, wrapped in an EdgeEventSafeHandle), and LibGpiodV2EventObserver.HandleEdgeEventsOfRequestInLoop never disposes it:
EdgeEvent edgeEvent = edgeEventBuffer.GetEvent((ulong)i);
HandleEdgeEvent(edgeEvent);
Every gen0 GC therefore has to promote and queue one finalizable object per edge received since the previous GC.
Repro
using var gpio = new GpioController();
gpio.OpenPin(23, PinMode.Output, PinValue.Low);
gpio.OpenPin(15, PinMode.InputPullUp);
PinValue state = PinValue.Low;
gpio.RegisterCallbackForPinValueChangedEvent(15, PinEventTypes.Falling, (_, _) => gpio.Write(23, state = !state));
Thread.Sleep(Timeout.Infinite);
1 kHz square wave on GPIO15, logic analyzer on GPIO15 and GPIO23.
Measured
Raspberry Pi CM4, .NET 10.0.13, System.Device.Gpio 4.2.0, libgpiod 2.2.1, Linux 6.18 PREEMPT_RT.
- Response is typically 31 µs, but every 2.25 s the process stalls for 3 ms and 3 edges are missed.
- EventPipe (GC keyword): a gen0 GC every 2.25 s with ~2250 finalization-promoted objects, one per edge.
- Pause 3.0 ms = suspend 45 µs + GC work 2.7 ms + restart 15 µs. The finalizer thread then runs for 1.2 ms.
- The pause grows with the number of edges since the previous GC: about 330 µs + 1.1 µs per edge.
DOTNET_GCgen0size=0x10000gives ~410 µs every 70 ms,0x40000gives ~740 µs every 280 ms.
In total about 1 KB is allocated per edge. WaitEdgeEventsRespectfully also creates an epoll fd, a pipe and an UnmanagedArray on every wait.
Suggested fix
Dispose the event after the callbacks have run:
using EdgeEvent edgeEvent = edgeEventBuffer.GetEvent((ulong)i);
A further step would be to read the event fields straight from the buffer instead of copying the event, which makes the event path allocation-free.
- Dominant language
- C#
- Stars
- 2.4k
- Forks
- 630
- Avg merge
- 6d 17h
- Merged PRs (30d)
- 10
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- No contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from dotnet/iot
-
GpioController.QueryComponentInformation() throws NotSupportedException with RaspberryPi3DriverOpenuntriaged
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
api-suggestion untriaged
Difficulty 3/5 1-2 days Newbie friendliness 35/100
dotnet/iot#2620 · 3 comments ·
Maintainers usually reply within 1 day
-
untriaged
Difficulty 4/5 3-5 days Newbie friendliness 30/100
Maintainers usually reply within 1 day
-
untriaged
Difficulty 5/5 Over a week Newbie friendliness 35/100
Maintainers usually reply within 1 day
-
untriaged
Difficulty 3/5 1-2 days Newbie friendliness 76/100
dotnet/iot#2614 · 2 comments ·
Maintainers usually reply within 1 day
Similar issues
-
bug effort:S P3
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
nightscout/nocturne#3093 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 67/100
Maintainers usually reply within 3 days
-
Difficulty 1/5 Under an hour Newbie friendliness 85/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100