aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llplugin/llpluginsharedmemory.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/llplugin/llpluginsharedmemory.cpp')
-rw-r--r--linden/indra/llplugin/llpluginsharedmemory.cpp506
1 files changed, 506 insertions, 0 deletions
diff --git a/linden/indra/llplugin/llpluginsharedmemory.cpp b/linden/indra/llplugin/llpluginsharedmemory.cpp
new file mode 100644
index 0000000..2be4648
--- /dev/null
+++ b/linden/indra/llplugin/llpluginsharedmemory.cpp
@@ -0,0 +1,506 @@
1/**
2 * @file llpluginsharedmemory.cpp
3 * @brief LLPluginSharedMemory manages a shared memory segment for use by the LLPlugin API.
4 *
5 * $LicenseInfo:firstyear=2008&license=viewergpl$
6 *
7 * Copyright (c) 2008-2009, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33#include "linden_common.h"
34
35#include "llpluginsharedmemory.h"
36
37// on Mac and Linux, we use the native shm_open/mmap interface by using
38// #define USE_SHM_OPEN_SHARED_MEMORY 1
39// in the appropriate sections below.
40
41// For Windows, use:
42// #define USE_WIN32_SHARED_MEMORY 1
43
44// If we ever want to fall back to the apr implementation for a platform, use:
45// #define USE_APR_SHARED_MEMORY 1
46
47#if LL_WINDOWS
48// #define USE_APR_SHARED_MEMORY 1
49 #define USE_WIN32_SHARED_MEMORY 1
50#elif LL_DARWIN
51 #define USE_SHM_OPEN_SHARED_MEMORY 1
52#elif LL_LINUX
53 #define USE_SHM_OPEN_SHARED_MEMORY 1
54#endif
55
56
57// FIXME: This path thing is evil and unacceptable.
58#if LL_WINDOWS
59 #define APR_SHARED_MEMORY_PREFIX_STRING "C:\\LLPlugin_"
60 // Apparnently using the "Global\\" prefix here only works from administrative accounts under Vista.
61 // Other options I've seen referenced are "Local\\" and "Session\\".
62 #define WIN32_SHARED_MEMORY_PREFIX_STRING "Local\\LL_"
63#else
64 // mac and linux
65 #define APR_SHARED_MEMORY_PREFIX_STRING "/tmp/LLPlugin_"
66 #define SHM_OPEN_SHARED_MEMORY_PREFIX_STRING "/LL"
67#endif
68
69#if USE_APR_SHARED_MEMORY
70 #include "llapr.h"
71 #include "apr_shm.h"
72#elif USE_SHM_OPEN_SHARED_MEMORY
73 #include <sys/fcntl.h>
74 #include <sys/mman.h>
75 #include <errno.h>
76#elif USE_WIN32_SHARED_MEMORY
77#include <windows.h>
78#endif // USE_APR_SHARED_MEMORY
79
80
81int LLPluginSharedMemory::sSegmentNumber = 0;
82
83std::string LLPluginSharedMemory::createName(void)
84{
85 std::stringstream newname;
86
87#if LL_WINDOWS
88 newname << GetCurrentProcessId();
89#else // LL_WINDOWS
90 newname << getpid();
91#endif // LL_WINDOWS
92
93 newname << "_" << sSegmentNumber++;
94
95 return newname.str();
96}
97
98/**
99 * @brief LLPluginSharedMemoryImpl is the platform-dependent implementation of LLPluginSharedMemory. TODO:DOC is this necessary/sufficient? kinda obvious.
100 *
101 */
102class LLPluginSharedMemoryPlatformImpl
103{
104public:
105 LLPluginSharedMemoryPlatformImpl();
106 ~LLPluginSharedMemoryPlatformImpl();
107
108#if USE_APR_SHARED_MEMORY
109 apr_shm_t* mAprSharedMemory;
110#elif USE_SHM_OPEN_SHARED_MEMORY
111 int mSharedMemoryFD;
112#elif USE_WIN32_SHARED_MEMORY
113 HANDLE mMapFile;
114#endif
115
116};
117
118/**
119 * Constructor. Creates a shared memory segment.
120 */
121LLPluginSharedMemory::LLPluginSharedMemory()
122{
123 mSize = 0;
124 mMappedAddress = NULL;
125 mNeedsDestroy = false;
126
127 mImpl = new LLPluginSharedMemoryPlatformImpl;
128}
129
130/**
131 * Destructor. Uses destroy() and detach() to ensure shared memory segment is cleaned up.
132 */
133LLPluginSharedMemory::~LLPluginSharedMemory()
134{
135 if(mNeedsDestroy)
136 destroy();
137 else
138 detach();
139
140 unlink();
141
142 delete mImpl;
143}
144
145#if USE_APR_SHARED_MEMORY
146// MARK: apr implementation
147
148LLPluginSharedMemoryPlatformImpl::LLPluginSharedMemoryPlatformImpl()
149{
150 mAprSharedMemory = NULL;
151}
152
153LLPluginSharedMemoryPlatformImpl::~LLPluginSharedMemoryPlatformImpl()
154{
155
156}
157
158bool LLPluginSharedMemory::map(void)
159{
160 mMappedAddress = apr_shm_baseaddr_get(mImpl->mAprSharedMemory);
161 if(mMappedAddress == NULL)
162 {
163 return false;
164 }
165
166 return true;
167}
168
169bool LLPluginSharedMemory::unmap(void)
170{
171 // This is a no-op under apr.
172 return true;
173}
174
175bool LLPluginSharedMemory::close(void)
176{
177 // This is a no-op under apr.
178 return true;
179}
180
181bool LLPluginSharedMemory::unlink(void)
182{
183 // This is a no-op under apr.
184 return true;
185}
186
187
188bool LLPluginSharedMemory::create(size_t size)
189{
190 mName = APR_SHARED_MEMORY_PREFIX_STRING;
191 mName += createName();
192 mSize = size;
193
194 apr_status_t status = apr_shm_create( &(mImpl->mAprSharedMemory), mSize, mName.c_str(), gAPRPoolp );
195
196 if(ll_apr_warn_status(status))
197 {
198 return false;
199 }
200
201 mNeedsDestroy = true;
202
203 return map();
204}
205
206bool LLPluginSharedMemory::destroy(void)
207{
208 if(mImpl->mAprSharedMemory)
209 {
210 apr_status_t status = apr_shm_destroy(mImpl->mAprSharedMemory);
211 if(ll_apr_warn_status(status))
212 {
213 // TODO: Is this a fatal error? I think not...
214 }
215 mImpl->mAprSharedMemory = NULL;
216 }
217
218 return true;
219}
220
221bool LLPluginSharedMemory::attach(const std::string &name, size_t size)
222{
223 mName = name;
224 mSize = size;
225
226 apr_status_t status = apr_shm_attach( &(mImpl->mAprSharedMemory), mName.c_str(), gAPRPoolp );
227
228 if(ll_apr_warn_status(status))
229 {
230 return false;
231 }
232
233 return map();
234}
235
236
237bool LLPluginSharedMemory::detach(void)
238{
239 if(mImpl->mAprSharedMemory)
240 {
241 apr_status_t status = apr_shm_detach(mImpl->mAprSharedMemory);
242 if(ll_apr_warn_status(status))
243 {
244 // TODO: Is this a fatal error? I think not...
245 }
246 mImpl->mAprSharedMemory = NULL;
247 }
248
249 return true;
250}
251
252
253#elif USE_SHM_OPEN_SHARED_MEMORY
254// MARK: shm_open/mmap implementation
255
256LLPluginSharedMemoryPlatformImpl::LLPluginSharedMemoryPlatformImpl()
257{
258 mSharedMemoryFD = -1;
259}
260
261LLPluginSharedMemoryPlatformImpl::~LLPluginSharedMemoryPlatformImpl()
262{
263}
264
265bool LLPluginSharedMemory::map(void)
266{
267 mMappedAddress = ::mmap(NULL, mSize, PROT_READ | PROT_WRITE, MAP_SHARED, mImpl->mSharedMemoryFD, 0);
268 if(mMappedAddress == NULL)
269 {
270 return false;
271 }
272
273 LL_DEBUGS("Plugin") << "memory mapped at " << mMappedAddress << LL_ENDL;
274
275 return true;
276}
277
278bool LLPluginSharedMemory::unmap(void)
279{
280 if(mMappedAddress != NULL)
281 {
282 LL_DEBUGS("Plugin") << "calling munmap(" << mMappedAddress << ", " << mSize << ")" << LL_ENDL;
283 if(::munmap(mMappedAddress, mSize) == -1)
284 {
285 // TODO: Is this a fatal error? I think not...
286 }
287
288 mMappedAddress = NULL;
289 }
290
291 return true;
292}
293
294bool LLPluginSharedMemory::close(void)
295{
296 if(mImpl->mSharedMemoryFD != -1)
297 {
298 LL_DEBUGS("Plugin") << "calling close(" << mImpl->mSharedMemoryFD << ")" << LL_ENDL;
299 if(::close(mImpl->mSharedMemoryFD) == -1)
300 {
301 // TODO: Is this a fatal error? I think not...
302 }
303
304 mImpl->mSharedMemoryFD = -1;
305 }
306 return true;
307}
308
309bool LLPluginSharedMemory::unlink(void)
310{
311 if(!mName.empty())
312 {
313 if(::shm_unlink(mName.c_str()) == -1)
314 {
315 return false;
316 }
317 }
318
319 return true;
320}
321
322
323bool LLPluginSharedMemory::create(size_t size)
324{
325 mName = SHM_OPEN_SHARED_MEMORY_PREFIX_STRING;
326 mName += createName();
327 mSize = size;
328
329 // Preemptive unlink, just in case something didn't get cleaned up.
330 unlink();
331
332 mImpl->mSharedMemoryFD = ::shm_open(mName.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
333 if(mImpl->mSharedMemoryFD == -1)
334 {
335 return false;
336 }
337
338 mNeedsDestroy = true;
339
340 if(::ftruncate(mImpl->mSharedMemoryFD, mSize) == -1)
341 {
342 return false;
343 }
344
345
346 return map();
347}
348
349bool LLPluginSharedMemory::destroy(void)
350{
351 unmap();
352 close();
353
354 return true;
355}
356
357
358bool LLPluginSharedMemory::attach(const std::string &name, size_t size)
359{
360 mName = name;
361 mSize = size;
362
363 mImpl->mSharedMemoryFD = ::shm_open(mName.c_str(), O_RDWR, S_IRUSR | S_IWUSR);
364 if(mImpl->mSharedMemoryFD == -1)
365 {
366 return false;
367 }
368
369 // unlink here so the segment will be cleaned up automatically after the last close.
370 unlink();
371
372 return map();
373}
374
375bool LLPluginSharedMemory::detach(void)
376{
377 unmap();
378 close();
379 return true;
380}
381
382#elif USE_WIN32_SHARED_MEMORY
383// MARK: Win32 CreateFileMapping-based implementation
384
385// Reference: http://msdn.microsoft.com/en-us/library/aa366551(VS.85).aspx
386
387LLPluginSharedMemoryPlatformImpl::LLPluginSharedMemoryPlatformImpl()
388{
389 mMapFile = NULL;
390}
391
392LLPluginSharedMemoryPlatformImpl::~LLPluginSharedMemoryPlatformImpl()
393{
394
395}
396
397bool LLPluginSharedMemory::map(void)
398{
399 mMappedAddress = MapViewOfFile(
400 mImpl->mMapFile, // handle to map object
401 FILE_MAP_ALL_ACCESS, // read/write permission
402 0,
403 0,
404 mSize);
405
406 if(mMappedAddress == NULL)
407 {
408 LL_WARNS("Plugin") << "MapViewOfFile failed: " << GetLastError() << LL_ENDL;
409 return false;
410 }
411
412 LL_DEBUGS("Plugin") << "memory mapped at " << mMappedAddress << LL_ENDL;
413
414 return true;
415}
416
417bool LLPluginSharedMemory::unmap(void)
418{
419 if(mMappedAddress != NULL)
420 {
421 UnmapViewOfFile(mMappedAddress);
422 mMappedAddress = NULL;
423 }
424
425 return true;
426}
427
428bool LLPluginSharedMemory::close(void)
429{
430 if(mImpl->mMapFile != NULL)
431 {
432 CloseHandle(mImpl->mMapFile);
433 mImpl->mMapFile = NULL;
434 }
435
436 return true;
437}
438
439bool LLPluginSharedMemory::unlink(void)
440{
441 // This is a no-op on Windows.
442 return true;
443}
444
445
446bool LLPluginSharedMemory::create(size_t size)
447{
448 mName = WIN32_SHARED_MEMORY_PREFIX_STRING;
449 mName += createName();
450 mSize = size;
451
452 mImpl->mMapFile = CreateFileMappingA(
453 INVALID_HANDLE_VALUE, // use paging file
454 NULL, // default security
455 PAGE_READWRITE, // read/write access
456 0, // max. object size
457 mSize, // buffer size
458 mName.c_str()); // name of mapping object
459
460 if(mImpl->mMapFile == NULL)
461 {
462 LL_WARNS("Plugin") << "CreateFileMapping failed: " << GetLastError() << LL_ENDL;
463 return false;
464 }
465
466 mNeedsDestroy = true;
467
468 return map();
469}
470
471bool LLPluginSharedMemory::destroy(void)
472{
473 unmap();
474 close();
475 return true;
476}
477
478bool LLPluginSharedMemory::attach(const std::string &name, size_t size)
479{
480 mName = name;
481 mSize = size;
482
483 mImpl->mMapFile = OpenFileMappingA(
484 FILE_MAP_ALL_ACCESS, // read/write access
485 FALSE, // do not inherit the name
486 mName.c_str()); // name of mapping object
487
488 if(mImpl->mMapFile == NULL)
489 {
490 LL_WARNS("Plugin") << "OpenFileMapping failed: " << GetLastError() << LL_ENDL;
491 return false;
492 }
493
494 return map();
495}
496
497bool LLPluginSharedMemory::detach(void)
498{
499 unmap();
500 close();
501 return true;
502}
503
504
505
506#endif