Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
7cda9431
R
roslyn
项目概览
lwm1986
/
roslyn
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
roslyn
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
7cda9431
编写于
4月 21, 2015
作者:
M
Matt Warren
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #2056 from mattwar/Bug1154956
Reduce likelyhood of race in EventMap
上级
4fd7e440
d60d7a2f
变更
6
显示空白变更内容
内联
并排
Showing
6 changed file
with
148 addition
and
81 deletion
+148
-81
src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests.cs
src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests.cs
+14
-3
src/Features/Core/Diagnostics/DiagnosticService.cs
src/Features/Core/Diagnostics/DiagnosticService.cs
+3
-7
src/Features/Core/SolutionCrawler/SolutionCrawlerProgressReporter.cs
...s/Core/SolutionCrawler/SolutionCrawlerProgressReporter.cs
+3
-6
src/Workspaces/Core/Portable/Notification/GlobalOperationNotificationService.cs
...rtable/Notification/GlobalOperationNotificationService.cs
+6
-12
src/Workspaces/Core/Portable/Utilities/EventMap.cs
src/Workspaces/Core/Portable/Utilities/EventMap.cs
+107
-23
src/Workspaces/Core/Portable/Workspace/Workspace_Events.cs
src/Workspaces/Core/Portable/Workspace/Workspace_Events.cs
+15
-30
未找到文件。
src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests.cs
浏览文件 @
7cda9431
...
...
@@ -27,27 +27,38 @@ private TestWorkspace CreateWorkspace(bool disablePartialSolutions = true)
private
static
void
WaitForWorkspaceOperationsToComplete
(
TestWorkspace
workspace
)
{
var
workspa
s
ceWaiter
=
workspace
.
ExportProvider
var
workspaceWaiter
=
workspace
.
ExportProvider
.
GetExports
<
IAsynchronousOperationListener
,
FeatureMetadata
>()
.
First
(
l
=>
l
.
Metadata
.
FeatureName
==
FeatureAttribute
.
Workspace
).
Value
as
IAsynchronousOperationWaiter
;
workspa
s
ceWaiter
.
CreateWaitTask
().
PumpingWait
();
workspaceWaiter
.
CreateWaitTask
().
PumpingWait
();
}
[
Fact
]
public
void
TestEmptySolutionUpdate
()
public
void
TestEmptySolutionUpdate
DoesNotFireEvents
()
{
using
(
var
workspace
=
CreateWorkspace
())
{
var
project
=
new
TestHostProject
(
workspace
);
workspace
.
AddTestProject
(
project
);
// wait for all previous operations to complete
WaitForWorkspaceOperationsToComplete
(
workspace
);
var
solution
=
workspace
.
CurrentSolution
;
bool
workspaceChanged
=
false
;
workspace
.
WorkspaceChanged
+=
(
s
,
e
)
=>
workspaceChanged
=
true
;
// make an 'empty' update by claiming something changed, but its the same as before
workspace
.
OnParseOptionsChanged
(
project
.
Id
,
project
.
ParseOptions
);
// wait for any new outstanding operations to complete (there shouldn't be any)
WaitForWorkspaceOperationsToComplete
(
workspace
);
// same solution instance == nothing changed
Assert
.
Equal
(
solution
,
workspace
.
CurrentSolution
);
// no event was fired because nothing was changed
Assert
.
False
(
workspaceChanged
);
}
}
...
...
src/Features/Core/Diagnostics/DiagnosticService.cs
浏览文件 @
7cda9431
...
...
@@ -58,18 +58,14 @@ internal class DiagnosticService : IDiagnosticService
private
void
RaiseDiagnosticsUpdated
(
object
sender
,
DiagnosticsUpdatedArgs
args
)
{
var
handlers
=
_eventMap
.
GetEventHandlers
<
EventHandler
<
DiagnosticsUpdatedArgs
>>(
DiagnosticsUpdatedEventName
);
if
(
handlers
.
Length
>
0
)
var
ev
=
_eventMap
.
GetEventHandlers
<
EventHandler
<
DiagnosticsUpdatedArgs
>>(
DiagnosticsUpdatedEventName
);
if
(
ev
.
HasHandlers
)
{
var
eventToken
=
_listener
.
BeginAsyncOperation
(
DiagnosticsUpdatedEventName
);
_eventQueue
.
ScheduleTask
(()
=>
{
UpdateDataMap
(
sender
,
args
);
foreach
(
var
handler
in
handlers
)
{
handler
(
sender
,
args
);
}
ev
.
RaiseEvent
(
handler
=>
handler
(
sender
,
args
));
}).
CompletesAsyncOperation
(
eventToken
);
}
}
...
...
src/Features/Core/SolutionCrawler/SolutionCrawlerProgressReporter.cs
浏览文件 @
7cda9431
...
...
@@ -106,15 +106,12 @@ private Task RaiseStopped()
private
Task
RaiseEvent
(
string
eventName
)
{
// this method name doesnt have Async since it should work as async void.
var
handlers
=
_eventMap
.
GetEventHandlers
<
EventHandler
>(
eventName
);
if
(
handlers
.
Length
>
0
)
var
ev
=
_eventMap
.
GetEventHandlers
<
EventHandler
>(
eventName
);
if
(
ev
.
HasHandlers
)
{
return
_eventQueue
.
ScheduleTask
(()
=>
{
foreach
(
var
handler
in
handlers
)
{
handler
(
this
,
EventArgs
.
Empty
);
}
ev
.
RaiseEvent
(
handler
=>
handler
(
this
,
EventArgs
.
Empty
));
});
}
...
...
src/Workspaces/Core/Portable/Notification/GlobalOperationNotificationService.cs
浏览文件 @
7cda9431
...
...
@@ -49,15 +49,12 @@ public override GlobalOperationRegistration Start(string operation)
protected
virtual
Task
RaiseGlobalOperationStarted
()
{
var
handlers
=
_eventMap
.
GetEventHandlers
<
EventHandler
>(
GlobalOperationStartedEventName
);
if
(
handlers
.
Length
>
0
)
var
ev
=
_eventMap
.
GetEventHandlers
<
EventHandler
>(
GlobalOperationStartedEventName
);
if
(
ev
.
HasHandlers
)
{
return
_eventQueue
.
ScheduleTask
(()
=>
{
foreach
(
var
handler
in
handlers
)
{
handler
(
this
,
EventArgs
.
Empty
);
}
ev
.
RaiseEvent
(
handler
=>
handler
(
this
,
EventArgs
.
Empty
));
});
}
...
...
@@ -66,17 +63,14 @@ protected virtual Task RaiseGlobalOperationStarted()
protected
virtual
Task
RaiseGlobalOperationStopped
(
IReadOnlyList
<
string
>
operations
,
bool
cancelled
)
{
var
handlers
=
_eventMap
.
GetEventHandlers
<
EventHandler
<
GlobalOperationEventArgs
>>(
GlobalOperationStoppedEventName
);
if
(
handlers
.
Length
>
0
)
var
ev
=
_eventMap
.
GetEventHandlers
<
EventHandler
<
GlobalOperationEventArgs
>>(
GlobalOperationStoppedEventName
);
if
(
ev
.
HasHandlers
)
{
var
args
=
new
GlobalOperationEventArgs
(
operations
,
cancelled
);
return
_eventQueue
.
ScheduleTask
(()
=>
{
foreach
(
var
handler
in
handlers
)
{
handler
(
this
,
args
);
}
ev
.
RaiseEvent
(
handler
=>
handler
(
this
,
args
));
});
}
...
...
src/Workspaces/Core/Portable/Utilities/EventMap.cs
浏览文件 @
7cda9431
...
...
@@ -3,6 +3,7 @@
using
System
;
using
System.Collections.Generic
;
using
System.Collections.Immutable
;
using
System.Linq
;
namespace
Roslyn.Utilities
{
...
...
@@ -10,7 +11,7 @@ internal class EventMap
{
private
readonly
NonReentrantLock
_guard
=
new
NonReentrantLock
();
private
readonly
Dictionary
<
string
,
object
>
_eventNameTo
Handler
s
=
private
readonly
Dictionary
<
string
,
object
>
_eventNameTo
Registrie
s
=
new
Dictionary
<
string
,
object
>();
public
EventMap
()
...
...
@@ -18,64 +19,147 @@ public EventMap()
}
public
void
AddEventHandler
<
TEventHandler
>(
string
eventName
,
TEventHandler
eventHandler
)
where
TEventHandler
:
class
{
using
(
_guard
.
DisposableWait
())
{
var
handlers
=
GetEvent
s_NoLock
<
TEventHandler
>(
eventName
);
var
new
Handlers
=
handlers
.
Add
(
eventHandler
);
Set
Events_NoLock
(
eventName
,
newHandler
s
);
var
registries
=
GetRegistrie
s_NoLock
<
TEventHandler
>(
eventName
);
var
new
Registries
=
registries
.
Add
(
new
Registry
<
TEventHandler
>(
eventHandler
)
);
Set
Registries_NoLock
(
eventName
,
newRegistrie
s
);
}
}
public
void
RemoveEventHandler
<
TEventHandler
>(
string
eventName
,
TEventHandler
eventHandler
)
where
TEventHandler
:
class
{
using
(
_guard
.
DisposableWait
())
{
var
handlers
=
GetEvents_NoLock
<
TEventHandler
>(
eventName
);
var
newHandlers
=
handlers
.
Remove
(
eventHandler
);
if
(
newHandlers
!=
handlers
)
var
registries
=
GetRegistries_NoLock
<
TEventHandler
>(
eventName
);
// remove disabled registrations from list
var
newRegistries
=
registries
.
RemoveAll
(
r
=>
r
.
HasHandler
(
eventHandler
));
if
(
newRegistries
!=
registries
)
{
// disable all registrations of this handler (so pending raise events can be squelched)
// This does not guarantee no race condition between Raise and Remove but greatly reduces it.
foreach
(
var
registry
in
registries
.
Where
(
r
=>
r
.
HasHandler
(
eventHandler
)))
{
SetEvents_NoLock
(
eventName
,
newHandlers
);
registry
.
Unregister
();
}
SetRegistries_NoLock
(
eventName
,
newRegistries
);
}
}
}
public
EventHandlerSet
<
TEventHandler
>
GetEventHandlers
<
TEventHandler
>(
string
eventName
)
where
TEventHandler
:
class
{
return
new
EventHandlerSet
<
TEventHandler
>(
this
.
GetRegistries
<
TEventHandler
>(
eventName
));
}
public
ImmutableArray
<
TEventHandler
>
GetEventHandlers
<
TEventHandler
>(
string
eventName
)
private
ImmutableArray
<
Registry
<
TEventHandler
>>
GetRegistries
<
TEventHandler
>(
string
eventName
)
where
TEventHandler
:
class
{
using
(
_guard
.
DisposableWait
())
{
return
Get
Event
s_NoLock
<
TEventHandler
>(
eventName
);
return
Get
Registrie
s_NoLock
<
TEventHandler
>(
eventName
);
}
}
p
ublic
void
RaiseEvent
<
TEventArgs
>(
string
eventName
,
object
sender
,
TEventArgs
args
)
where
TEvent
Args
:
EventArg
s
p
rivate
ImmutableArray
<
Registry
<
TEventHandler
>>
GetRegistries_NoLock
<
TEventHandler
>(
string
eventName
)
where
TEvent
Handler
:
clas
s
{
var
handlers
=
GetEventHandlers
<
EventHandler
<
TEventArgs
>>(
eventName
);
foreach
(
var
handler
in
handlers
)
_guard
.
AssertHasLock
();
object
registries
;
if
(
_eventNameToRegistries
.
TryGetValue
(
eventName
,
out
registries
))
{
handler
(
sender
,
args
)
;
return
(
ImmutableArray
<
Registry
<
TEventHandler
>>)
registries
;
}
return
ImmutableArray
.
Create
<
Registry
<
TEventHandler
>>();
}
private
ImmutableArray
<
TEventHandler
>
GetEvents_NoLock
<
TEventHandler
>(
string
eventName
)
private
void
SetRegistries_NoLock
<
TEventHandler
>(
string
eventName
,
ImmutableArray
<
Registry
<
TEventHandler
>>
registries
)
where
TEventHandler
:
class
{
_guard
.
AssertHasLock
();
object
handlers
;
if
(
_eventNameToHandlers
.
TryGetValue
(
eventName
,
out
handlers
))
_eventNameToRegistries
[
eventName
]
=
registries
;
}
private
class
Registry
<
TEventHandler
>
:
IEquatable
<
Registry
<
TEventHandler
>>
where
TEventHandler
:
class
{
private
TEventHandler
handler
;
public
Registry
(
TEventHandler
handler
)
{
return
(
ImmutableArray
<
TEventHandler
>)
handlers
;
this
.
handler
=
handler
;
}
return
ImmutableArray
.
Create
<
TEventHandler
>();
public
void
Unregister
()
{
this
.
handler
=
null
;
}
private
void
SetEvents_NoLock
<
TEventHandler
>(
string
name
,
ImmutableArray
<
TEventHandler
>
events
)
public
void
Invoke
(
Action
<
TEventHandler
>
invoker
)
{
_guard
.
AssertHasLock
();
var
handler
=
this
.
handler
;
if
(
handler
!=
null
)
{
invoker
(
handler
);
}
}
public
bool
HasHandler
(
TEventHandler
handler
)
{
return
this
.
handler
==
handler
;
}
_eventNameToHandlers
[
name
]
=
events
;
public
bool
Equals
(
Registry
<
TEventHandler
>
other
)
{
return
other
!=
null
&&
other
.
handler
==
this
.
handler
;
}
public
override
bool
Equals
(
object
obj
)
{
return
Equals
(
obj
as
Registry
<
TEventHandler
>);
}
public
override
int
GetHashCode
()
{
return
this
.
handler
.
GetHashCode
();
}
}
internal
struct
EventHandlerSet
<
TEventHandler
>
where
TEventHandler
:
class
{
private
ImmutableArray
<
Registry
<
TEventHandler
>>
registries
;
internal
EventHandlerSet
(
object
registries
)
{
this
.
registries
=
(
ImmutableArray
<
Registry
<
TEventHandler
>>)
registries
;
}
public
bool
HasHandlers
{
get
{
return
this
.
registries
!=
null
&&
this
.
registries
.
Length
>
0
;
}
}
public
void
RaiseEvent
(
Action
<
TEventHandler
>
invoker
)
{
if
(
this
.
HasHandlers
)
{
foreach
(
var
registry
in
registries
)
{
registry
.
Invoke
(
invoker
);
}
}
}
}
}
}
src/Workspaces/Core/Portable/Workspace/Workspace_Events.cs
浏览文件 @
7cda9431
...
...
@@ -48,16 +48,13 @@ protected Task RaiseWorkspaceChangedEventAsync(WorkspaceChangeKind kind, Solutio
projectId
=
documentId
.
ProjectId
;
}
var
handlers
=
_eventMap
.
GetEventHandlers
<
EventHandler
<
WorkspaceChangeEventArgs
>>(
WorkspaceChangeEventName
);
if
(
handlers
.
Length
>
0
)
var
ev
=
_eventMap
.
GetEventHandlers
<
EventHandler
<
WorkspaceChangeEventArgs
>>(
WorkspaceChangeEventName
);
if
(
ev
.
HasHandlers
)
{
return
this
.
ScheduleTask
(()
=>
{
var
args
=
new
WorkspaceChangeEventArgs
(
kind
,
oldSolution
,
newSolution
,
projectId
,
documentId
);
foreach
(
var
handler
in
handlers
)
{
handler
(
this
,
args
);
}
ev
.
RaiseEvent
(
handler
=>
handler
(
this
,
args
));
},
"Workspace.WorkspaceChanged"
);
}
else
...
...
@@ -85,14 +82,11 @@ protected Task RaiseWorkspaceChangedEventAsync(WorkspaceChangeKind kind, Solutio
protected
internal
virtual
void
OnWorkspaceFailed
(
WorkspaceDiagnostic
diagnostic
)
{
var
handlers
=
_eventMap
.
GetEventHandlers
<
EventHandler
<
WorkspaceDiagnosticEventArgs
>>(
WorkspaceFailedEventName
);
if
(
handlers
.
Length
>
0
)
var
ev
=
_eventMap
.
GetEventHandlers
<
EventHandler
<
WorkspaceDiagnosticEventArgs
>>(
WorkspaceFailedEventName
);
if
(
ev
.
HasHandlers
)
{
var
args
=
new
WorkspaceDiagnosticEventArgs
(
diagnostic
);
foreach
(
var
handler
in
handlers
)
{
handler
(
this
,
args
);
}
ev
.
RaiseEvent
(
handler
=>
handler
(
this
,
args
));
}
}
...
...
@@ -114,16 +108,13 @@ protected internal virtual void OnWorkspaceFailed(WorkspaceDiagnostic diagnostic
protected
Task
RaiseDocumentOpenedEventAsync
(
Document
document
)
{
var
handlers
=
_eventMap
.
GetEventHandlers
<
EventHandler
<
DocumentEventArgs
>>(
DocumentOpenedEventName
);
if
(
handlers
.
Length
>
0
)
var
ev
=
_eventMap
.
GetEventHandlers
<
EventHandler
<
DocumentEventArgs
>>(
DocumentOpenedEventName
);
if
(
ev
.
HasHandlers
)
{
return
this
.
ScheduleTask
(()
=>
{
var
args
=
new
DocumentEventArgs
(
document
);
foreach
(
var
handler
in
handlers
)
{
handler
(
this
,
args
);
}
ev
.
RaiseEvent
(
handler
=>
handler
(
this
,
args
));
},
"Workspace.WorkspaceChanged"
);
}
else
...
...
@@ -150,16 +141,13 @@ protected Task RaiseDocumentOpenedEventAsync(Document document)
protected
Task
RaiseDocumentClosedEventAsync
(
Document
document
)
{
var
handlers
=
_eventMap
.
GetEventHandlers
<
EventHandler
<
DocumentEventArgs
>>(
DocumentClosedEventName
);
if
(
handlers
.
Length
>
0
)
var
ev
=
_eventMap
.
GetEventHandlers
<
EventHandler
<
DocumentEventArgs
>>(
DocumentClosedEventName
);
if
(
ev
.
HasHandlers
)
{
return
this
.
ScheduleTask
(()
=>
{
var
args
=
new
DocumentEventArgs
(
document
);
foreach
(
var
handler
in
handlers
)
{
handler
(
this
,
args
);
}
ev
.
RaiseEvent
(
handler
=>
handler
(
this
,
args
));
},
"Workspace.DocumentClosed"
);
}
else
...
...
@@ -187,16 +175,13 @@ protected Task RaiseDocumentClosedEventAsync(Document document)
protected
Task
RaiseDocumentActiveContextChangedEventAsync
(
Document
document
)
{
var
handlers
=
_eventMap
.
GetEventHandlers
<
EventHandler
<
DocumentEventArgs
>>(
DocumentActiveContextChangedName
);
if
(
handlers
.
Length
>
0
)
var
ev
=
_eventMap
.
GetEventHandlers
<
EventHandler
<
DocumentEventArgs
>>(
DocumentActiveContextChangedName
);
if
(
ev
.
HasHandlers
)
{
return
this
.
ScheduleTask
(()
=>
{
var
args
=
new
DocumentEventArgs
(
document
);
foreach
(
var
handler
in
handlers
)
{
handler
(
this
,
args
);
}
ev
.
RaiseEvent
(
handler
=>
handler
(
this
,
args
));
},
"Workspace.WorkspaceChanged"
);
}
else
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录