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