SST  10.0.0
StructuralSimulationToolkit
tunneldef.h
1 // Copyright 2009-2020 NTESS. Under the terms
2 // of Contract DE-NA0003525 with NTESS, the U.S.
3 // Government retains certain rights in this software.
4 //
5 // Copyright (c) 2009-2020, NTESS
6 // All rights reserved.
7 //
8 // This file is part of the SST software package. For license
9 // information, see the LICENSE file in the top level directory of the
10 // distribution.
11 
12 #ifndef SST_CORE_INTERPROCESS_TUNNEL_DEF_H
13 #define SST_CORE_INTERPROCESS_TUNNEL_DEF_H 1
14 
15 /*
16  * This may be compiled into both SST and an Intel Pin3 tool
17  * Therefore it has the following restrictions:
18  * - Nothing that uses runtime type info (e.g., dynamic cast)
19  * - No c++11 (auto, nullptr, etc.)
20  * - Includes must all be PinCRT-enabled but not require PinCRT
21  */
22 
23 #include <inttypes.h>
24 #include <vector>
25 #include <unistd.h>
26 
27 #include "sst/core/interprocess/circularBuffer.h"
28 
29 namespace SST {
30 namespace Core {
31 namespace Interprocess {
32 
33 
34 extern uint32_t globalMMAPIPCCount;
35 
36 /* Internal bookkeeping */
38  volatile uint32_t expectedChildren;
39  size_t shmSegSize;
40  size_t numBuffers;
41  size_t offsets[0]; // offset[0] points to user region, offset[1]... points to circular buffers
42 };
43 
44 /**
45  * This class defines a shared-memory region between a master process and
46  * one or more child processes
47  * Region has three data structures:
48  * - internal bookkeeping (InternalSharedData),
49  * - user defined shared data (ShareDataType)
50  * - multiple circular-buffer queues with entries of type MsgType
51  *
52  * @tparam ShareDataType Type to put in the shared data region
53  * @tparam MsgType Type of messages being sent in the circular buffers
54  */
55 template<typename ShareDataType, typename MsgType>
56 class TunnelDef {
57 
59 
60 public:
61  /** Create a new tunnel
62  *
63  * @param numBuffers Number of buffers for which we should tunnel
64  * @param bufferSize How large each buffer should be
65  * @param expectedChildren Number of child processes that will connect to this tunnel
66  */
67  TunnelDef(size_t numBuffers, size_t bufferSize, uint32_t expectedChildren) : master(true), shmPtr(NULL) {
68  // Locally buffer info
69  numBuffs = numBuffers;
70  buffSize = bufferSize;
71  children = expectedChildren;
72  shmSize = calculateShmemSize(numBuffers, bufferSize);
73  }
74 
75  /** Access an existing tunnel
76  * Child creates the TunnelDef, reads the shmSize, and then resizes its map accordingly
77  * @param sPtr Location of shared memory region
78  */
79  TunnelDef(void* sPtr) : master(false), shmPtr(sPtr) {
80  isd = (InternalSharedData*)shmPtr;
81  shmSize = isd->shmSegSize;
82  }
83 
84  /** Finish setting up a tunnel once the manager knows the correct size of the tunnel
85  * and has mmap'd a large enough region for it
86  * @param sPtr Location of shared memory region
87  * returns number of children left to attach
88  */
89  uint32_t initialize(void* sPtr) {
90  shmPtr = sPtr;
91 
92  if (master) {
93  nextAllocPtr = (uint8_t*)shmPtr;
94 
95  // Reserve space for InternalSharedData
96  // Including an offset array entry for each buffer & sharedData structure
97  std::pair<size_t, InternalSharedData*> aResult = reserveSpace<InternalSharedData>((1 + numBuffs) * sizeof(size_t));
98  isd = aResult.second;
99  isd->expectedChildren = children;
100  isd->shmSegSize = shmSize;
101  isd->numBuffers = numBuffs;
102 
103  // Reserve space for ShareDataType structure
104  std::pair<size_t, ShareDataType*> bResult = reserveSpace<ShareDataType>(0);
105  isd->offsets[0] = bResult.first;
106  sharedData = bResult.second;
107 
108  // Reserve space for circular buffers
109  const size_t cbSize = sizeof(MsgType) * buffSize;
110  for (size_t c = 0; c < isd->numBuffers; c++) {
111  CircBuff_t* cPtr = NULL;
112 
113  std::pair<size_t, CircBuff_t*> cResult = reserveSpace<CircBuff_t>(cbSize);
114  isd->offsets[1+c] = cResult.first;
115  cPtr = cResult.second;
116  if (!cPtr->setBufferSize(buffSize))
117  exit(1); // function prints error message
118  circBuffs.push_back(cPtr);
119  }
120  return isd->expectedChildren;
121  } else {
122  isd = (InternalSharedData*)shmPtr;
123  shmSize = isd->shmSegSize;
124 
125  sharedData = (ShareDataType*)((uint8_t*)shmPtr + isd->offsets[0]);
126 
127  for ( size_t c = 0 ; c < isd->numBuffers ; c++ ) {
128  circBuffs.push_back((CircBuff_t*)((uint8_t*)shmPtr + isd->offsets[c+1]));
129  }
130  numBuffs = isd->numBuffers;
131 
132  return --(isd->expectedChildren);
133  }
134  }
135 
136 
137  /** Destructor */
138  virtual ~TunnelDef()
139  {
140  shutdown();
141  }
142 
143  /** Clean up a region */
144  void shutdown() {
145  if ( master ) {
146  for (size_t i = 0; i < circBuffs.size(); i++) {
147  circBuffs[i]->~CircBuff_t();
148  }
149  }
150 
151  if (shmPtr) {
152  shmPtr = NULL;
153  isd = NULL;
154  sharedData = NULL;
155  shmSize = 0;
156  }
157  }
158 
159  /** return size of tunnel */
160  size_t getTunnelSize() { return shmSize; }
161 
162  /** return a pointer to the ShareDataType region */
163  ShareDataType* getSharedData() { return sharedData; }
164 
165  /** Write data to buffer, blocks until space is available
166  * @param buffer which buffer index to write to
167  * @param command message to write to buffer
168  */
169  void writeMessage(size_t buffer, const MsgType &command) {
170  circBuffs[buffer]->write(command);
171  }
172 
173  /** Read data from buffer, blocks until message received
174  * @param buffer which buffer to read from
175  * return the message
176  */
177  MsgType readMessage(size_t buffer) {
178  return circBuffs[buffer]->read();
179  }
180 
181  /** Read data from buffer, non-blocking
182  * @param buffer which buffer to read from
183  * @param result pointer to return read message at
184  * return whether a message was read
185  */
186  bool readMessageNB(size_t buffer, MsgType *result) {
187  return circBuffs[buffer]->readNB(result);
188  }
189 
190  /** Empty the messages in a buffer
191  * @param buffer which buffer to empty
192  */
193  void clearBuffer(size_t buffer) {
194  circBuffs[buffer]->clearBuffer();
195  }
196 
197  /** return whether this is a master-side tunnel or a child*/
198  bool isMaster() {
199  return master;
200  }
201 
202 private:
203  /** Allocate space for a data structure in the shared region
204  * @tparam T data structure type to allocate space for
205  * @param extraSpace how many extra bytes to reserve with this allocation
206  * return offset from shmPtr where structure was allocated and pointer to structure
207  */
208  template <typename T>
209  std::pair<size_t, T*> reserveSpace(size_t extraSpace = 0)
210  {
211  size_t space = sizeof(T) + extraSpace;
212  if ( (size_t)((nextAllocPtr + space) - (uint8_t*)shmPtr) > shmSize )
213  return std::make_pair<size_t, T*>(0, NULL);
214  T* ptr = (T*)nextAllocPtr;
215  nextAllocPtr += space;
216  new (ptr) T(); // Call constructor if need be
217  return std::make_pair((uint8_t*)ptr - (uint8_t*)shmPtr, ptr);
218  }
219 
220  /** Calculate the size of the tunnel */
221  static size_t calculateShmemSize(size_t numBuffers, size_t bufferSize) {
222  long pagesize = sysconf(_SC_PAGESIZE);
223  /* Count how many pages are needed, at minimum */
224  size_t isd = 1 + ((sizeof(InternalSharedData) + (1+numBuffers)*sizeof(size_t)) / pagesize);
225  size_t buffer = 1 + ((sizeof(CircularBuffer<MsgType>) + bufferSize*sizeof(MsgType)) / pagesize);
226  size_t shdata = 1 + ((sizeof(ShareDataType) + sizeof(InternalSharedData)) / pagesize);
227 
228  /* Alloc 2 extra pages just in case */
229  return (2 + isd + shdata + numBuffers*buffer) * pagesize;
230  }
231 
232 
233 protected:
234  /** Pointer to the Shared Data Region */
235  ShareDataType *sharedData;
236 
237  /** Return the number of buffers */
238  size_t getNumBuffers() { return numBuffs; }
239 
240 private:
241  bool master;
242  void *shmPtr;
243 
244  uint8_t *nextAllocPtr;
245  size_t shmSize;
246 
247  // Local data
248  size_t numBuffs;
249  size_t buffSize;
250  uint32_t children;
251 
252  // Shared objects
253  InternalSharedData *isd;
254  std::vector<CircBuff_t* > circBuffs;
255 };
256 
257 }
258 }
259 }
260 
261 
262 
263 #endif
ShareDataType * getSharedData()
return a pointer to the ShareDataType region
Definition: tunneldef.h:163
void clearBuffer(size_t buffer)
Empty the messages in a buffer.
Definition: tunneldef.h:193
size_t getTunnelSize()
return size of tunnel
Definition: tunneldef.h:160
ShareDataType * sharedData
Pointer to the Shared Data Region.
Definition: tunneldef.h:235
TunnelDef(void *sPtr)
Access an existing tunnel Child creates the TunnelDef, reads the shmSize, and then resizes its map ac...
Definition: tunneldef.h:79
size_t getNumBuffers()
Return the number of buffers.
Definition: tunneldef.h:238
uint32_t initialize(void *sPtr)
Finish setting up a tunnel once the manager knows the correct size of the tunnel and has mmap&#39;d a lar...
Definition: tunneldef.h:89
Definition: circularBuffer.h:22
void shutdown()
Clean up a region.
Definition: tunneldef.h:144
This class defines a shared-memory region between a master process and one or more child processes Re...
Definition: tunneldef.h:56
virtual ~TunnelDef()
Destructor.
Definition: tunneldef.h:138
bool readMessageNB(size_t buffer, MsgType *result)
Read data from buffer, non-blocking.
Definition: tunneldef.h:186
void writeMessage(size_t buffer, const MsgType &command)
Write data to buffer, blocks until space is available.
Definition: tunneldef.h:169
MsgType readMessage(size_t buffer)
Read data from buffer, blocks until message received.
Definition: tunneldef.h:177
TunnelDef(size_t numBuffers, size_t bufferSize, uint32_t expectedChildren)
Create a new tunnel.
Definition: tunneldef.h:67
bool isMaster()
return whether this is a master-side tunnel or a child
Definition: tunneldef.h:198