/src/libtomahawk/thirdparty/kdsingleapplicationguard/kdlockedsharedmemorypointer.cpp

http://github.com/tomahawk-player/tomahawk · C++ · 475 lines · 182 code · 79 blank · 214 comment · 17 complexity · 345387bce466a451c420067f0db4c0eb MD5 · raw file

  1. #include "kdlockedsharedmemorypointer.h"
  2. #if QT_VERSION >= 0x040400 || defined( DOXYGEN_RUN )
  3. #ifndef QT_NO_SHAREDMEMORY
  4. namespace kdtools
  5. {
  6. }
  7. using namespace kdtools;
  8. KDLockedSharedMemoryPointerBase::KDLockedSharedMemoryPointerBase( QSharedMemory * m )
  9. : locker( m ),
  10. mem( m )
  11. {
  12. }
  13. KDLockedSharedMemoryPointerBase::KDLockedSharedMemoryPointerBase( QSharedMemory & m )
  14. : locker( &m ),
  15. mem( &m )
  16. {
  17. }
  18. KDLockedSharedMemoryPointerBase::~KDLockedSharedMemoryPointerBase() {}
  19. void * KDLockedSharedMemoryPointerBase::get() {
  20. return mem ? mem->data() : 0 ;
  21. }
  22. const void * KDLockedSharedMemoryPointerBase::get() const {
  23. return mem ? mem->data() : 0 ;
  24. }
  25. size_t KDLockedSharedMemoryPointerBase::byteSize() const {
  26. return mem ? mem->size() : 0;
  27. }
  28. /*!
  29. \class KDLockedSharedMemoryPointer
  30. \ingroup core raii smartptr
  31. \brief Locking pointer for Qt shared memory segments
  32. \since_c 2.1
  33. (The exception safety of this class has not been evaluated yet.)
  34. KDLockedSharedMemoryPointer is a smart immutable pointer, which gives convenient and safe access to a QSharedMemory data segment.
  35. The content of a KDLockedSharedMemoryPointer cannot be changed during it's lifetime.
  36. You can use this class like a normal pointer to the shared memory segment and be sure it's locked while accessing it.
  37. \note You can only put simple types/structs/classes into it. structs and classes shall not contain any other pointers. See the
  38. documentation of QSharedMemory for details.
  39. */
  40. /*!
  41. \fn KDLockedSharedMemoryPointer::KDLockedSharedMemoryPointer( QSharedMemory * mem )
  42. Constructor. Constructs a KDLockedSharedMemory pointer which points to the data segment of \a mem.
  43. The constructor locks \a mem. If the memory segment is already locked by another process, this constructor
  44. blocks until the lock is released.
  45. \post data() == mem->data() and the memory segment has been locked
  46. */
  47. /*!
  48. \fn KDLockedSharedMemoryPointer::KDLockedSharedMemoryPointer( QSharedMemory & mem )
  49. \overload
  50. \post data() == mem.data() and the memory segment has been locked
  51. */
  52. /*!
  53. \fn KDLockedSharedMemoryPointer::~KDLockedSharedMemoryPointer()
  54. Destructor. Unlocks the shared memory segment.
  55. \post The shared memory segment has been unlocked
  56. */
  57. /*!
  58. \fn T * KDLockedSharedMemoryPointer::get()
  59. \returns a pointer to the contained object.
  60. */
  61. /*!
  62. \fn const T * KDLockedSharedMemoryPointer::get() const
  63. \returns a const pointer to the contained object
  64. \overload
  65. */
  66. /*!
  67. \fn T * KDLockedSharedMemoryPointer::data()
  68. Equivalent to get(), provided for consistency with Qt naming conventions.
  69. */
  70. /*!
  71. \fn const T * KDLockedSharedMemoryPointer::data() const
  72. \overload
  73. */
  74. /*!
  75. \fn T & KDLockedSharedMemoryPointer::operator*()
  76. Dereference operator. Returns \link get() *get()\endlink.
  77. */
  78. /*!
  79. \fn const T & KDLockedSharedMemoryPointer::operator*() const
  80. Dereference operator. Returns \link get() *get()\endlink.
  81. \overload
  82. */
  83. /*!
  84. \fn T * KDLockedSharedMemoryPointer::operator->()
  85. Member-by-pointer operator. Returns get().
  86. */
  87. /*!
  88. \fn const T * KDLockedSharedMemoryPointer::operator->() const
  89. Member-by-pointer operator. Returns get().
  90. \overload
  91. */
  92. /*!
  93. \class KDLockedSharedMemoryArray
  94. \ingroup core raii smartptr
  95. \brief Locking array pointer to Qt shared memory segments
  96. \since_c 2.1
  97. (The exception safety of this class has not been evaluated yet.)
  98. KDLockedSharedMemoryArray is a smart immutable pointer, which gives convenient and safe access to array data stored in a QSharedMemory
  99. data segment.
  100. The content of a KDLockedSharedMemoryArray cannot be changed during it's lifetime.
  101. You can use this class like a normal pointer to the shared memory segment and be sure it's locked while accessing it.
  102. \note You can only put arrays of simple types/structs/classes into it. structs and classes shall not contain any other pointers. See the
  103. documentation of QSharedMemory for details.
  104. \sa KDLockedSharedMemoryPointer
  105. */
  106. /*!
  107. \fn KDLockedSharedMemoryArray::KDLockedSharedMemoryArray( QSharedMemory* mem )
  108. Constructor. Constructs a KDLockedSharedMemoryArray which points to the data segment of \a mem. The constructor locks \a mem. If the memory
  109. segment is already locked by another process, this constructor blocks until the lock is release.
  110. \post get() == mem->data() and the memory segment has been locked
  111. */
  112. /*!
  113. \fn KDLockedSharedMemoryArray::KDLockedSharedMemoryArray( QSharedMemory& mem )
  114. \overload
  115. \post get() == mem->data() and the memory segment has been locked
  116. */
  117. /*!
  118. \typedef KDLockedSharedMemoryArray::size_type
  119. Typedef for std::size_t. Provided for STL compatibility.
  120. */
  121. /*!
  122. \typedef KDLockedSharedMemoryArray::difference_type
  123. Typedef for std::ptrdiff_t. Provided for STL compatibility.
  124. */
  125. /*!
  126. \typedef KDLockedSharedMemoryArray::iterator
  127. Typedef for T*. Provided for STL compatibility.
  128. \since_t 2.2
  129. */
  130. /*!
  131. \typedef KDLockedSharedMemoryArray::const_iterator
  132. Typedef for const T*. Provided for STL compatibility.
  133. \since_t 2.2
  134. */
  135. /*!
  136. \typedef KDLockedSharedMemoryArray::reverse_iterator
  137. Typedef for std::reverse_iterator< \link KDLockedSharedMemoryArray::iterator iterator\endlink >. Provided for STL compatibility.
  138. \since_t 2.2
  139. */
  140. /*!
  141. \typedef KDLockedSharedMemoryArray::const_reverse_iterator
  142. Typedef for std::reverse_iterator< \link KDLockedSharedMemoryArray::const_iterator const_iterator\endlink >. Provided for STL compatibility.
  143. \since_t 2.2
  144. */
  145. /*!
  146. \fn KDLockedSharedMemoryArray::iterator KDLockedSharedMemoryArray::begin()
  147. Returns an \link KDLockedSharedMemoryArray::iterator iterator\endlink pointing to the first item of the array.
  148. \since_f 2.2
  149. */
  150. /*!
  151. \fn KDLockedSharedMemoryArray::const_iterator KDLockedSharedMemoryArray::begin() const
  152. \overload
  153. \since_f 2.2
  154. */
  155. /*!
  156. \fn KDLockedSharedMemoryArray::iterator KDLockedSharedMemoryArray::end()
  157. Returns an \link KDLockedSharedMemoryArray::iterator iterator\endlink pointing to the item after the last item of the array.
  158. \since_f 2.2
  159. */
  160. /*!
  161. \fn KDLockedSharedMemoryArray::const_iterator KDLockedSharedMemoryArray::end() const
  162. \overload
  163. \since_f 2.2
  164. */
  165. /*!
  166. \fn KDLockedSharedMemoryArray::reverse_iterator KDLockedSharedMemoryArray::rbegin()
  167. Returns an \link KDLockedSharedMemoryArray::reverse_iterator reverse_iterator\endlink pointing to the item after the last item of the array.
  168. \since_f 2.2
  169. */
  170. /*!
  171. \fn KDLockedSharedMemoryArray::const_reverse_iterator KDLockedSharedMemoryArray::rbegin() const
  172. \overload
  173. \since_f 2.2
  174. */
  175. /*!
  176. \fn KDLockedSharedMemoryArray::reverse_iterator KDLockedSharedMemoryArray::rend()
  177. Returns an \link KDLockedSharedMemoryArray::reverse_iterator reverse_iterator\endlink pointing to the first item of the array.
  178. \since_f 2.2
  179. */
  180. /*!
  181. \fn KDLockedSharedMemoryArray::const_reverse_iterator KDLockedSharedMemoryArray::rend() const
  182. \overload
  183. \since_f 2.2
  184. */
  185. /*!
  186. \fn KDLockedSharedMemoryArray::size_type KDLockedSharedMemoryArray::size() const
  187. Returns the size of this array. The size is calculated from the storage size of T and
  188. the size of the shared memory segment.
  189. \since_f 2.2
  190. */
  191. /*!
  192. \fn T& KDLockedSharedMemoryArray::operator[]( difference_type n )
  193. Array access operator. Returns a reference to the item at index position \a n.
  194. */
  195. /*!
  196. \fn const T& KDLockedSharedMemoryArray::operator[]( difference_type n ) const
  197. \overload
  198. */
  199. /*!
  200. \fn T& KDLockedSharedMemoryArray::front()
  201. Returns a reference to the first item in the array. This is the same as operator[](0).
  202. */
  203. /*!
  204. \fn const T& KDLockedSharedMemoryArray::front() const
  205. \overload
  206. */
  207. /*!
  208. \fn T& KDLockedSharedMemoryArray::back()
  209. Returns a reference to the last item in the array. This is the same as operator[](size()-1).
  210. \since_f 2.2
  211. */
  212. /*!
  213. \fn const T& KDLockedSharedMemoryArray::back() const
  214. \overload
  215. \since_f 2.2
  216. */
  217. #ifdef eKDTOOLSCORE_UNITTESTS
  218. #include <KDUnitTest/Test>
  219. #include <QThread>
  220. #include <QUuid>
  221. namespace
  222. {
  223. struct TestStruct
  224. {
  225. TestStruct( uint nn = 0 )
  226. : n( nn ),
  227. f( 0.0 ),
  228. c( '\0' ),
  229. b( false )
  230. {
  231. }
  232. uint n;
  233. double f;
  234. char c;
  235. bool b;
  236. };
  237. bool operator==( const TestStruct& lhs, const TestStruct& rhs )
  238. {
  239. return lhs.n == rhs.n && lhs.f == rhs.f && lhs.c == rhs.c && lhs.b == rhs.b;
  240. }
  241. class TestThread : public QThread
  242. {
  243. public:
  244. TestThread( const QString& key )
  245. : mem( key )
  246. {
  247. mem.attach();
  248. }
  249. void run()
  250. {
  251. while( true )
  252. {
  253. msleep( 100 );
  254. kdtools::KDLockedSharedMemoryPointer< TestStruct > p( &mem );
  255. if( !p->b )
  256. continue;
  257. p->n = 5;
  258. p->f = 3.14;
  259. p->c = 'A';
  260. p->b = false;
  261. return;
  262. }
  263. }
  264. QSharedMemory mem;
  265. };
  266. bool isConst( TestStruct* )
  267. {
  268. return false;
  269. }
  270. bool isConst( const TestStruct* )
  271. {
  272. return true;
  273. }
  274. }
  275. KDAB_UNITTEST_SIMPLE( KDLockedSharedMemoryPointer, "kdcoretools" ) {
  276. const QString key = QUuid::createUuid();
  277. QSharedMemory mem( key );
  278. const bool created = mem.create( sizeof( TestStruct ) );
  279. assertTrue( created );
  280. if ( !created )
  281. return; // don't execute tests if shm coulnd't be created
  282. // On Windows, shared mem is only available in increments of page
  283. // size (4k), so don't fail if the segment is larger:
  284. const unsigned long mem_size = mem.size();
  285. assertGreaterOrEqual( mem_size, sizeof( TestStruct ) );
  286. {
  287. kdtools::KDLockedSharedMemoryPointer< TestStruct > p( &mem );
  288. assertTrue( p );
  289. *p = TestStruct();
  290. assertEqual( p->n, 0u );
  291. assertEqual( p->f, 0.0 );
  292. assertEqual( p->c, '\0' );
  293. assertFalse( p->b );
  294. }
  295. {
  296. TestThread thread( key );
  297. assertEqual( thread.mem.key().toStdString(), key.toStdString() );
  298. assertEqual( static_cast< unsigned long >( thread.mem.size() ), mem_size );
  299. thread.start();
  300. assertTrue( thread.isRunning() );
  301. thread.wait( 2000 );
  302. assertTrue( thread.isRunning() );
  303. {
  304. kdtools::KDLockedSharedMemoryPointer< TestStruct > p( &mem );
  305. p->b = true;
  306. }
  307. thread.wait( 2000 );
  308. assertFalse( thread.isRunning() );
  309. }
  310. {
  311. kdtools::KDLockedSharedMemoryPointer< TestStruct > p( &mem );
  312. assertEqual( p->n, 5u );
  313. assertEqual( p->f, 3.14 );
  314. assertEqual( p->c, 'A' );
  315. assertFalse( p->b );
  316. }
  317. {
  318. kdtools::KDLockedSharedMemoryPointer< TestStruct > p( mem );
  319. assertEqual( mem.data(), p.get() );
  320. assertEqual( p.get(), p.operator->() );
  321. assertEqual( p.get(), &(*p) );
  322. assertEqual( p.get(), p.data() );
  323. assertFalse( isConst( p.get() ) );
  324. }
  325. {
  326. const kdtools::KDLockedSharedMemoryPointer< TestStruct > p( &mem );
  327. assertEqual( mem.data(), p.get() );
  328. assertEqual( p.get(), p.operator->() );
  329. assertEqual( p.get(), &(*p) );
  330. assertEqual( p.get(), p.data() );
  331. assertTrue( isConst( p.get() ) );
  332. }
  333. {
  334. QSharedMemory mem2( key + key );
  335. const bool created2 = mem2.create( 16 * sizeof( TestStruct ) );
  336. assertTrue( created2 );
  337. if ( !created2 )
  338. return; // don't execute tests if shm coulnd't be created
  339. kdtools::KDLockedSharedMemoryArray<TestStruct> a( mem2 );
  340. assertTrue( a );
  341. assertEqual( a.get(), mem2.data() );
  342. assertEqual( &a[0], a.get() );
  343. a[1] = a[0];
  344. assertTrue( a[0] == a[1] );
  345. TestStruct ts;
  346. ts.n = 5;
  347. ts.f = 3.14;
  348. a[0] = ts;
  349. assertFalse( a[0] == a[1] );
  350. assertEqual( a.front().n, ts.n );
  351. assertEqual( a[0].f, ts.f );
  352. a[0].n = 10;
  353. assertEqual( a.front().n, 10u );
  354. ts = a[0];
  355. assertEqual( ts.n, 10u );
  356. std::vector< TestStruct > v;
  357. for( uint i = 0; i < a.size(); ++i )
  358. v.push_back( TestStruct( i ) );
  359. std::copy( v.begin(), v.end(), a.begin() );
  360. for( uint i = 0; i < a.size(); ++i )
  361. assertEqual( a[ i ].n, i );
  362. assertEqual( a.front().n, 0u );
  363. assertEqual( a.back().n, a.size() - 1 );
  364. std::copy( v.begin(), v.end(), a.rbegin() );
  365. for( uint i = 0; i < a.size(); ++i )
  366. assertEqual( a[ i ].n, a.size() - 1 - i );
  367. assertEqual( a.front().n, a.size() - 1 );
  368. assertEqual( a.back().n, 0u );
  369. }
  370. }
  371. #endif // KDTOOLSCORE_UNITTESTS
  372. #endif // QT_NO_SHAREDMEMORY
  373. #endif // QT_VERSION >= 0x040400 || defined( DOXYGEN_RUN )