From d489f31903d603a05e0c1d80c6fe442cc989f7f4 Mon Sep 17 00:00:00 2001 From: Alan McGovern Date: Thu, 13 Jan 2022 22:10:06 +0000 Subject: [PATCH] [core] Ensure the dht node cahe is written safely (#501) Now it's threadsafe when users call StartAsync/StopAsync on multiple different TorrentManager instances concurrently. Fixes #499 --- src/MonoTorrent/MonoTorrent.Client/ClientEngine.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/MonoTorrent/MonoTorrent.Client/ClientEngine.cs b/src/MonoTorrent/MonoTorrent.Client/ClientEngine.cs index aebc5511c..3edce9b99 100644 --- a/src/MonoTorrent/MonoTorrent.Client/ClientEngine.cs +++ b/src/MonoTorrent/MonoTorrent.Client/ClientEngine.cs @@ -174,6 +174,8 @@ public async Task SaveStateAsync (string pathToStateFile) #region Member Variables + readonly SemaphoreSlim dhtNodeLocker; + readonly ListenManager listenManager; // Listens for incoming connections and passes them off to the correct TorrentManager int tickCount; /// @@ -269,6 +271,7 @@ public ClientEngine (EngineSettings settings) CheckSettingsAreValid (Settings); allTorrents = new List (); + dhtNodeLocker = new SemaphoreSlim (1, 1); publicTorrents = new List (); Torrents = new ReadOnlyCollection (publicTorrents); @@ -823,12 +826,19 @@ async ReusableTasks.ReusableTask MaybeSaveDhtNodes () if (nodes.Length == 0) return; - await Task.Run (() => { + // Perform this action on a threadpool thread. + await MainLoop.SwitchThread (); + + // Ensure only 1 thread at a time tries to save DhtNodes. + // Users can call StartAsync/StopAsync many times on + // TorrentManagers and the file write could happen + // concurrently. + using (await dhtNodeLocker.EnterAsync ().ConfigureAwait (false)) { var savePath = Settings.GetDhtNodeCacheFilePath (); var parentDir = Path.GetDirectoryName (savePath); Directory.CreateDirectory (parentDir); File.WriteAllBytes (savePath, nodes); - }); + } } public async Task UpdateSettingsAsync (EngineSettings settings)