| 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 | // CCacheLineAllocator |
| 6 | // |
| 7 | |
| 8 | // |
| 9 | // This file dImplements the CCacheLineAllocator class. |
| 10 | // |
| 11 | // @comm |
| 12 | // |
| 13 | // Notes: |
| 14 | // The CacheLineAllocator maintains a pool of free CacheLines |
| 15 | // |
| 16 | // The CacheLine Allocator provides static member functions |
| 17 | // GetCacheLine and FreeCacheLine, |
| 18 | //--------------------------------------------------------------------------- |
| 19 | |
| 20 | |
| 21 | |
| 22 | #include "common.h" |
| 23 | #include <stddef.h> |
| 24 | #include "cachelinealloc.h" |
| 25 | |
| 26 | #include "threads.h" |
| 27 | #include "excep.h" |
| 28 | |
| 29 | /////////////////////////////////////////////////////// |
| 30 | // CCacheLineAllocator::CCacheLineAllocator() |
| 31 | // |
| 32 | ////////////////////////////////////////////////////// |
| 33 | |
| 34 | CCacheLineAllocator::CCacheLineAllocator() |
| 35 | { |
| 36 | CONTRACTL |
| 37 | { |
| 38 | NOTHROW; |
| 39 | GC_NOTRIGGER; |
| 40 | MODE_ANY; |
| 41 | } |
| 42 | CONTRACTL_END; |
| 43 | |
| 44 | m_freeList32.Init(); |
| 45 | m_freeList64.Init(); |
| 46 | m_registryList.Init(); |
| 47 | } |
| 48 | |
| 49 | /////////////////////////////////////////////////////// |
| 50 | // void CCacheLineAllocator::~CCacheLineAllocator() |
| 51 | // |
| 52 | ////////////////////////////////////////////////////// |
| 53 | |
| 54 | CCacheLineAllocator::~CCacheLineAllocator() |
| 55 | { |
| 56 | CONTRACTL |
| 57 | { |
| 58 | NOTHROW; |
| 59 | GC_NOTRIGGER; |
| 60 | MODE_ANY; |
| 61 | } |
| 62 | CONTRACTL_END; |
| 63 | |
| 64 | LPCacheLine tempPtr = NULL; |
| 65 | while((tempPtr = m_registryList.RemoveHead()) != NULL) |
| 66 | { |
| 67 | for (int i =0; i < CacheLine::numEntries; i++) |
| 68 | { |
| 69 | if(tempPtr->m_pAddr[i] != NULL) |
| 70 | { |
| 71 | if (!g_fProcessDetach) |
| 72 | VFree(tempPtr->m_pAddr[i]); |
| 73 | } |
| 74 | } |
| 75 | delete tempPtr; |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | |
| 80 | |
| 81 | /////////////////////////////////////////////////////// |
| 82 | // static void *CCacheLineAllocator::VAlloc(ULONG cbSize) |
| 83 | // |
| 84 | ////////////////////////////////////////////////////// |
| 85 | |
| 86 | |
| 87 | void *CCacheLineAllocator::VAlloc(ULONG cbSize) |
| 88 | { |
| 89 | CONTRACT(void*) |
| 90 | { |
| 91 | NOTHROW; |
| 92 | GC_NOTRIGGER; |
| 93 | MODE_ANY; |
| 94 | INJECT_FAULT(CONTRACT_RETURN NULL); |
| 95 | POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); |
| 96 | } |
| 97 | CONTRACT_END; |
| 98 | |
| 99 | // helper to call virtual free to release memory |
| 100 | |
| 101 | int i =0; |
| 102 | void* pv = ClrVirtualAlloc (NULL, cbSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); |
| 103 | if (pv != NULL) |
| 104 | { |
| 105 | LPCacheLine tempPtr = m_registryList.GetHead(); |
| 106 | if (tempPtr == NULL) |
| 107 | { |
| 108 | goto LNew; |
| 109 | } |
| 110 | |
| 111 | for (i =0; i < CacheLine::numEntries; i++) |
| 112 | { |
| 113 | if(tempPtr->m_pAddr[i] == NULL) |
| 114 | { |
| 115 | tempPtr->m_pAddr[i] = pv; |
| 116 | RETURN pv; |
| 117 | } |
| 118 | } |
| 119 | |
| 120 | LNew: |
| 121 | // initialize the bucket before returning |
| 122 | tempPtr = new (nothrow) CacheLine(); |
| 123 | if (tempPtr != NULL) |
| 124 | { |
| 125 | tempPtr->Init64(); |
| 126 | tempPtr->m_pAddr[0] = pv; |
| 127 | m_registryList.InsertHead(tempPtr); |
| 128 | } |
| 129 | else |
| 130 | { |
| 131 | // couldn't find space to register this page |
| 132 | ClrVirtualFree(pv, 0, MEM_RELEASE); |
| 133 | RETURN NULL; |
| 134 | } |
| 135 | } |
| 136 | RETURN pv; |
| 137 | } |
| 138 | |
| 139 | /////////////////////////////////////////////////////// |
| 140 | // void CCacheLineAllocator::VFree(void* pv) |
| 141 | // |
| 142 | ////////////////////////////////////////////////////// |
| 143 | |
| 144 | |
| 145 | void CCacheLineAllocator::VFree(void* pv) |
| 146 | { |
| 147 | BOOL bRes = FALSE; |
| 148 | |
| 149 | CONTRACT_VOID |
| 150 | { |
| 151 | NOTHROW; |
| 152 | GC_NOTRIGGER; |
| 153 | MODE_ANY; |
| 154 | PRECONDITION(CheckPointer(pv)); |
| 155 | POSTCONDITION(bRes); |
| 156 | } |
| 157 | CONTRACT_END; |
| 158 | |
| 159 | // helper to call virtual free to release memory |
| 160 | |
| 161 | bRes = ClrVirtualFree (pv, 0, MEM_RELEASE); |
| 162 | |
| 163 | RETURN_VOID; |
| 164 | } |
| 165 | |
| 166 | /////////////////////////////////////////////////////// |
| 167 | // void *CCacheLineAllocator::GetCacheLine() |
| 168 | // |
| 169 | ////////////////////////////////////////////////////// |
| 170 | |
| 171 | //WARNING: must have a lock when calling this function |
| 172 | void *CCacheLineAllocator::GetCacheLine64() |
| 173 | { |
| 174 | CONTRACT(void*) |
| 175 | { |
| 176 | NOTHROW; |
| 177 | GC_NOTRIGGER; |
| 178 | MODE_ANY; |
| 179 | INJECT_FAULT(CONTRACT_RETURN NULL); |
| 180 | POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); |
| 181 | } |
| 182 | CONTRACT_END; |
| 183 | |
| 184 | LPCacheLine tempPtr = m_freeList64.RemoveHead(); |
| 185 | if (tempPtr != NULL) |
| 186 | { |
| 187 | // initialize the bucket before returning |
| 188 | tempPtr->Init64(); |
| 189 | RETURN tempPtr; |
| 190 | } |
| 191 | |
| 192 | #define AllocSize 4096*16 |
| 193 | |
| 194 | ////////////////////////////////' |
| 195 | /// Virtual Allocation for some more cache lines |
| 196 | |
| 197 | BYTE* ptr = (BYTE*)VAlloc(AllocSize); |
| 198 | |
| 199 | if(!ptr) |
| 200 | RETURN NULL; |
| 201 | |
| 202 | |
| 203 | tempPtr = (LPCacheLine)ptr; |
| 204 | // Link all the buckets |
| 205 | tempPtr = tempPtr+1; |
| 206 | LPCacheLine maxPtr = (LPCacheLine)(ptr + AllocSize); |
| 207 | |
| 208 | while(tempPtr < maxPtr) |
| 209 | { |
| 210 | m_freeList64.InsertHead(tempPtr); |
| 211 | tempPtr++; |
| 212 | } |
| 213 | |
| 214 | // return the first block |
| 215 | tempPtr = (LPCacheLine)ptr; |
| 216 | tempPtr->Init64(); |
| 217 | RETURN tempPtr; |
| 218 | } |
| 219 | |
| 220 | |
| 221 | /////////////////////////////////////////////////////// |
| 222 | // void *CCacheLineAllocator::GetCacheLine32() |
| 223 | // |
| 224 | ////////////////////////////////////////////////////// |
| 225 | |
| 226 | //WARNING: must have a lock when calling this function |
| 227 | void *CCacheLineAllocator::GetCacheLine32() |
| 228 | { |
| 229 | CONTRACT(void*) |
| 230 | { |
| 231 | NOTHROW; |
| 232 | GC_NOTRIGGER; |
| 233 | MODE_ANY; |
| 234 | INJECT_FAULT(CONTRACT_RETURN NULL); |
| 235 | POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); |
| 236 | } |
| 237 | CONTRACT_END; |
| 238 | |
| 239 | LPCacheLine tempPtr = m_freeList32.RemoveHead(); |
| 240 | if (tempPtr != NULL) |
| 241 | { |
| 242 | // initialize the bucket before returning |
| 243 | tempPtr->Init32(); |
| 244 | RETURN tempPtr; |
| 245 | } |
| 246 | tempPtr = (LPCacheLine)GetCacheLine64(); |
| 247 | if (tempPtr != NULL) |
| 248 | { |
| 249 | m_freeList32.InsertHead(tempPtr); |
| 250 | tempPtr = (LPCacheLine)((BYTE *)tempPtr+32); |
| 251 | } |
| 252 | RETURN tempPtr; |
| 253 | } |
| 254 | /////////////////////////////////////////////////////// |
| 255 | // void CCacheLineAllocator::FreeCacheLine64(void * tempPtr) |
| 256 | // |
| 257 | ////////////////////////////////////////////////////// |
| 258 | //WARNING: must have a lock when calling this function |
| 259 | void CCacheLineAllocator::FreeCacheLine64(void * tempPtr) |
| 260 | { |
| 261 | CONTRACTL |
| 262 | { |
| 263 | NOTHROW; |
| 264 | GC_NOTRIGGER; |
| 265 | MODE_ANY; |
| 266 | |
| 267 | PRECONDITION(CheckPointer(tempPtr)); |
| 268 | } |
| 269 | CONTRACTL_END; |
| 270 | |
| 271 | LPCacheLine pCLine = (LPCacheLine )tempPtr; |
| 272 | m_freeList64.InsertHead(pCLine); |
| 273 | } |
| 274 | |
| 275 | |
| 276 | /////////////////////////////////////////////////////// |
| 277 | // void CCacheLineAllocator::FreeCacheLine32(void * tempPtr) |
| 278 | // |
| 279 | ////////////////////////////////////////////////////// |
| 280 | //WARNING: must have a lock when calling this function |
| 281 | void CCacheLineAllocator::FreeCacheLine32(void * tempPtr) |
| 282 | { |
| 283 | CONTRACTL |
| 284 | { |
| 285 | NOTHROW; |
| 286 | GC_NOTRIGGER; |
| 287 | MODE_ANY; |
| 288 | |
| 289 | PRECONDITION(CheckPointer(tempPtr)); |
| 290 | } |
| 291 | CONTRACTL_END; |
| 292 | |
| 293 | LPCacheLine pCLine = (LPCacheLine )tempPtr; |
| 294 | m_freeList32.InsertHead(pCLine); |
| 295 | } |
| 296 | |