All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
SharedMemory.cpp
Go to the documentation of this file.
1 /*
2  * SharedMemory.cpp
3  *
4  * This file is part of the HausmiSEP project
5  *
6  * Copyright (C) 2012, 2013 Marco Alvarado (malvcr@gmail.com)
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <HSEP/SharedMemory.h>
23 
24 #include <sys/mman.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <cstring>
28 
29 #include <iostream>
30 
31 using namespace std;
32 
33 namespace HSEP {
34 
35 
36  char* SharedMemory::calcAddressPtr(int pSlotId) const {
37  return aSharedHeaderPtr->calcAddressPtr(aSharedBufferPtr,pSlotId);
38  } // SharedMemory::calcAddress
39 
40 
41  void SharedMemory::cleanSlot(int pSlotId) {
42  aSharedHeaderPtr->cleanSlot(aSharedBufferPtr,pSlotId);
43  } // SharedMemory::cleanSlot
44 
45  SharedMemory::SharedMemory(const string& pNameRef) : HSEPObject("SharedMemory"){
46 
47  aOwner = false;
48 
49  aHeaderName = "/" + pNameRef + "-header";
50  aBufferName = "/" + pNameRef + "-buffer";
51 
52  // think of shm_open as a regular POSIX open, but related with a
53  // shared memory zone
54  //
55  // First we create a shared memory area for the header information
56  // and if the creation is successful, we proceed to create one for
57  // the working memory itself.
58  //
59  aSharedHeaderHandle = shm_open(
60  aHeaderName.c_str(),
61  O_RDWR,
62  S_IRGRP|S_IWGRP // Read by group | Write by group
63  );
64 
65  if (-1 != aSharedHeaderHandle) {
66 
67  // being shm_open the one creates or provides access to a previously created
68  // shared memory area, the given handler is not enough to work with that memory.
69  // So, we use mmap to actually provide a pointer that will permit us to carry on
70  // every operation we want to perform on the shared memory area, as if it be
71  // a normal memory variable.
72  //
73  aSharedHeaderPtr = (ManagedBuffer*)mmap(
74  nullptr, // no preference
75  sizeof(ManagedBuffer),
76  (PROT_READ | PROT_WRITE),
77  MAP_SHARED,
78  aSharedHeaderHandle,
79  0
80  );
81 
82  if (MAP_FAILED != aSharedHeaderPtr) {
83 
84  aSharedBufferHandle = shm_open(
85  aBufferName.c_str(),
86  O_RDWR,
87  S_IRGRP|S_IWGRP // Read by group | Write by group
88  );
89 
90  if (-1 != aSharedBufferHandle) {
91 
92  aSharedBufferPtr = (char*) mmap(
93  nullptr,
94  aSharedHeaderPtr->dataSize(),
95  (PROT_READ | PROT_WRITE),
96  MAP_SHARED,
97  aSharedBufferHandle,
98  0
99  );
100  if (MAP_FAILED != aSharedBufferPtr) {
101  aInitialized = true;
102  }
103  //return errno;
104  }
105  }
106  }
107  else {
108  int vErrno = errno;
109  switch(vErrno) {
110  case EACCES:
112  setLastError("Permission to shm_open object was denied.");
113  break;
114  case EEXIST:
116  setLastError("Creation permission requested on an already created memory area.");
117  break;
118  case EINVAL:
120  setLastError("The provided name on shm_open is invalid");
121  break;
122  case EMFILE:
123  case ENFILE:
125  break;
126  case ENAMETOOLONG:
128  break;
129  case ENOENT:
131  setLastError("shm_opentried to open an inexistent shm area or O_CREAT was not specified");
132  break;
133  }
134  }
135 
136  } // SharedMemory constructor client
137 
138  SharedMemory::SharedMemory(const string& pNameRef, size_t pSlotSize, int pSlotQty) : HSEPObject("SharedMemory") {
139 
140  aOwner = true;
141 
142  aHeaderName = "/" + pNameRef + "-header";
143  aBufferName = "/" + pNameRef + "-buffer";
144 
145  aSharedHeaderHandle = shm_open(
146  aHeaderName.c_str(),
147  O_CREAT | O_EXCL |O_RDWR, // Create if doesn't exist as Read Write
148  S_IRUSR | S_IWUSR | // Read by owner | Write by owner
149  S_IRGRP | S_IWGRP // Read by group | Write by group
150  );
151 
152  if (-1 != aSharedHeaderHandle) {
153 
154  // must be noticed that the shm_open with O_CREAT flag doesn't specify
155  // any size for the shared memory area. Once the area has been created
156  // the ftruncate function must be called to provide the real memory area
157  // with the specified zone for the shared memory area to be really
158  // useful.
159  //
160  ftruncate(aSharedHeaderHandle,sizeof(ManagedBuffer));
161 
162  aOwner = true;
163  aInitialized = false;
164 
165  aSharedHeaderPtr = (ManagedBuffer*)mmap(
166  nullptr,
167  sizeof(ManagedBuffer),
168  (PROT_READ | PROT_WRITE),
169  MAP_SHARED,
170  aSharedHeaderHandle,
171  0
172  );
173 
174  if (MAP_FAILED != aSharedHeaderPtr) {
175 
176  new (aSharedHeaderPtr) ManagedBuffer(pSlotSize,pSlotQty);
177 
178  aSharedBufferHandle = shm_open(
179  aBufferName.c_str(),
180  O_CREAT|O_EXCL|O_RDWR,
181  S_IRUSR | S_IWUSR | // Read by owner | Write by owner
182  S_IRGRP | S_IWGRP // Read by group | Write by group
183  );
184 
185  if (-1 != aSharedBufferHandle) {
186 
187  size_t vMemoryBlockSize = aSharedHeaderPtr->dataSize();
188 
189  ftruncate(aSharedBufferHandle,vMemoryBlockSize);
190 
191  aSharedBufferPtr = (char*) mmap(
192  nullptr,
193  vMemoryBlockSize,
194  (PROT_READ | PROT_WRITE),
195  MAP_SHARED,
196  aSharedBufferHandle,
197  0
198  );
199  if (MAP_FAILED != aSharedBufferPtr) {
200  aInitialized = true;
201  memset(aSharedBufferPtr,0,vMemoryBlockSize);
202  }
203  //return errno;
204  }
205 
206  }
207 
208  }
209  else {
210  int vErrno = errno;
211  switch(vErrno) {
212  case EACCES:
214  setLastError("Permission to shm_open object was denied.");
215  break;
216  case EEXIST:
218  setLastError("Creation permission requested on an already created memory area.");
219  break;
220  case EINVAL:
222  setLastError("The provided name on shm_open is invalid");
223  break;
224  case EMFILE:
225  case ENFILE:
227  break;
228  case ENAMETOOLONG:
230  break;
231  case ENOENT:
233  setLastError("shm_opentried to open an inexistent shm area or O_CREAT was not specified");
234  break;
235  }
236  }
237 
238  } // SharedMemory constructor owner
239 
241 
242  // guarantees that any pendant data to be written by the current instance
243  // be actually written before performing the munmap task. As the MS_SYNC
244  // flag is provided, the destructor will wait for the data to be updated.
245  //
246  msync(aSharedBufferPtr,aSharedHeaderPtr->dataSize(),MS_SYNC);
247  msync(aSharedHeaderPtr,sizeof(ManagedBuffer),MS_SYNC);
248 
249  // reduce the "usage" counter for the shared memory area
250  //
251  munmap(aSharedBufferPtr,aSharedHeaderPtr->dataSize());
252  munmap(aSharedHeaderPtr,sizeof(ManagedBuffer));
253 
254  // ask the Operating System to destroy the shared memory area
255  // once the last SharedMemory area instance related with the given
256  // memory area perform the corresponding munmap in its destructor
257  //
258  if (aOwner) {
259  shm_unlink(aBufferName.c_str());
260  shm_unlink(aHeaderName.c_str());
261  }
262 
263  } // SharedMemory destructor
264 
265 
267  int vResult = -2;
268  if (aInitialized) {
269  vResult = aSharedHeaderPtr->popFree(aSharedBufferPtr);
270  }
271  return vResult;
272  } // SharedMemory::obtainSlot
273 
274  void SharedMemory::releaseSlot(int pSlotId) {
275  if (aInitialized) {
276  cleanSlot(pSlotId); // security measure, to avoid further calls to obtain old data
277  aSharedHeaderPtr->pushFree(aSharedBufferPtr,pSlotId);
278  }
279  } // SharedMemory::releaseSlot
280 
281  ErrorCode SharedMemory::write(int pSlotId, char* pSourcePtr, size_t pBufferSize) {
282 
284 
285  if (pSlotId < 0) {
286  vResult = EC::BufferUnderflow;
287  }
288  else if (pSlotId >= aSharedHeaderPtr->slotQty()) {
289  vResult = EC::BufferOverflow;
290  }
291  else {
292  size_t vBufferSize;
293  size_t vCleanArea;
294  size_t vSlotSize = aSharedHeaderPtr->slotSize();
295 
296  if (pBufferSize > vSlotSize) {
297  vBufferSize = vSlotSize;
298  vCleanArea = 0;
299  }
300  else {
301  vBufferSize = pBufferSize;
302  vCleanArea = vSlotSize - vBufferSize;
303  }
304  char* vSlotPtr = calcAddressPtr(pSlotId);
305 
306  strncpy(vSlotPtr,pSourcePtr,vBufferSize);
307  memset (vSlotPtr+vBufferSize,0,vCleanArea); // clean the remaining
308 
309  vResult = EC::OK;
310  }
311  return vResult;
312 
313  } // SharedMemory::write
314 
315  ErrorCode SharedMemory::read (int pSlotId, char* pDestinationPtr, size_t pBufferSize) {
316 
318 
319  if (pSlotId < 0) {
320  vResult = EC::BufferUnderflow;
321  } else if (pSlotId >= aSharedHeaderPtr->slotQty()) {
322  vResult = EC::BufferOverflow;
323  }
324  else {
325  size_t vBufferSize;
326  size_t vCleanArea;
327  size_t vSlotSize = aSharedHeaderPtr->slotSize();
328 
329  if (pBufferSize > vSlotSize) {
330  vBufferSize = vSlotSize;
331  vCleanArea = 0;
332  }
333  else {
334  vBufferSize = pBufferSize;
335  vCleanArea = pBufferSize - vBufferSize;
336  }
337 
338  char* vSlotPtr = this->calcAddressPtr(pSlotId);
339 
340  strncpy(pDestinationPtr,vSlotPtr,vBufferSize);
341  memset (pDestinationPtr+vBufferSize,0,vCleanArea); // clean the remaining
342 
343  vResult = EC::OK;
344  }
345  return vResult;
346 
347  } // SharedMemory::read
348 
350  return aSharedHeaderPtr->wait();
351  } // SharedMemory::wait
352 
353 
354  void SharedMemory::signal(int pSlotId) {
355  aSharedHeaderPtr->signal(pSlotId);
356  } // SharedMemory::signal
357 
358 } // HSEP namespace
359 
360