Browse Source

Fix some issues with LoadSolutionProjects-thread.

newNRvisualizers
Daniel Grunwald 15 years ago
parent
commit
19820f6cc2
  1. 8
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Parser/Parser.cs
  2. 3
      src/Main/Base/Project/Src/Project/Items/ProjectReferenceProjectItem.cs
  3. 1
      src/Main/Base/Project/Src/Project/Solution/Solution.cs
  4. 53
      src/Main/Base/Project/Src/Services/ParserService/AssemblyParserService.cs
  5. 51
      src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs
  6. 8
      src/Main/Base/Project/Src/Services/ProjectService/ProjectService.cs

8
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Parser/Parser.cs

@ -71,7 +71,13 @@ namespace CSharpBinding.Parser @@ -71,7 +71,13 @@ namespace CSharpBinding.Parser
{
CSharpParser parser = new CSharpParser();
parser.GenerateTypeSystemMode = !fullParseInformationRequested;
CompilationUnit cu = parser.Parse(fileContent.CreateReader());
CompilationUnit cu;
try {
cu = parser.Parse(fileContent.CreateReader());
} catch (Exception ex) {
LoggingService.Error(ex);
cu = new CompilationUnit();
}
TypeSystemConvertVisitor cv = new TypeSystemConvertVisitor(projectContent, fileName);
ParsedFile file = cv.Convert(cu);

3
src/Main/Base/Project/Src/Project/Items/ProjectReferenceProjectItem.cs

@ -10,11 +10,12 @@ namespace ICSharpCode.SharpDevelop.Project @@ -10,11 +10,12 @@ namespace ICSharpCode.SharpDevelop.Project
{
public class ProjectReferenceProjectItem : ReferenceProjectItem
{
IProject referencedProject;
volatile IProject referencedProject;
[Browsable(false)]
public IProject ReferencedProject {
get {
// must be thread-safe because it's used by LoadSolutionProjectsThread
if (referencedProject == null)
referencedProject = ProjectService.GetProject(this.FileName);
return referencedProject;

1
src/Main/Base/Project/Src/Project/Solution/Solution.cs

@ -63,6 +63,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -63,6 +63,7 @@ namespace ICSharpCode.SharpDevelop.Project
[Browsable(false)]
public IEnumerable<IProject> Projects {
get {
// TODO: make this property thread-safe
Stack<ISolutionFolder> stack = new Stack<ISolutionFolder>();
foreach (ISolutionFolder solutionFolder in Folders) {

53
src/Main/Base/Project/Src/Services/ParserService/AssemblyParserService.cs

@ -3,8 +3,10 @@ @@ -3,8 +3,10 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
@ -38,7 +40,8 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -38,7 +40,8 @@ namespace ICSharpCode.SharpDevelop.Parser
}
}
static Dictionary<FileName, WeakReference> projectContentDictionary = new Dictionary<FileName, WeakReference>();
// TODO: use weak reference to IProjectContent (not to LoadedAssembly!) so that unused assemblies can be unloaded
static Dictionary<FileName, LoadedAssembly> projectContentDictionary = new Dictionary<FileName, LoadedAssembly>();
[ThreadStatic] static Dictionary<FileName, LoadedAssembly> up2dateProjectContents;
@ -90,8 +93,8 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -90,8 +93,8 @@ namespace ICSharpCode.SharpDevelop.Parser
{
List<FileName> removed = new List<FileName>();
foreach (var pair in projectContentDictionary) {
if (!pair.Value.IsAlive)
removed.Add(pair.Key);
//if (!pair.Value.IsAlive)
// removed.Add(pair.Key);
}
foreach (var key in removed)
projectContentDictionary.Remove(key);
@ -108,26 +111,21 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -108,26 +111,21 @@ namespace ICSharpCode.SharpDevelop.Parser
}
DateTime lastWriteTime = File.GetLastWriteTimeUtc(fileName);
lock (projectContentDictionary) {
WeakReference wr;
if (projectContentDictionary.TryGetValue(fileName, out wr)) {
asm = (LoadedAssembly)wr.Target;
if (asm != null && asm.AssemblyFileLastWriteTime == lastWriteTime) {
if (projectContentDictionary.TryGetValue(fileName, out asm)) {
if (asm.AssemblyFileLastWriteTime == lastWriteTime) {
return asm;
}
} else {
wr = null;
asm = null;
}
var task = new Task<IProjectContent>(() => LoadAssembly(fileName, CancellationToken.None));
isNewTask = true;
asm = new LoadedAssembly(task, lastWriteTime);
if (wr != null) {
wr.Target = asm;
} else {
if (up2dateProjectContents == null)
CleanWeakDictionary();
wr = new WeakReference(asm);
projectContentDictionary.Add(fileName, wr);
}
if (up2dateProjectContents == null)
CleanWeakDictionary();
projectContentDictionary.Add(fileName, asm);
return asm;
}
}
@ -278,14 +276,23 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -278,14 +276,23 @@ namespace ICSharpCode.SharpDevelop.Parser
if (cacheFileName == null)
return;
LoggingService.Debug("Serializing to " + cacheFileName);
Directory.CreateDirectory(DomPersistencePath);
using (FileStream fs = new FileStream(cacheFileName, FileMode.Create, FileAccess.Write)) {
using (BinaryWriter writer = new BinaryWriterWith7BitEncodedInts(fs)) {
writer.Write(lastWriteTime.Ticks);
FastSerializer s = new FastSerializer();
s.SerializationBinder = new MySerializationBinder();
s.Serialize(writer, pc);
try {
Directory.CreateDirectory(DomPersistencePath);
using (FileStream fs = new FileStream(cacheFileName, FileMode.Create, FileAccess.Write)) {
using (BinaryWriter writer = new BinaryWriterWith7BitEncodedInts(fs)) {
writer.Write(lastWriteTime.Ticks);
FastSerializer s = new FastSerializer();
s.SerializationBinder = new MySerializationBinder();
s.Serialize(writer, pc);
}
}
} catch (IOException ex) {
LoggingService.Warn(ex);
// Can happen if two SD instances are trying to access the file at the same time.
// We'll just let one of them win, and instance that got the exception won't write to the cache at all.
// Similarly, we also ignore the other kinds of IO exceptions.
} catch (UnauthorizedAccessException ex) {
LoggingService.Warn(ex);
}
}

51
src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs

@ -58,9 +58,11 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -58,9 +58,11 @@ namespace ICSharpCode.SharpDevelop.Parser
return string.Format("[{0}: {1}]", GetType().Name, project.Name);
}
const int LoadingReferencesWorkAmount = 15; // in number of C# files
int GetInitializationWorkAmount()
{
return project.Items.Count + 15;
return project.Items.Count + LoadingReferencesWorkAmount;
}
void Initialize(IProgressMonitor progressMonitor)
@ -73,8 +75,9 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -73,8 +75,9 @@ namespace ICSharpCode.SharpDevelop.Parser
ProjectService.ProjectItemAdded += OnProjectItemAdded;
ProjectService.ProjectItemRemoved += OnProjectItemRemoved;
}
using (IProgressMonitor initReferencesProgressMonitor = progressMonitor.CreateSubTask(15),
parseProgressMonitor = progressMonitor.CreateSubTask(projectItems.Count))
double scalingFactor = 1.0 / (project.Items.Count + LoadingReferencesWorkAmount);
using (IProgressMonitor initReferencesProgressMonitor = progressMonitor.CreateSubTask(LoadingReferencesWorkAmount * scalingFactor),
parseProgressMonitor = progressMonitor.CreateSubTask(projectItems.Count * scalingFactor))
{
var resolveReferencesTask = ResolveReferencesAsync(projectItems, initReferencesProgressMonitor);
@ -122,18 +125,42 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -122,18 +125,42 @@ namespace ICSharpCode.SharpDevelop.Parser
return System.Threading.Tasks.Task.Factory.StartNew(
delegate {
project.ResolveAssemblyReferences();
List<ITypeResolveContext> contexts = new List<ITypeResolveContext>();
const double assemblyResolvingProgress = 0.3;
progressMonitor.Progress += assemblyResolvingProgress;
progressMonitor.CancellationToken.ThrowIfCancellationRequested();
List<string> assemblyFiles = new List<string>();
string mscorlib = project.MscorlibPath;
if (mscorlib != null && File.Exists(mscorlib)) {
var pc = AssemblyParserService.GetAssembly(FileName.Create(mscorlib), progressMonitor.CancellationToken);
contexts.Add(pc);
}
if (mscorlib != null)
assemblyFiles.Add(mscorlib);
List<ITypeResolveContext> contexts = new List<ITypeResolveContext>();
contexts.Add(this);
foreach (ReferenceProjectItem reference in projectItems.OfType<ReferenceProjectItem>()) {
if (File.Exists(reference.FileName)) {
var pc = AssemblyParserService.GetAssembly(FileName.Create(reference.FileName), progressMonitor.CancellationToken);
contexts.Add(pc);
foreach (ProjectItem item in projectItems) {
ReferenceProjectItem reference = item as ReferenceProjectItem;
if (reference != null) {
if (ItemType.ReferenceItemTypes.Contains(reference.ItemType)) {
ProjectReferenceProjectItem projectReference = reference as ProjectReferenceProjectItem;
if (projectReference != null) {
IProject p = projectReference.ReferencedProject;
if (p != null)
contexts.Add(p.ProjectContent);
} else {
assemblyFiles.Add(reference.FileName);
}
}
}
}
foreach (string file in assemblyFiles) {
progressMonitor.CancellationToken.ThrowIfCancellationRequested();
if (File.Exists(file)) {
var pc = AssemblyParserService.GetAssembly(FileName.Create(file), progressMonitor.CancellationToken);
if (pc != null) {
contexts.Add(pc);
}
}
progressMonitor.Progress += (1.0 - assemblyResolvingProgress) / assemblyFiles.Count;
}
this.typeResolveContext = new CompositeTypeResolveContext(contexts);
}, progressMonitor.CancellationToken);

8
src/Main/Base/Project/Src/Services/ProjectService/ProjectService.cs

@ -16,7 +16,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -16,7 +16,7 @@ namespace ICSharpCode.SharpDevelop.Project
{
public static class ProjectService
{
static Solution openSolution;
volatile static Solution openSolution;
volatile static IProject currentProject;
public static Solution OpenSolution {
@ -52,8 +52,10 @@ namespace ICSharpCode.SharpDevelop.Project @@ -52,8 +52,10 @@ namespace ICSharpCode.SharpDevelop.Project
/// </summary>
public static IProject GetProject(string projectFilename)
{
if (openSolution == null) return null;
foreach (IProject project in openSolution.Projects) {
Solution sln = openSolution;
if (sln == null)
return null;
foreach (IProject project in sln.Projects) {
if (FileUtility.IsEqualFileName(project.FileName, projectFilename)) {
return project;
}

Loading…
Cancel
Save