Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
e6fed01a
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,发现更多精彩内容 >>
未验证
提交
e6fed01a
编写于
3月 19, 2019
作者:
J
Jason Malinowski
提交者:
GitHub
3月 19, 2019
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #34103 from jasonmalinowski/hack-around-filewatcher-deadlock
Workaround a deadlock caused by watching .editorconfigs
上级
79994e71
8097ff9d
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
131 addition
and
1 deletion
+131
-1
src/EditorFeatures/Core.Wpf/Options/EditorConfigDocumentOptionsProviderFactory.cs
...Wpf/Options/EditorConfigDocumentOptionsProviderFactory.cs
+131
-1
src/EditorFeatures/Core.Wpf/Options/EditorConfigDocumentOptionsProvider_Ide.cs
...re.Wpf/Options/EditorConfigDocumentOptionsProvider_Ide.cs
+0
-0
未找到文件。
src/EditorFeatures/Core.Wpf/Options/EditorConfigDocumentOptionsProviderFactory.cs
浏览文件 @
e6fed01a
...
@@ -2,10 +2,13 @@
...
@@ -2,10 +2,13 @@
using
System
;
using
System
;
using
System.Composition
;
using
System.Composition
;
using
System.IO
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.Host.Mef
;
using
Microsoft.CodeAnalysis.Host.Mef
;
using
Microsoft.CodeAnalysis.Options
;
using
Microsoft.CodeAnalysis.Options
;
using
Microsoft.CodeAnalysis.Shared.TestHooks
;
using
Microsoft.CodeAnalysis.Shared.TestHooks
;
using
Microsoft.VisualStudio.CodingConventions
;
using
Microsoft.VisualStudio.CodingConventions
;
using
Roslyn.Utilities
;
namespace
Microsoft.CodeAnalysis.Editor.Options
namespace
Microsoft.CodeAnalysis.Editor.Options
{
{
...
@@ -13,21 +16,148 @@ namespace Microsoft.CodeAnalysis.Editor.Options
...
@@ -13,21 +16,148 @@ namespace Microsoft.CodeAnalysis.Editor.Options
class
EditorConfigDocumentOptionsProviderFactory
:
IDocumentOptionsProviderFactory
class
EditorConfigDocumentOptionsProviderFactory
:
IDocumentOptionsProviderFactory
{
{
private
readonly
ICodingConventionsManager
_codingConventionsManager
;
private
readonly
ICodingConventionsManager
_codingConventionsManager
;
private
readonly
IFileWatcher
_fileWatcher
;
private
readonly
IAsynchronousOperationListenerProvider
_asynchronousOperationListenerProvider
;
private
readonly
IAsynchronousOperationListenerProvider
_asynchronousOperationListenerProvider
;
[
ImportingConstructor
]
[
ImportingConstructor
]
[
Obsolete
(
MefConstruction
.
ImportingConstructorMessage
,
error
:
true
)]
[
Obsolete
(
MefConstruction
.
ImportingConstructorMessage
,
error
:
true
)]
public
EditorConfigDocumentOptionsProviderFactory
(
public
EditorConfigDocumentOptionsProviderFactory
(
ICodingConventionsManager
codingConventionsManager
,
ICodingConventionsManager
codingConventionsManager
,
IFileWatcher
fileWatcher
,
IAsynchronousOperationListenerProvider
asynchronousOperationListenerProvider
)
IAsynchronousOperationListenerProvider
asynchronousOperationListenerProvider
)
{
{
_codingConventionsManager
=
codingConventionsManager
;
_codingConventionsManager
=
codingConventionsManager
;
_fileWatcher
=
fileWatcher
;
_asynchronousOperationListenerProvider
=
asynchronousOperationListenerProvider
;
_asynchronousOperationListenerProvider
=
asynchronousOperationListenerProvider
;
}
}
public
IDocumentOptionsProvider
Create
(
Workspace
workspace
)
public
IDocumentOptionsProvider
Create
(
Workspace
workspace
)
{
{
return
new
EditorConfigDocumentOptionsProvider
(
workspace
,
_codingConventionsManager
,
_asynchronousOperationListenerProvider
);
ICodingConventionsManager
codingConventionsManager
;
if
(
workspace
.
Kind
==
WorkspaceKind
.
RemoteWorkspace
)
{
// If it's the remote workspace, it's our own implementation of the file watcher which is already doesn't have
// UI thread dependencies.
codingConventionsManager
=
_codingConventionsManager
;
}
else
{
// The default file watcher implementation inside Visual Studio accientally depends on the UI thread
// (sometimes!) when trying to add a watch to a file. This can cause us to deadlock, since our assumption is
// consumption of a coding convention can be done freely without having to use a JTF-friendly wait.
// So we'll wrap the standard file watcher with one that defers the file watches until later.
var
deferredFileWatcher
=
new
DeferredFileWatcher
(
_fileWatcher
,
_asynchronousOperationListenerProvider
);
codingConventionsManager
=
CodingConventionsManagerFactory
.
CreateCodingConventionsManager
(
deferredFileWatcher
);
}
return
new
EditorConfigDocumentOptionsProvider
(
workspace
,
codingConventionsManager
,
_asynchronousOperationListenerProvider
);
}
/// <summary>
/// An implementation of <see cref="IFileWatcher"/> that ensures we don't watch for a file synchronously to
/// avoid deadlocks.
/// </summary>
internal
class
DeferredFileWatcher
:
IFileWatcher
{
private
readonly
IFileWatcher
_fileWatcher
;
private
readonly
SimpleTaskQueue
_taskQueue
=
new
SimpleTaskQueue
(
TaskScheduler
.
Default
);
private
readonly
IAsynchronousOperationListener
_listener
;
public
DeferredFileWatcher
(
IFileWatcher
fileWatcher
,
IAsynchronousOperationListenerProvider
asynchronousOperationListenerProvider
)
{
_fileWatcher
=
fileWatcher
;
_fileWatcher
.
ConventionFileChanged
+=
OnConventionFileChanged
;
_listener
=
asynchronousOperationListenerProvider
.
GetListener
(
FeatureAttribute
.
Workspace
);
}
private
Task
OnConventionFileChanged
(
object
sender
,
ConventionsFileChangeEventArgs
arg
)
{
return
ConventionFileChanged
?.
Invoke
(
this
,
arg
)
??
Task
.
CompletedTask
;
}
public
event
ConventionsFileChangedAsyncEventHandler
ConventionFileChanged
;
public
event
ContextFileMovedAsyncEventHandler
ContextFileMoved
{
add
{
_fileWatcher
.
ContextFileMoved
+=
value
;
}
remove
{
_fileWatcher
.
ContextFileMoved
-=
value
;
}
}
public
void
Dispose
()
{
_fileWatcher
.
ConventionFileChanged
-=
OnConventionFileChanged
;
_fileWatcher
.
Dispose
();
}
public
void
StartWatching
(
string
fileName
,
string
directoryPath
)
{
var
asyncToken
=
_listener
.
BeginAsyncOperation
(
nameof
(
DeferredFileWatcher
)
+
"."
+
nameof
(
StartWatching
));
// Read the file time stamp right now; we want to know if it changes between now
// and our ability to get the file watcher in place.
var
originalFileTimeStamp
=
TryGetFileTimeStamp
(
fileName
,
directoryPath
);
_taskQueue
.
ScheduleTask
(()
=>
{
_fileWatcher
.
StartWatching
(
fileName
,
directoryPath
);
var
newFileTimeStamp
=
TryGetFileTimeStamp
(
fileName
,
directoryPath
);
if
(
originalFileTimeStamp
!=
newFileTimeStamp
)
{
ChangeType
changeType
;
if
(!
originalFileTimeStamp
.
HasValue
&&
newFileTimeStamp
.
HasValue
)
{
changeType
=
ChangeType
.
FileCreated
;
}
else
if
(
originalFileTimeStamp
.
HasValue
&&
!
newFileTimeStamp
.
HasValue
)
{
changeType
=
ChangeType
.
FileDeleted
;
}
else
{
changeType
=
ChangeType
.
FileModified
;
}
ConventionFileChanged
?.
Invoke
(
this
,
new
ConventionsFileChangeEventArgs
(
fileName
,
directoryPath
,
changeType
));
}
}).
CompletesAsyncOperation
(
asyncToken
);
}
private
static
DateTime
?
TryGetFileTimeStamp
(
string
fileName
,
string
directoryPath
)
{
try
{
var
fullFilePath
=
Path
.
Combine
(
directoryPath
,
fileName
);
// Avoid a first-chance exception if the file definitely doesn't exist
if
(!
File
.
Exists
(
fullFilePath
))
{
return
null
;
}
return
FileUtilities
.
GetFileTimeStamp
(
fullFilePath
);
}
catch
(
IOException
)
{
return
null
;
}
}
public
void
StopWatching
(
string
fileName
,
string
directoryPath
)
{
_taskQueue
.
ScheduleTask
(()
=>
_fileWatcher
.
StopWatching
(
fileName
,
directoryPath
));
}
}
}
}
}
}
}
src/EditorFeatures/Core.Wpf/Options/EditorConfigDocumentOptionsProvider
.
Ide.cs
→
src/EditorFeatures/Core.Wpf/Options/EditorConfigDocumentOptionsProvider
_
Ide.cs
浏览文件 @
e6fed01a
文件已移动
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录