summaryrefslogtreecommitdiff
path: root/lib/circular_buffer.cpp
diff options
context:
space:
mode:
authorJosh Blum2012-12-13 19:45:08 -0800
committerJosh Blum2012-12-13 19:45:08 -0800
commit83ad787f994d6efbde505ce9915f44bef2b5408d (patch)
treee9af973d7232d586ce5a61069e8b796369e77607 /lib/circular_buffer.cpp
parent59d8dafe387b11ecf8bfff892e1e30fe07e33caa (diff)
downloadsandhi-83ad787f994d6efbde505ce9915f44bef2b5408d.tar.gz
sandhi-83ad787f994d6efbde505ce9915f44bef2b5408d.tar.bz2
sandhi-83ad787f994d6efbde505ce9915f44bef2b5408d.zip
some work on the circular buffer alloc
Diffstat (limited to 'lib/circular_buffer.cpp')
-rw-r--r--lib/circular_buffer.cpp149
1 files changed, 149 insertions, 0 deletions
diff --git a/lib/circular_buffer.cpp b/lib/circular_buffer.cpp
new file mode 100644
index 0000000..820129d
--- /dev/null
+++ b/lib/circular_buffer.cpp
@@ -0,0 +1,149 @@
+// Copyright (C) by Josh Blum. See LICENSE.txt for licensing information.
+
+#include <gras_impl/endless_buffer_queue.hpp>
+#include <boost/format.hpp>
+#include <boost/bind.hpp>
+#include <boost/interprocess/shared_memory_object.hpp>
+#include <boost/interprocess/mapped_region.hpp>
+#include <boost/uuid/uuid.hpp>
+#include <boost/uuid/uuid_io.hpp>
+#include <ctime>
+
+using namespace gras;
+namespace ipc = boost::interprocess;
+
+/*!
+* This routine generates an incredibly unique name for the allocation.
+*
+* Because we are using boost IPC, and it expects that we share the memory;
+* IPC allocation requires a unique name to share amongst the processes.
+* Since we are not actually using IPC, the sharing aspect isnt very useful,
+* but we still need a unique name for the shared memory allocation anyway.
+* (I would like if a empty string would suffice as an anonymous allocation)
+*/
+static std::string omg_so_unique(void)
+{
+ boost::uuids::uuid u1; // initialize uuid
+ return boost::str(boost::format("shmem-%s-%u-%u-%u")
+ % to_string(u1) % std::rand() % clock() % time(NULL));
+}
+
+struct CircularBuffer
+{
+ CircularBuffer(const size_t);
+
+ ~CircularBuffer(void)
+ {
+ ipc::shared_memory_object::remove(shm_name.c_str());
+ }
+
+ char *buff_addr;
+ size_t actual_length;
+ std::string shm_name;
+ ipc::shared_memory_object shm_obj;
+ ipc::mapped_region region1;
+ ipc::mapped_region region2;
+};
+
+CircularBuffer::CircularBuffer(const size_t num_bytes)
+{
+ const size_t chunk = ipc::mapped_region::get_page_size();
+ const size_t len = chunk*((num_bytes + chunk - 1)/chunk);
+ actual_length = len;
+
+ ////////////////////////////////////////////////////////////////
+ // Step 0) Find an address that can be mapped across 2x length:
+ // Allocate physical memory 2x the required size.
+ // Map a virtual memory region across this memory.
+ // Now we have a 2x length swath of virtual memory.
+ ////////////////////////////////////////////////////////////////
+ {
+ shm_name = omg_so_unique();
+
+ //std::cout << "make shmem 2x\n" << std::endl;
+ ipc::shared_memory_object shm_obj_2x(
+ ipc::create_only, //only create
+ shm_name.c_str(), //name
+ ipc::read_write //read-write mode
+ );
+
+ //std::cout << "truncate 2x\n" << std::endl;
+ shm_obj_2x.truncate(2*len);
+
+ //std::cout << "map region 0\n" << std::endl;
+ ipc::mapped_region region0(
+ shm_obj_2x, //Memory-mappable object
+ ipc::read_write, //Access mode
+ 0, //Offset from the beginning of shm
+ 2*len //Length of the region
+ );
+ //std::cout << "region0.get_address() " << size_t(region0.get_address()) << std::endl;
+
+ ipc::shared_memory_object::remove(shm_name.c_str());
+ buff_addr = (char *)region0.get_address();
+ }
+
+ ////////////////////////////////////////////////////////////////
+ // Step 1) Allocate a chunk of physical memory of length bytes
+ ////////////////////////////////////////////////////////////////
+ //std::cout << "make shmem\n" << std::endl;
+ shm_name = omg_so_unique();
+ shm_obj = ipc::shared_memory_object(
+ ipc::create_only, //only create
+ shm_name.c_str(), //name
+ ipc::read_write //read-write mode
+ );
+
+ //std::cout << "truncate\n" << std::endl;
+ shm_obj.truncate(len);
+
+ ////////////////////////////////////////////////////////////////
+ //Step 2) Remap region1 of the virtual memory space
+ ////////////////////////////////////////////////////////////////
+ //std::cout << "map region 1\n" << std::endl;
+ region1 = ipc::mapped_region(
+ shm_obj, //Memory-mappable object
+ ipc::read_write, //Access mode
+ 0, //Offset from the beginning of shm
+ len, //Length of the region
+ buff_addr
+ );
+ //std::cout << "region1.get_address() " << size_t(region1.get_address()) << std::endl;
+
+ ////////////////////////////////////////////////////////////////
+ //Step 3) Remap region2 of the virtual memory space
+ ////////////////////////////////////////////////////////////////
+ //std::cout << "map region 2\n" << std::endl;
+ region2 = ipc::mapped_region(
+ shm_obj, //Memory-mappable object
+ ipc::read_write, //Access mode
+ 0, //Offset from the beginning of shm
+ len, //Length of the region
+ buff_addr + len
+ );
+
+ //std::cout << "region2.get_address() " << size_t(region2.get_address()) << std::endl;
+ //std::cout << "diff " << (long(region2.get_address()) - long(region1.get_address())) << std::endl;
+
+ ////////////////////////////////////////////////////////////////
+ //4) Zero out the memory for good measure
+ ////////////////////////////////////////////////////////////////
+ std::memset(region1.get_address(), 0, region1.get_size());
+ std::memset(region2.get_address(), 0, region2.get_size());
+}
+
+static void circular_buffer_delete(SBuffer &buff, CircularBuffer *circ_buff)
+{
+ delete circ_buff;
+}
+
+SBuffer EndlessBufferQueue::make_circular_buffer(const size_t num_bytes)
+{
+ CircularBuffer *circ_buff = new CircularBuffer(num_bytes);
+ SBufferDeleter deleter = boost::bind(&circular_buffer_delete, _1, circ_buff);
+ SBufferConfig config;
+ config.memory = circ_buff->buff_addr;
+ config.length = circ_buff->actual_length;
+ config.deleter = deleter;
+ return SBuffer(config);
+}