Skip to content

Commit 55a40aa

Browse files
authored
Merge pull request #1910 from paulvanbrenk/bug589521
Make HierarchyIdMap thread handling more explicit
2 parents e68a3ee + 8def84e commit 55a40aa

File tree

1 file changed

+35
-24
lines changed

1 file changed

+35
-24
lines changed

Nodejs/Product/Nodejs/SharedProject/HierarchyIdMap.cs

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
1+
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
22

33
using System;
44
using System.Collections.Generic;
@@ -8,16 +8,18 @@ namespace Microsoft.VisualStudioTools.Project
88
{
99
internal sealed class HierarchyIdMap
1010
{
11-
private readonly List<WeakReference<HierarchyNode>> _ids = new List<WeakReference<HierarchyNode>>();
12-
private readonly Stack<int> _freedIds = new Stack<int>();
11+
private readonly List<WeakReference<HierarchyNode>> ids = new List<WeakReference<HierarchyNode>>();
12+
private readonly Stack<int> freedIds = new Stack<int>();
13+
14+
private readonly object theLock = new object();
1315

1416
/// <summary>
1517
/// Must be called from the UI thread
1618
/// </summary>
1719
public uint Add(HierarchyNode node)
1820
{
1921
#if DEBUG
20-
foreach (var reference in this._ids)
22+
foreach (var reference in this.ids)
2123
{
2224
if (reference != null)
2325
{
@@ -28,17 +30,23 @@ public uint Add(HierarchyNode node)
2830
}
2931
}
3032
#endif
31-
if (this._freedIds.Count > 0)
32-
{
33-
var i = this._freedIds.Pop();
34-
this._ids[i] = new WeakReference<HierarchyNode>(node);
35-
return (uint)i + 1;
36-
}
37-
else
33+
34+
VisualStudio.Shell.ThreadHelper.ThrowIfNotOnUIThread();
35+
36+
lock (this.theLock)
3837
{
39-
this._ids.Add(new WeakReference<HierarchyNode>(node));
40-
// ids are 1 based
41-
return (uint)this._ids.Count;
38+
if (this.freedIds.Count > 0)
39+
{
40+
var i = this.freedIds.Pop();
41+
this.ids[i] = new WeakReference<HierarchyNode>(node);
42+
return (uint)i + 1;
43+
}
44+
else
45+
{
46+
this.ids.Add(new WeakReference<HierarchyNode>(node));
47+
// ids are 1 based
48+
return (uint)this.ids.Count;
49+
}
4250
}
4351
}
4452

@@ -47,16 +55,19 @@ public uint Add(HierarchyNode node)
4755
/// </summary>
4856
public void Remove(HierarchyNode node)
4957
{
50-
var i = (int)node.ID - 1;
51-
if (i < 0 ||
52-
i >= this._ids.Count ||
53-
(this._ids[i].TryGetTarget(out var found) && !object.ReferenceEquals(node, found)))
58+
VisualStudio.Shell.ThreadHelper.ThrowIfNotOnUIThread();
59+
60+
lock (this.theLock)
5461
{
55-
throw new InvalidOperationException("Removing node with invalid ID or map is corrupted");
56-
}
62+
var i = (int)node.ID - 1;
63+
if (i < 0 || i >= this.ids.Count || (this.ids[i].TryGetTarget(out var found) && !object.ReferenceEquals(node, found)))
64+
{
65+
throw new InvalidOperationException("Removing node with invalid ID or map is corrupted");
66+
}
5767

58-
this._ids[i] = null;
59-
this._freedIds.Push(i);
68+
this.ids[i] = null;
69+
this.freedIds.Push(i);
70+
}
6071
}
6172

6273
/// <summary>
@@ -67,9 +78,9 @@ public HierarchyNode this[uint itemId]
6778
get
6879
{
6980
var i = (int)itemId - 1;
70-
if (0 <= i && i < this._ids.Count)
81+
if (0 <= i && i < this.ids.Count)
7182
{
72-
var reference = this._ids[i];
83+
var reference = this.ids[i];
7384
if (reference != null && reference.TryGetTarget(out var node))
7485
{
7586
return node;

0 commit comments

Comments
 (0)