public void TestDeadlockWhenRemovingAnActiveDataSource() { var logFile = new Mock <ILogSource>(); var dataSource = new Mock <IDataSource>(); dataSource.Setup(x => x.UnfilteredLogSource).Returns(logFile.Object); var collection = new BookmarkCollection(_bookmarks.Object, TimeSpan.Zero); logFile.Setup(x => x.RemoveListener(It.IsAny <ILogSourceListener>())) .Callback((ILogSourceListener unused) => { // In order to produce the deadlock, we have to simulate what's happening in reality. // Any ILogFile implementation will hold a lock both while invoking listeners and while // Removing them. Waiting on the OnLogFileModified() call simulates exactly that... var task = new Task(() => { collection.OnLogFileModified(logFile.Object, LogSourceModification.Removed(0, 10)); }, TaskCreationOptions.LongRunning); task.Start(); task.Wait(); }); collection.AddDataSource(dataSource.Object); var removeTask = Task.Factory.StartNew(() => collection.RemoveDataSource(dataSource.Object)); removeTask.Wait(TimeSpan.FromSeconds(1)).Should().BeTrue("because RemoveDataSource should not block at all"); logFile.Verify(x => x.RemoveListener(collection), Times.Once); }
private bool RemoveNoLock(IDataSource dataSource) { _settings.Remove(dataSource.Settings); if (_dataSources.Remove(dataSource)) { _bookmarks.RemoveDataSource(dataSource); dataSource.Dispose(); return(true); } return(false); }
public bool Remove(IDataSource dataSource) { lock (_syncRoot) { _settings.Remove(dataSource.Settings); if (_dataSources.Remove(dataSource)) { _bookmarks.RemoveDataSource(dataSource); dataSource.Dispose(); return(true); } return(false); } }