PageRenderTime 496ms CodeModel.GetById 161ms app.highlight 153ms RepoModel.GetById 179ms app.codeStats 0ms

/indra/llplugin/llpluginsharedmemory.cpp

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