[AI Task] [Tizen.Multimedia.Remoting] Add RunContinuationsAsynchronously to async TCS#7696
[AI Task] [Tizen.Multimedia.Remoting] Add RunContinuationsAsynchronously to async TCS#7696JoonghyunCho wants to merge 2 commits into
Conversation
…nc TCS The 8 TaskCompletionSource sites in ScreenMirroring, WebRTC, MediaController and MediaControlServer complete on native/event-manager callback threads. Without RunContinuationsAsynchronously their continuations run inline on the completing thread, which can occupy native callback threads and risk deadlock on SynchronizationContext re-entry. Mirrors the WiFi fix in #7620. Fixes #7639 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request updates several instances of TaskCompletionSource to use TaskCreationOptions.RunContinuationsAsynchronously across the remoting and multimedia modules. The review feedback suggests simplifying RunAsync in ScreenMirroring.cs by returning the Task from Task.Run directly instead of wrapping it in a redundant TaskCompletionSource<bool>. Additionally, multiple await Task.Yield(); calls in WebRTC.cs are now redundant due to the asynchronous continuation guarantee and should be removed to avoid unnecessary context switching.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| private Task RunAsync(Func<IntPtr, ScreenMirroringErrorCode> func, string failMessage) | ||
| { | ||
| var tcs = new TaskCompletionSource<bool>(); | ||
| var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously); |
There was a problem hiding this comment.
The RunAsync method can be simplified by returning the Task from Task.Run directly, rather than wrapping it in a redundant TaskCompletionSource<bool>. Since RunAsync returns a non-generic Task, the bool result is ignored anyway.
Refactoring this avoids the allocation of the TaskCompletionSource and its associated task, and simplifies error propagation.
For example:
private Task RunAsync(Func<IntPtr, ScreenMirroringErrorCode> func, string failMessage)
{
return Task.Run(() =>
{
var ret = func(Handle);
if (ret != ScreenMirroringErrorCode.None)
{
throw ret.AsException(failMessage);
}
});
}| ValidateWebRTCState(WebRTCState.Idle); | ||
|
|
||
| var tcs = new TaskCompletionSource<bool>(); | ||
| var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously); |
There was a problem hiding this comment.
Now that TaskCreationOptions.RunContinuationsAsynchronously is specified on the TaskCompletionSource, the continuation of await tcs.Task is guaranteed to execute asynchronously on the thread pool.
As a result, the await Task.Yield(); on line 196 is redundant and can be safely removed to avoid unnecessary context switching and thread rescheduling.
| ValidateWebRTCState(WebRTCState.Negotiating, WebRTCState.Playing); | ||
|
|
||
| var tcsSdpCreated = new TaskCompletionSource<string>(); | ||
| var tcsSdpCreated = new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously); |
There was a problem hiding this comment.
Now that TaskCreationOptions.RunContinuationsAsynchronously is specified on tcsSdpCreated, the continuation of await tcsSdpCreated.Task is guaranteed to execute asynchronously on the thread pool.
Therefore, the await Task.Yield(); on line 261 is redundant and can be safely removed to avoid unnecessary context switching and thread rescheduling.
| ValidateWebRTCState(WebRTCState.Negotiating, WebRTCState.Playing); | ||
|
|
||
| var tcsSdpCreated = new TaskCompletionSource<string>(); | ||
| var tcsSdpCreated = new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously); |
There was a problem hiding this comment.
Now that TaskCreationOptions.RunContinuationsAsynchronously is specified on tcsSdpCreated, the continuation of await tcsSdpCreated.Task is guaranteed to execute asynchronously on the thread pool.
Therefore, the await Task.Yield(); on line 300 is redundant and can be safely removed to avoid unnecessary context switching and thread rescheduling.
Simplify ScreenMirroring.RunAsync to return Task.Run directly (drop redundant TaskCompletionSource), and remove now-redundant await Task.Yield() after awaiting RunContinuationsAsynchronously TCS in WebRTC.StartAsync/CreateOfferAsync/CreateAnswerAsync. Applied-Human-Comments: 3410546783,3410546787,3410546789,3410546792 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
🤖 [AI Review] |
Internal API ChangedAdded: 17, Removed: 0, Changed: 0Added+ /// <since_tizen>none</since_tizen
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ Tizen.NUI.Gesture/SourceSubType Tizen.NUI.Gesture::SourceSub()
+ /// <since_tizen>none</since_tizen
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ Tizen.NUI.Gesture/SourceSubType
+ /// <since_tizen>none</since_tizen
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ static Tizen.NUI.Gesture/SourceSubType Tizen.NUI.Gesture/SourceSubType::Finger
+ /// <since_tizen>none</since_tizen
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ static Tizen.NUI.Gesture/SourceSubType Tizen.NUI.Gesture/SourceSubType::Fingernail
+ /// <since_tizen>none</since_tizen
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ static Tizen.NUI.Gesture/SourceSubType Tizen.NUI.Gesture/SourceSubType::HandFlat
+ /// <since_tizen>none</since_tizen
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ static Tizen.NUI.Gesture/SourceSubType Tizen.NUI.Gesture/SourceSubType::HandSide
+ /// <since_tizen>none</since_tizen
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ static Tizen.NUI.Gesture/SourceSubType Tizen.NUI.Gesture/SourceSubType::Knuckle
+ /// <since_tizen>none</since_tizen
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ static Tizen.NUI.Gesture/SourceSubType Tizen.NUI.Gesture/SourceSubType::None
+ /// <since_tizen>none</since_tizen
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ static Tizen.NUI.Gesture/SourceSubType Tizen.NUI.Gesture/SourceSubType::Palm
+ /// <since_tizen>none</since_tizen
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ static Tizen.NUI.Gesture/SourceSubType Tizen.NUI.Gesture/SourceSubType::PenTip
+ /// <since_tizen>none</since_tizen
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ static Tizen.NUI.Gesture/SourceSubType Tizen.NUI.Gesture/SourceSubType::Remocon
+ /// <since_tizen>none</since_tizen
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ static Tizen.NUI.Gesture/SourceSubType Tizen.NUI.Gesture/SourceSubType::Trackball
+ /// <since_tizen>none</since_tizen
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ static Tizen.NUI.Gesture/SourceSubType Tizen.NUI.Gesture/SourceSubType::Trackpad
+ /// <since_tizen>none</since_tizen
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ static Tizen.NUI.Gesture/SourceSubType Tizen.NUI.Gesture/SourceSubType::Trackpoint
+ /// <since_tizen>none</since_tizen
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ static Tizen.NUI.Gesture/SourceSubType Tizen.NUI.Gesture/SourceSubType::VirtualKeyboard
+ /// <since_tizen>none</since_tizen
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ static Tizen.NUI.Gesture/SourceSubType Tizen.NUI.Gesture/SourceSubType::VirtualMouse
+ /// <since_tizen>none</since_tizen
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ static Tizen.NUI.Gesture/SourceSubType Tizen.NUI.Gesture/SourceSubType::VirtualRemocon
|
Summary
Tizen.Multimedia.Remotinghad 8TaskCompletionSource<T>sites that omittedTaskCreationOptions.RunContinuationsAsynchronously. Thesetcsinstances are completed on native callback threads or external event-manager callback threads (e.g.CommandCompleted += ...), so by default their continuations run inline on the completing thread. That can occupy the native callback thread with arbitrary user continuation code (blocking subsequent callbacks / harming ABI stability) and risks deadlock when the awaiter re-enters the sameSynchronizationContext.This is the Remoting counterpart of the same known-critical pattern fixed for
Tizen.Network.WiFiin #7620.WebRTC/WebRTCSignalingServer.cs:165already specified the option correctly and is left unchanged.Changes
src/Tizen.Multimedia.Remoting/ScreenMirroring/ScreenMirroring.cs—RunAsynctcs (1 site)src/Tizen.Multimedia.Remoting/WebRTC/WebRTC.cs—StartAsync,CreateOfferAsync,CreateAnswerAsynctcs (3 sites)src/Tizen.Multimedia.Remoting/MediaController/MediaController.cs—RequestAsync(Command),RequestAsync(Command, Bundle)tcs (2 sites)src/Tizen.Multimedia.Remoting/MediaController/MediaControlServer.cs—RequestAsync(clientId, command),RequestAsync(clientId, command, Bundle)tcs (2 sites)Each change adds
TaskCreationOptions.RunContinuationsAsynchronouslyto theTaskCompletionSource<T>constructor. No public API signatures change; the returnedTaskis unchanged. Behavior is preserved — moving continuations to the ThreadPool does not alterawaitsemantics.Mode
Refactoring
Verification
dotnet build -c ReleaseonTizen.Multimedia.Remoting, 0 errors)sdb deviceslists none). Manual benchmark verification required.Fixes #7639