From c1c98d8798a20f0f8e137b276707c9525a19fcbf Mon Sep 17 00:00:00 2001 From: Jay Cho Date: Sun, 31 May 2026 20:06:23 +0900 Subject: [PATCH] [Tizen.Network.WiFi] Use RunContinuationsAsynchronously on async TCS Every TaskCompletionSource in the WiFi async path is completed from a native callback thread. Without TaskCreationOptions.RunContinuationsAsynchronously, each SetResult/SetException runs the awaiter's continuation inline on that native callback thread. That risks deadlock when the continuation re-enters Interop.WiFi.* synchronously, and pins user code to the callback thread instead of the ThreadPool/SynchronizationContext. Adds the flag to all 13 TaskCompletionSource construction sites: WiFiManagerImpl.cs: Activate, ActivateWithWiFiPickerTested, Deactivate, Scan, ScanSpecificAP, BssidScan, HiddenAPConnect, StartMultiScan (8) WiFiAP.cs: Connect, ConnectWps, ConnectWpsWithoutSsid, Disconnect, ForgetAP (5) No public API change. Behavior change is limited to which thread runs the awaiter's continuation, which matches the documented async contract. Fixes #7620 --- .../Tizen.Network.WiFi/WiFiAP.cs | 10 +++++----- .../Tizen.Network.WiFi/WiFiManagerImpl.cs | 16 ++++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Tizen.Network.WiFi/Tizen.Network.WiFi/WiFiAP.cs b/src/Tizen.Network.WiFi/Tizen.Network.WiFi/WiFiAP.cs index 7e3811d87c3..4b365ad87c3 100644 --- a/src/Tizen.Network.WiFi/Tizen.Network.WiFi/WiFiAP.cs +++ b/src/Tizen.Network.WiFi/Tizen.Network.WiFi/WiFiAP.cs @@ -228,7 +228,7 @@ public Task ConnectAsync() { throw new ObjectDisposedException("Invalid AP instance (Object may have been disposed or released)"); } - TaskCompletionSource task = new TaskCompletionSource(); + TaskCompletionSource task = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); IntPtr id; lock (_callback_map) { @@ -309,7 +309,7 @@ public Task ConnectWpsAsync(WpsInfo info) throw new ObjectDisposedException("Invalid AP instance (Object may have been disposed or released)"); } - TaskCompletionSource wpsTask = new TaskCompletionSource(); + TaskCompletionSource wpsTask = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); _wpsTaskMap[_apHandle] = wpsTask; IntPtr id; @@ -407,7 +407,7 @@ public Task ConnectWpsAsync(WpsInfo info) public static Task ConnectWpsWithoutSsidAsync(WpsInfo info) { Log.Info(Globals.LogTag, "ConnectWpsWithoutSsidAsync"); - wpsWithoutSsidTask = new TaskCompletionSource(); + wpsWithoutSsidTask = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); IntPtr id; lock (s_callbackMap) { @@ -536,7 +536,7 @@ public Task DisconnectAsync() { throw new ObjectDisposedException("Invalid AP instance (Object may have been disposed or released)"); } - TaskCompletionSource task = new TaskCompletionSource(); + TaskCompletionSource task = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); IntPtr id; lock (_callback_map) { @@ -638,7 +638,7 @@ public Task ForgetAPAsync() { throw new ObjectDisposedException("Invalid AP instance (Object may have been disposed or released)"); } - TaskCompletionSource task = new TaskCompletionSource(); + TaskCompletionSource task = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); IntPtr id; lock (_callback_map) { diff --git a/src/Tizen.Network.WiFi/Tizen.Network.WiFi/WiFiManagerImpl.cs b/src/Tizen.Network.WiFi/Tizen.Network.WiFi/WiFiManagerImpl.cs index 21762e8f180..03074b34a4e 100644 --- a/src/Tizen.Network.WiFi/Tizen.Network.WiFi/WiFiManagerImpl.cs +++ b/src/Tizen.Network.WiFi/Tizen.Network.WiFi/WiFiManagerImpl.cs @@ -316,7 +316,7 @@ internal WiFiAP GetConnectedAP() internal Task ActivateAsync() { Log.Info(Globals.LogTag, "ActivateAsync"); - TaskCompletionSource task = new TaskCompletionSource(); + TaskCompletionSource task = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); IntPtr id; lock (_callback_map) { @@ -362,7 +362,7 @@ internal Task ActivateAsync() internal Task ActivateWithWiFiPickerTestedAsync() { Log.Info(Globals.LogTag, "ActivateWithWiFiPickerTestedAsync"); - TaskCompletionSource task = new TaskCompletionSource(); + TaskCompletionSource task = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); IntPtr id; lock (_callback_map) { @@ -408,7 +408,7 @@ internal Task ActivateWithWiFiPickerTestedAsync() internal Task DeactivateAsync() { Log.Info(Globals.LogTag, "DeactivateAsync"); - TaskCompletionSource task = new TaskCompletionSource(); + TaskCompletionSource task = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); IntPtr id; lock (_callback_map) { @@ -454,7 +454,7 @@ internal Task DeactivateAsync() internal Task ScanAsync() { Log.Info(Globals.LogTag, "ScanAsync"); - TaskCompletionSource task = new TaskCompletionSource(); + TaskCompletionSource task = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); IntPtr id; lock (_callback_map) { @@ -500,7 +500,7 @@ internal Task ScanAsync() internal Task ScanSpecificAPAsync(string essid) { Log.Info(Globals.LogTag, $"ScanSpecificAPAsync {essid}"); - TaskCompletionSource task = new TaskCompletionSource(); + TaskCompletionSource task = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); IntPtr id; lock (_callback_map) { @@ -546,7 +546,7 @@ internal Task ScanSpecificAPAsync(string essid) internal Task BssidScanAsync() { Log.Info(Globals.LogTag, "BssidScanAsync"); - TaskCompletionSource task = new TaskCompletionSource(); + TaskCompletionSource task = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); IntPtr id; lock (_callback_map) { @@ -599,7 +599,7 @@ internal void SetAutoScanMode(int scanMode) internal Task HiddenAPConnectAsync(string essid, int secType, string passphrase) { Log.Info(Globals.LogTag, "HiddenAPConnect"); - TaskCompletionSource task = new TaskCompletionSource(); + TaskCompletionSource task = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); IntPtr id; lock (_callback_map) { @@ -667,7 +667,7 @@ internal void SetSpecificScanFreq(int freq) internal Task StartMultiScan() { Log.Debug(Globals.LogTag, "StartMultiScan"); - TaskCompletionSource task = new TaskCompletionSource(); + TaskCompletionSource task = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); IntPtr id; lock (_callback_map) {