Skip to content

[AI Task] [Tizen.Multimedia.Remoting] Add RunContinuationsAsynchronously to async TCS#7696

Open
JoonghyunCho wants to merge 2 commits into
mainfrom
ai-task/issue-7639
Open

[AI Task] [Tizen.Multimedia.Remoting] Add RunContinuationsAsynchronously to async TCS#7696
JoonghyunCho wants to merge 2 commits into
mainfrom
ai-task/issue-7639

Conversation

@JoonghyunCho

Copy link
Copy Markdown
Member

Summary

Tizen.Multimedia.Remoting had 8 TaskCompletionSource<T> sites that omitted TaskCreationOptions.RunContinuationsAsynchronously. These tcs instances 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 same SynchronizationContext.

This is the Remoting counterpart of the same known-critical pattern fixed for Tizen.Network.WiFi in #7620. WebRTC/WebRTCSignalingServer.cs:165 already specified the option correctly and is left unchanged.

Changes

  • src/Tizen.Multimedia.Remoting/ScreenMirroring/ScreenMirroring.csRunAsync tcs (1 site)
  • src/Tizen.Multimedia.Remoting/WebRTC/WebRTC.csStartAsync, CreateOfferAsync, CreateAnswerAsync tcs (3 sites)
  • src/Tizen.Multimedia.Remoting/MediaController/MediaController.csRequestAsync(Command), RequestAsync(Command, Bundle) tcs (2 sites)
  • src/Tizen.Multimedia.Remoting/MediaController/MediaControlServer.csRequestAsync(clientId, command), RequestAsync(clientId, command, Bundle) tcs (2 sites)

Each change adds TaskCreationOptions.RunContinuationsAsynchronously to the TaskCompletionSource<T> constructor. No public API signatures change; the returned Task is unchanged. Behavior is preserved — moving continuations to the ThreadPool does not alter await semantics.

Mode

Refactoring

Verification

  • Build: passed (dotnet build -c Release on Tizen.Multimedia.Remoting, 0 errors)
  • Tests: N/A (no behavior change; internal async completion semantics only)
  • Benchmark: skipped (sdb error: no device connected — sdb devices lists none). Manual benchmark verification required.

Fixes #7639

…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>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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);
        }
    });
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 [AI Review]
Addressed in 64f1117.

ValidateWebRTCState(WebRTCState.Idle);

var tcs = new TaskCompletionSource<bool>();
var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 [AI Review]
Addressed in 64f1117.

ValidateWebRTCState(WebRTCState.Negotiating, WebRTCState.Playing);

var tcsSdpCreated = new TaskCompletionSource<string>();
var tcsSdpCreated = new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 [AI Review]
Addressed in 64f1117.

ValidateWebRTCState(WebRTCState.Negotiating, WebRTCState.Playing);

var tcsSdpCreated = new TaskCompletionSource<string>();
var tcsSdpCreated = new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 [AI Review]
Addressed in 64f1117.

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>
@JoonghyunCho

Copy link
Copy Markdown
Member Author

🤖 [AI Review]
Addressed review feedback in commit 64f1117. Summary: simplified ScreenMirroring.RunAsync to return Task.Run(...) directly (dropping the redundant TaskCompletionSource<bool>), and removed the now-redundant await Task.Yield(); after the RunContinuationsAsynchronously TCS awaits in WebRTC.StartAsync, CreateOfferAsync, and CreateAnswerAsync. Built Tizen.Multimedia.Remoting (Release) — 0 errors.

@TizenAPI-Bot

Copy link
Copy Markdown
Collaborator

Internal API Changed

Added: 17, Removed: 0, Changed: 0

Added

+ /// <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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants