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 |
|
---|
19 | DECLARE_STATIC_LOGGER("pacpus.framwork.SharedMemory");
|
---|
20 |
|
---|
21 | using namespace pacpus;
|
---|
22 |
|
---|
23 | //////////////////////////////////////////////////////////////////////////
|
---|
24 | SharedMemory::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 |
|
---|
166 | SharedMemory::~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 |
|
---|
184 | bool 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 |
|
---|
207 | void* 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 |
|
---|
220 | void SharedMemory::read(void* dst, int size)
|
---|
221 | {
|
---|
222 | lockMemory();
|
---|
223 | memcpy(dst, shMem_, size);
|
---|
224 | unlockMemory();
|
---|
225 | }
|
---|
226 |
|
---|
227 | void* 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 |
|
---|
237 | void 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 |
|
---|
266 | void 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 |
|
---|
278 | void 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 | }
|
---|