12#ifndef SST_CORE_INTERPROCESS_IPCTUNNEL_H
13#define SST_CORE_INTERPROCESS_IPCTUNNEL_H
15#include "sst/core/interprocess/circularBuffer.h"
29namespace Interprocess {
31extern uint32_t globalIPCTunnelCount;
40template <
typename ShareDataType,
typename MsgType>
46 struct InternalSharedData
48 volatile uint32_t expectedChildren;
61 IPCTunnel(uint32_t comp_id,
size_t numBuffers,
size_t bufferSize, uint32_t expectedChildren = 1) :
67 memset(key,
'\0',
sizeof(key));
69 snprintf(key,
sizeof(key),
"/sst_shmem_%u-%" PRIu32
"-%d", getpid(), comp_id, rand());
72 fd = shm_open(filename.c_str(), O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
80 }
while ( (fd < 0) && (errno == EEXIST) );
83 fprintf(stderr,
"Failed to create IPC region '%s': %s\n", filename.c_str(), strerror(errno));
87 shmSize = calculateShmemSize(numBuffers, bufferSize);
88 if ( ftruncate(fd, shmSize) ) {
90 fprintf(stderr,
"Resizing shared file '%s' failed: %s\n", filename.c_str(), strerror(errno));
94 shmPtr = mmap(
nullptr, shmSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
95 if ( shmPtr == MAP_FAILED ) {
97 fprintf(stderr,
"mmap failed: %s\n", strerror(errno));
100 nextAllocPtr = (uint8_t*)shmPtr;
101 memset(shmPtr,
'\0', shmSize);
104 auto resResult = reserveSpace<InternalSharedData>((1 + numBuffers) *
sizeof(
size_t));
105 isd = resResult.second;
106 isd->expectedChildren = expectedChildren;
107 isd->shmSegSize = shmSize;
108 isd->numBuffers = numBuffers;
111 auto shareResult = reserveSpace<ShareDataType>(0);
112 isd->offsets[0] = shareResult.first;
116 const size_t cbSize =
sizeof(MsgType) * bufferSize;
117 for (
size_t c = 0; c < isd->numBuffers; c++ ) {
120 auto resResult = reserveSpace<CircBuff_t>(cbSize);
121 isd->offsets[1 + c] = resResult.first;
122 cPtr = resResult.second;
123 if ( !cPtr->setBufferSize(bufferSize) ) exit(1);
124 circBuffs.push_back(cPtr);
132 IPCTunnel(
const std::string& region_name) : master(false), shmPtr(nullptr), fd(-1)
134 fd = shm_open(region_name.c_str(), O_RDWR, S_IRUSR | S_IWUSR);
135 filename = region_name;
139 fprintf(stderr,
"Failed to open IPC region '%s': %s\n", filename.c_str(), strerror(errno));
143 shmPtr = mmap(
nullptr,
sizeof(InternalSharedData), PROT_READ, MAP_SHARED, fd, 0);
144 if ( shmPtr == MAP_FAILED ) {
146 fprintf(stderr,
"mmap 0 failed: %s\n", strerror(errno));
150 isd = (InternalSharedData*)shmPtr;
151 shmSize = isd->shmSegSize;
152 munmap(shmPtr,
sizeof(InternalSharedData));
154 shmPtr = mmap(
nullptr, shmSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
155 if ( shmPtr == MAP_FAILED ) {
157 fprintf(stderr,
"mmap 1 failed: %s\n", strerror(errno));
160 isd = (InternalSharedData*)shmPtr;
161 sharedData = (ShareDataType*)((uint8_t*)shmPtr + isd->offsets[0]);
163 for (
size_t c = 0; c < isd->numBuffers; c++ ) {
164 circBuffs.push_back((
CircBuff_t*)((uint8_t*)shmPtr + isd->offsets[c + 1]));
168 if ( --isd->expectedChildren == 0 ) { shm_unlink(filename.c_str()); }
187 munmap(shmPtr, shmSize);
197 const std::string& getRegionName(
void)
const {
return filename; }
203 void writeMessage(
size_t core,
const MsgType& command) { circBuffs[core]->write(command); }
206 MsgType
readMessage(
size_t buffer) {
return circBuffs[buffer]->read(); }
209 bool readMessageNB(
size_t buffer, MsgType* result) {
return circBuffs[buffer]->readNB(result); }
215 template <
typename T>
216 std::pair<size_t, T*> reserveSpace(
size_t extraSpace = 0)
218 size_t space =
sizeof(T) + extraSpace;
219 if ( ((nextAllocPtr + space) - (uint8_t*)shmPtr) > shmSize )
return std::make_pair<size_t, T*>(0,
nullptr);
220 T* ptr = (T*)nextAllocPtr;
221 nextAllocPtr += space;
223 return std::make_pair((uint8_t*)ptr - (uint8_t*)shmPtr, ptr);
226 size_t static calculateShmemSize(
size_t numBuffers,
size_t bufferSize)
228 long page_size = sysconf(_SC_PAGESIZE);
231 size_t isd = 1 + ((
sizeof(InternalSharedData) + (1 + numBuffers) *
sizeof(size_t)) / page_size);
232 size_t buffer = 1 + ((
sizeof(CircBuff_t) + bufferSize *
sizeof(MsgType)) / page_size);
233 size_t shdata = 1 + ((
sizeof(ShareDataType) +
sizeof(InternalSharedData)) / page_size);
236 return (2 + isd + shdata + numBuffers * buffer) * page_size;
248 std::string filename;
249 uint8_t* nextAllocPtr;
251 InternalSharedData* isd;
252 std::vector<CircBuff_t*> circBuffs;
Definition: circularBuffer.h:23
Tunneling class between two processes, connected by shared memory.
Definition: ipctunnel.h:42
ShareDataType * getSharedData()
return a pointer to the ShareDataType region
Definition: ipctunnel.h:200
virtual ~IPCTunnel()
Destructor.
Definition: ipctunnel.h:174
void clearBuffer(size_t core)
Empty the messages in the buffer.
Definition: ipctunnel.h:212
IPCTunnel(uint32_t comp_id, size_t numBuffers, size_t bufferSize, uint32_t expectedChildren=1)
Construct a new Tunnel for IPC Communications.
Definition: ipctunnel.h:61
void shutdown(bool all=false)
Shutdown.
Definition: ipctunnel.h:179
void writeMessage(size_t core, const MsgType &command)
Blocks until space is available.
Definition: ipctunnel.h:203
IPCTunnel(const std::string ®ion_name)
Access an existing Tunnel.
Definition: ipctunnel.h:132
MsgType readMessage(size_t buffer)
Blocks until a command is available.
Definition: ipctunnel.h:206
bool readMessageNB(size_t buffer, MsgType *result)
Non-blocking version of readMessage.
Definition: ipctunnel.h:209
ShareDataType * sharedData
Pointer to the Shared Data Region.
Definition: ipctunnel.h:241