Merge "Clean up the code to build successfully on macOS" into devel/master
[platform/core/uifw/dali-core.git] / automated-tests / src / dali / utc-Dali-Mutex.cpp
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd.
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
18 #include <dali-test-suite-utils.h>
19 #include <dali/devel-api/threading/mutex.h>
20 #include <dali/devel-api/threading/thread.h>
21 #include <dali/public-api/dali-core.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24
25 #include <iostream>
26 #include <type_traits>
27 #include <utility>
28
29 using Dali::Mutex;
30 using Dali::Thread;
31
32 int UtcDaliMutexSingleThread(void)
33 {
34   tet_infoline("Testing Dali::Mutex in a single thread");
35
36   {
37     Mutex mutex1;
38     DALI_TEST_EQUALS(false, mutex1.IsLocked(), TEST_LOCATION);
39   }
40
41   {
42     Mutex             mutex2;
43     Mutex::ScopedLock lock(mutex2);
44     DALI_TEST_EQUALS(true, mutex2.IsLocked(), TEST_LOCATION);
45   }
46
47   Mutex mutex3;
48   {
49     Mutex::ScopedLock lock(mutex3);
50   }
51   DALI_TEST_EQUALS(false, mutex3.IsLocked(), TEST_LOCATION);
52
53   {
54     Mutex mutex4;
55     Mutex mutex5(std::move(mutex4)); // move constructor
56     Mutex::ScopedLock lock(mutex5);
57     DALI_TEST_EQUALS(true, mutex5.IsLocked(), TEST_LOCATION);
58   }
59
60   {
61     Mutex mutex4, mutex5;
62     mutex5 = std::move(mutex4); // move assignment
63     Mutex::ScopedLock lock(mutex5);
64     DALI_TEST_EQUALS(true, mutex5.IsLocked(), TEST_LOCATION);
65   }
66
67   END_TEST;
68 }
69
70 namespace // for local variables to avoid name clashes
71 {
72 // make all these volatile to pre-empt any optimization screwing up the logic
73 volatile int  gGlobalValue                                 = 0;
74 volatile bool gWorkerThreadWait                            = true;
75 volatile enum ThreadState { INIT,
76                             RUN,
77                             LOCKING,
78                             TERMINATE } gWorkerThreadState = INIT;
79 Mutex* volatile gGlobalValueMutex; // volatile pointer to a mutex object
80
81 class TestThread : public Thread
82 {
83   virtual void Run()
84   {
85     gWorkerThreadState = RUN;
86     {
87       Mutex::ScopedLock lock(*gGlobalValueMutex);
88       gWorkerThreadState = LOCKING;
89       gGlobalValue       = -1;
90       while(gWorkerThreadWait) // wait till we can exit
91       {
92         usleep(1); // 1 microsecond
93       }
94     }
95     gWorkerThreadState = TERMINATE;
96   }
97 };
98 } // namespace
99
100 int UtcDaliMutexMultiThread(void)
101 {
102   tet_infoline("Testing Dali::Mutex multithreaded");
103
104   gGlobalValueMutex = new Dali::Mutex();
105
106   TestThread thread1;
107   // initialize values
108   gGlobalValue      = 0;
109   gWorkerThreadWait = true;
110   DALI_TEST_EQUALS(INIT, gWorkerThreadState, TEST_LOCATION);
111   DALI_TEST_EQUALS(0, gGlobalValue, TEST_LOCATION);
112   DALI_TEST_EQUALS(false, gGlobalValueMutex->IsLocked(), TEST_LOCATION);
113
114   // lock the mutex
115   {
116     Mutex::ScopedLock lock(*gGlobalValueMutex);
117     DALI_TEST_EQUALS(true, gGlobalValueMutex->IsLocked(), TEST_LOCATION);
118     thread1.Start();
119     // wait till the thread is in run state
120     while(RUN != gWorkerThreadState)
121     {
122       usleep(1); // 1 microsecond
123     }
124     // now the thread is running and mutex is still locked by this thread so value is not changed
125     DALI_TEST_EQUALS(true, gGlobalValueMutex->IsLocked(), TEST_LOCATION);
126     DALI_TEST_EQUALS(0, gGlobalValue, TEST_LOCATION);
127     // drop out of scope, releases our lock
128   }
129   // now child thread is allowed to change the value
130   // wait till the thread is in locking state
131   while(LOCKING != gWorkerThreadState)
132   {
133     usleep(1); // 1 microsecond
134   }
135   // mutex is locked, but not by us, by the child thread
136   DALI_TEST_EQUALS(true, gGlobalValueMutex->IsLocked(), TEST_LOCATION);
137   // value is changed
138   DALI_TEST_EQUALS(-1, gGlobalValue, TEST_LOCATION);
139   // let worker finish
140   gWorkerThreadWait = false;
141   // wait till the thread is terminated state
142   while(TERMINATE != gWorkerThreadState)
143   {
144     usleep(1); // 1 microsecond
145   }
146   DALI_TEST_EQUALS(false, gGlobalValueMutex->IsLocked(), TEST_LOCATION);
147   thread1.Join();
148
149   END_TEST;
150 }
151
152 int UtcDaliMutexNonCopyable(void)
153 {
154   // we want to make sure that mutex is not copyable (its copy constructor is not defined)
155   // this test will stop compiling if Mutex has compiler generated copy constructor
156   static_assert(!__has_trivial_copy(Mutex), "Mutex should NOT be copyable");
157
158   DALI_TEST_CHECK(true);
159   END_TEST;
160 }