Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitb89d98e

Browse files
dsymeKevinRansom
authored andcommitted
Make concurrency assumptions more explicit via token passing (dotnet#2371)
* tame concurrency draft* tame-conc* fix tests* fix build
1 parentab0d7a7 commitb89d98e

File tree

42 files changed

+1204
-958
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1204
-958
lines changed

‎FSharp.sln‎

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "HostedCompilerServer", "tes
4343
EndProject
4444
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") ="ILComparer","tests\fsharpqa\testenv\src\ILComparer\ILComparer.fsproj","{2E60864A-E3FF-4BCC-810F-DC7C34E6B236}"
4545
EndProject
46-
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") ="FSharp.Tests.FSharpSuite.DrivingCoreCLR","tests\fsharp\FSharp.Tests.FSharpSuite.DrivingCoreCLR.fsproj","{BDA4D411-6AD9-4B3E-A3B3-07BAD6BEF1ED}"
46+
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") ="FSharp.LanguageService.Compiler","src\fsharp\FSharp.LanguageService.Compiler\FSharp.LanguageService.Compiler.fsproj","{A437A6EC-5323-47C2-8F86-E2CAC54FF152}"
4747
EndProject
4848
Global
4949
GlobalSection(SolutionConfigurationPlatforms) =preSolution
@@ -206,18 +206,18 @@ Global
206206
{2E60864A-E3FF-4BCC-810F-DC7C34E6B236}.Release|Any CPU.Build.0=Release|Any CPU
207207
{2E60864A-E3FF-4BCC-810F-DC7C34E6B236}.Release|x86.ActiveCfg=Release|Any CPU
208208
{2E60864A-E3FF-4BCC-810F-DC7C34E6B236}.Release|x86.Build.0=Release|Any CPU
209-
{BDA4D411-6AD9-4B3E-A3B3-07BAD6BEF1ED}.Debug|Any CPU.ActiveCfg=Debug|Any CPU
210-
{BDA4D411-6AD9-4B3E-A3B3-07BAD6BEF1ED}.Debug|Any CPU.Build.0=Debug|Any CPU
211-
{BDA4D411-6AD9-4B3E-A3B3-07BAD6BEF1ED}.Debug|x86.ActiveCfg=Debug|Any CPU
212-
{BDA4D411-6AD9-4B3E-A3B3-07BAD6BEF1ED}.Debug|x86.Build.0=Debug|Any CPU
213-
{BDA4D411-6AD9-4B3E-A3B3-07BAD6BEF1ED}.Proto|Any CPU.ActiveCfg=Proto|Any CPU
214-
{BDA4D411-6AD9-4B3E-A3B3-07BAD6BEF1ED}.Proto|Any CPU.Build.0=Proto|Any CPU
215-
{BDA4D411-6AD9-4B3E-A3B3-07BAD6BEF1ED}.Proto|x86.ActiveCfg=Proto|Any CPU
216-
{BDA4D411-6AD9-4B3E-A3B3-07BAD6BEF1ED}.Proto|x86.Build.0=Proto|Any CPU
217-
{BDA4D411-6AD9-4B3E-A3B3-07BAD6BEF1ED}.Release|Any CPU.ActiveCfg=Release|Any CPU
218-
{BDA4D411-6AD9-4B3E-A3B3-07BAD6BEF1ED}.Release|Any CPU.Build.0=Release|Any CPU
219-
{BDA4D411-6AD9-4B3E-A3B3-07BAD6BEF1ED}.Release|x86.ActiveCfg=Release|Any CPU
220-
{BDA4D411-6AD9-4B3E-A3B3-07BAD6BEF1ED}.Release|x86.Build.0=Release|Any CPU
209+
{A437A6EC-5323-47C2-8F86-E2CAC54FF152}.Debug|Any CPU.ActiveCfg=Debug|Any CPU
210+
{A437A6EC-5323-47C2-8F86-E2CAC54FF152}.Debug|Any CPU.Build.0=Debug|Any CPU
211+
{A437A6EC-5323-47C2-8F86-E2CAC54FF152}.Debug|x86.ActiveCfg=Debug|Any CPU
212+
{A437A6EC-5323-47C2-8F86-E2CAC54FF152}.Debug|x86.Build.0=Debug|Any CPU
213+
{A437A6EC-5323-47C2-8F86-E2CAC54FF152}.Proto|Any CPU.ActiveCfg=Proto|Any CPU
214+
{A437A6EC-5323-47C2-8F86-E2CAC54FF152}.Proto|Any CPU.Build.0=Proto|Any CPU
215+
{A437A6EC-5323-47C2-8F86-E2CAC54FF152}.Proto|x86.ActiveCfg=Proto|Any CPU
216+
{A437A6EC-5323-47C2-8F86-E2CAC54FF152}.Proto|x86.Build.0=Proto|Any CPU
217+
{A437A6EC-5323-47C2-8F86-E2CAC54FF152}.Release|Any CPU.ActiveCfg=Release|Any CPU
218+
{A437A6EC-5323-47C2-8F86-E2CAC54FF152}.Release|Any CPU.Build.0=Release|Any CPU
219+
{A437A6EC-5323-47C2-8F86-E2CAC54FF152}.Release|x86.ActiveCfg=Release|Any CPU
220+
{A437A6EC-5323-47C2-8F86-E2CAC54FF152}.Release|x86.Build.0=Release|Any CPU
221221
EndGlobalSection
222222
GlobalSection(SolutionProperties) =preSolution
223223
HideSolutionNode =FALSE
@@ -236,6 +236,6 @@ Global
236236
{88E2D422-6852-46E3-A740-83E391DC7973} ={CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}
237237
{4239EFEA-E746-446A-BF7A-51FCBAB13946} ={CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}
238238
{2E60864A-E3FF-4BCC-810F-DC7C34E6B236} ={CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}
239-
{BDA4D411-6AD9-4B3E-A3B3-07BAD6BEF1ED} ={CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}
239+
{A437A6EC-5323-47C2-8F86-E2CAC54FF152} ={3881429D-A97A-49EB-B7AE-A82BA5FE9C77}
240240
EndGlobalSection
241241
EndGlobal

‎src/absil/il.fs‎

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,10 @@ let rec splitNamespaceAux (nm:string) =
8080
s1::splitNamespaceAux s2
8181

8282
/// Global State. All namespace splits ever seen
83-
// ++GLOBAL MUTABLE STATE
83+
// ++GLOBAL MUTABLE STATE (concurrency-safe)
8484
letmemoizeNamespaceTable=new ConcurrentDictionary<string,string list>()
8585

86-
// ++GLOBAL MUTABLE STATE
86+
// ++GLOBAL MUTABLE STATE (concurrency-safe)
8787
letmemoizeNamespaceRightTable=new ConcurrentDictionary<string,string option* string>()
8888

8989

@@ -92,7 +92,7 @@ let splitNamespace nm =
9292

9393
letsplitNamespaceMemoized nm= splitNamespace nm
9494

95-
// ++GLOBAL MUTABLE STATE
95+
// ++GLOBAL MUTABLE STATE (concurrency-safe)
9696
letmemoizeNamespaceArrayTable=
9797
Concurrent.ConcurrentDictionary<string,string[]>()
9898

@@ -1865,15 +1865,9 @@ let andTailness x y =
18651865

18661866
letformatCodeLabel(x:int)="L"+string x
18671867

1868-
letnew_generator()=
1869-
leti= ref0
1870-
fun _n->
1871-
incr i;!i
1872-
1873-
// ++GLOBAL MUTABLE STATE
1874-
letcodeLabelGenerator=(new_generator(): unit-> ILCodeLabel)
1875-
letgenerateCodeLabel x= codeLabelGenerator x
1876-
1868+
// ++GLOBAL MUTABLE STATE (concurrency safe)
1869+
letcodeLabelCount= ref0
1870+
letgenerateCodeLabel()= System.Threading.Interlocked.Increment(codeLabelCount)
18771871

18781872
letinstrIsRet i=
18791873
match iwith

‎src/absil/illib.fs‎

Lines changed: 63 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,46 @@ module Dictionary =
448448
moduleLazy=
449449
letforce(x:Lazy<'T>)= x.Force()
450450

451+
//----------------------------------------------------------------------------
452+
// Singe threaded execution and mutual exclusion
453+
454+
/// Represents a permission active at this point in execution
455+
typeExecutionToken=interfaceend
456+
457+
/// Represents a token that indicates execution on the compilation thread, i.e.
458+
/// - we have full access to the (partially mutable) TAST and TcImports data structures
459+
/// - compiler execution may result in type provider invocations when resolving types and members
460+
/// - we can access various caches in the SourceCodeServices
461+
///
462+
/// Like other execution tokens this should be passed via argument passing and not captured/stored beyond
463+
/// the lifetime of stack-based calls. This is not checked, it is a discipline withinn the compiler code.
464+
typeCompilationThreadToken()=interface ExecutionToken
465+
466+
/// Represnts a place where we are stating that execution on the compilation thread is required. The
467+
/// reason why will be documented in a comment in the code at the callsite.
468+
letRequireCompilationThread(_ctok:CompilationThreadToken)=()
469+
470+
/// Represnts a place in the compiler codebase where we are passed a CompilationThreadToken unnecessarily.
471+
/// This reprents code that may potentially not need to be executed on the compilation thread.
472+
letDoesNotRequireCompilerThreadTokenAndCouldPossiblyBeMadeConcurrent(_ctok:CompilationThreadToken)=()
473+
474+
/// Represnts a place in the compiler codebase where we assume we are executing on a compilation thread
475+
letAssumeCompilationThreadWithoutEvidence()= Unchecked.defaultof<CompilationThreadToken>
476+
477+
/// Represents a token that indicates execution on a any of several potential user threads calling the F# compiler services.
478+
typeAnyCallerThreadToken()=interface ExecutionToken
479+
letAssumeAnyCallerThreadWithoutEvidence()= Unchecked.defaultof<AnyCallerThreadToken>
480+
481+
/// A base type for various types of tokens that must be passed when a lock is taken.
482+
/// Each different static lock should declare a new subtype of this type.
483+
typeLockToken=inherit ExecutionToken
484+
letAssumeLockWithoutEvidence<'LockTokenTypewhen'LockTokenType:>LockToken>()= Unchecked.defaultof<'LockTokenType>
485+
486+
/// Encapsulates a lock associated with a particular token-type representing the acquisition of that lock.
487+
typeLock<'LockTokenTypewhen'LockTokenType:>LockToken>()=
488+
letlockObj= obj()
489+
member__.AcquireLock f= lock lockObj(fun()-> f(AssumeLockWithoutEvidence<'LockTokenType>()))
490+
451491
//---------------------------------------------------
452492
// Misc
453493

@@ -495,7 +535,7 @@ module ResultOrException =
495535
/// Eventually.repeatedlyProgressUntilDoneOrTimeShareOverOrCanceled
496536
typeEventually<'T>=
497537
| Doneof'T
498-
| NotYetDoneof(unit->Eventually<'T>)
538+
| NotYetDoneof(CompilationThreadToken->Eventually<'T>)
499539

500540
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
501541
moduleEventually=
@@ -504,42 +544,42 @@ module Eventually =
504544
let recbox e=
505545
match ewith
506546
| Done x-> Done(Operators.box x)
507-
| NotYetDone(work)-> NotYetDone(fun()-> box(work()))
547+
| NotYetDone(work)-> NotYetDone(functok-> box(work ctok))
508548

509-
let recforceWhile check e=
549+
let recforceWhilectokcheck e=
510550
match ewith
511551
| Done x-> Some(x)
512552
| NotYetDone(work)->
513553
ifnot(check())
514554
then None
515-
else forceWhile check(work())
555+
else forceWhilectokcheck(work ctok)
516556

517-
letforce e= Option.get(forceWhile(fun()->true) e)
557+
letforcectoke= Option.get(forceWhile ctok(fun()->true) e)
518558

519559

520560
/// Keep running the computation bit by bit until a time limit is reached.
521561
/// The runner gets called each time the computation is restarted
522562
letrepeatedlyProgressUntilDoneOrTimeShareOverOrCanceled timeShareInMilliseconds(ct:CancellationToken)runner e=
523563
letsw=new System.Diagnostics.Stopwatch()
524-
let recrunTimeShare e=
525-
runner(fun()->
564+
let recrunTimeSharectoke=
565+
runnerctok(functok->
526566
sw.Reset()
527567
sw.Start();
528-
let recloop(e)=
529-
matchewith
530-
| Done_->e
568+
let recloop ctok ev2=
569+
matchev2with
570+
| Done_->ev2
531571
| NotYetDone work->
532572
if ct.IsCancellationRequested|| sw.ElapsedMilliseconds> timeShareInMillisecondsthen
533573
sw.Stop();
534-
NotYetDone(fun()-> runTimeSharee)
574+
NotYetDone(functok-> runTimeSharectok ev2)
535575
else
536-
loop(work())
537-
loop(e))
538-
runTimeSharee
576+
loop ctok(work ctok)
577+
loop ctok e)
578+
NotYetDone(fun ctok->runTimeSharectok e)
539579

540580
/// Keep running the asynchronous computation bit by bit. The runner gets called each time the computation is restarted.
541581
/// Can be cancelled in the normal way.
542-
letforceAsync(runner:(unit-> Eventually<'T>)->Async<Eventually<'T>>)(e:Eventually<'T>):Async<'Toption>=
582+
letforceAsync(runner:(CompilationThreadToken-> Eventually<'T>)->Async<Eventually<'T>>)(e:Eventually<'T>):Async<'Toption>=
543583
let recloop(e:Eventually<'T>)=
544584
async{
545585
match ewith
@@ -553,7 +593,7 @@ module Eventually =
553593
let recbind k e=
554594
match ewith
555595
| Done x-> k x
556-
| NotYetDone work-> NotYetDone(fun()-> bind k(work()))
596+
| NotYetDone work-> NotYetDone(functok-> bind k(work ctok))
557597

558598
letfold f acc seq=
559599
(Done acc,seq)||> Seq.fold(fun acc x-> acc|> bind(fun acc-> f acc x))
@@ -562,13 +602,13 @@ module Eventually =
562602
match ewith
563603
| Done x-> Done(Result x)
564604
| NotYetDone work->
565-
NotYetDone(fun()->
566-
letres=try Result(work())with| e-> Exception e
605+
NotYetDone(functok->
606+
letres=try Result(work ctok)with| e-> Exception e
567607
match reswith
568608
| Result cont-> catch cont
569609
| Exception e-> Done(Exception e))
570610

571-
letdelayf= NotYetDone(fun()-> f())
611+
letdelay(f:unit->Eventually<'T>)= NotYetDone(fun_ctok-> f())
572612

573613
lettryFinally e compensation=
574614
catch(e)
@@ -581,6 +621,10 @@ module Eventually =
581621
catch e
582622
|> bind(function Result v-> Done v| Exception e-> handler e)
583623

624+
// All eventually computations carry a CompiationThreadToken
625+
lettoken=
626+
NotYetDone(fun ctok-> Done ctok)
627+
584628
typeEventuallyBuilder()=
585629
memberx.Bind(e,k)= Eventually.bind k e
586630
memberx.Return(v)= Eventually.Done v

‎src/absil/ilread.fs‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ open System.IO
1414
openSystem.Runtime.InteropServices
1515
openSystem.Collections.Generic
1616
openInternal.Utilities
17+
openInternal.Utilities.Collections
1718
openMicrosoft.FSharp.Compiler.AbstractIL
1819
openMicrosoft.FSharp.Compiler.AbstractIL.Internal
1920
#if!FX_NO_PDB_READER
@@ -3964,10 +3965,10 @@ let OpenILModuleReader infile opts =
39643965
dispose=(fun()->
39653966
ClosePdbReader pdb)}
39663967

3967-
// ++GLOBAL MUTABLE STATE
3968-
letilModuleReaderCache=
3969-
newInternal.Utilities.Collections.AgedLookup<(string* System.DateTime),ILModuleReader>(0, areSame=(fun(x,y)-> x= y))
3970-
3968+
// ++GLOBAL MUTABLE STATE (concurrency safe via locking)
3969+
typeILModuleReaderCacheLockToken()=interface LockToken
3970+
letilModuleReaderCache=new AgedLookup<ILModuleReaderCacheLockToken,(string* System.DateTime),ILModuleReader>(0, areSame=(fun(x,y)-> x= y))
3971+
letilModuleReaderCacheLock= Lock()
39713972

39723973
letOpenILModuleReaderAfterReadingAllBytes infile opts=
39733974
// Pseudo-normalize the paths.
@@ -3979,7 +3980,7 @@ let OpenILModuleReaderAfterReadingAllBytes infile opts =
39793980
letcacheResult=
39803981
ifnot succeededthen None// Fall back to uncached.
39813982
elseif opts.pdbPath.IsSomethen None// can't used a cached entry when reading PDBs, since it makes the returned object IDisposable
3982-
else ilModuleReaderCache.TryGet(key)
3983+
elseilModuleReaderCacheLock.AcquireLock(fun ltok->ilModuleReaderCache.TryGet(ltok,key))
39833984
match cacheResultwith
39843985
| Some(ilModuleReader)-> ilModuleReader
39853986
| None->
@@ -3990,7 +3991,7 @@ let OpenILModuleReaderAfterReadingAllBytes infile opts =
39903991
ilAssemblyRefs= ilAssemblyRefs
39913992
dispose=(fun()-> ClosePdbReader pdb)}
39923993
if Option.isNone pdb&& succeededthen
3993-
ilModuleReaderCache.Put(key, ilModuleReader)
3994+
ilModuleReaderCacheLock.AcquireLock(fun ltok->ilModuleReaderCache.Put(ltok,key, ilModuleReader))
39943995
ilModuleReader
39953996

39963997
letOpenILModuleReaderFromBytes fileNameForDebugOutput bytes opts=

‎src/absil/ilread.fsi‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ open Internal.Utilities
3030
openMicrosoft.FSharp.Compiler.AbstractIL
3131
openMicrosoft.FSharp.Compiler.AbstractIL.IL
3232
openMicrosoft.FSharp.Compiler.AbstractIL.Internal
33+
openMicrosoft.FSharp.Compiler.ErrorLogger
3334
openSystem.IO
3435

3536

‎src/absil/ilreflect.fs‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ type cenv =
336336
{ ilg:ILGlobals
337337
tryFindSysILTypeRef:string-> ILTypeRef option
338338
generatePdb:bool
339-
resolvePath:(ILAssemblyRef-> Choice<string,System.Reflection.Assembly> option)}
339+
resolveAssemblyRef:(ILAssemblyRef-> Choice<string,System.Reflection.Assembly> option)}
340340

341341
/// Convert an Abstract IL type reference to Reflection.Emit System.Type value.
342342
// This ought to be an adequate substitute for this whole function, but it needs
@@ -350,7 +350,7 @@ let convTypeRefAux (cenv:cenv) (tref:ILTypeRef) =
350350
match tref.Scopewith
351351
| ILScopeRef.Assembly asmref->
352352
letassembly=
353-
match cenv.resolvePath asmrefwith
353+
match cenv.resolveAssemblyRef asmrefwith
354354
| Some(Choice1Of2 path)->
355355
FileSystem.AssemblyLoadFrom(path)
356356
| Some(Choice2Of2 assembly)->
@@ -2003,8 +2003,8 @@ let mkDynamicAssemblyAndModule (assemblyName, optimize, debugInfo, collectible)
20032003
letmodB= asmB.DefineDynamicModuleAndLog(assemblyName,filename,debugInfo)
20042004
asmB,modB
20052005

2006-
letemitModuleFragment(ilg,emEnv,asmB:AssemblyBuilder,modB:ModuleBuilder,modul:IL.ILModuleDef,debugInfo:bool,resolvePath,tryFindSysILTypeRef)=
2007-
letcenv={ ilg= ilg; generatePdb= debugInfo;resolvePath=resolvePath; tryFindSysILTypeRef=tryFindSysILTypeRef}
2006+
letemitModuleFragment(ilg,emEnv,asmB:AssemblyBuilder,modB:ModuleBuilder,modul:IL.ILModuleDef,debugInfo:bool,resolveAssemblyRef,tryFindSysILTypeRef)=
2007+
letcenv={ ilg= ilg; generatePdb= debugInfo;resolveAssemblyRef=resolveAssemblyRef; tryFindSysILTypeRef=tryFindSysILTypeRef}
20082008

20092009
letemEnv= buildModuleFragment cenv emEnv asmB modB modul
20102010
match modul.Manifestwith

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp