| 886 | }; |
| 887 | |
| 888 | static void* SlowLFAlloc(int nSizeIdx, int blockSize, EDefrag defrag) { |
| 889 | IncrementCounter(CT_SLOW_ALLOC_CNT, 1); |
| 890 | |
| 891 | TLFLockHolder ls; |
| 892 | for (;;) { |
| 893 | bool locked = ls.TryLock(&LFGlobalLock); |
| 894 | void* res = LFAllocFromCurrentChunk(nSizeIdx, blockSize, 1); |
| 895 | if (res) { |
| 896 | return res; // might happen when other thread allocated new current chunk |
| 897 | } |
| 898 | if (locked) { |
| 899 | break; |
| 900 | } |
| 901 | } |
| 902 | for (;;) { |
| 903 | uintptr_t nChunk; |
| 904 | if (GetFreeChunk(&nChunk)) { |
| 905 | char* newPlace = ALLOC_START + nChunk * N_CHUNK_SIZE; |
| 906 | #ifdef _MSC_VER |
| 907 | void* pTest = VirtualAlloc(newPlace, N_CHUNK_SIZE, MEM_COMMIT, PAGE_READWRITE); |
| 908 | Y_ASSERT_NOBT(pTest == newPlace); |
| 909 | #endif |
| 910 | chunkSizeIdx[nChunk] = (char)nSizeIdx; |
| 911 | globalCurrentPtr[nSizeIdx] = newPlace + blockSize; |
| 912 | return newPlace; |
| 913 | } |
| 914 | |
| 915 | // out of luck, try to defrag |
| 916 | if (defrag == MEM_DEFRAG && DefragmentMem()) { |
| 917 | continue; |
| 918 | } |
| 919 | |
| 920 | char* largeBlock = AllocWithMMap(N_LARGE_ALLOC_SIZE, MM_NORMAL); |
| 921 | uintptr_t addr = ((largeBlock - ALLOC_START) + N_CHUNK_SIZE - 1) & (~(N_CHUNK_SIZE - 1)); |
| 922 | uintptr_t endAddr = ((largeBlock - ALLOC_START) + N_LARGE_ALLOC_SIZE) & (~(N_CHUNK_SIZE - 1)); |
| 923 | for (uintptr_t p = addr; p < endAddr; p += N_CHUNK_SIZE) { |
| 924 | uintptr_t chunk = p / N_CHUNK_SIZE; |
| 925 | Y_ASSERT_NOBT(chunk * N_CHUNK_SIZE == p); |
| 926 | Y_ASSERT_NOBT(chunkSizeIdx[chunk] == 0); |
| 927 | AddFreeChunk(chunk); |
| 928 | } |
| 929 | } |
| 930 | return nullptr; |
| 931 | } |
| 932 | |
| 933 | // allocate single block |
| 934 | static Y_FORCE_INLINE void* LFAllocNoCache(int nSizeIdx, EDefrag defrag) { |
no test coverage detected