source: pacpusframework/trunk/src/PacpusTools/src/SharedMemory.cpp@ 300

Last change on this file since 300 was 300, checked in by Marek Kurdej, 10 years ago

Created unified SharedMemory.

File size: 8.3 KB
Line 
1// %pacpus:license{
2// This file is part of the PACPUS framework distributed under the
3// CECILL-C License, Version 1.0.
4/// @author Marek Kurdej <firstname.surname@utc.fr>
5/// @date 2014-04-07 10:17:22
6// %pacpus:license}
7
8#include <Pacpus/PacpusTools/SharedMemory.h>
9#include <Pacpus/kernel/Log.h>
10
11#include <boost/assert.hpp>
12#include <cstdlib>
13#include <iomanip>
14#include <sstream>
15#if PACPUS_OS_WINDOWS
16# include <windows.h>
17#endif
18
19DECLARE_STATIC_LOGGER("pacpus.framwork.SharedMemory");
20
21using namespace pacpus;
22
23//////////////////////////////////////////////////////////////////////////
24SharedMemory::SharedMemory(const char* name, int size)
25{
26 LOG_TRACE("constructor(" << name << ", " << size << ")");
27 LOG_INFO("creating shared memory" << "\t"
28 << "name=" << name << "\t"
29 << "size=" << size
30 );
31
32#if PACPUS_OS_WINDOWS
33 // semaphore name
34 std::stringstream semaphoreNameSs;
35 semaphoreNameSs << (const char *) "SemShMem_" << name;
36 std::string semaphoreName = semaphoreNameSs.str();
37 // event name
38 std::stringstream eventNameSs;
39 eventNameSs << (const char *) "EvtShMem_" << name;
40 std::string eventName = eventNameSs.str();
41
42 LOG_DEBUG("semaphore name = " << semaphoreName);
43 LOG_DEBUG("event name = " << eventName);
44
45 semaphore_ = CreateSemaphore(NULL, /* lInitialCount = */ 1, /* lMaximumCount = */ 1, semaphoreName.c_str());
46 if (semaphore_ == NULL) {
47 LPVOID lpMsgBuf;
48 DWORD dw = GetLastError();
49
50 FormatMessage(
51 /* flags = */ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
52 /* source = */ NULL,
53 /* messageId = */ dw,
54 /* languageId = */ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
55 /* out buffer = */ (LPTSTR) &lpMsgBuf,
56 /* size = */ 0,
57 /* args = */ NULL
58 );
59
60 LOG_FATAL("cannot create semaphore protection of shared memory segment '" << name << "'"
61 << ". Error: " << GetLastError()
62 << ". Message: " << (const char *) lpMsgBuf
63 << ". Program will exit"
64 );
65 ::exit(-1);
66 }
67
68 // create the event - autoreset mode
69 event_ = CreateEvent(NULL, false, false, eventName.c_str());
70
71 // lock the semaphore and try to create the shared memory
72 lockMemory();
73 shMemHandle_ = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, name);
74 if (shMemHandle_ == NULL) {
75 LOG_FATAL("cannot create shared memory segment '" << name << "'"
76 << ". Error: " << GetLastError()
77 << ". Program will exit"
78 );
79 ::exit(-1);
80 }
81
82 // Map the memory to a local pointer
83 shMem_ = MapViewOfFile(shMemHandle_, FILE_MAP_ALL_ACCESS, 0, 0, 0);
84 if (shMem_ == NULL) {
85 LOG_FATAL("cannot map the view of file of the shared memory segment '" << name << "'"
86 << ". Error: " << GetLastError()
87 << ". Program will exit"
88 );
89 ::exit(-1);
90 }
91
92 LOG_INFO("created Win32 shared memory '" << name << "'");
93
94 unlockMemory();
95
96#elif PACPUS_OS_UNIX
97
98 {
99 QString memoryName = QString(name);
100 memory_ = new QSharedMemory(memoryName);
101 }
102 if (!memory_) {
103 LOG_FATAL("out of memory: cannot create shared memory object");
104 exit(-1);
105 }
106
107 bool result = false;
108 LOG_DEBUG("trying to create a memory segment");
109 if (!memory_->create(size)) {
110 if (QSharedMemory::AlreadyExists == memory_->error()) {
111 LOG_DEBUG("trying to attach to an existing memory segment");
112 if (!memory_->attach()) {
113 LOG_ERROR("cannot attach to an existing shared memory segment '" << name << "'"
114 << ". error code: " << memory_->error()
115 << ". error message:" << memory_->errorString().toStdString()
116 );
117 } else {
118 LOG_INFO("attached shared memory segment '" << name << "'");
119 int attachedMemorySize = memory_->size();
120 LOG_INFO("attached memory size = " << attachedMemorySize);
121 if (attachedMemorySize < size) {
122 LOG_ERROR("attached memory is smaller than requested, unexpected behaviour possible");
123 LOG_INFO("use system tools like 'ipcs' and 'ipcrm' to remove shared memory and re-run");
124 }
125 result = true;
126 }
127 } else {
128 LOG_ERROR("cannot create shared memory segment '" << name << "'"
129 << ". error code: " << memory_->error()
130 << ". error message:" << memory_->errorString().toStdString()
131 );
132 }
133 } else {
134 LOG_INFO("created shared memory segment '" << name << "'");
135 result = true;
136 }
137
138 /////////////////////////////////////////
139 if (result) {
140 // create the equivalent Windows event (autoreset mode?)
141 QString eventName = "EvtShMem_" + QString(name);
142 LOG_DEBUG("creating event '" << eventName << "'...");
143 event_ = new QSystemSemaphore(eventName, 0, QSystemSemaphore::Create);
144 if (event_) {
145 LOG_DEBUG("created event '" << eventName << "'");
146 } else {
147 LOG_ERROR("cannot create event '" << eventName << "'"
148 );
149 }
150
151 // get a pointer to the shared memory segment
152 shMem_ = memory_->data();
153 } else {
154 LOG_FATAL("cannot create shared memory segment '" << name << "'");
155 //throw MemoryCreationError();
156 exit(memory_->error());
157 }
158
159#else
160
161#error UNIMPLEMENTED for this operating system
162
163#endif
164}
165
166SharedMemory::~SharedMemory()
167{
168 LOG_TRACE("destructor");
169#if PACPUS_OS_WINDOWS
170 // free the semaphore
171 CloseHandle(semaphore_);
172 UnmapViewOfFile(shMem_);
173 CloseHandle(shMemHandle_);
174#elif PACPUS_OS_UNIX
175 // detach this process from the shared memory
176 memory_->detach();
177 // free shared memory
178 delete memory_;
179 // free event
180 delete event_;
181#endif
182}
183
184bool SharedMemory::wait(unsigned long timeout)
185{
186#if PACPUS_OS_WINDOWS
187 if (timeout == 0) {
188 timeout = INFINITE;
189 }
190
191 DWORD status = 0;
192 status = WaitForSingleObject(event_, timeout);
193
194 if (status == WAIT_OBJECT_0) {
195 return true;
196 } else {
197 return false;
198 }
199#elif PACPUS_OS_UNIX
200 (void) timeout; // unused
201 bool result = event_->acquire();
202 LOG_TRACE("event acquired: note that timeout doesn't work yet on linux platform");
203 return result;
204#endif
205}
206
207void* SharedMemory::read()
208{
209 void* shMem;
210#if PACPUS_OS_WINDOWS
211 lockMemory();
212#endif
213 shMem = shMem_;
214#if PACPUS_OS_WINDOWS
215 unlockMemory();
216#endif
217 return shMem;
218}
219
220void SharedMemory::read(void* dst, int size)
221{
222 lockMemory();
223 memcpy(dst, shMem_, size);
224 unlockMemory();
225}
226
227void* SharedMemory::getEventIdentifier()
228{
229#if PACPUS_OS_WINDOWS
230 return event_;
231#elif PACPUS_OS_UNIX
232 LOG_TRACE("no event identifier");
233 return NULL;
234#endif
235}
236
237void SharedMemory::write(void *data, int size, unsigned long offset)
238{
239 using std::hex;
240
241 LOG_TRACE("writing " << size << " bytes to shared memory at offset " << offset);
242#if PACPUS_OS_WINDOWS
243 lockMemory();
244 //unsigned long * dest = (unsigned long *)shMem_ + offset;
245 char * dest = (char *)shMem_ + offset;
246 //printf("adresses : shm : %x dest : %x offset : %x \n",shMem_, dest, offset);
247 memcpy(dest, data, size);
248 unlockMemory();
249 SetEvent(event_);
250#elif PACPUS_OS_UNIX
251 lockMemory();
252 uint32_t * dest = (uint32_t *) shMem_ + offset;
253
254 LOG_TRACE("adresses:"
255 << " shm = " << hex << shMem_
256 << " dst = " << hex << dest
257 << " src = " << hex << data
258 );
259
260 memcpy(dest, data, size);
261 unlockMemory();
262 event_->release();
263#endif
264}
265
266void SharedMemory::lockMemory()
267{
268#if PACPUS_OS_WINDOWS
269 WaitForSingleObject(semaphore_, INFINITE);
270#elif PACPUS_OS_UNIX
271 BOOST_ASSERT(memory_);
272 if (!memory_->lock()) {
273 LOG_ERROR("cannot lock memory '" << memory_->key().toStdString() << "'");
274 }
275#endif
276}
277
278void SharedMemory::unlockMemory()
279{
280#if PACPUS_OS_WINDOWS
281 ReleaseSemaphore(semaphore_, 1, NULL);
282#elif PACPUS_OS_UNIX
283 BOOST_ASSERT(memory_);
284 if (!memory_->unlock()) {
285 LOG_ERROR("cannot unlock memory '" << memory_->key().toStdString() << "'");
286 }
287#endif
288}
Note: See TracBrowser for help on using the repository browser.