1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | |
5 | |
6 | #include "common.h" |
7 | |
8 | #include "syncclean.hpp" |
9 | #include "virtualcallstub.h" |
10 | #include "threadsuspend.h" |
11 | |
12 | VolatilePtr<Bucket> SyncClean::m_HashMap = NULL; |
13 | VolatilePtr<EEHashEntry*> SyncClean::m_EEHashTable; |
14 | |
15 | void SyncClean::Terminate() |
16 | { |
17 | CONTRACTL { |
18 | NOTHROW; |
19 | GC_NOTRIGGER; |
20 | } CONTRACTL_END; |
21 | |
22 | CleanUp(); |
23 | } |
24 | |
25 | void SyncClean::AddHashMap (Bucket *bucket) |
26 | { |
27 | WRAPPER_NO_CONTRACT; |
28 | |
29 | if (!g_fEEStarted) { |
30 | delete [] bucket; |
31 | return; |
32 | } |
33 | |
34 | BEGIN_GETTHREAD_ALLOWED |
35 | _ASSERTE (GetThread() == NULL || GetThread()->PreemptiveGCDisabled()); |
36 | END_GETTHREAD_ALLOWED |
37 | |
38 | Bucket * pTempBucket = NULL; |
39 | do |
40 | { |
41 | pTempBucket = (Bucket *)m_HashMap; |
42 | NextObsolete (bucket) = pTempBucket; |
43 | } |
44 | while (FastInterlockCompareExchangePointer(m_HashMap.GetPointer(), bucket, pTempBucket) != pTempBucket); |
45 | } |
46 | |
47 | void SyncClean::AddEEHashTable (EEHashEntry** entry) |
48 | { |
49 | WRAPPER_NO_CONTRACT; |
50 | |
51 | if (!g_fEEStarted) { |
52 | delete [] (entry-1); |
53 | return; |
54 | } |
55 | |
56 | BEGIN_GETTHREAD_ALLOWED |
57 | _ASSERTE (GetThread() == NULL || GetThread()->PreemptiveGCDisabled()); |
58 | END_GETTHREAD_ALLOWED |
59 | |
60 | EEHashEntry ** pTempHashEntry = NULL; |
61 | do |
62 | { |
63 | pTempHashEntry = (EEHashEntry**)m_EEHashTable; |
64 | entry[-1] = (EEHashEntry *)pTempHashEntry; |
65 | } |
66 | while (FastInterlockCompareExchangePointer(m_EEHashTable.GetPointer(), entry, pTempHashEntry) != pTempHashEntry); |
67 | } |
68 | |
69 | void SyncClean::CleanUp () |
70 | { |
71 | LIMITED_METHOD_CONTRACT; |
72 | |
73 | // Only GC thread can call this. |
74 | _ASSERTE (g_fProcessDetach || |
75 | IsGCSpecialThread() || |
76 | (GCHeapUtilities::IsGCInProgress() && GetThread() == ThreadSuspend::GetSuspensionThread())); |
77 | if (m_HashMap) |
78 | { |
79 | Bucket * pTempBucket = FastInterlockExchangePointer(m_HashMap.GetPointer(), NULL); |
80 | |
81 | while (pTempBucket) |
82 | { |
83 | Bucket* pNextBucket = NextObsolete (pTempBucket); |
84 | delete [] pTempBucket; |
85 | pTempBucket = pNextBucket; |
86 | } |
87 | } |
88 | |
89 | if (m_EEHashTable) |
90 | { |
91 | EEHashEntry ** pTempHashEntry = FastInterlockExchangePointer(m_EEHashTable.GetPointer(), NULL); |
92 | |
93 | while (pTempHashEntry) { |
94 | EEHashEntry **pNextHashEntry = (EEHashEntry **)pTempHashEntry[-1]; |
95 | pTempHashEntry --; |
96 | delete [] pTempHashEntry; |
97 | pTempHashEntry = pNextHashEntry; |
98 | } |
99 | } |
100 | |
101 | // Give others we want to reclaim during the GC sync point a chance to do it |
102 | VirtualCallStubManager::ReclaimAll(); |
103 | } |
104 | |