Tizen 2.0 Release
[framework/web/wrt-commons.git] / tests / dpl / unused / test_shm.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /*
17  * @file    test_shm.h
18  * @author  Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
19  * @version 1.0
20  * @brief   Implementation file for test cases for shared data framework
21  */
22
23 #include <stdlib.h>
24 #include <ctime>
25 #include <sys/shm.h>
26 #include <dpl/semaphore.h>
27 #include <dpl/test_runner.h>
28 #include <dpl/thread.h>
29 #include <dpl/controller.h>
30 #include <dpl/generic_event.h>
31 #include <dpl/log.h>
32 #include <dpl/shared_object.h>
33 #include <dpl/shared_property.h>
34 #include <memory>
35
36 RUNNER_TEST_GROUP_INIT(DPL)
37
38 using namespace DPL;
39
40 namespace {
41 const SharedMemory::Key SHM_KEY = 12345;
42 const char* SEM_NAME = "/wrt_engine_shared_object_semaphore";
43 const size_t VERSION = 1;
44
45 const size_t MAX_THREADS = 10;
46 const size_t TEST_AND_SET_REPEATS = 100;
47
48 const size_t SHARED_PROP_REPEATS = 3;
49
50 const size_t SINGLETON_TEST_REPEATS = 3;
51
52 // maximum random delay in singleton listener addition/removal
53 const size_t MAX_SINGLETON_LISTENER_DELAY = 50;
54
55 const int SINGLE_PROCESS_REPEATS = 50;
56
57 /*
58  * 5 seconds expected timeout for waitable events
59  * 30 seconds unexpected timeout for waitable events
60  * We don't want to block tests
61  */
62 const size_t EXPECTED_WAITABLE_TIMEOUT = 5 * 1000;
63 const size_t UNEXPECTED_WAITABLE_TIMEOUT = 30 * 1000;
64
65 bool g_enumTestCorrect = false;
66 bool g_enumTestIncorrect = false;
67 size_t g_delegateCalls = 0;
68
69 void Wait(DPL::WaitableEvent& event, bool expectedTimeout = false)
70 {
71     LogDebug("WaitForSingleHandle...");
72     DPL::WaitableHandleIndexList list = DPL::WaitForSingleHandle(
73             event.GetHandle(),
74             expectedTimeout ?
75             EXPECTED_WAITABLE_TIMEOUT : UNEXPECTED_WAITABLE_TIMEOUT);
76     if (list.size() == 0) {
77         LogDebug("...timeout.");
78     } else {
79         LogDebug("...signaled.");
80         event.Reset();
81     }
82
83     if (expectedTimeout) {
84         RUNNER_ASSERT(list.size() == 0);
85     } else {
86         RUNNER_ASSERT(list.size() == 1);
87     }
88 }
89
90 void RemoveIpcs()
91 {
92     Try {
93         SharedMemory::Remove(SHM_KEY);
94     }
95     Catch(SharedMemory::Exception::RemoveFailed) {
96         // ignore
97     }
98
99     Try {
100         DPL::Semaphore::Remove(SEM_NAME);
101     }
102     Catch(DPL::Semaphore::Exception::RemoveFailed) {
103         // ignore
104     }
105 }
106
107 typedef DPL::TypeListDecl<int, int, char, int[64]>::Type TestTypeList;
108 typedef DPL::TypeListDecl<int, int, char, int[63]>::Type TestTypeList2;
109 typedef DPL::TypeListDecl<int, int, char, int[63], int>::Type TestTypeList3;
110
111 typedef SharedObject<TestTypeList> TestSharedObject;
112 typedef SharedObject<TestTypeList2> TestSharedObject2;
113 typedef SharedObject<TestTypeList3> TestSharedObject3;
114
115 typedef std::shared_ptr<TestSharedObject> TestSharedObjectPtr;
116
117 const int INIT_EVENT = 0;
118 const int DESTROY_EVENT = 1;
119
120 int g_values[TestTypeList::Size];
121
122 /*
123  * helper listening controller
124  */
125 template <typename SharedType>
126 class ListeningController :
127     public DPL::Controller<DPL::TypeListDecl<int>::Type>
128 {
129   public:
130     explicit ListeningController(DPL::WaitableEvent* waitable);
131     ~ListeningController();
132
133     virtual void OnEventReceived(const int &event);
134
135     virtual void OnEvent(const int /*event*/) {}
136
137   protected:
138     std::shared_ptr<SharedType> m_so;
139     DPL::Thread m_thread;
140     DPL::WaitableEvent* m_waitable;
141 };
142
143 template <typename SharedType>
144 ListeningController<SharedType>::ListeningController(
145     DPL::WaitableEvent* waitable) :
146     m_waitable(waitable)
147 {
148     Touch();
149     m_thread.Run();
150     SwitchToThread(&m_thread);
151     PostEvent(INIT_EVENT);
152 }
153
154 template <typename SharedType>
155 ListeningController<SharedType>::~ListeningController()
156 {
157     m_thread.Quit();
158 }
159
160 template <typename SharedType>
161 void ListeningController<SharedType>::OnEventReceived(const int& event)
162 {
163     if (event == INIT_EVENT) {
164         m_so = SharedObjectFactory<SharedType>::Create(SHM_KEY, SEM_NAME);
165         OnEvent(event);
166         m_waitable->Signal();
167     } else if (event == DESTROY_EVENT) {
168         LogDebug("Destroying shared object");
169         OnEvent(event);
170
171         // deregister, destroy ad notify main thread
172         m_so.Reset();
173         LogDebug("4");
174         m_waitable->Signal();
175         LogDebug("5");
176     } else {
177         OnEvent(event);
178     }
179 }
180
181 typedef DPL::TypeListDecl<size_t, bool>::Type SharedTypeList;
182
183 class TestSharedObject4;
184 typedef std::shared_ptr<TestSharedObject4> TestSharedObject4Ptr;
185
186 class TestSharedObject4 : public SharedObject<SharedTypeList>
187 {
188   public:
189     enum
190     {
191         SIZE_T,
192         BOOLEAN
193     };
194
195     static TestSharedObject4Ptr Create()
196     {
197         return SharedObjectFactory<TestSharedObject4>::Create(SHM_KEY, SEM_NAME);
198     }
199
200     ~TestSharedObject4()
201     {
202         LogDebug("dtor");
203     }
204
205   protected:
206     explicit TestSharedObject4(const std::string& semaphore) :
207         SharedObject<SharedTypeList>(semaphore)
208     {}
209
210   private:
211     void Init()
212     {
213         SetPropertyInternal<BOOLEAN>(false);
214     }
215     friend class SharedObjectFactory<TestSharedObject4>;
216 };
217 } // anonymus namespace
218
219 //////////////////////////////////////////////
220
221 RUNNER_TEST(SharedMemory_002_AccessByType)
222 {
223     RemoveIpcs();
224
225     SharedData<TestTypeList> str;
226
227     // access by type
228     str.Embedded<0, int>::value = 4;
229     str.Embedded<1, int>::value = 5;
230     str.Embedded<2, char>::value = 'd';
231     str.Embedded<3, int[64]>::value[0] = 1;
232     str.Embedded<3, int[64]>::value[1] = 20;
233
234     RUNNER_ASSERT((str.Embedded<0, int>::value) == 4);
235     RUNNER_ASSERT((str.Embedded<1, int>::value) == 5);
236     RUNNER_ASSERT((str.Embedded<2, char>::value) == 'd');
237     RUNNER_ASSERT((str.Embedded<3, int[64]>::value[0]) == 1);
238     RUNNER_ASSERT((str.Embedded<3, int[64]>::value[1]) == 20);
239 }
240
241 //////////////////////////////////////////////
242
243 RUNNER_TEST(SharedMemory_003_AccessByIndex)
244 {
245     RemoveIpcs();
246
247     SharedData<TestTypeList> str;
248     // access by enum
249     str.Embedded<0, TestTypeList::Element<0>::Type>::value = 4;
250     str.Embedded<1, TestTypeList::Element<1>::Type>::value = 5;
251     str.Embedded<2, TestTypeList::Element<2>::Type>::value = 'd';
252     str.Embedded<3, TestTypeList::Element<3>::Type>::value[0] = 1;
253     str.Embedded<3, TestTypeList::Element<3>::Type>::value[1] = 20;
254
255     RUNNER_ASSERT(
256         (str.Embedded<0, TestTypeList::Element<0>::Type>::value) == 4);
257     RUNNER_ASSERT(
258         (str.Embedded<1, TestTypeList::Element<1>::Type>::value) == 5);
259     RUNNER_ASSERT(
260         (str.Embedded<2, TestTypeList::Element<2>::Type>::value) == 'd');
261     RUNNER_ASSERT(
262         (str.Embedded<3, TestTypeList::Element<3>::Type>::value[0]) == 1);
263     RUNNER_ASSERT(
264         (str.Embedded<3, TestTypeList::Element<3>::Type>::value[1]) == 20);
265 }
266
267 //////////////////////////////////////////////
268
269 RUNNER_TEST(SharedMemory_004_SimplifiedAccess)
270 {
271     RemoveIpcs();
272
273     SharedData<TestTypeList> str;
274
275     // access via PropertyRef
276     str.PropertyRef<1>() = 3;
277     RUNNER_ASSERT(str.PropertyRef<1>() == 3);
278
279     int (&array)[64] = str.PropertyRef<3>();
280     array[0] = 2;
281     RUNNER_ASSERT(str.PropertyRef<3>()[0] == 2);
282
283     str.PropertyRef<3>()[1] = 19;
284     RUNNER_ASSERT(str.PropertyRef<3>()[1] == 19);
285
286     // access via macro
287     str.SHARED_PROPERTY(0) = 2;
288     RUNNER_ASSERT(str.SHARED_PROPERTY(0) == 2);
289
290     str.SHARED_PROPERTY(2) = 'c';
291     RUNNER_ASSERT(str.SHARED_PROPERTY(2) == 'c');
292
293     str.SHARED_PROPERTY(3)[2] = 10;
294     RUNNER_ASSERT(str.SHARED_PROPERTY(3)[2] == 10);
295
296     // old style check
297     RUNNER_ASSERT((str.Embedded<0, int>::value) == 2);
298     RUNNER_ASSERT((str.Embedded<1, int>::value) == 3);
299     RUNNER_ASSERT((str.Embedded<2, char>::value) == 'c');
300     RUNNER_ASSERT((str.Embedded<3, int[64]>::value[0]) == 2);
301     RUNNER_ASSERT((str.Embedded<3, int[64]>::value[1]) == 19);
302     RUNNER_ASSERT((str.Embedded<3, int[64]>::value[2]) == 10);
303 }
304
305 //////////////////////////////////////////////
306
307 struct SharedStruct
308 {
309     int a;
310     int b;
311     char c;
312     int d[64];
313 };
314
315 typedef std::shared_ptr<SharedMemory::Segment<SharedStruct> > SharedStructPtr;
316
317 RUNNER_TEST(SharedMemory_010_BaseShmTest)
318 {
319     RemoveIpcs();
320
321     typedef std::unique_ptr<SharedMemory> SharedMemoryPtr;
322
323     // write
324     SharedMemoryPtr shm;
325     Try {
326         shm.Reset(SharedMemory::Create<SharedStruct>(SHM_KEY, false));
327     }
328     Catch(SharedMemory::Exception::NotFound) {
329         shm.Reset(SharedMemory::Create<SharedStruct>(SHM_KEY, true, true));
330     }
331
332     SharedStructPtr str = shm->Attach<SharedStruct>();
333
334     str->Data()->a = 1;
335     str->Data()->b = 2;
336     str->Data()->c = '3';
337     str->Data()->d[0] = 4;
338     str->Data()->d[1] = 5;
339
340     // read
341     SharedMemoryPtr shm2;
342     Try {
343         shm2.Reset(SharedMemory::Create<SharedStruct>(SHM_KEY, false));
344     }
345     Catch(SharedMemory::Exception::NotFound) {
346         shm2.Reset(SharedMemory::Create<SharedStruct>(SHM_KEY, true, true));
347     }
348
349     SharedStructPtr str2 = shm2->Attach<SharedStruct>();
350     SharedStructPtr str3 = shm2->Attach<SharedStruct>();
351
352     RUNNER_ASSERT(str2->Data()->a == 1);
353     RUNNER_ASSERT(str2->Data()->b == 2);
354     RUNNER_ASSERT(str2->Data()->c == '3');
355     RUNNER_ASSERT(str2->Data()->d[0] == 4);
356     RUNNER_ASSERT(str2->Data()->d[1] == 5);
357
358     RUNNER_ASSERT(str3->Data()->a == 1);
359     RUNNER_ASSERT(str3->Data()->b == 2);
360     RUNNER_ASSERT(str3->Data()->c == '3');
361     RUNNER_ASSERT(str3->Data()->d[0] == 4);
362     RUNNER_ASSERT(str3->Data()->d[1] == 5);
363
364     str2->Data()->b = 4;
365     str2->Data()->c = 'c';
366     str2->Data()->d[0] = 0;
367     RUNNER_ASSERT(str3->Data()->a == 1);
368     RUNNER_ASSERT(str3->Data()->b == 4);
369     RUNNER_ASSERT(str3->Data()->c == 'c');
370     RUNNER_ASSERT(str3->Data()->d[0] == 0);
371     RUNNER_ASSERT(str3->Data()->d[1] == 5);
372 }
373
374 //////////////////////////////////////////////
375
376 RUNNER_TEST(SharedMemory_020_SharedObjectTest)
377 {
378     RemoveIpcs();
379
380     typedef SharedObject<SharedTypeList> MySharedObj;
381
382     MySharedObj::Ptr so =
383         SharedObjectFactory<MySharedObj>::Create(SHM_KEY, SEM_NAME);
384
385     RUNNER_ASSERT((so->GetProperty<0, size_t>()) == 0);
386     so->SetProperty<0, size_t>(4);
387     RUNNER_ASSERT((so->GetProperty<0, size_t>()) == 4);
388 }
389
390 //////////////////////////////////////////////
391
392 class InitTestSharedObject : public TestSharedObject
393 {
394   protected:
395     explicit InitTestSharedObject(const std::string& semaphore) :
396         TestSharedObject(semaphore) {}
397
398     virtual void Init();    // from SharedObject
399
400   private:
401     friend class SharedObjectFactory<InitTestSharedObject>;
402 };
403
404 void InitTestSharedObject::Init()
405 {
406     SetPropertyInternal<0>(1);
407     SetPropertyInternal<1>(2);
408     SetPropertyInternal<2>('c');
409 }
410
411 RUNNER_TEST(SharedMemory_021_InitTest)
412 {
413     RemoveIpcs();   // we need non existing shm
414
415     std::shared_ptr<InitTestSharedObject> sho =
416         SharedObjectFactory<InitTestSharedObject>::Create(
417             SHM_KEY, SEM_NAME);
418     RUNNER_ASSERT((sho->GetProperty<0, int>()) == 1);
419     RUNNER_ASSERT((sho->GetProperty<1, int>()) == 2);
420     RUNNER_ASSERT((sho->GetProperty<2, char>()) == 'c');
421 }
422
423 //////////////////////////////////////////////
424
425 class VersionTestSO1 : public TestSharedObject
426 {
427   protected:
428     explicit VersionTestSO1(const std::string& semaphore) :
429         TestSharedObject(semaphore) {}
430
431     virtual SizeType GetVersion() const
432     {
433         return 1;
434     }                                                    // from SharedObject
435
436   private:
437     friend class SharedObjectFactory<VersionTestSO1>;
438 };
439
440 class VersionTestSO2 : public TestSharedObject
441 {
442   protected:
443     explicit VersionTestSO2(const std::string& semaphore) :
444         TestSharedObject(semaphore) {}
445
446     virtual SizeType GetVersion() const
447     {
448         return 2;
449     }                                                    // from SharedObject
450
451   private:
452     friend class SharedObjectFactory<VersionTestSO2>;
453 };
454
455 RUNNER_TEST(SharedMemory_022_InvalidVersionTest)
456 {
457     RemoveIpcs();   // we need non existing shm
458
459     std::shared_ptr<VersionTestSO1> sho =
460         SharedObjectFactory<VersionTestSO1>::Create(SHM_KEY, SEM_NAME);
461
462     Try {
463         std::shared_ptr<VersionTestSO2> sho2 =
464             SharedObjectFactory<VersionTestSO2>::Create(SHM_KEY, SEM_NAME);
465
466         RUNNER_ASSERT_MSG(false, "Invalid shm version has been accepted");
467     }
468     Catch(SharedObjectBase::Exception::InvalidVersion) {
469         RUNNER_ASSERT(true);
470     }
471 }
472
473 //////////////////////////////////////////////
474
475 RUNNER_TEST(SharedMemory_023_InvalidSizeTest)
476 {
477     RemoveIpcs();   // we need non existing shm
478
479     typedef SharedObject<TestTypeList> SO1;
480     typedef SharedObject<TestTypeList2> SO2;
481
482     SO1::Ptr sho = SharedObjectFactory<SO1>::Create(SHM_KEY, SEM_NAME);
483
484     Try {
485         SO2::Ptr sho2 = SharedObjectFactory<SO2>::Create(SHM_KEY, SEM_NAME);
486
487         RUNNER_ASSERT_MSG(false, "Invalid shm size has been accepted");
488     }
489     Catch(SharedObjectBase::Exception::InvalidSize) {
490         RUNNER_ASSERT(true);
491     }
492 }
493
494 //////////////////////////////////////////////
495
496 class MagicTestSO1 : public TestSharedObject
497 {
498   protected:
499     explicit MagicTestSO1(const std::string& semaphore) :
500         TestSharedObject(semaphore) {}
501
502     // from SharedObject
503     virtual MagicType GetMagicNumber() const
504     {
505         return 661;
506     }
507
508   private:
509     friend class SharedObjectFactory<MagicTestSO1>;
510 };
511
512 class MagicTestSO2 : public TestSharedObject
513 {
514   protected:
515     explicit MagicTestSO2(const std::string& semaphore) :
516         TestSharedObject(semaphore) {}
517
518     // from SharedObject
519     virtual MagicType GetMagicNumber() const
520     {
521         return 662;
522     }
523
524   private:
525     friend class SharedObjectFactory<MagicTestSO2>;
526 };
527
528 RUNNER_TEST(SharedMemory_024_InvalidMagicTest)
529 {
530     RemoveIpcs();   // we need non existing shm
531
532     std::shared_ptr<MagicTestSO1> sho =
533         SharedObjectFactory<MagicTestSO1>::Create(SHM_KEY, SEM_NAME);
534
535     Try {
536         std::shared_ptr<MagicTestSO2> sho2 =
537             SharedObjectFactory<MagicTestSO2>::Create(SHM_KEY, SEM_NAME);
538
539         RUNNER_ASSERT_MSG(false, "Invalid shm magic number has been accepted");
540     }
541     Catch(SharedObjectBase::Exception::InvalidMagicNumber) {
542         RUNNER_ASSERT(true);
543     }
544 }
545
546 //////////////////////////////////////////////
547
548 /*
549  * Listening shared object
550  */
551 class EnumTestSO1 : public TestSharedObject
552 {
553   public:
554     void SetWaitable(DPL::WaitableEvent* waitable)
555     {
556         m_waitable = waitable;
557     }
558
559   protected:
560     explicit EnumTestSO1(const std::string& semaphore) :
561         TestSharedObject(semaphore) {}
562
563     virtual void PropertyChanged(size_t propertyEnum);
564
565   private:
566     friend class SharedObjectFactory<EnumTestSO1>;
567
568     DPL::WaitableEvent* m_waitable;
569 };
570
571 void EnumTestSO1::PropertyChanged(size_t propertyEnum)
572 {
573     if (propertyEnum == 1) {
574         LogDebug("Property enum " << propertyEnum << " correctly set");
575         g_enumTestCorrect = true;
576     }
577     if (propertyEnum == 4) {
578         // This is bad. We only have 4 types
579         LogError("Property enum " << propertyEnum << " should be skipped");
580         g_enumTestIncorrect = true;
581     }
582     // confirm property change notification
583     m_waitable->Signal();
584 }
585
586 class EnumController : public ListeningController<EnumTestSO1>
587 {
588   public:
589     explicit EnumController(DPL::WaitableEvent* waitable) :
590         ListeningController<EnumTestSO1>(waitable) {}
591
592     virtual void OnEvent(const int event);
593 };
594
595 void EnumController::OnEvent(const int event)
596 {
597     if (event == INIT_EVENT) {
598         m_so->SetWaitable(m_waitable);
599     }
600 }
601
602 /*
603  * Writing shared object with correct size but different number of types
604  */
605 class EnumTestSO2 : public TestSharedObject3
606 {
607   protected:
608     explicit EnumTestSO2(const std::string& semaphore) :
609         TestSharedObject3(semaphore) {}
610
611   private:
612     friend class SharedObjectFactory<EnumTestSO2>;
613 };
614
615 RUNNER_TEST(SharedMemory_025_InvalidEnumTest)
616 {
617     RemoveIpcs();   // we need non existing shm
618
619     g_enumTestCorrect = false;
620     g_enumTestIncorrect = false;
621
622     DPL::WaitableEvent waitable;
623
624     // create listening controller and wait until it registers
625     EnumController controller(&waitable);
626     Wait(waitable);
627     LogDebug("Listening controller created");
628
629     // create writing shared object
630     std::shared_ptr<EnumTestSO2> sho2 =
631         SharedObjectFactory<EnumTestSO2>::Create(SHM_KEY, SEM_NAME);
632     DPL::WaitableHandleIndexList list;
633
634     // write property and wait for confirmation
635     sho2->SetProperty<1>(2);
636     Wait(waitable);
637
638     // write incorrect property and wait for confirmation
639     // we expect timeout
640     sho2->SetProperty<4>(2);
641     Wait(waitable, true);
642
643     // schedule listener deregistration and wait for confirmation
644     controller.PostEvent(DESTROY_EVENT);
645     Wait(waitable);
646
647     // check results
648     RUNNER_ASSERT(g_enumTestCorrect == true);
649     RUNNER_ASSERT(g_enumTestIncorrect == false);
650 }
651
652 //////////////////////////////////////////////
653
654 class MultiThreadSO : public TestSharedObject
655 {
656   public:
657     void TestAndSetProperty();
658
659   protected:
660     explicit MultiThreadSO(const std::string& semaphore) :
661         TestSharedObject(semaphore) {}
662
663   private:
664     friend class SharedObjectFactory<MultiThreadSO>;
665 };
666
667 void MultiThreadSO::TestAndSetProperty()
668 {
669     ScopedFlaggedLock lock(*this);
670
671     int value = PropertyRef<0, int>();
672     DPL::Thread::MicroSleep(100);
673     SetPropertyInternal<0>(value + 1);
674 }
675
676 class ShmController : public ListeningController<MultiThreadSO>
677 {
678   public:
679     explicit ShmController(DPL::WaitableEvent* event) :
680         ListeningController<MultiThreadSO>(event), m_counter(0)
681     {}
682
683     virtual void OnEventReceived(const int& event);
684
685   private:
686     size_t m_counter;
687 };
688
689 void ShmController::OnEventReceived(const int& event)
690 {
691     if (event == INIT_EVENT) {
692         m_so = SharedObjectFactory<MultiThreadSO>::Create(SHM_KEY, SEM_NAME);
693         PostEvent(2);
694     } else if (event == DESTROY_EVENT) {
695         LogDebug("Destroying shared object");
696         // deregister, destroy ad notify main thread
697         m_so.Reset();
698         m_waitable->Signal();
699     } else if (event == 2) {
700         m_so->TestAndSetProperty();
701         m_counter++;
702         if (m_counter >= TEST_AND_SET_REPEATS) {
703             LogDebug("Max tests reached. Finishing thread");
704             PostEvent(DESTROY_EVENT);
705             return;
706         }
707         PostEvent(2);
708     }
709 }
710
711 RUNNER_TEST(SharedMemory_030_MultithreadTest)
712 {
713     RemoveIpcs();   // we need non existing shm
714
715     typedef SharedObject<TestTypeList> SHO;
716     SHO::Ptr sho = SharedObjectFactory<SHO>::Create(SHM_KEY, SEM_NAME);
717
718     ShmController* controller[MAX_THREADS];
719     DPL::WaitableEvent finalEvent[MAX_THREADS];
720
721     for (size_t i = 0; i < MAX_THREADS; ++i) {
722         controller[i] = new ShmController(&finalEvent[i]);
723     }
724
725     for (size_t i = 0; i < MAX_THREADS; ++i) {
726         Wait(finalEvent[i]);
727     }
728
729     for (size_t i = 0; i < MAX_THREADS; ++i) {
730         delete controller[i];
731         controller[i] = NULL;
732     }
733
734     int value = sho->GetProperty<0, int>();
735     LogDebug("Final value is " << value << ", expected " <<
736              MAX_THREADS * TEST_AND_SET_REPEATS);
737     RUNNER_ASSERT(value == MAX_THREADS * TEST_AND_SET_REPEATS);
738 }
739
740 //////////////////////////////////////////////
741
742 class MyModel10 : public DPL::Model
743 {
744   public:
745     explicit MyModel10(const TestSharedObject4Ptr& shared_object) :
746         DPL::Model(), boolValue(this, shared_object) {}
747
748     SharedProperty<bool, TestSharedObject4::BOOLEAN, TestSharedObject4>
749     boolValue;
750 };
751
752 /*
753  * Listening controller
754  */
755 class ShmController3 : public ListeningController<TestSharedObject4>
756 {
757   public:
758     explicit ShmController3(DPL::WaitableEvent* event) :
759         ListeningController<TestSharedObject4>(event)
760     {}
761
762     virtual void OnEvent(const int event);
763
764     void OnValueChanged(const DPL::PropertyEvent<bool>& event);
765
766   private:
767     typedef std::unique_ptr<MyModel10> MyModelPtr;
768
769     // model with property bound to shared object
770     MyModelPtr m_model;
771 };
772
773 void ShmController3::OnEvent(const int event)
774 {
775     if (event == INIT_EVENT) {
776         m_model.Reset(new MyModel10(m_so));
777         m_model->boolValue.AddListener(
778             DPL::FastDelegate<void (const DPL::PropertyEvent<bool>&)>(
779                 this,
780                 &ShmController3::OnValueChanged));
781     } else if (event == DESTROY_EVENT) {
782         m_model->boolValue.RemoveListener(
783             DPL::FastDelegate<void (const DPL::PropertyEvent<bool>&)>(
784                 this,
785                 &ShmController3::OnValueChanged));
786         m_model.Reset();
787     }
788 }
789
790 void ShmController3::OnValueChanged(const DPL::PropertyEvent<bool>& event)
791 {
792     if (event.value) {
793         // change back
794         m_model->boolValue.Set(false);
795     } else {
796         LogError("Expected value = true, got false");
797     }
798
799     m_waitable->Signal();
800 }
801
802 RUNNER_TEST(SharedMemory_050_SharedProperty)
803 {
804     RemoveIpcs();
805
806     bool result = true;
807     DPL::WaitableEvent waitable;
808     // listener controller
809     ShmController3 controller(&waitable);
810     Wait(waitable);
811
812     TestSharedObject4Ptr sharedObject = TestSharedObject4::Create();
813
814     for (size_t i = 0; i < SHARED_PROP_REPEATS; ++i) {
815         sharedObject->SetProperty<TestSharedObject4::BOOLEAN>(true);
816         Wait(waitable);
817         result = sharedObject->GetProperty<TestSharedObject4::BOOLEAN,
818                                            bool>();
819         RUNNER_ASSERT(result == false);
820     }
821     controller.PostEvent(DESTROY_EVENT);
822     Wait(waitable);
823 }
824
825 //////////////////////////////////////////////
826
827 class MyModel2 : public DPL::Model
828 {
829   public:
830     explicit MyModel2(const TestSharedObjectPtr& shared_object) :
831         counter(this, shared_object) {}
832
833     SharedProperty<int, 0, TestSharedObject> counter;
834 };
835
836 class SPController : public ListeningController<TestSharedObject>
837 {
838   public:
839     explicit SPController(DPL::WaitableEvent* event) :
840         ListeningController<TestSharedObject>(event), m_repeats(1) {}
841
842     virtual void OnEvent(const int event);
843
844     void OnValueChanged1(const DPL::PropertyEvent<int>& event);
845     void OnValueChanged2(const DPL::PropertyEvent<int>& event);
846
847   private:
848     std::unique_ptr<MyModel2> m_model1;
849     std::unique_ptr<MyModel2> m_model2;
850
851     int m_repeats;
852     std::shared_ptr<TestSharedObject> m_so2;
853 };
854
855 void SPController::OnEvent(const int event)
856 {
857     if (event == INIT_EVENT) {
858         m_so2 = SharedObjectFactory<TestSharedObject>::Create(SHM_KEY,
859                                                               SEM_NAME);
860
861         // create and register 2 models sharing the same property
862         m_model1.Reset(new MyModel2(m_so));
863         m_model2.Reset(new MyModel2(m_so2));
864         m_model1->counter.AddListener(
865             DPL::FastDelegate<void (const DPL::PropertyEvent<int>&)>(
866                 this,
867                 &SPController::OnValueChanged1));
868         m_model2->counter.AddListener(
869             DPL::FastDelegate<void (const DPL::PropertyEvent<int>&)>(
870                 this,
871                 &SPController::OnValueChanged2));
872         m_model1->counter.Set(1);
873     } else if (event == DESTROY_EVENT) {
874         m_model1->counter.RemoveListener(
875             DPL::FastDelegate<void (const DPL::PropertyEvent<int>&)>(
876                 this,
877                 &SPController::OnValueChanged1));
878         m_model2->counter.RemoveListener(
879             DPL::FastDelegate<void (const DPL::PropertyEvent<int>&)>(
880                 this,
881                 &SPController::OnValueChanged2));
882
883         m_model1.Reset();
884         m_model2.Reset();
885         m_so2.Reset();
886     }
887 }
888
889 void SPController::OnValueChanged1(const DPL::PropertyEvent<int>& event)
890 {
891     if (m_repeats >= SINGLE_PROCESS_REPEATS) {
892         PostEvent(DESTROY_EVENT);
893         return;
894     }
895
896     LogDebug("[1] Value changed to " << event.value);
897     m_repeats++;
898     m_model1->counter.Set(event.value + 1);
899 }
900
901 void SPController::OnValueChanged2(const DPL::PropertyEvent<int>& event)
902 {
903     if (m_repeats >= SINGLE_PROCESS_REPEATS) {
904         PostEvent(DESTROY_EVENT);
905         return;
906     }
907
908     LogDebug("[2] Value changed to " << event.value);
909     m_repeats++;
910     m_model2->counter.Set(event.value + 1);
911 }
912
913 RUNNER_TEST(SharedMemory_060_SingleProcess)
914 {
915     RemoveIpcs();
916
917     DPL::WaitableEvent waitable;
918     SPController controller(&waitable);
919     TestSharedObjectPtr sho = SharedObjectFactory<TestSharedObject>::Create(
920             SHM_KEY,
921             SEM_NAME);
922
923     // wait for creation
924     Wait(waitable);
925
926     // wait for destruction
927     Wait(waitable);
928
929     int value = sho->GetProperty<0, int>();
930
931     LogDebug("final value: " << value);
932
933     // check value
934     RUNNER_ASSERT(value == SINGLE_PROCESS_REPEATS);
935 }
936
937 //////////////////////////////////////////////
938
939 class ListenerTestController : public ListeningController<TestSharedObject>,
940     public ISharedObjectListener<0, int>,
941     public ISharedObjectListener<1, int>,
942     public ISharedObjectListener<2, char>,
943     public ISharedObjectListener<3, int[64]>
944 {
945   public:
946     explicit ListenerTestController(DPL::WaitableEvent* event) :
947         ListeningController<TestSharedObject>(event) {}
948
949     ~ListenerTestController();
950
951     virtual void OnEvent(const int event);
952
953     virtual void ValueChanged(size_t propertyEnum,
954                               const int& value,
955                               const void* info = NULL);
956     virtual void ValueChanged(size_t propertyEnum,
957                               const char& value,
958                               const void* info = NULL);
959     virtual void ValueChanged(size_t propertyEnum,
960                               const int(&value)[64],
961                               const void* info = NULL);
962 };
963
964 ListenerTestController::~ListenerTestController()
965 {}
966
967 void ListenerTestController::OnEvent(const int event)
968 {
969     if (event == INIT_EVENT) {
970         // add self as a listener to shared object
971         m_so->AddListener<0, int>(this);
972         m_so->AddListener<1, int>(this);
973         m_so->AddListener<2, char>(this);
974         m_so->AddListener<3, int[64]>(this);
975     } else if (event == DESTROY_EVENT) {
976         // remove self from listener list
977         m_so->RemoveListener<0, int>(this);
978         m_so->RemoveListener<1, int>(this);
979         m_so->RemoveListener<2, char>(this);
980         m_so->RemoveListener<3, int[64]>(this);
981     }
982 }
983
984 void ListenerTestController::ValueChanged(size_t propertyEnum,
985                                           const int& value,
986                                           const void* /*info*/)
987 {
988     LogDebug("ValueChanged(int) " << propertyEnum << " " << value);
989     if ((propertyEnum == 0 &&
990          value == 1) || (propertyEnum == 1 && value == 2))
991     {
992         g_values[propertyEnum]++;
993         if (g_values[propertyEnum] == 3) {
994             m_waitable->Signal();
995         }
996     }
997 }
998
999 void ListenerTestController::ValueChanged(size_t propertyEnum,
1000                                           const char& value,
1001                                           const void* /*info*/)
1002 {
1003     LogDebug("ValueChanged(char) " << propertyEnum << " " << value);
1004     if (propertyEnum == 2 && value == 'c') {
1005         g_values[propertyEnum]++;
1006         if (g_values[propertyEnum] == 3) {
1007             m_waitable->Signal();
1008         }
1009     }
1010 }
1011
1012 void ListenerTestController::ValueChanged(size_t propertyEnum,
1013                                           const int(&value)[64],
1014                                           const void* /*info*/)
1015 {
1016     LogDebug("ValueChanged(int[64]) " << propertyEnum << " " << value[5]);
1017     if (propertyEnum == 3 && value[5] == 5) {
1018         g_values[propertyEnum]++;
1019         if (g_values[propertyEnum] == 3) {
1020             m_waitable->Signal();
1021         }
1022     }
1023 }
1024
1025 RUNNER_TEST(SharedMemory_070_SharedObjectListeners)
1026 {
1027     RemoveIpcs();
1028
1029     // setup global flags
1030     for (size_t i = 0; i < TestTypeList::Size; ++i) {
1031         g_values[i] = 0;
1032     }
1033
1034     // create shared object
1035     TestSharedObjectPtr sho = SharedObjectFactory<TestSharedObject>::Create(
1036             SHM_KEY, SEM_NAME);
1037
1038     // create 1st listener and wait for it
1039     DPL::WaitableEvent waitable;
1040     ListenerTestController c1(&waitable);
1041     Wait(waitable);
1042
1043     // create 2nd listener and wait for it
1044     ListenerTestController c2(&waitable);
1045     Wait(waitable);
1046
1047     // create 3rd listener and wait for it
1048     ListenerTestController c3(&waitable);
1049     Wait(waitable);
1050
1051     // set properties and wait for result
1052     sho->SetProperty<0, int>(1);
1053     Wait(waitable);
1054
1055     RUNNER_ASSERT(g_values[0] == 3);
1056
1057     sho->SetProperty<1, int>(2);
1058     Wait(waitable);
1059
1060     RUNNER_ASSERT(g_values[1] == 3);
1061
1062     sho->SetProperty<2, char>('c');
1063     Wait(waitable);
1064
1065     RUNNER_ASSERT(g_values[2] == 3);
1066
1067     int array[64];
1068     memset(array, 64 * sizeof(array[0]), 0);
1069     array[5] = 5;
1070     sho->SetProperty<3, int[64]>(array);
1071     Wait(waitable);
1072
1073     RUNNER_ASSERT(g_values[3] == 3);
1074
1075     // finalize listeners
1076     c1.PostEvent(DESTROY_EVENT);
1077     Wait(waitable);
1078
1079     c2.PostEvent(DESTROY_EVENT);
1080     Wait(waitable);
1081
1082     c3.PostEvent(DESTROY_EVENT);
1083     Wait(waitable);
1084 }
1085
1086 //////////////////////////////////////////////
1087
1088 /*
1089  * class simulating DB access
1090  */
1091 class DAO : public DPL::Noncopyable
1092 {
1093   public:
1094     DAO() : m_boolValue(false) {}
1095
1096     void SetBoolValue(const bool& value)
1097     {
1098         m_boolValue = value;
1099     }
1100
1101     bool GetBoolValue() const
1102     {
1103         return m_boolValue;
1104     }
1105
1106   private:
1107     bool m_boolValue;
1108 };
1109
1110 /*
1111  * Model with property having set delegate defined
1112  */
1113 class MyModel3 : public DPL::Model
1114 {
1115   public:
1116     typedef SharedPropertyEx<bool,
1117                              TestSharedObject4::BOOLEAN,
1118                              TestSharedObject4> PropertyType;
1119
1120     MyModel3(const TestSharedObject4Ptr& shared_object, DAO* dao) :
1121         boolValue(this,
1122                   shared_object,
1123                   PropertyType::SetDelegate(dao, &DAO::SetBoolValue))
1124     {}
1125
1126     PropertyType boolValue;
1127 };
1128
1129 RUNNER_TEST(SharedMemory_090_SetPropertyDelegate)
1130 {
1131     RemoveIpcs();
1132
1133     // dao object
1134     DAO dao;
1135
1136     // create shared object
1137     TestSharedObject4Ptr sho = TestSharedObject4::Create();
1138
1139     // set property but call dao delegate within semaphore
1140     sho->SetProperty<TestSharedObject4::BOOLEAN>(
1141         true,
1142         MyModel3::PropertyType::SetDelegate(&dao, &DAO::SetBoolValue));
1143
1144     // check dao value
1145     RUNNER_ASSERT(dao.GetBoolValue() == true);
1146
1147     // check shared object value
1148     bool shoValue = sho->GetProperty<TestSharedObject4::BOOLEAN, bool>();
1149     RUNNER_ASSERT(shoValue == true);
1150
1151     // try the same with shared property
1152     MyModel3 model(sho, &dao);
1153
1154     // set property
1155     model.boolValue.Set(false);
1156
1157     // check dao value
1158     RUNNER_ASSERT(dao.GetBoolValue() == false);
1159
1160     // check sho value
1161     shoValue = sho->GetProperty<TestSharedObject4::BOOLEAN, bool>();
1162     RUNNER_ASSERT(shoValue == false);
1163
1164     // check property value
1165     RUNNER_ASSERT(model.boolValue.Get() == false);
1166 }
1167
1168 //////////////////////////////////////////////
1169
1170 /*
1171  * Lazy initialization test shared object
1172  */
1173 class LazySharedObject : public SharedObject<TestTypeList>
1174 {
1175   public:
1176     explicit LazySharedObject(const std::string& semaphore) :
1177         SharedObject<TestTypeList>(semaphore)
1178         , m_read(false)
1179     {}
1180
1181     void Init();
1182
1183     bool IsRead() const
1184     {
1185         return m_read;
1186     }
1187
1188   private:
1189     friend class SharedObjectFactory<LazySharedObject>;
1190
1191     bool m_read;
1192 };
1193
1194 void LazySharedObject::Init()
1195 {
1196     SetPropertyInternal<0>(42);
1197     m_read = true;
1198 }
1199
1200 RUNNER_TEST(SharedMemory_100_LazyInit)
1201 {
1202     RemoveIpcs();
1203
1204     typedef std::shared_ptr<LazySharedObject> LazySharedObjectPtr;
1205
1206     // create shared object
1207     LazySharedObjectPtr sho = SharedObjectFactory<LazySharedObject>::Create(
1208             SHM_KEY, SEM_NAME);
1209
1210     RUNNER_ASSERT(sho->IsRead() == false);
1211
1212     // get property causing lazy init
1213     int value = sho->GetProperty<0, int>();
1214
1215     RUNNER_ASSERT(sho->IsRead() == true);
1216     RUNNER_ASSERT(value == 42);
1217
1218     // create another object
1219     LazySharedObjectPtr sho2 = SharedObjectFactory<LazySharedObject>::Create(
1220             SHM_KEY, SEM_NAME);
1221
1222     RUNNER_ASSERT(sho2->IsRead() == false);
1223
1224     // get property NOT causing lazy init
1225     value = sho2->GetProperty<0, int>();
1226
1227     RUNNER_ASSERT(sho2->IsRead() == false);
1228     RUNNER_ASSERT(value == 42);
1229
1230     // destroy both objects
1231     sho.Reset();
1232     sho2.Reset();
1233
1234     // create shared object
1235     LazySharedObjectPtr sho3 = SharedObjectFactory<LazySharedObject>::Create(
1236             SHM_KEY, SEM_NAME);
1237
1238     RUNNER_ASSERT(sho3->IsRead() == false);
1239
1240     // set property causing lazy init
1241     sho3->SetProperty<0>(43);
1242     value = sho3->GetProperty<0, int>();
1243
1244     RUNNER_ASSERT(sho3->IsRead() == true);
1245     RUNNER_ASSERT(value == 43);
1246 }
1247
1248 //////////////////////////////////////////////
1249
1250 bool SetCondition(const int& readValue, int& setValue);
1251 bool SetCondition(const int& readValue, int& setValue)
1252 {
1253     LogDebug("Condition delegate called with read value = " << readValue <<
1254              " and set value = " << setValue);
1255
1256     if (readValue > 3) {
1257         LogDebug("Condition is false");
1258         return false;
1259     }
1260
1261     LogDebug("Condition is true");
1262     if (4 == setValue) {
1263         setValue = 10;
1264         LogDebug("Changing set value to " << setValue);
1265     }
1266     return true;
1267 }
1268
1269 void SetDelegate(const int& readValue);
1270 void SetDelegate(const int& readValue)
1271 {
1272     LogDebug("Set delegate called " << readValue);
1273     g_delegateCalls++;
1274 }
1275
1276 RUNNER_TEST(SharedMemory_120_ConditionalSet)
1277 {
1278     RemoveIpcs();
1279
1280     TestSharedObjectPtr sho = SharedObjectFactory<TestSharedObject>::Create(
1281             SHM_KEY,
1282             SEM_NAME);
1283
1284     g_delegateCalls = 0;
1285
1286     RUNNER_ASSERT(0 == (sho->GetProperty<0, int>()));
1287
1288     DPL::FastDelegate<bool (const int&, int&)> condition(&SetCondition);
1289     DPL::FastDelegate<void (const int&)> delegate(&SetDelegate);
1290
1291     bool succeeded = false;
1292
1293     succeeded = sho->ConditionalSetProperty<0>(-2, condition);
1294
1295     RUNNER_ASSERT(succeeded);
1296     RUNNER_ASSERT(-2 == (sho->GetProperty<0, int>()));
1297
1298     succeeded = sho->ConditionalSetProperty<0>(4, condition, delegate);
1299
1300     RUNNER_ASSERT(succeeded);
1301     RUNNER_ASSERT(10 == (sho->GetProperty<0, int>()));
1302     RUNNER_ASSERT(1 == g_delegateCalls);
1303
1304     succeeded = sho->ConditionalSetProperty<0>(5, condition);
1305
1306     RUNNER_ASSERT(!succeeded);
1307     RUNNER_ASSERT(10 == (sho->GetProperty<0, int>()));
1308
1309     succeeded = sho->ConditionalSetProperty<0>(666, condition, delegate);
1310
1311     RUNNER_ASSERT(!succeeded);
1312     RUNNER_ASSERT(10 == (sho->GetProperty<0, int>()));
1313     RUNNER_ASSERT(1 == g_delegateCalls);
1314 }
1315
1316 //////////////////////////////////////////////
1317
1318 /*
1319  * Shared object used by multiple threads as a singleton.
1320  */
1321 class MTSharedObject : public SharedObject<TestTypeList>
1322 {
1323   public:
1324     explicit MTSharedObject(const std::string& semaphore) :
1325         SharedObject<TestTypeList>(semaphore)
1326     {}
1327
1328     void Clear();
1329
1330   private:
1331     friend class SharedObjectFactory<MTSharedObject>;
1332 };
1333
1334 typedef std::shared_ptr<MTSharedObject> MTSharedObjectPtr;
1335
1336 void MTSharedObject::Clear()
1337 {
1338     int array[64] = {};
1339     SetProperty<0>(0);
1340     SetProperty<1>(0);
1341     SetProperty<2>(static_cast<char>(0));
1342     SetProperty<3>(array);
1343 }
1344
1345 /*
1346  * Shared object singleton
1347  */
1348 class SharedObjectSingleton
1349 {
1350   public:
1351     static MTSharedObjectPtr Instance();
1352     static void Destroy();
1353
1354   private:
1355     static MTSharedObjectPtr m_sho;
1356     static DPL::Mutex m_mutex;
1357 };
1358
1359 MTSharedObjectPtr SharedObjectSingleton::m_sho;
1360 DPL::Mutex SharedObjectSingleton::m_mutex;
1361
1362 MTSharedObjectPtr SharedObjectSingleton::Instance()
1363 {
1364     DPL::Mutex::ScopedLock lock(&m_mutex);
1365     if (!m_sho) {
1366         m_sho = SharedObjectFactory<MTSharedObject>::Create(SHM_KEY, SEM_NAME);
1367     }
1368     return m_sho;
1369 }
1370
1371 void SharedObjectSingleton::Destroy()
1372 {
1373     DPL::Mutex::ScopedLock lock(&m_mutex);
1374     m_sho.Reset();
1375 }
1376
1377 /*
1378  * Listening controller
1379  */
1380 class ShmController4 : public ListeningController<MTSharedObject>,
1381     public ISharedObjectListener<0, int>,
1382     public ISharedObjectListener<1, int>,
1383     public ISharedObjectListener<2, char>,
1384     public ISharedObjectListener<3, int[64]>
1385 {
1386   public:
1387     enum {
1388         ADD_LISTENERS = 2,
1389         REMOVE_LISTENERS = 3,
1390         DESTROY_SINGLETON = 4
1391     };
1392
1393     explicit ShmController4(DPL::WaitableEvent* event) :
1394         ListeningController<MTSharedObject>(event)
1395     {}
1396
1397     virtual void OnEventReceived(const int& event);
1398
1399     virtual void ValueChanged(size_t propertyEnum,
1400                               const int& value,
1401                               const void* info = NULL);
1402     virtual void ValueChanged(size_t propertyEnum,
1403                               const char& value,
1404                               const void* info = NULL);
1405     virtual void ValueChanged(size_t propertyEnum,
1406                               const int(&value)[64],
1407                               const void* info = NULL);
1408
1409     bool NotRegistered();
1410
1411   private:
1412     void Sleep();
1413
1414     size_t m_counter;
1415 };
1416
1417 void ShmController4::ValueChanged(size_t propertyEnum,
1418                                   const int& value,
1419                                   const void* /*info*/)
1420 {
1421     LogDebug("ValueChanged(int) " << propertyEnum << " " << value);
1422     if ((propertyEnum == 0 && value == 1) ||
1423         (propertyEnum == 1 && value == 11))
1424     {
1425         m_waitable->Signal();
1426     }
1427 }
1428
1429 void ShmController4::ValueChanged(size_t propertyEnum,
1430                                   const char& value,
1431                                   const void* /*info*/)
1432 {
1433     LogDebug("ValueChanged(char) " << propertyEnum << " " << value);
1434     if (propertyEnum == 2 && value == 'a') {
1435         m_waitable->Signal();
1436     }
1437 }
1438
1439 void ShmController4::ValueChanged(size_t propertyEnum,
1440                                   const int(&value)[64],
1441                                   const void* /*info*/)
1442 {
1443     LogDebug("ValueChanged(int[64]) " << propertyEnum << " " << value[5]);
1444     if (propertyEnum == 3 && value[0] == 0 && value[1] == 1 && value[2] == 2) {
1445         m_waitable->Signal();
1446     }
1447 }
1448
1449 void ShmController4::Sleep()
1450 {
1451     DPL::Thread::GetCurrentThread()->MiliSleep(
1452         rand() % MAX_SINGLETON_LISTENER_DELAY);
1453 }
1454
1455 void ShmController4::OnEventReceived(const int& event)
1456 {
1457     switch (event) {
1458     case INIT_EVENT:
1459         m_so = SharedObjectSingleton::Instance();
1460         m_waitable->Signal();
1461         break;
1462
1463     case DESTROY_EVENT:
1464         LogDebug("Destroying shared object");
1465         // deregister, destroy and notify main thread
1466         m_so.Reset();
1467         m_waitable->Signal();
1468         break;
1469
1470     case ADD_LISTENERS:
1471         // add listener and notify
1472         m_so->AddListener<0, int>(this);
1473         Sleep();
1474         m_so->AddListener<1, int>(this);
1475         Sleep();
1476         m_so->AddListener<2, char>(this);
1477         Sleep();
1478         m_so->AddListener<3, int[64]>(this);
1479         Sleep();
1480         m_waitable->Signal();
1481         break;
1482
1483     case REMOVE_LISTENERS:
1484         // remove listener and notify
1485         m_so->RemoveListener<0, int>(this);
1486         Sleep();
1487         m_so->RemoveListener<1, int>(this);
1488         Sleep();
1489         m_so->RemoveListener<2, char>(this);
1490         Sleep();
1491         m_so->RemoveListener<3, int[64]>(this);
1492         Sleep();
1493         m_waitable->Signal();
1494         break;
1495
1496     case DESTROY_SINGLETON:
1497         SharedObjectSingleton::Destroy();
1498         m_waitable->Signal();
1499         break;
1500
1501     default:
1502         LogError("Unsupported event received: " << event);
1503     }
1504 }
1505
1506 void MultipleWait(DPL::WaitableEvent(&event)[MAX_THREADS]);
1507 void MultipleWait(DPL::WaitableEvent(&event)[MAX_THREADS])
1508 {
1509     for (size_t i = 0; i < MAX_THREADS; ++i) {
1510         Wait(event[i]);
1511     }
1512 }
1513
1514 /*
1515  * Try to remove property listener. If there's no such listener an exception
1516  * should be thrown.
1517  */
1518 #define LISTENER_ASSERT(property) \
1519     Try { \
1520         singleton->RemoveListener<(property)>(controller[i]); \
1521         LogError("Controller " << i << " is still listening for property " \
1522                                << #property); \
1523         RUNNER_ASSERT_MSG(false, "No listeners expected"); \
1524     } \
1525     Catch(MTSharedObject::Exception::ListenerNotFound) { \
1526         RUNNER_ASSERT(true); \
1527     } \
1528
1529 // test
1530 RUNNER_TEST(SharedMemory_130_SharedObjectSingleton)
1531 {
1532     RemoveIpcs();   // we need non existing shm
1533
1534     srand(time(NULL));
1535
1536     // writer shared object
1537     TestSharedObjectPtr sho = SharedObjectFactory<TestSharedObject>::Create(
1538             SHM_KEY, SEM_NAME);
1539
1540     ShmController4* controller[MAX_THREADS];
1541     DPL::WaitableEvent waitable[MAX_THREADS];
1542
1543     const int array[64] = { 0, 1, 2 };
1544
1545     // Create and wait for notification. Make sure that the thread/controller 0
1546     // is created first
1547     LogInfo("Creating controllers");
1548     for (size_t i = 0; i < MAX_THREADS; ++i) {
1549         controller[i] = new ShmController4(&waitable[i]);
1550         Wait(waitable[i]);
1551     }
1552
1553     // singleton will be created by thread/controller 0 by now
1554     MTSharedObjectPtr singleton = SharedObjectSingleton::Instance();
1555
1556     for (size_t repeats = 0; repeats < SINGLETON_TEST_REPEATS; ++repeats) {
1557         LogInfo("%%%%%%%%%%%%%%%%%%%%%");
1558         LogInfo("Iteration " << repeats + 1 << " of " << SINGLETON_TEST_REPEATS);
1559         singleton->Clear();
1560
1561         // add listeners
1562         LogInfo("Adding listeners");
1563         for (size_t i = 0; i < MAX_THREADS; ++i) {
1564             controller[i]->PostEvent(ShmController4::ADD_LISTENERS);
1565         }
1566         // wait for listeners
1567         MultipleWait(waitable);
1568
1569         RUNNER_ASSERT((singleton->GetProperty<0, int>()) == 0);
1570         RUNNER_ASSERT((singleton->GetProperty<1, int>()) == 0);
1571         RUNNER_ASSERT((singleton->GetProperty<2, char>()) == 0);
1572
1573         int checkArray[64] = {};
1574         singleton->GetProperty<3>(checkArray);
1575         RUNNER_ASSERT(checkArray[0] == 0);
1576         RUNNER_ASSERT(checkArray[1] == 0);
1577         RUNNER_ASSERT(checkArray[2] == 0);
1578
1579         // change
1580         LogInfo("Setting property 0");
1581         sho->SetProperty<0>(1);
1582         // wait for confirmations
1583         MultipleWait(waitable);
1584
1585         // change
1586         LogInfo("Setting property 1");
1587         sho->SetProperty<1>(11);
1588         // wait for confirmations
1589         MultipleWait(waitable);
1590
1591         // change
1592         LogInfo("Setting property 2");
1593         sho->SetProperty<2>('a');
1594         // wait for confirmations
1595         MultipleWait(waitable);
1596
1597         // change
1598         LogInfo("Setting property 3");
1599         sho->SetProperty<3>(array);
1600         // wait for confirmations
1601         MultipleWait(waitable);
1602
1603         // remove listeners
1604         LogInfo("Removing listeners");
1605         for (size_t i = 0; i < MAX_THREADS; ++i) {
1606             controller[i]->PostEvent(ShmController4::REMOVE_LISTENERS);
1607         }
1608         // wait for listeners
1609         MultipleWait(waitable);
1610
1611         // check if listeners array is empty
1612         LogInfo("Checking listeners");
1613         for (size_t i = 0; i < MAX_THREADS; ++i) {
1614             LISTENER_ASSERT(0);
1615             LISTENER_ASSERT(1);
1616             LISTENER_ASSERT(2);
1617             LISTENER_ASSERT(3);
1618         }
1619
1620         RUNNER_ASSERT((singleton->GetProperty<0, int>()) == 1);
1621         RUNNER_ASSERT((singleton->GetProperty<1, int>()) == 11);
1622         RUNNER_ASSERT((singleton->GetProperty<2, char>()) == 'a');
1623         singleton->GetProperty<3>(checkArray);
1624         RUNNER_ASSERT(checkArray[0] == 0);
1625         RUNNER_ASSERT(checkArray[1] == 1);
1626         RUNNER_ASSERT(checkArray[2] == 2);
1627     }
1628
1629     singleton.Reset();
1630
1631     // Destroy controllers and wait for confirmation. Make sure that
1632     // thread/controller 0 is destroyed in the end
1633     LogInfo("Destroying controllers");
1634     for (int i = MAX_THREADS - 1; i >= 0; --i) {
1635         controller[i]->PostEvent(DESTROY_EVENT);
1636         Wait(waitable[i]);
1637         if (i == 0) {
1638             /*
1639              * Destroy singleton before thread that created it finishes.
1640              * This is to properly close all waitable handles opened by
1641              * SharedObject in thread 0.
1642              */
1643             LogInfo("Destroying singleton");
1644             controller[i]->PostEvent(ShmController4::DESTROY_SINGLETON);
1645             Wait(waitable[i]);
1646         }
1647         delete controller[i];
1648     }
1649 }
1650
1651 #undef LISTENER_ASSERT
1652
1653 /*
1654  *  test preconditions & postconditions:
1655  *   - no existing shared memory with given SHM_KEY
1656  *   - no existing semaphore of given SEM_NAME
1657  */
1658 RUNNER_TEST(SharedMemory_001_Preconditions) {
1659     RemoveIpcs();
1660 }
1661
1662 RUNNER_TEST(SharedMemory_999_Postconditions) {
1663     RemoveIpcs();
1664 }