Monday, May 23, 2016

Fast ring buffer

Fast ring buffer implementation based on mapping of two continuous
virtual ranges on one physical range

static const int PAGE_SIZE = 4096;
class RingBuffer
{
public:
   RingBuffer(int bytesCapacity) :
      m_bytesCapacity(bytesCapacity),
      m_bufferPtr(NULL),
      m_head(0),
      m_tail(0)
   {
      assert(bytesCapacity > 0);
      assert((bytesCapacity & (PAGE_SIZE - 1)) == 0);

      ULONG_PTR toAllocate = bytesCapacity / PAGE_SIZE;
      BOOL needContinue = FALSE;

      m_hMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE | SEC_COMMIT, 0, m_bytesCapacity, NULL);

      while (1) {
         m_bufferPtr = VirtualAlloc(NULL, m_bytesCapacity * 2, MEM_RESERVE, PAGE_READWRITE);
         VirtualFree(m_bufferPtr, 0, MEM_RELEASE);
         if (!MapViewOfFileEx(m_hMap, FILE_MAP_ALL_ACCESS, 0, 0, m_bytesCapacity, m_bufferPtr))
            continue;
         if (!MapViewOfFileEx(m_hMap, FILE_MAP_ALL_ACCESS, 0, 0, m_bytesCapacity, (BYTE*)m_bufferPtr + m_bytesCapacity))
            continue;

         break;
      }
   }

   ~RingBuffer()
   {
      if (m_bufferPtr) {
         UnmapViewOfFile(m_bufferPtr);
         UnmapViewOfFile((BYTE*)m_bufferPtr + m_bytesCapacity);
      }
   }

   void Push(BYTE *b, DWORD sz)
   {
      memcpy((BYTE*)m_bufferPtr + m_tail, b, sz);
      m_tail += sz;
      m_tail %= m_bytesCapacity;
   }

   void Pop(BYTE *b, DWORD sz)
   {
      memcpy(b, (BYTE*)m_bufferPtr + m_head, sz);
      m_head += sz;
      m_head %= m_bytesCapacity;
   }

   int GetSize(void) const
   {
      return m_tail > m_head ? (m_tail - m_head) : (m_tail + m_bytesCapacity - m_head);
   }
  


private:
   HANDLE     m_hMap;
   LPVOID     m_bufferPtr;
   DWORD      m_bytesCapacity;
   DWORD      m_head;
   DWORD      m_tail;
};

No comments:

Post a Comment