Skip to content

Commit fc93d09

Browse files
authored
Merge pull request #4072 from Flow-Launcher/program_plugin_index_issue
Fix Possible OperationCancelException for WaitAsync Operations
2 parents e2ac321 + 2adbc33 commit fc93d09

File tree

3 files changed

+82
-19
lines changed

3 files changed

+82
-19
lines changed

Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@ public static class PluginsManifest
2626

2727
public static async Task<bool> UpdateManifestAsync(bool usePrimaryUrlOnly = false, CancellationToken token = default)
2828
{
29+
bool lockAcquired = false;
2930
try
3031
{
3132
await manifestUpdateLock.WaitAsync(token).ConfigureAwait(false);
33+
lockAcquired = true;
3234

3335
if (UserPlugins == null || usePrimaryUrlOnly || DateTime.Now.Subtract(lastFetchedAt) >= fetchTimeout)
3436
{
@@ -54,13 +56,18 @@ public static async Task<bool> UpdateManifestAsync(bool usePrimaryUrlOnly = fals
5456
return true;
5557
}
5658
}
59+
catch (OperationCanceledException)
60+
{
61+
// Ignored
62+
}
5763
catch (Exception e)
5864
{
5965
PublicApi.Instance.LogException(ClassName, "Http request failed", e);
6066
}
6167
finally
6268
{
63-
manifestUpdateLock.Release();
69+
// Only release the lock if it was acquired
70+
if (lockAcquired) manifestUpdateLock.Release();
6471
}
6572

6673
return false;

Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,18 @@ public static bool IsFastSortOption(EverythingSortOption sortOption)
4848

4949
public static async ValueTask<bool> IsEverythingRunningAsync(CancellationToken token = default)
5050
{
51-
await _semaphore.WaitAsync(token);
51+
try
52+
{
53+
await _semaphore.WaitAsync(token);
54+
}
55+
catch (OperationCanceledException)
56+
{
57+
return false;
58+
}
5259

5360
try
5461
{
55-
EverythingApiDllImport.Everything_GetMajorVersion();
62+
_ = EverythingApiDllImport.Everything_GetMajorVersion();
5663
var result = EverythingApiDllImport.Everything_GetLastError() != StateCode.IPCError;
5764
return result;
5865
}
@@ -77,8 +84,14 @@ public static async IAsyncEnumerable<SearchResult> SearchAsync(EverythingSearchO
7784
if (option.MaxCount < 0)
7885
throw new ArgumentOutOfRangeException(nameof(option.MaxCount), option.MaxCount, "MaxCount must be greater than or equal to 0");
7986

80-
await _semaphore.WaitAsync(token);
81-
87+
try
88+
{
89+
await _semaphore.WaitAsync(token);
90+
}
91+
catch (OperationCanceledException)
92+
{
93+
yield break;
94+
}
8295

8396
try
8497
{
@@ -120,8 +133,6 @@ public static async IAsyncEnumerable<SearchResult> SearchAsync(EverythingSearchO
120133
EverythingApiDllImport.Everything_SetRequestFlags(EVERYTHING_REQUEST_FULL_PATH_AND_FILE_NAME);
121134
}
122135

123-
124-
125136
if (token.IsCancellationRequested) yield break;
126137

127138
if (!EverythingApiDllImport.Everything_QueryW(true))

Plugins/Flow.Launcher.Plugin.Program/Main.cs

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ public class Main : ISettingProvider, IAsyncPlugin, IPluginI18n, IContextMenu, I
3131

3232
internal static PluginInitContext Context { get; private set; }
3333

34+
private static readonly Lock _lastIndexTimeLock = new();
35+
3436
private static readonly List<Result> emptyResults = [];
3537

3638
private static readonly MemoryCacheOptions cacheOptions = new() { SizeLimit = 1560 };
@@ -82,8 +84,45 @@ public async Task<List<Result>> QueryAsync(Query query, CancellationToken token)
8284
{
8385
var resultList = await Task.Run(async () =>
8486
{
85-
await _win32sLock.WaitAsync(token);
86-
await _uwpsLock.WaitAsync(token);
87+
// Preparing win32 programs
88+
List<Win32> win32s;
89+
bool win32LockAcquired = false;
90+
try
91+
{
92+
await _win32sLock.WaitAsync(token);
93+
win32LockAcquired = true;
94+
win32s = [.. _win32s];
95+
}
96+
catch (OperationCanceledException)
97+
{
98+
return emptyResults;
99+
}
100+
finally
101+
{
102+
// Only release the lock if it was acquired
103+
if (win32LockAcquired) _win32sLock.Release();
104+
}
105+
106+
// Preparing UWP programs
107+
List<UWPApp> uwps;
108+
bool uwpsLockAcquired = false;
109+
try
110+
{
111+
await _uwpsLock.WaitAsync(token);
112+
uwpsLockAcquired = true;
113+
uwps = [.. _uwps];
114+
}
115+
catch (OperationCanceledException)
116+
{
117+
return emptyResults;
118+
}
119+
finally
120+
{
121+
// Only release the lock if it was acquired
122+
if (uwpsLockAcquired) _uwpsLock.Release();
123+
}
124+
125+
// Start querying programs
87126
try
88127
{
89128
// Collect all UWP Windows app directories
@@ -94,8 +133,8 @@ public async Task<List<Result>> QueryAsync(Query query, CancellationToken token)
94133
.Distinct(StringComparer.OrdinalIgnoreCase)
95134
.ToArray() : null;
96135

97-
return _win32s.Cast<IProgram>()
98-
.Concat(_uwps)
136+
return win32s.Cast<IProgram>()
137+
.Concat(uwps)
99138
.AsParallel()
100139
.WithCancellation(token)
101140
.Where(HideUninstallersFilter)
@@ -109,11 +148,6 @@ public async Task<List<Result>> QueryAsync(Query query, CancellationToken token)
109148
{
110149
return emptyResults;
111150
}
112-
finally
113-
{
114-
_uwpsLock.Release();
115-
_win32sLock.Release();
116-
}
117151
}, token);
118152

119153
resultList = resultList.Count != 0 ? resultList : emptyResults;
@@ -275,7 +309,12 @@ static void MoveFile(string sourcePath, string destinationPath)
275309

276310
var cacheEmpty = _win32sCount == 0 || _uwpsCount == 0;
277311

278-
if (cacheEmpty || _settings.LastIndexTime.AddHours(30) < DateTime.Now)
312+
bool needReindex;
313+
lock (_lastIndexTimeLock)
314+
{
315+
needReindex = _settings.LastIndexTime.AddHours(30) < DateTime.Now;
316+
}
317+
if (cacheEmpty || needReindex)
279318
{
280319
_ = Task.Run(async () =>
281320
{
@@ -308,7 +347,10 @@ public static async Task IndexWin32ProgramsAsync()
308347
}
309348
ResetCache();
310349
await Context.API.SaveCacheBinaryStorageAsync<List<Win32>>(Win32CacheName, Context.CurrentPluginMetadata.PluginCacheDirectoryPath);
311-
_settings.LastIndexTime = DateTime.Now;
350+
lock (_lastIndexTimeLock)
351+
{
352+
_settings.LastIndexTime = DateTime.Now;
353+
}
312354
}
313355
catch (Exception e)
314356
{
@@ -333,7 +375,10 @@ public static async Task IndexUwpProgramsAsync()
333375
}
334376
ResetCache();
335377
await Context.API.SaveCacheBinaryStorageAsync<List<UWPApp>>(UwpCacheName, Context.CurrentPluginMetadata.PluginCacheDirectoryPath);
336-
_settings.LastIndexTime = DateTime.Now;
378+
lock (_lastIndexTimeLock)
379+
{
380+
_settings.LastIndexTime = DateTime.Now;
381+
}
337382
}
338383
catch (Exception e)
339384
{

0 commit comments

Comments
 (0)