@@ -52,7 +52,6 @@ SPTR_IMPL(ReadyToRunJitManager, ExecutionManager, m_pReadyToRunJitManager);
5252SVAL_IMPL_INIT (LONG, ExecutionManager, m_dwForbidDeletionCounter, 0 );
5353SPTR_IMPL_INIT (RangeSectionHandleHeader, ExecutionManager, m_RangeSectionHandleReaderHeader, nullptr );
5454SPTR_IMPL_INIT (RangeSectionHandleHeader, ExecutionManager, m_RangeSectionHandleWriterHeader, nullptr );
55- VOLATILE_SPTR_IMPL_INIT (RangeSection, ExecutionManager, m_RangeSectionPendingDeletion, nullptr );
5655
5756#ifndef DACCESS_COMPILE
5857
@@ -678,14 +677,10 @@ ExecutionManager::ForbidDeletionHolder::~ForbidDeletionHolder()
678677
679678// ---------------------------------------------------------------------------------------
680679//
681- // ReaderLockHolder::ReaderLockHolder takes the reader lock, checks for the writer lock
682- // and either aborts if the writer lock is held, or yields until the writer lock is released,
683- // keeping the reader lock. This is normally called in the constructor for the
684- // ReaderLockHolder.
685- //
686- // The writer cannot be taken if there are any readers. The WriterLockHolder functions take the
687- // writer lock and check for any readers. If there are any, the WriterLockHolder functions
688- // release the writer and yield to wait for the readers to be done.
680+ // ReaderLockHolder::ReaderLockHolder Increments rh->count.
681+ // This is normally called in the constructor for the ReaderLockHolder.
682+ // Always succeeds and never yields.
683+ // Detailed explanation provided in codeman.h on top of the document.
689684
690685ExecutionManager::ReaderLockHolder::ReaderLockHolder (HostCallPreference pref): m_pref(pref)
691686{
@@ -713,7 +708,8 @@ ExecutionManager::ReaderLockHolder::ReaderLockHolder(HostCallPreference pref): m
713708
714709// ---------------------------------------------------------------------------------------
715710//
716- // See code:ExecutionManager::ReaderLockHolder::ReaderLockHolder. This just decrements the reader count.
711+ // Decrements the reader count.
712+ // Detailed explanation provided in codeman.h on top of the document.
717713
718714ExecutionManager::ReaderLockHolder::~ReaderLockHolder ()
719715{
@@ -738,19 +734,15 @@ ExecutionManager::ReaderLockHolder::~ReaderLockHolder()
738734 {
739735 // we are here in relatively rare case
740736 // such code executes once per swap of arrays,
741- // so we should not worry about enormous amount
742- // of m_RangeSectionPendingDeletion accesses
743737 if (m_pref == AllowHostCalls)
744738 {
745- while ((RangeSection*)m_RangeSectionPendingDeletion != NULL )
739+ if (h-> pDelete != NULL )
746740 {
747- RangeSection* pNext = ((RangeSection*)m_RangeSectionPendingDeletion)->pNextPendingDeletion ;
748741#if defined(TARGET_AMD64)
749- if (((RangeSection*)m_RangeSectionPendingDeletion) ->pUnwindInfoTable != 0 )
750- delete ((RangeSection*)m_RangeSectionPendingDeletion)-> pUnwindInfoTable ;
742+ if (h-> pDelete ->pUnwindInfoTable != 0 )
743+ delete (h-> pDelete -> pUnwindInfoTable ) ;
751744#endif // defined(TARGET_AMD64)
752- delete (RangeSection*)m_RangeSectionPendingDeletion;
753- m_RangeSectionPendingDeletion = pNext;
745+ delete h->pDelete ;
754746 }
755747 }
756748
@@ -763,6 +755,11 @@ ExecutionManager::ReaderLockHolder::~ReaderLockHolder()
763755}
764756
765757
758+ // ---------------------------------------------------------------------------------------
759+ //
760+ // WriterLockHolder::WriterLockHolder wraps wh->rh substitution logic
761+ // Detailed explanation provided in codeman.h on top of the document.
762+
766763ExecutionManager::WriterLockHolder::WriterLockHolder (int purpose): m_purpose(purpose)
767764{
768765 CONTRACTL {
@@ -793,6 +790,11 @@ ExecutionManager::WriterLockHolder::WriterLockHolder(int purpose): m_purpose(pur
793790 EE_LOCK_TAKEN ((void *)h);
794791}
795792
793+ // ---------------------------------------------------------------------------------------
794+ //
795+ // WriterLockHolder::~WriterLockHolder wraps wh->rh substitution logic
796+ // Detailed explanation provided in codeman.h on top of the document.
797+
796798ExecutionManager::WriterLockHolder::~WriterLockHolder ()
797799{
798800 LIMITED_METHOD_CONTRACT;
@@ -837,15 +839,13 @@ ExecutionManager::WriterLockHolder::~WriterLockHolder()
837839 if (count == 1 )// h->count == 0, all readers left, we've just removed EM's unit,
838840 // now attach the header to writer's slot:
839841 {
840- while ((RangeSection*)m_RangeSectionPendingDeletion != NULL )
842+ if (old_rh-> pDelete != NULL )
841843 {
842- RangeSection* pNext = ((RangeSection*)m_RangeSectionPendingDeletion)->pNextPendingDeletion ;
843844#if defined(TARGET_AMD64)
844- if (((RangeSection*)m_RangeSectionPendingDeletion) ->pUnwindInfoTable != 0 )
845- delete ((RangeSection*)m_RangeSectionPendingDeletion)-> pUnwindInfoTable ;
845+ if (old_rh-> pDelete ->pUnwindInfoTable != 0 )
846+ delete (old_rh-> pDelete -> pUnwindInfoTable ) ;
846847#endif // defined(TARGET_AMD64)
847- delete (RangeSection*)m_RangeSectionPendingDeletion;
848- m_RangeSectionPendingDeletion = pNext;
848+ delete old_rh->pDelete ;
849849 }
850850
851851 VolatileStore (&m_RangeSectionHandleWriterHeader, old_rh);
@@ -864,7 +864,6 @@ ExecutionManager::WriterLockHolder::~WriterLockHolder()
864864}
865865#else
866866
867- // For DAC builds we never actually take the lock.
868867// Note: Throws
869868ExecutionManager::ReaderLockHolder::ReaderLockHolder (HostCallPreference pref)
870869{
@@ -910,21 +909,30 @@ ExecutionManager::ForbidDeletionHolder::~ForbidDeletionHolder()
910909//-----------------------------------------------------------------------------
911910
912911==============================================================================
913- ExecutionManger::ReaderLockHolder and ExecutionManger::WriterLockHolder
914- Protects the callers of ExecutionManager::GetRangeSection from heap deletions
915- while walking RangeSections. You need to take a reader lock before reading the
916- values: m_CodeRangeList and hold it while walking the lists
912+ ExecutionManger::ReaderLockHolder, ExecutionManger::WriterLockHolder
913+ and ExecutionManger::ForbidDeletionHolder
914+ protect the callers of ExecutionManager::GetRangeSection from heap deletions
915+ while walking RangeSections. You need to initialize a ForbidDeletionHolder
916+ if someone simultaneously may call DeleteRange
917+
918+ Detailed explanation provided in codeman.h on top of the document.
917919
918- Uses ReaderLockHolder (allows multiple reeaders with no writers)
920+
921+ Uses ReaderLockHolder
919922-----------------------------------------
920- ExecutionManager::FindCodeRange
921- ExecutionManager::FindZapModule
922- ExecutionManager::EnumMemoryRegions
923+ ExecutionManager::GetRangeSection
923924
924- Uses WriterLockHolder (allows single writer and no readers)
925+ Uses WriterLockHolder
925926-----------------------------------------
926- ExecutionManager::AddRangeHelper
927- ExecutionManager::DeleteRangeHelper
927+ ExecutionManager::AddRangeSection
928+ ExecutionManager::DeleteRange
929+
930+ Uses ForbidDeletionHolder
931+ -----------------------------------------
932+ ExecutionManager::IsManagedCodeWithLock
933+ ExecutionManager::IsManagedCode
934+ ExecutionManager::FindZapModule
935+ ExecutionManager::FindReadyToRunModule
928936
929937*/
930938
@@ -1087,10 +1095,10 @@ IJitManager::IJitManager()
10871095#endif // #ifndef DACCESS_COMPILE
10881096
10891097// When we unload an appdomain, we need to make sure that any threads that are crawling through
1090- // our heap or rangelist are out. For cooperative-mode threads, we know that they will have
1098+ // our heap list or range storage are out. For cooperative-mode threads, we know that they will have
10911099// been stopped when we suspend the EE so they won't be touching an element that is about to be deleted.
10921100// However for pre-emptive mode threads, they could be stalled right on top of the element we want
1093- // to delete, so we need to apply the reader lock to them and wait for them to drain.
1101+ // to delete, so we need to apply the ForbidDeletionHolder to them and wait for them to drain.
10941102ExecutionManager::ScanFlag ExecutionManager::GetScanFlags ()
10951103{
10961104 CONTRACTL {
@@ -2419,7 +2427,7 @@ void CodeFragmentHeap::RealBackoutMem(void *pMem
24192427// **************************************************************************
24202428
24212429LoaderCodeHeap::LoaderCodeHeap ()
2422- : m_LoaderHeap(NULL , // RangeList *pRangeList
2430+ : m_LoaderHeap(NULL ,
24232431 TRUE ), // BOOL fMakeExecutable
24242432 m_cbMinNextPad(0 )
24252433{
@@ -4730,8 +4738,8 @@ BOOL ExecutionManager::IsManagedCode(PCODE currentPC, HostCallPreference hostCal
47304738}
47314739
47324740// **************************************************************************
4733- // Assumes that the ExecutionManager reader/writer lock is taken or that
4734- // it is safe not to take it. //TODO edit comment
4741+ // Assumes that the ExecutionManager ForbidDeletionHolder is taken or that
4742+ // it is safe not to take it.
47354743BOOL ExecutionManager::IsManagedCodeWorker (PCODE currentPC, HostCallPreference pref)
47364744{
47374745 CONTRACTL {
@@ -4772,7 +4780,7 @@ BOOL ExecutionManager::IsManagedCodeWorker(PCODE currentPC, HostCallPreference p
47724780}
47734781
47744782// **************************************************************************
4775- // Assumes that it is safe not to take it the ExecutionManager reader/writer lock
4783+ // Assumes that it is safe not to take the ForbidDeletionHolder
47764784BOOL ExecutionManager::IsReadyToRunCode (PCODE currentPC)
47774785{
47784786 CONTRACTL{
@@ -5130,12 +5138,14 @@ void ExecutionManager::AddRangeSection(RangeSection *pRS)
51305138 wh->array [0 ].pRS = pRS;
51315139 wh->count = 0 ;
51325140 wh->last_used_index = 0 ;
5141+ wh->pDelete = nullptr ;
51335142
51345143 RangeSectionHandleHeader *rh = new RangeSectionHandleHeader ();
51355144 rh->capacity = wh->capacity ;
51365145 rh->size = wh->size ;
51375146 rh->count = 1 ; // EM's unit
51385147 rh->last_used_index = wh->last_used_index ;
5148+ rh->pDelete = nullptr ;
51395149 rh->array = new RangeSectionHandle[rh->capacity ];
51405150
51415151 rh->array [0 ] = wh->array [0 ];
@@ -5192,6 +5202,7 @@ void ExecutionManager::AddRangeSection(RangeSection *pRS)
51925202 wh->array [size].LowAddress = pRS->LowAddress ;
51935203 wh->array [size].pRS = pRS;
51945204 wh->size = size + 1 ;
5205+ wh->pDelete = nullptr ;
51955206 // last used index was not changed by this operation
51965207 return ; // assume that ~WriterLockHolder() executes before ~CrstHolder()
51975208 }
@@ -5206,11 +5217,13 @@ void ExecutionManager::AddRangeSection(RangeSection *pRS)
52065217 wh->array [index].LowAddress = pRS->LowAddress ;
52075218 wh->array [index].pRS = pRS;
52085219 wh->size = size + 1 ;
5220+ wh->pDelete = nullptr ;
52095221 int ri = VolatileLoad (&(rh->last_used_index ));
52105222 if (ri >= index)
52115223 wh->last_used_index = ri + 1 ;
52125224 return ;
52135225 }
5226+ wh->pDelete = nullptr ;
52145227 return ;
52155228}
52165229
@@ -5253,24 +5266,28 @@ void ExecutionManager::DeleteRange(TADDR pStartRange)
52535266 } CONTRACTL_END;
52545267
52555268 {
5256- // Acquire the Crst before unlinking a RangeList.
5257- // NOTE: The Crst must be acquired BEFORE we grab the writer lock, as the
5258- // writer lock forces us into a forbid suspend thread region, and it's illegal
5259- // to enter a Crst after the forbid suspend thread region is entered
5269+ // Acquire the Crst to protect writers from each other.
5270+ // NOTE: The Crst must be acquired BEFORE we grab the wlh, as the
5271+ // wlh us into a forbid suspend thread region, and it's illegal
5272+ // to enter a Crst after the forbid suspend thread region is entered.
5273+ // Also wlh acts as a wrapper of reader/writer header interchanging
5274+ // logic and depends on Crst to allow only one wlh accessor at a time.
52605275 CrstHolder ch (&m_RangeCrst);
52615276
5262- // Acquire the WriterLock and prevent any readers from walking the RangeList .
5263- // This also forces us to enter a forbid suspend thread region, to prevent
5277+ // Acquirnig the wlh DOES NOT prevent any readers from walking the RangeSectionStorage .
5278+ // Wlh forces us to enter a forbid suspend thread region, to prevent
52645279 // hijacking profilers from grabbing this thread and walking it (the walk may
52655280 // require the reader lock, which would cause a deadlock).
5281+
5282+ // Detailed explanation of rlh/wlh/fdh model provided in codeman.h on top of the document.
5283+
52665284 WriterLockHolder wlh (1 ); // 1 for deletion purpose
52675285 RangeSectionHandleHeader *rh = VolatileLoad (&m_RangeSectionHandleReaderHeader);
52685286 int index = FindRangeSectionHandleHelper (rh, pStartRange);
52695287
52705288 if (index >= 0 )
52715289 {
5272- rh->array [index].pRS ->pNextPendingDeletion = (RangeSection*)m_RangeSectionPendingDeletion;
5273- m_RangeSectionPendingDeletion = rh->array [index].pRS ;
5290+ wlh.h ->pDelete = rh->array [index].pRS ;
52745291 DeleteRangeSection (wlh.h , rh, index);
52755292 }
52765293 }
0 commit comments