Skip to content

Commit 2fbaea2

Browse files
authored
Merge pull request dotnet#43197 from mdh1418/add_deadlock_warning_for_eventsource_callbacks
[Diagnostics] Add EventSource Callback Possible Deadlock Warning
2 parents 8366cfa + 96fad7b commit 2fbaea2

File tree

1 file changed

+31
-0
lines changed

1 file changed

+31
-0
lines changed

Diff for: docs/core/diagnostics/eventsource-collect-and-view-traces.md

+31
Original file line numberDiff line numberDiff line change
@@ -272,3 +272,34 @@ this isn't required. Following is an example `EventListener` implementation that
272272
3/24/2022 9:23:35 AM RequestStart
273273
3/24/2022 9:23:35 AM RequestStop
274274
```
275+
276+
> [!WARNING]
277+
> Potential Pitfalls when implementing EventSource Callbacks via EventListener include deadlocks, infinite recursions, and uninitialized types.
278+
>
279+
> EventSource instances are initialized early in the runtime, before some core features are fully initialized. As a result, acquiring locks inside an EventSource callback like <xref:System.Diagnostics.Tracing.EventListener.OnEventWritten%2A> when the thread normally would not have done so may cause deadlocks.
280+
>
281+
> To mitigate this risk, consider the following precautions:
282+
>
283+
> - **Use Queues to Defer Work**: There are a variety of APIs you might want to call in OnEventWritten() that do non-trivial work, for example File IO, Console, or Http. For most events, these APIs work fine, but if you tried to call Console.WriteLine() in an event handler during the initialization of the Console class then it would probably fail. If you don't know whether a given event handler occurs at a time when APIs are safe to call, consider adding some information about the event to an in-memory queue instead. Then, on a separate thread, process items in the queue.
284+
> - **Minimize Lock Duration**: Ensure that any locks acquired within the callback are not held for extended periods.
285+
> - **Use Non-blocking APIs**: Prefer using non-blocking APIs within the callback to avoid potential deadlocks.
286+
> - **Implement a Re-entrancy Guard**: Use a re-entrancy guard to prevent infinite recursion. For example:
287+
>
288+
> ```csharp
289+
> [ThreadStatic] private static bool t_insideCallback;
290+
>
291+
> public void OnEventWritten(...)
292+
> {
293+
> if (t_insideCallback) return; // if our callback triggered the event to occur recursively
294+
> // exit now to avoid infinite recursion
295+
> try
296+
> {
297+
> t_insideCallback = true;
298+
> // do callback work
299+
> }
300+
> finally
301+
> {
302+
> t_insideCallback = false;
303+
> }
304+
> }
305+
> ```

0 commit comments

Comments
 (0)