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