File indexing completed on 2024-04-28 16:59:49

0001 #ifndef MALLOCCACHE_H
0002 #define MALLOCCACHE_H
0003 
0004 #include <cassert>
0005 #include <cstdlib>
0006 
0007 // no-op the cache, sometimes useful for debugging memory issues
0008 //#define MALLOCCACHE_PASSTHROUGH
0009 
0010 // On MinGW, we got crashes in multithreaded code due do an apparent problem with thread-local variable
0011 // support in MinGW. It *should* be fixed in MinGW with GCC 13. In lower versions, disable MallocCache.
0012 // It will still have uninitialized memory, but in passthrough mode it never accesses anything behind
0013 // the this pointer, so it's effectively just a bunch of free functions that call malloc and free.
0014 // https://github.com/msys2/MINGW-packages/issues/2519
0015 // https://github.com/msys2/MINGW-packages/discussions/13259
0016 #if defined(__GNUC__) && defined(__MINGW32__) && __GNUC__ < 13
0017 #define MALLOCCACHE_PASSTHROUGH
0018 #endif
0019 
0020 template <size_t blockSize, size_t blockCount>
0021 class MallocCache
0022 {
0023 public:
0024     MallocCache()
0025        : m_blocksCached(0)
0026     {
0027     }
0028 
0029     ~MallocCache()
0030     {
0031 #ifndef MALLOCCACHE_PASSTHROUGH
0032         assert(m_blocksCached <= blockCount);
0033         for (size_t i = 0; i < m_blocksCached; i++) {
0034             ::free(m_blocks[i]);
0035         }
0036 #endif
0037     }
0038 
0039     void *allocate()
0040     {
0041 #ifndef MALLOCCACHE_PASSTHROUGH
0042         assert(m_blocksCached <= blockCount);
0043         if (m_blocksCached) {
0044             return m_blocks[--m_blocksCached];
0045         } else {
0046             return ::malloc(blockSize);
0047         }
0048 #else
0049         return ::malloc(blockSize);
0050 #endif
0051     }
0052 
0053     void free(void *allocation)
0054     {
0055 #ifndef MALLOCCACHE_PASSTHROUGH
0056         assert(m_blocksCached <= blockCount);
0057         if (m_blocksCached < blockCount) {
0058             m_blocks[m_blocksCached++] = allocation;
0059         } else {
0060             ::free(allocation);
0061         }
0062 #else
0063         ::free(allocation);
0064 #endif
0065     }
0066 
0067 private:
0068     void *m_blocks[blockCount];
0069     size_t m_blocksCached;
0070 };
0071 
0072 #endif // MALLOCCACHE_H