-
-
Notifications
You must be signed in to change notification settings - Fork 39
Fix event subscription memory leak #39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -1,10 +1,12 @@ | ||||||||
| using System; | ||||||||
| using System.Collections; | ||||||||
| using System.Collections.Concurrent; | ||||||||
| using System.Collections.Generic; | ||||||||
| using System.Linq; | ||||||||
| using System.Linq.Expressions; | ||||||||
| using System.Reflection; | ||||||||
| using System.Text; | ||||||||
| using System.Threading; | ||||||||
| using System.Threading.Tasks; | ||||||||
|
|
||||||||
| namespace Westwind.WebConnection | ||||||||
|
|
@@ -18,13 +20,10 @@ public sealed class EventSubscriber : IDisposable | |||||||
| private readonly object _source; | ||||||||
| private readonly List<DelegateInfo> _eventHandlers = new List<DelegateInfo>(); | ||||||||
| private readonly ConcurrentQueue<RaisedEvent> _raisedEvents = new ConcurrentQueue<RaisedEvent>(); | ||||||||
| private TaskCompletionSource<RaisedEvent> _completion = new TaskCompletionSource<RaisedEvent>(); | ||||||||
| private volatile SemaphoreSlim _signal = new SemaphoreSlim(0); | ||||||||
|
|
||||||||
| public EventSubscriber(object source, String prefix = "", dynamic vfp = null) | ||||||||
| { | ||||||||
| // Indicates that initially the client is not waiting. | ||||||||
| _completion.SetResult(null); | ||||||||
|
|
||||||||
| // For each event, adds a handler that calls QueueInteropEvent. | ||||||||
| _source = source; | ||||||||
| foreach (var ev in source.GetType().GetEvents()) | ||||||||
|
|
@@ -62,16 +61,37 @@ public DelegateInfo(Delegate handler, EventInfo eventInfo) | |||||||
|
|
||||||||
| public void Dispose() | ||||||||
| { | ||||||||
| if (_signal == null) | ||||||||
| return; | ||||||||
|
|
||||||||
| // Unsubscribe from all events. | ||||||||
| foreach (var item in _eventHandlers) | ||||||||
| item.EventInfo.RemoveEventHandler(_source, item.Delegate); | ||||||||
| _completion.TrySetCanceled(); | ||||||||
|
|
||||||||
| // Remove references to objects. | ||||||||
| _eventHandlers.Clear(); | ||||||||
| while (_raisedEvents.TryDequeue(out _)) { } | ||||||||
|
|
||||||||
| // Release any waiting thread and dispose the semaphore. | ||||||||
| _signal.Release(); | ||||||||
|
Comment on lines
+75
to
+76
|
||||||||
| // Release any waiting thread and dispose the semaphore. | |
| _signal.Release(); | |
| // Dispose the semaphore. |
Copilot
AI
Oct 30, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Creating an ArrayList wrapper for every event is inefficient. Since ArrayList can be initialized directly from a collection, consider using new ArrayList(parameters) instead, which eliminates the AddRange call and improves performance.
| var parametersArrayList = new ArrayList(parameters.Length); | |
| parametersArrayList.AddRange(parameters); | |
| var parametersArrayList = new ArrayList(parameters); |
Copilot
AI
Oct 30, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Poor error handling: empty catch block.
| try { signal.Wait(); } catch (ObjectDisposedException) { } | |
| try { signal.Wait(); } catch (ObjectDisposedException ex) { System.Diagnostics.Debug.WriteLine($"ObjectDisposedException in WaitForEvent: {ex.Message}"); } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment describes a workaround for a race condition but doesn't explain its root cause or propose a proper fix. If the race condition is fixed by the C# changes in this PR, this comment should be updated or removed. If the issue persists, the comment should provide more details about when and why this occurs to help future maintainers address it properly.