Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
StackExchange.Redis
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
tsai
StackExchange.Redis
Commits
de41b0e6
Commit
de41b0e6
authored
Nov 05, 2015
by
Marc Gravell
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use RunContinuationsAsynchronously when PLAT_SAFE_CONTINUATIONS is defined (NET46, DNXCORE50, etc)
parent
2bca2a52
Changes
12
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
496 additions
and
66 deletions
+496
-66
StackExchange.Redis.StrongName.nuspec
StackExchange.Redis.StrongName.nuspec
+3
-0
StackExchange.Redis.Tests.csproj
StackExchange.Redis.Tests/StackExchange.Redis.Tests.csproj
+10
-8
TaskTests.cs
StackExchange.Redis.Tests/TaskTests.cs
+3
-1
StackExchange.Redis.nuspec
StackExchange.Redis.nuspec
+3
-0
StackExchange.Redis.sln
StackExchange.Redis.sln
+25
-1
ResultBox.cs
StackExchange.Redis/StackExchange/Redis/ResultBox.cs
+8
-4
TaskSource.cs
StackExchange.Redis/StackExchange/Redis/TaskSource.cs
+62
-52
StackExchange.Redis.snk
StackExchange.Redis_Net46/StackExchange.Redis.snk
+0
-0
StackExchange.Redis_Net46.StrongName.csproj
...e.Redis_Net46/StackExchange.Redis_Net46.StrongName.csproj
+185
-0
StackExchange.Redis_Net46.csproj
StackExchange.Redis_Net46/StackExchange.Redis_Net46.csproj
+179
-0
app.config
StackExchange.Redis_Net46/app.config
+15
-0
packages.config
StackExchange.Redis_Net46/packages.config
+3
-0
No files found.
StackExchange.Redis.StrongName.nuspec
View file @
de41b0e6
...
...
@@ -20,9 +20,12 @@
</group>
<group
targetFramework=
"net45"
>
</group>
<group
targetFramework=
"net46"
>
</group>
</dependencies>
</metadata>
<files>
<file
src=
"StackExchange.Redis_Net46\bin.snk\Release\StackExchange.Redis*.*"
target=
"lib\net46"
/>
<file
src=
"StackExchange.Redis\bin.snk\Release\StackExchange.Redis*.*"
target=
"lib\net45"
/>
<file
src=
"StackExchange.Redis_Net40\bin.snk\Release\StackExchange.Redis*.*"
target=
"lib\net40"
/>
</files>
...
...
StackExchange.Redis.Tests/StackExchange.Redis.Tests.csproj
View file @
de41b0e6
...
...
@@ -9,24 +9,26 @@
<AppDesignerFolder>
Properties
</AppDesignerFolder>
<RootNamespace>
StackExchange.Redis.Tests
</RootNamespace>
<AssemblyName>
StackExchange.Redis.Tests
</AssemblyName>
<TargetFrameworkVersion>
v4.
5
</TargetFrameworkVersion>
<TargetFrameworkVersion>
v4.
6
</TargetFrameworkVersion>
<FileAlignment>
512
</FileAlignment>
<TargetFrameworkProfile
/>
</PropertyGroup>
<PropertyGroup
Condition=
" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "
>
<DebugSymbols>
true
</DebugSymbols>
<DebugType>
full
</DebugType>
<Optimize>
false
</Optimize>
<OutputPath>
bin\Debug\
</OutputPath>
<DefineConstants>
DEBUG;TRACE
</DefineConstants>
<DefineConstants>
TRACE;DEBUG;PLAT_SAFE_CONTINUATIONS
</DefineConstants>
<ErrorReport>
prompt
</ErrorReport>
<WarningLevel>
4
</WarningLevel>
<PlatformTarget>
AnyCPU
</PlatformTarget>
<AllowUnsafeBlocks>
false
</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup
Condition=
" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "
>
<DebugType>
pdbonly
</DebugType>
<Optimize>
true
</Optimize>
<OutputPath>
bin\Release\
</OutputPath>
<DefineConstants>
TRACE
</DefineConstants>
<DefineConstants>
TRACE
;PLAT_SAFE_CONTINUATIONS
</DefineConstants>
<ErrorReport>
prompt
</ErrorReport>
<WarningLevel>
4
</WarningLevel>
</PropertyGroup>
...
...
@@ -139,13 +141,13 @@
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference
Include=
"..\StackExchange.Redis\StackExchange.Redis.csproj"
>
<Project>
{7cec07f2-8c03-4c42-b048-738b215824c1}
</Project>
<Name>
StackExchange.Redis
</Name>
</ProjectReference>
<Service
Include=
"{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}"
/>
</ItemGroup>
<ItemGroup>
<Service
Include=
"{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}"
/>
<ProjectReference
Include=
"..\StackExchange.Redis_Net46\StackExchange.Redis_Net46.csproj"
>
<Project>
{8c473a6f-b0de-4add-88f8-c41b441e407c}
</Project>
<Name>
StackExchange.Redis_Net46
</Name>
</ProjectReference>
</ItemGroup>
<Import
Project=
"$(MSBuildToolsPath)\Microsoft.CSharp.targets"
/>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
...
...
StackExchange.Redis.Tests/TaskTests.cs
View file @
de41b0e6
...
...
@@ -9,6 +9,8 @@ namespace StackExchange.Redis.Tests
public
class
TaskTests
{
#if DEBUG
#if !PLAT_SAFE_CONTINUATIONS // IsSyncSafe doesn't exist if PLAT_SAFE_CONTINUATIONS is defined
[
Test
]
[
TestCase
(
SourceOrign
.
NewTCS
,
false
)]
[
TestCase
(
SourceOrign
.
Create
,
false
)]
...
...
@@ -18,7 +20,7 @@ public void VerifyIsSyncSafe(SourceOrign origin, bool expected)
var
source
=
Create
<
int
>(
origin
);
Assert
.
AreEqual
(
expected
,
TaskSource
.
IsSyncSafe
(
source
.
Task
));
}
#endif
static
TaskCompletionSource
<
T
>
Create
<
T
>(
SourceOrign
origin
)
{
switch
(
origin
)
...
...
StackExchange.Redis.nuspec
View file @
de41b0e6
...
...
@@ -20,9 +20,12 @@
</group>
<group
targetFramework=
"net45"
>
</group>
<group
targetFramework=
"net46"
>
</group>
</dependencies>
</metadata>
<files>
<file
src=
"StackExchange.Redis_Net46\bin\Release\StackExchange.Redis*.*"
target=
"lib\net46"
/>
<file
src=
"StackExchange.Redis\bin\Release\StackExchange.Redis*.*"
target=
"lib\net45"
/>
<file
src=
"StackExchange.Redis_Net40\bin\Release\StackExchange.Redis*.*"
target=
"lib\net40"
/>
</files>
...
...
StackExchange.Redis.sln
View file @
de41b0e6
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.2
3107.0
VisualStudioVersion = 14.0.2
4606.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StackExchange.Redis", "StackExchange.Redis\StackExchange.Redis.csproj", "{7CEC07F2-8C03-4C42-B048-738B215824C1}"
EndProject
...
...
@@ -56,6 +56,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StackExchange.Redis.StrongN
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StackExchange.Redis_Net40.StrongName", "StackExchange.Redis_Net40\StackExchange.Redis_Net40.StrongName.csproj", "{75CED009-AAC6-4AC1-9C38-A0530619062D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StackExchange.Redis_Net46", "StackExchange.Redis_Net46\StackExchange.Redis_Net46.csproj", "{8C473A6F-B0DE-4ADD-88F8-C41B441E407C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StackExchange.Redis_Net46.StrongName", "StackExchange.Redis_Net46\StackExchange.Redis_Net46.StrongName.csproj", "{8CE5D027-E332-42DD-BA54-16310DCD529C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
...
...
@@ -155,6 +159,26 @@ Global
{75CED009-AAC6-4AC1-9C38-A0530619062D}.Release|Any CPU.Build.0 = Release|Any CPU
{75CED009-AAC6-4AC1-9C38-A0530619062D}.Verbose|Any CPU.ActiveCfg = Release|Any CPU
{75CED009-AAC6-4AC1-9C38-A0530619062D}.Verbose|Any CPU.Build.0 = Release|Any CPU
{8C473A6F-B0DE-4ADD-88F8-C41B441E407C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8C473A6F-B0DE-4ADD-88F8-C41B441E407C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8C473A6F-B0DE-4ADD-88F8-C41B441E407C}.Log Output|Any CPU.ActiveCfg = Mono|Any CPU
{8C473A6F-B0DE-4ADD-88F8-C41B441E407C}.Log Output|Any CPU.Build.0 = Mono|Any CPU
{8C473A6F-B0DE-4ADD-88F8-C41B441E407C}.Mono|Any CPU.ActiveCfg = Mono|Any CPU
{8C473A6F-B0DE-4ADD-88F8-C41B441E407C}.Mono|Any CPU.Build.0 = Mono|Any CPU
{8C473A6F-B0DE-4ADD-88F8-C41B441E407C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8C473A6F-B0DE-4ADD-88F8-C41B441E407C}.Release|Any CPU.Build.0 = Release|Any CPU
{8C473A6F-B0DE-4ADD-88F8-C41B441E407C}.Verbose|Any CPU.ActiveCfg = Mono|Any CPU
{8C473A6F-B0DE-4ADD-88F8-C41B441E407C}.Verbose|Any CPU.Build.0 = Mono|Any CPU
{8CE5D027-E332-42DD-BA54-16310DCD529C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8CE5D027-E332-42DD-BA54-16310DCD529C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8CE5D027-E332-42DD-BA54-16310DCD529C}.Log Output|Any CPU.ActiveCfg = Mono|Any CPU
{8CE5D027-E332-42DD-BA54-16310DCD529C}.Log Output|Any CPU.Build.0 = Mono|Any CPU
{8CE5D027-E332-42DD-BA54-16310DCD529C}.Mono|Any CPU.ActiveCfg = Mono|Any CPU
{8CE5D027-E332-42DD-BA54-16310DCD529C}.Mono|Any CPU.Build.0 = Mono|Any CPU
{8CE5D027-E332-42DD-BA54-16310DCD529C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8CE5D027-E332-42DD-BA54-16310DCD529C}.Release|Any CPU.Build.0 = Release|Any CPU
{8CE5D027-E332-42DD-BA54-16310DCD529C}.Verbose|Any CPU.ActiveCfg = Mono|Any CPU
{8CE5D027-E332-42DD-BA54-16310DCD529C}.Verbose|Any CPU.Build.0 = Mono|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
...
...
StackExchange.Redis/StackExchange/Redis/ResultBox.cs
View file @
de41b0e6
...
...
@@ -99,8 +99,10 @@ public override bool TryComplete(bool isAsync)
{
if
(
stateOrCompletionSource
is
TaskCompletionSource
<
T
>)
{
var
tcs
=
(
TaskCompletionSource
<
T
>)
stateOrCompletionSource
;
if
(
isAsync
||
TaskSource
.
IsSyncSafe
(
tcs
.
Task
))
var
tcs
=
(
TaskCompletionSource
<
T
>)
stateOrCompletionSource
;
#if !PLAT_SAFE_CONTINUATIONS // we don't need to check in this scenario
if
(
isAsync
||
TaskSource
.
IsSyncSafe
(
tcs
.
Task
))
#endif
{
T
val
;
Exception
ex
;
...
...
@@ -116,11 +118,13 @@ public override bool TryComplete(bool isAsync)
GC
.
SuppressFinalize
(
tcs
.
Task
);
}
return
true
;
}
}
#if !PLAT_SAFE_CONTINUATIONS
else
{
// looks like continuations; push to async to preserve the reader thread
return
false
;
}
}
#endif
}
else
{
...
...
StackExchange.Redis/StackExchange/Redis/TaskSource.cs
View file @
de41b0e6
...
...
@@ -16,75 +16,85 @@ namespace StackExchange.Redis
#endif
static
class
TaskSource
{
#if !PLAT_SAFE_CONTINUATIONS
// on .NET < 4.6, it was possible to have threads hijacked; this is no longer a problem in 4.6 and core-clr 5,
// thanks to the new TaskCreationOptions.RunContinuationsAsynchronously, however we still need to be a little
// "test and react", as we could be targeting 4.5 but running on a 4.6 machine, in which case *it can still
// work the magic* (thanks to over-the-top install)
/// <summary>
/// Indicates whether the specified task will not hijack threads when results are set
/// </summary>
public
static
readonly
Func
<
Task
,
bool
>
IsSyncSafe
;
static
TaskSource
()
{
static
TaskSource
()
{
try
{
Type
taskType
=
typeof
(
Task
);
FieldInfo
continuationField
=
taskType
.
GetField
(
"m_continuationObject"
,
BindingFlags
.
Instance
|
BindingFlags
.
NonPublic
);
Type
safeScenario
=
taskType
.
GetNestedType
(
"SetOnInvokeMres"
,
BindingFlags
.
NonPublic
);
if
(
continuationField
!=
null
&&
continuationField
.
FieldType
==
typeof
(
object
)
&&
safeScenario
!=
null
)
{
var
method
=
new
DynamicMethod
(
"IsSyncSafe"
,
typeof
(
bool
),
new
[]
{
typeof
(
Task
)
},
typeof
(
Task
),
true
);
var
il
=
method
.
GetILGenerator
();
//var hasContinuation = il.DefineLabel();
il
.
Emit
(
OpCodes
.
Ldarg_0
);
il
.
Emit
(
OpCodes
.
Ldfld
,
continuationField
);
Label
nonNull
=
il
.
DefineLabel
(),
goodReturn
=
il
.
DefineLabel
();
// check if null
il
.
Emit
(
OpCodes
.
Brtrue_S
,
nonNull
);
il
.
MarkLabel
(
goodReturn
);
il
.
Emit
(
OpCodes
.
Ldc_I4_1
);
il
.
Emit
(
OpCodes
.
Ret
);
{
Type
taskType
=
typeof
(
Task
);
FieldInfo
continuationField
=
taskType
.
GetField
(
"m_continuationObject"
,
BindingFlags
.
Instance
|
BindingFlags
.
NonPublic
);
Type
safeScenario
=
taskType
.
GetNestedType
(
"SetOnInvokeMres"
,
BindingFlags
.
NonPublic
);
if
(
continuationField
!=
null
&&
continuationField
.
FieldType
==
typeof
(
object
)
&&
safeScenario
!=
null
)
{
var
method
=
new
DynamicMethod
(
"IsSyncSafe"
,
typeof
(
bool
),
new
[]
{
typeof
(
Task
)
},
typeof
(
Task
),
true
);
var
il
=
method
.
GetILGenerator
();
//var hasContinuation = il.DefineLabel();
il
.
Emit
(
OpCodes
.
Ldarg_0
);
il
.
Emit
(
OpCodes
.
Ldfld
,
continuationField
);
Label
nonNull
=
il
.
DefineLabel
(),
goodReturn
=
il
.
DefineLabel
();
// check if null
il
.
Emit
(
OpCodes
.
Brtrue_S
,
nonNull
);
il
.
MarkLabel
(
goodReturn
);
il
.
Emit
(
OpCodes
.
Ldc_I4_1
);
il
.
Emit
(
OpCodes
.
Ret
);
// check if is a SetOnInvokeMres - if so, we're OK
il
.
MarkLabel
(
nonNull
);
il
.
Emit
(
OpCodes
.
Ldarg_0
);
il
.
Emit
(
OpCodes
.
Ldfld
,
continuationField
);
il
.
Emit
(
OpCodes
.
Isinst
,
safeScenario
);
il
.
Emit
(
OpCodes
.
Brtrue_S
,
goodReturn
);
// check if is a SetOnInvokeMres - if so, we're OK
il
.
MarkLabel
(
nonNull
);
il
.
Emit
(
OpCodes
.
Ldarg_0
);
il
.
Emit
(
OpCodes
.
Ldfld
,
continuationField
);
il
.
Emit
(
OpCodes
.
Isinst
,
safeScenario
);
il
.
Emit
(
OpCodes
.
Brtrue_S
,
goodReturn
);
il
.
Emit
(
OpCodes
.
Ldc_I4_0
);
il
.
Emit
(
OpCodes
.
Ret
);
il
.
Emit
(
OpCodes
.
Ldc_I4_0
);
il
.
Emit
(
OpCodes
.
Ret
);
IsSyncSafe
=
(
Func
<
Task
,
bool
>)
method
.
CreateDelegate
(
typeof
(
Func
<
Task
,
bool
>));
IsSyncSafe
=
(
Func
<
Task
,
bool
>)
method
.
CreateDelegate
(
typeof
(
Func
<
Task
,
bool
>));
// and test them (check for an exception etc)
var
tcs
=
new
TaskCompletionSource
<
int
>();
bool
expectTrue
=
IsSyncSafe
(
tcs
.
Task
);
tcs
.
Task
.
ContinueWith
(
delegate
{
});
bool
expectFalse
=
IsSyncSafe
(
tcs
.
Task
);
tcs
.
SetResult
(
0
);
if
(!
expectTrue
||
expectFalse
)
{
Debug
.
WriteLine
(
"IsSyncSafe reported incorrectly!"
);
Trace
.
WriteLine
(
"IsSyncSafe reported incorrectly!"
);
// revert to not trusting /them
IsSyncSafe
=
null
;
}
}
}
catch
(
Exception
ex
)
{
Debug
.
WriteLine
(
ex
.
Message
);
Trace
.
WriteLine
(
ex
.
Message
);
IsSyncSafe
=
null
;
}
// and test them (check for an exception etc)
var
tcs
=
new
TaskCompletionSource
<
int
>();
bool
expectTrue
=
IsSyncSafe
(
tcs
.
Task
);
tcs
.
Task
.
ContinueWith
(
delegate
{
});
bool
expectFalse
=
IsSyncSafe
(
tcs
.
Task
);
tcs
.
SetResult
(
0
);
if
(!
expectTrue
||
expectFalse
)
{
Debug
.
WriteLine
(
"IsSyncSafe reported incorrectly!"
);
Trace
.
WriteLine
(
"IsSyncSafe reported incorrectly!"
);
// revert to not trusting /them
IsSyncSafe
=
null
;
}
}
}
catch
(
Exception
ex
)
{
Debug
.
WriteLine
(
ex
.
Message
);
Trace
.
WriteLine
(
ex
.
Message
);
IsSyncSafe
=
null
;
}
if
(
IsSyncSafe
==
null
)
IsSyncSafe
=
t
=>
false
;
// assume: not
}
#endif
/// <summary>
/// Create a new TaskCompletion source
/// </summary>
public
static
TaskCompletionSource
<
T
>
Create
<
T
>(
object
asyncState
)
{
return
new
TaskCompletionSource
<
T
>(
asyncState
);
}
#if PLAT_SAFE_CONTINUATIONS
return
new
TaskCompletionSource
<
T
>(
asyncState
,
TaskCreationOptions
.
RunContinuationsAsynchronously
);
#else
return
new
TaskCompletionSource
<
T
>(
asyncState
,
TaskCreationOptions
.
None
);
#endif
}
/// <summary>
/// Create a new TaskCompletionSource that will not allow result-setting threads to be hijacked
...
...
StackExchange.Redis_Net46/StackExchange.Redis.snk
0 → 100644
View file @
de41b0e6
File added
StackExchange.Redis_Net46/StackExchange.Redis_Net46.StrongName.csproj
0 → 100644
View file @
de41b0e6
This diff is collapsed.
Click to expand it.
StackExchange.Redis_Net46/StackExchange.Redis_Net46.csproj
0 → 100644
View file @
de41b0e6
This diff is collapsed.
Click to expand it.
StackExchange.Redis_Net46/app.config
0 → 100644
View file @
de41b0e6
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
configuration
>
<
runtime
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Runtime"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-2.6.10.0"
newVersion
=
"2.6.10.0"
/>
</
dependentAssembly
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Threading.Tasks"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-2.6.10.0"
newVersion
=
"2.6.10.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
</
runtime
>
<
startup
><
supportedRuntime
version
=
"v4.0"
sku
=
".NETFramework,Version=v4.6"
/></
startup
></
configuration
>
StackExchange.Redis_Net46/packages.config
0 → 100644
View file @
de41b0e6
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
packages
>
</
packages
>
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment