/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. #include "linden_common.h"
  29. #include "llpluginsharedmemory.h"
  30. // on Mac and Linux, we use the native shm_open/mmap interface by using
  31. // #define USE_SHM_OPEN_SHARED_MEMORY 1
  32. // in the appropriate sections below.
  33. // For Windows, use:
  34. // #define USE_WIN32_SHARED_MEMORY 1
  35. // If we ever want to fall back to the apr implementation for a platform, use:
  36. // #define USE_APR_SHARED_MEMORY 1
  37. #if LL_WINDOWS
  38. // #define USE_APR_SHARED_MEMORY 1
  39. #define USE_WIN32_SHARED_MEMORY 1
  40. #elif LL_DARWIN
  41. #define USE_SHM_OPEN_SHARED_MEMORY 1
  42. #elif LL_LINUX
  43. #define USE_SHM_OPEN_SHARED_MEMORY 1
  44. #endif
  45. // FIXME: This path thing is evil and unacceptable.
  46. #if LL_WINDOWS
  47. #define APR_SHARED_MEMORY_PREFIX_STRING "C:\\LLPlugin_"
  48. // Apparnently using the "Global\\" prefix here only works from administrative accounts under Vista.
  49. // Other options I've seen referenced are "Local\\" and "Session\\".
  50. #define WIN32_SHARED_MEMORY_PREFIX_STRING "Local\\LL_"
  51. #else
  52. // mac and linux
  53. #define APR_SHARED_MEMORY_PREFIX_STRING "/tmp/LLPlugin_"
  54. #define SHM_OPEN_SHARED_MEMORY_PREFIX_STRING "/LL"
  55. #endif
  56. #if USE_APR_SHARED_MEMORY
  57. #include "llapr.h"
  58. #include "apr_shm.h"
  59. #elif USE_SHM_OPEN_SHARED_MEMORY
  60. #include <sys/fcntl.h>
  61. #include <sys/mman.h>
  62. #include <errno.h>
  63. #elif USE_WIN32_SHARED_MEMORY
  64. #include <windows.h>
  65. #endif // USE_APR_SHARED_MEMORY
  66. int LLPluginSharedMemory::sSegmentNumber = 0;
  67. std::string LLPluginSharedMemory::createName(void)
  68. {
  69. std::stringstream newname;
  70. #if LL_WINDOWS
  71. newname << GetCurrentProcessId();
  72. #else // LL_WINDOWS
  73. newname << getpid();
  74. #endif // LL_WINDOWS
  75. newname << "_" << sSegmentNumber++;
  76. return newname.str();
  77. }
  78. /**
  79. * @brief LLPluginSharedMemoryImpl is the platform-dependent implementation of LLPluginSharedMemory. TODO:DOC is this necessary/sufficient? kinda obvious.
  80. *
  81. */
  82. class LLPluginSharedMemoryPlatformImpl
  83. {
  84. public:
  85. LLPluginSharedMemoryPlatformImpl();
  86. ~LLPluginSharedMemoryPlatformImpl();
  87. #if USE_APR_SHARED_MEMORY
  88. apr_shm_t* mAprSharedMemory;
  89. #elif USE_SHM_OPEN_SHARED_MEMORY
  90. int mSharedMemoryFD;
  91. #elif USE_WIN32_SHARED_MEMORY
  92. HANDLE mMapFile;
  93. #endif
  94. };
  95. /**
  96. * Constructor. Creates a shared memory segment.
  97. */
  98. LLPluginSharedMemory::LLPluginSharedMemory()
  99. {
  100. mSize = 0;
  101. mMappedAddress = NULL;
  102. mNeedsDestroy = false;
  103. mImpl = new LLPluginSharedMemoryPlatformImpl;
  104. }
  105. /**
  106. * Destructor. Uses destroy() and detach() to ensure shared memory segment is cleaned up.
  107. */
  108. LLPluginSharedMemory::~LLPluginSharedMemory()
  109. {
  110. if(mNeedsDestroy)
  111. destroy();
  112. else
  113. detach();
  114. unlink();
  115. delete mImpl;
  116. }
  117. #if USE_APR_SHARED_MEMORY
  118. // MARK: apr implementation
  119. LLPluginSharedMemoryPlatformImpl::LLPluginSharedMemoryPlatformImpl()
  120. {
  121. mAprSharedMemory = NULL;
  122. }
  123. LLPluginSharedMemoryPlatformImpl::~LLPluginSharedMemoryPlatformImpl()
  124. {
  125. }
  126. bool LLPluginSharedMemory::map(void)
  127. {
  128. mMappedAddress = apr_shm_baseaddr_get(mImpl->mAprSharedMemory);
  129. if(mMappedAddress == NULL)
  130. {
  131. return false;
  132. }
  133. return true;
  134. }
  135. bool LLPluginSharedMemory::unmap(void)
  136. {
  137. // This is a no-op under apr.
  138. return true;
  139. }
  140. bool LLPluginSharedMemory::close(void)
  141. {
  142. // This is a no-op under apr.
  143. return true;
  144. }
  145. bool LLPluginSharedMemory::unlink(void)
  146. {
  147. // This is a no-op under apr.
  148. return true;
  149. }
  150. bool LLPluginSharedMemory::create(size_t size)
  151. {
  152. mName = APR_SHARED_MEMORY_PREFIX_STRING;
  153. mName += createName();
  154. mSize = size;
  155. apr_status_t status = apr_shm_create( &(mImpl->mAprSharedMemory), mSize, mName.c_str(), gAPRPoolp );
  156. if(ll_apr_warn_status(status))
  157. {
  158. return false;
  159. }
  160. mNeedsDestroy = true;
  161. return map();
  162. }
  163. bool LLPluginSharedMemory::destroy(void)
  164. {
  165. if(mImpl->mAprSharedMemory)
  166. {
  167. apr_status_t status = apr_shm_destroy(mImpl->mAprSharedMemory);
  168. if(ll_apr_warn_status(status))
  169. {
  170. // TODO: Is this a fatal error? I think not...
  171. }
  172. mImpl->mAprSharedMemory = NULL;
  173. }
  174. return true;
  175. }
  176. bool LLPluginSharedMemory::attach(const std::string &name, size_t size)
  177. {
  178. mName = name;
  179. mSize = size;
  180. apr_status_t status = apr_shm_attach( &(mImpl->mAprSharedMemory), mName.c_str(), gAPRPoolp );
  181. if(ll_apr_warn_status(status))
  182. {
  183. return false;
  184. }
  185. return map();
  186. }
  187. bool LLPluginSharedMemory::detach(void)
  188. {
  189. if(mImpl->mAprSharedMemory)
  190. {
  191. apr_status_t status = apr_shm_detach(mImpl->mAprSharedMemory);
  192. if(ll_apr_warn_status(status))
  193. {
  194. // TODO: Is this a fatal error? I think not...
  195. }
  196. mImpl->mAprSharedMemory = NULL;
  197. }
  198. return true;
  199. }
  200. #elif USE_SHM_OPEN_SHARED_MEMORY
  201. // MARK: shm_open/mmap implementation
  202. LLPluginSharedMemoryPlatformImpl::LLPluginSharedMemoryPlatformImpl()
  203. {
  204. mSharedMemoryFD = -1;
  205. }
  206. LLPluginSharedMemoryPlatformImpl::~LLPluginSharedMemoryPlatformImpl()
  207. {
  208. }
  209. bool LLPluginSharedMemory::map(void)
  210. {
  211. mMappedAddress = ::mmap(NULL, mSize, PROT_READ | PROT_WRITE, MAP_SHARED, mImpl->mSharedMemoryFD, 0);
  212. if(mMappedAddress == NULL)
  213. {
  214. return false;
  215. }
  216. LL_DEBUGS("Plugin") << "memory mapped at " << mMappedAddress << LL_ENDL;
  217. return true;
  218. }
  219. bool LLPluginSharedMemory::unmap(void)
  220. {
  221. if(mMappedAddress != NULL)
  222. {
  223. LL_DEBUGS("Plugin") << "calling munmap(" << mMappedAddress << ", " << mSize << ")" << LL_ENDL;
  224. if(::munmap(mMappedAddress, mSize) == -1)
  225. {
  226. // TODO: Is this a fatal error? I think not...
  227. }
  228. mMappedAddress = NULL;
  229. }
  230. return true;
  231. }
  232. bool LLPluginSharedMemory::close(void)
  233. {
  234. if(mImpl->mSharedMemoryFD != -1)
  235. {
  236. LL_DEBUGS("Plugin") << "calling close(" << mImpl->mSharedMemoryFD << ")" << LL_ENDL;
  237. if(::close(mImpl->mSharedMemoryFD) == -1)
  238. {
  239. // TODO: Is this a fatal error? I think not...
  240. }
  241. mImpl->mSharedMemoryFD = -1;
  242. }
  243. return true;
  244. }
  245. bool LLPluginSharedMemory::unlink(void)
  246. {
  247. if(!mName.empty())
  248. {
  249. if(::shm_unlink(mName.c_str()) == -1)
  250. {
  251. return false;
  252. }
  253. }
  254. return true;
  255. }
  256. bool LLPluginSharedMemory::create(size_t size)
  257. {
  258. mName = SHM_OPEN_SHARED_MEMORY_PREFIX_STRING;
  259. mName += createName();
  260. mSize = size;
  261. // Preemptive unlink, just in case something didn't get cleaned up.
  262. unlink();
  263. mImpl->mSharedMemoryFD = ::shm_open(mName.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
  264. if(mImpl->mSharedMemoryFD == -1)
  265. {
  266. return false;
  267. }
  268. mNeedsDestroy = true;
  269. if(::ftruncate(mImpl->mSharedMemoryFD, mSize) == -1)
  270. {
  271. return false;
  272. }
  273. return map();
  274. }
  275. bool LLPluginSharedMemory::destroy(void)
  276. {
  277. unmap();
  278. close();
  279. return true;
  280. }
  281. bool LLPluginSharedMemory::attach(const std::string &name, size_t size)
  282. {
  283. mName = name;
  284. mSize = size;
  285. mImpl->mSharedMemoryFD = ::shm_open(mName.c_str(), O_RDWR, S_IRUSR | S_IWUSR);
  286. if(mImpl->mSharedMemoryFD == -1)
  287. {
  288. return false;
  289. }
  290. // unlink here so the segment will be cleaned up automatically after the last close.
  291. unlink();
  292. return map();
  293. }
  294. bool LLPluginSharedMemory::detach(void)
  295. {
  296. unmap();
  297. close();
  298. return true;
  299. }
  300. #elif USE_WIN32_SHARED_MEMORY
  301. // MARK: Win32 CreateFileMapping-based implementation
  302. // Reference: http://msdn.microsoft.com/en-us/library/aa366551(VS.85).aspx
  303. LLPluginSharedMemoryPlatformImpl::LLPluginSharedMemoryPlatformImpl()
  304. {
  305. mMapFile = NULL;
  306. }
  307. LLPluginSharedMemoryPlatformImpl::~LLPluginSharedMemoryPlatformImpl()
  308. {
  309. }
  310. bool LLPluginSharedMemory::map(void)
  311. {
  312. mMappedAddress = MapViewOfFile(
  313. mImpl->mMapFile, // handle to map object
  314. FILE_MAP_ALL_ACCESS, // read/write permission
  315. 0,
  316. 0,
  317. mSize);
  318. if(mMappedAddress == NULL)
  319. {
  320. LL_WARNS("Plugin") << "MapViewOfFile failed: " << GetLastError() << LL_ENDL;
  321. return false;
  322. }
  323. LL_DEBUGS("Plugin") << "memory mapped at " << mMappedAddress << LL_ENDL;
  324. return true;
  325. }
  326. bool LLPluginSharedMemory::unmap(void)
  327. {
  328. if(mMappedAddress != NULL)
  329. {
  330. UnmapViewOfFile(mMappedAddress);
  331. mMappedAddress = NULL;
  332. }
  333. return true;
  334. }
  335. bool LLPluginSharedMemory::close(void)
  336. {
  337. if(mImpl->mMapFile != NULL)
  338. {
  339. CloseHandle(mImpl->mMapFile);
  340. mImpl->mMapFile = NULL;
  341. }
  342. return true;
  343. }
  344. bool LLPluginSharedMemory::unlink(void)
  345. {
  346. // This is a no-op on Windows.
  347. return true;
  348. }
  349. bool LLPluginSharedMemory::create(size_t size)
  350. {
  351. mName = WIN32_SHARED_MEMORY_PREFIX_STRING;
  352. mName += createName();
  353. mSize = size;
  354. mImpl->mMapFile = CreateFileMappingA(
  355. INVALID_HANDLE_VALUE, // use paging file
  356. NULL, // default security
  357. PAGE_READWRITE, // read/write access
  358. 0, // max. object size
  359. mSize, // buffer size
  360. mName.c_str()); // name of mapping object
  361. if(mImpl->mMapFile == NULL)
  362. {
  363. LL_WARNS("Plugin") << "CreateFileMapping failed: " << GetLastError() << LL_ENDL;
  364. return false;
  365. }
  366. mNeedsDestroy = true;
  367. return map();
  368. }
  369. bool LLPluginSharedMemory::destroy(void)
  370. {
  371. unmap();
  372. close();
  373. return true;
  374. }
  375. bool LLPluginSharedMemory::attach(const std::string &name, size_t size)
  376. {
  377. mName = name;
  378. mSize = size;
  379. mImpl->mMapFile = OpenFileMappingA(
  380. FILE_MAP_ALL_ACCESS, // read/write access
  381. FALSE, // do not inherit the name
  382. mName.c_str()); // name of mapping object
  383. if(mImpl->mMapFile == NULL)
  384. {
  385. LL_WARNS("Plugin") << "OpenFileMapping failed: " << GetLastError() << LL_ENDL;
  386. return false;
  387. }
  388. return map();
  389. }
  390. bool LLPluginSharedMemory::detach(void)
  391. {
  392. unmap();
  393. close();
  394. return true;
  395. }
  396. #endif