diff --git a/src/System.Device.Gpio.Tests/LibGpiodDriverTests.cs b/src/System.Device.Gpio.Tests/LibGpiodDriverTests.cs index 1d97ca22a6eb473b16e74a3b8237534f5b789f0f..d160e633328f24ec6f01a2401879c34e60d27fb8 100644 --- a/src/System.Device.Gpio.Tests/LibGpiodDriverTests.cs +++ b/src/System.Device.Gpio.Tests/LibGpiodDriverTests.cs @@ -54,5 +54,22 @@ namespace System.Device.Gpio.Tests controller.ClosePin(InputPin); } } + + [Fact] + public void UnregisterPinValueChangedShallNotThrow() + { + using var gc = new GpioController(GetTestNumberingScheme(), GetTestDriver()); + gc.OpenPin(InputPin, PinMode.Input); + + static void PinChanged(object sender, PinValueChangedEventArgs args) + { + } + + for (var i = 0; i < 1000; i++) + { + gc.RegisterCallbackForPinValueChangedEvent(InputPin, PinEventTypes.Rising | PinEventTypes.Falling, PinChanged); + gc.UnregisterCallbackForPinValueChangedEvent(InputPin, PinChanged); + } + } } } diff --git a/src/System.Device.Gpio/System/Device/Gpio/Drivers/LibGpiodDriver.cs b/src/System.Device.Gpio/System/Device/Gpio/Drivers/LibGpiodDriver.cs index af821231411e6e51ee428e38ec4ebae79ef45f56..748edbaeae89e21d856cdf97552579ee1d2a8e21 100644 --- a/src/System.Device.Gpio/System/Device/Gpio/Drivers/LibGpiodDriver.cs +++ b/src/System.Device.Gpio/System/Device/Gpio/Drivers/LibGpiodDriver.cs @@ -339,7 +339,7 @@ namespace System.Device.Gpio.Drivers typeOfEventOccured = e.ChangeType; } - WaitForEventResult(cancellationToken, eventHandler.CancellationTokenSource.Token, ref eventOccurred); + WaitForEventResult(cancellationToken, eventHandler.CancellationToken, ref eventOccurred); RemoveCallbackForPinValueChangedEvent(pinNumber, Callback); return new WaitForEventResult diff --git a/src/System.Device.Gpio/System/Device/Gpio/LibgpiodDriverEventHandler.cs b/src/System.Device.Gpio/System/Device/Gpio/LibgpiodDriverEventHandler.cs index 47c59e2601a8e9074867309685f7c6059a3e4ac6..b24472da2a0352753a4066800437c22d182a6670 100644 --- a/src/System.Device.Gpio/System/Device/Gpio/LibgpiodDriverEventHandler.cs +++ b/src/System.Device.Gpio/System/Device/Gpio/LibgpiodDriverEventHandler.cs @@ -12,24 +12,26 @@ namespace System.Device.Gpio.Drivers { private const int ERROR_CODE_EINTR = 4; // Interrupted system call - private static string s_consumerName = Process.GetCurrentProcess().ProcessName; + private static readonly string s_consumerName = Process.GetCurrentProcess().ProcessName; public event PinChangeEventHandler? ValueRising; public event PinChangeEventHandler? ValueFalling; - private int _pinNumber; - public CancellationTokenSource CancellationTokenSource; - private Task _task; - private bool _disposing = false; + private readonly int _pinNumber; + private readonly CancellationTokenSource _cancellationTokenSource; + private readonly Task _task; + private bool _disposing; public LibGpiodDriverEventHandler(int pinNumber, SafeLineHandle safeLineHandle) { _pinNumber = pinNumber; - CancellationTokenSource = new CancellationTokenSource(); + _cancellationTokenSource = new CancellationTokenSource(); SubscribeForEvent(safeLineHandle); - _task = InitializeEventDetectionTask(CancellationTokenSource.Token, safeLineHandle); + _task = InitializeEventDetectionTask(_cancellationTokenSource.Token, safeLineHandle); } + public CancellationToken CancellationToken => _cancellationTokenSource.Token; + private void SubscribeForEvent(SafeLineHandle pinHandle) { int eventSuccess = Interop.libgpiod.gpiod_line_request_both_edges_events(pinHandle, s_consumerName); @@ -103,8 +105,17 @@ namespace System.Device.Gpio.Drivers public void Dispose() { _disposing = true; - CancellationTokenSource.Cancel(); - _task?.Wait(); + _cancellationTokenSource.Cancel(); + + try + { + _task.GetAwaiter().GetResult(); + } + catch (TaskCanceledException) + { + // ignore cancellation exception + } + ValueRising = null; ValueFalling = null; }