Remove unused pkg dependancy
[platform/upstream/iotivity.git] / resource / csdk / connectivity / test / octhread_tests.cpp
1 //******************************************************************
2 //
3 // Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20 //
21 //
22 //*********************************************************************
23
24 // Defining _POSIX_C_SOURCE macro with 200809L (or greater) as value
25 // causes header files to expose definitions
26 // corresponding to the POSIX.1-2008 base
27 // specification (excluding the XSI extension).
28 // For POSIX.1-2008 base specification,
29 // Refer http://pubs.opengroup.org/stage7tc1/
30 //
31 // For this specific file, see use of usleep
32 #ifndef _POSIX_C_SOURCE
33 #define _POSIX_C_SOURCE 200809L
34 #endif // _POSIX_C_SOURCE
35
36 #include "iotivity_config.h"
37 #include "gtest/gtest.h"
38
39 #include "octhread.h"
40 #include <cathreadpool.h>
41
42 #ifdef HAVE_TIME_H
43 #include <time.h>
44 #endif
45 #ifdef HAVE_SYS_TIME_H
46 #include <sys/time.h>
47 #endif
48 #ifdef HAVE_UNISTD_H
49 #include <unistd.h>
50 #endif
51 #ifdef HAVE_WINDOWS_H
52 #include <windows.h>
53 #endif
54
55 #define HNS_PER_US 10
56
57 //#define DEBUG_VERBOSE 1
58
59 // The debug print lines are left in for now since the output can be
60 // helpful for developers trying to debug or extend the tests.
61 // However, by default they are #defined out so as not to get in
62 // the way of normal test runs.
63 #ifdef DEBUG_VERBOSE
64 #define DBG_printf(...) printf(__VA_ARGS__)
65 #else
66 #define DBG_printf(...)
67 #endif
68
69 static const uint64_t USECS_PER_SEC = 1000000;
70
71 static const uint64_t USECS_PER_MSEC = 1000;
72
73 static const int MINIMAL_LOOP_SLEEP = 20;
74 static const int MINIMAL_EXTRA_SLEEP = 25;
75
76 uint64_t getAbsTime()
77 {
78     uint64_t currentTime=0;
79 #if _POSIX_TIMERS > 0
80     struct timespec ts;
81     clock_gettime(CLOCK_MONOTONIC, &ts);
82     currentTime = ts.tv_sec * USECS_PER_SEC + ts.tv_nsec / 1000;
83 #elif defined(_WIN32)
84     FILETIME time;
85     ULARGE_INTEGER microseconds;
86
87     GetSystemTimeAsFileTime(&time);
88
89     // Time is in hundreds of nanoseconds, so we must convert to uS
90     microseconds.LowPart = time.dwLowDateTime;
91     microseconds.HighPart = time.dwHighDateTime;
92     microseconds.QuadPart /= HNS_PER_US;
93
94     currentTime = microseconds.QuadPart;
95 #else
96     struct timeval tv;
97     gettimeofday(&tv, NULL);
98     currentTime = tv.tv_sec * USECS_PER_SEC + tv.tv_usec;
99 #endif
100     return currentTime;
101 }
102
103 TEST(MutexTests, TC_01_CREATE)
104 {
105     oc_mutex mymutex = oc_mutex_new();
106
107     EXPECT_TRUE(mymutex != NULL);
108     if (mymutex != NULL)
109     {
110         oc_mutex_free(mymutex);
111     }
112 }
113
114 typedef struct _tagFunc1
115 {
116     oc_mutex mutex;
117     volatile bool thread_up;
118     volatile bool finished;
119 } _func1_struct;
120
121 void mutexFunc(void *context)
122 {
123     _func1_struct* pData = (_func1_struct*) context;
124
125     DBG_printf("Thread: trying to lock\n");
126
127     // setting the flag must be done before lock attempt, as the test
128     // thread starts off with the mutex locked
129     pData->thread_up = true;
130     oc_mutex_lock(pData->mutex);
131
132     DBG_printf("Thread: got lock\n");
133     usleep(MINIMAL_LOOP_SLEEP * USECS_PER_MSEC);
134     DBG_printf("Thread: releasing\n");
135
136     pData->finished = true; // assignment guarded by lock
137
138     oc_mutex_unlock(pData->mutex);
139 }
140
141 TEST(MutexTests, TC_03_THREAD_LOCKING)
142 {
143     ca_thread_pool_t mythreadpool;
144
145     EXPECT_EQ(CA_STATUS_OK, ca_thread_pool_init(3, &mythreadpool));
146
147     _func1_struct pData = {0, false, false};
148
149     pData.mutex = oc_mutex_new();
150
151     EXPECT_TRUE(pData.mutex != NULL);
152     if (pData.mutex != NULL)
153     {
154         DBG_printf("test: Holding mutex in test\n");
155         oc_mutex_lock(pData.mutex);
156
157         DBG_printf("test: starting thread\n");
158         //start thread
159         EXPECT_EQ(CA_STATUS_OK,
160                   ca_thread_pool_add_task(mythreadpool, mutexFunc, &pData, NULL));
161
162         DBG_printf("test: waiting for thread to be up.\n");
163
164         while (!pData.thread_up)
165         {
166             usleep(MINIMAL_LOOP_SLEEP * USECS_PER_MSEC);
167         }
168         // At this point the thread is running and close to trying to lock.
169         // For test purposes only, use of condition variables is being avoided,
170         // so a minor sleep is used.
171         usleep(MINIMAL_EXTRA_SLEEP * USECS_PER_MSEC);
172
173         DBG_printf("test: unlocking\n");
174
175         oc_mutex_unlock(pData.mutex);
176
177         DBG_printf("test: waiting for thread to release\n");
178         while (!pData.finished)
179         {
180             usleep(MINIMAL_LOOP_SLEEP * USECS_PER_MSEC);
181         }
182
183         oc_mutex_lock(pData.mutex);
184
185         // Cleanup Everything
186
187         oc_mutex_unlock(pData.mutex);
188         oc_mutex_free(pData.mutex);
189     }
190
191     ca_thread_pool_free(mythreadpool);
192 }
193
194 TEST(ConditionTests, TC_01_CREATE)
195 {
196     oc_cond mycond = oc_cond_new();
197
198     EXPECT_TRUE(mycond != NULL);
199     if (mycond != NULL)
200     {
201         oc_cond_free(mycond);
202     }
203 }
204
205 // Normally we would use one pair of mutex/cond-var communicating to the
206 // worker threads and one pair back to the main thread. However since
207 // testing the oc_cond itself is the point, only one pair is used here.
208 typedef struct _tagFunc2
209 {
210     int id;
211     oc_mutex mutex;
212     oc_cond condition;
213     volatile bool thread_up;
214     volatile bool finished;
215 } _func2_struct;
216
217 void condFunc(void *context)
218 {
219     _func2_struct* pData = (_func2_struct*) context;
220
221     DBG_printf("Thread_%d: waiting on condition\n", pData->id);
222
223     oc_mutex_lock(pData->mutex);
224
225     pData->thread_up = true;
226
227     oc_cond_wait(pData->condition, pData->mutex);
228
229     pData->finished = true; // assignment guarded by lock
230
231     oc_mutex_unlock(pData->mutex);
232
233     DBG_printf("Thread_%d: completed.\n", pData->id);
234 }
235
236 #ifdef _WIN32
237 /** @todo: Enable.  Need to solve nanosleep issue */
238 TEST(ConditionTests, DISABLED_TC_02_SIGNAL)
239 #else
240 TEST(ConditionTests, TC_02_SIGNAL)
241 #endif
242 {
243     const int MAX_WAIT_MS = 2000;
244     ca_thread_pool_t mythreadpool;
245
246     EXPECT_EQ(CA_STATUS_OK, ca_thread_pool_init(3, &mythreadpool));
247
248     oc_mutex sharedMutex = oc_mutex_new();
249     oc_cond sharedCond = oc_cond_new();
250
251     _func2_struct pData1 =
252     { 1, sharedMutex, sharedCond, false, false };
253     _func2_struct pData2 =
254     { 2, sharedMutex, sharedCond, false, false };
255
256     EXPECT_TRUE(pData1.mutex != NULL);
257     if (pData1.mutex != NULL)
258     {
259         DBG_printf("starting thread\n");
260         // start threads
261         EXPECT_EQ(CA_STATUS_OK,
262                   ca_thread_pool_add_task(mythreadpool, condFunc, &pData1, NULL));
263         EXPECT_EQ(CA_STATUS_OK,
264                   ca_thread_pool_add_task(mythreadpool, condFunc, &pData2, NULL));
265
266         DBG_printf("test    : sleeping\n");
267
268         while (!pData1.thread_up || !pData2.thread_up)
269         {
270             // For test purposes only, use of condition variables is being
271             // avoided, so a minor sleep is used.
272             usleep(MINIMAL_LOOP_SLEEP * USECS_PER_MSEC);
273         }
274         // At this point the threads are running and both have locked. One
275         // has already started waiting on the condition and the other is at
276         // least close.
277
278         oc_mutex_lock(sharedMutex);
279         // once the lock is acquired it means both threads were waiting.
280         DBG_printf("test    : signaling first thread\n");
281         oc_cond_signal(sharedCond);
282         oc_mutex_unlock(sharedMutex);
283
284         // At this point either of the child threads might lock the mutex in
285         // their cond_wait call, or this test thread might lock it again if
286         // mutex_lock gets executed before the child threads can react to
287         // the signaling. Thus we wait on their flag variables
288         int waitCount = 1; // start with 1 for minumum targetWait value.
289         while (!pData1.finished && !pData2.finished)
290         {
291             usleep(MINIMAL_LOOP_SLEEP * USECS_PER_MSEC);
292             waitCount++;
293         }
294
295         // As a rough hueristic wait twice as long for the second to possibly
296         // finish:
297         int targetWait = waitCount * 2;
298         for (int i = 0;
299              (i < targetWait) && (!pData1.finished && !pData2.finished); i++)
300         {
301             usleep(MINIMAL_LOOP_SLEEP * USECS_PER_MSEC);
302         }
303         usleep(MINIMAL_EXTRA_SLEEP);
304
305         // only one should be finished
306         oc_mutex_lock(sharedMutex);
307         EXPECT_NE(pData1.finished, pData2.finished);
308         oc_mutex_unlock(sharedMutex);
309
310         DBG_printf("test    : signaling another thread\n");
311
312         oc_mutex_lock(sharedMutex);
313         oc_cond_signal(sharedCond);
314         oc_mutex_unlock(sharedMutex);
315
316         waitCount = 0;
317         while ((!pData1.finished || !pData2.finished)
318                && ((waitCount * MINIMAL_EXTRA_SLEEP) < MAX_WAIT_MS))
319         {
320             usleep(MINIMAL_LOOP_SLEEP * USECS_PER_MSEC);
321             waitCount++;
322         }
323
324         // both should finally be finished
325         EXPECT_TRUE(pData1.finished);
326         EXPECT_TRUE(pData2.finished);
327
328         // Cleanup Everything
329
330         oc_mutex_free(pData1.mutex);
331     }
332
333     oc_cond_free(pData1.condition);
334
335     ca_thread_pool_free(mythreadpool);
336 }
337
338 TEST(ConditionTests, TC_03_BROADCAST)
339 {
340     const int MAX_WAIT_MS = 2000;
341     ca_thread_pool_t mythreadpool;
342
343     EXPECT_EQ(CA_STATUS_OK, ca_thread_pool_init(3, &mythreadpool));
344
345     oc_mutex sharedMutex = oc_mutex_new();
346     oc_cond sharedCond = oc_cond_new();
347
348     _func2_struct pData1 =
349     { 1, sharedMutex, sharedCond, false, false };
350     _func2_struct pData2 =
351     { 2, sharedMutex, sharedCond, false, false };
352
353     EXPECT_TRUE(pData1.mutex != NULL);
354     if (pData1.mutex != NULL)
355     {
356         DBG_printf("starting thread\n");
357         // start threads
358         EXPECT_EQ(CA_STATUS_OK,
359                   ca_thread_pool_add_task(mythreadpool, condFunc, &pData1, NULL));
360         EXPECT_EQ(CA_STATUS_OK,
361                   ca_thread_pool_add_task(mythreadpool, condFunc, &pData2, NULL));
362
363         DBG_printf("test    : sleeping\n");
364
365         while (!pData1.thread_up || !pData2.thread_up)
366         {
367             // For test purposes only, use of condition variables is being
368             // avoided, so a minor sleep is used.
369             usleep(MINIMAL_LOOP_SLEEP * USECS_PER_MSEC);
370         }
371         // At this point the threads are running and both have locked. One
372         // has already started waiting on the condition and the other is at
373         // least close.
374
375         DBG_printf("test    : signaling all threads\n");
376
377         oc_mutex_lock(sharedMutex);
378         // once the lock is acquired it means both threads were waiting.
379         oc_cond_broadcast(sharedCond);
380         oc_mutex_unlock(sharedMutex);
381
382         int waitCount = 0;
383         while ((!pData1.finished || !pData2.finished)
384                && ((waitCount * MINIMAL_EXTRA_SLEEP) < MAX_WAIT_MS))
385         {
386             usleep(MINIMAL_LOOP_SLEEP * USECS_PER_MSEC);
387             waitCount++;
388         }
389
390         // both should finally be finished
391         EXPECT_TRUE(pData1.finished);
392         EXPECT_TRUE(pData2.finished);
393
394         // Cleanup Everything
395
396         oc_mutex_free(sharedMutex);
397     }
398
399     oc_cond_free(sharedCond);
400
401     ca_thread_pool_free(mythreadpool);
402 }
403
404 #ifdef _WIN32
405 /** @todo: Enable.  Need to solve nanosleep issue */
406 TEST(ConditionTests, DISABLED_TC_04_TIMECHECK)
407 #else
408 TEST(ConditionTests, TC_04_TIMECHECK)
409 #endif
410 {
411     uint64_t begin = getAbsTime();
412
413     usleep(1);
414
415     uint64_t end = getAbsTime();
416
417     EXPECT_LT(begin, end); // should never be the same value
418 }
419
420 void timedFunc(void *context)
421 {
422     _func2_struct* pData = (_func2_struct*) context;
423
424     DBG_printf("Thread_%d: waiting for timeout \n", pData->id);
425
426     oc_mutex_lock(pData->mutex);
427
428     uint64_t abs = USECS_PER_SEC / 2; // 1/2 seconds
429
430     // test UTIMEDOUT
431     OCWaitResult_t ret = oc_cond_wait_for(pData->condition,
432                                           pData->mutex, abs);
433     EXPECT_EQ(OC_WAIT_TIMEDOUT, ret);
434
435     pData->thread_up = true;
436
437     DBG_printf("Thread_%d: waiting for signal \n", pData->id);
438
439     abs = 5 * USECS_PER_SEC; // 5 seconds
440
441     // test signal
442     ret = oc_cond_wait_for(pData->condition, pData->mutex, abs);
443     EXPECT_EQ(OC_WAIT_SUCCESS, ret);
444
445     pData->finished = true; // assignment guarded by lock
446
447     oc_mutex_unlock(pData->mutex);
448
449     DBG_printf("Thread_%d: stopping\n", pData->id);
450 }
451
452 TEST(ConditionTests, TC_05_WAIT)
453 {
454     const int MAX_WAIT_MS = 5000;
455     ca_thread_pool_t mythreadpool;
456
457     EXPECT_EQ(CA_STATUS_OK, ca_thread_pool_init(3, &mythreadpool));
458
459     oc_mutex sharedMutex = oc_mutex_new();
460     oc_cond sharedCond = oc_cond_new();
461
462     _func2_struct pData1 =
463     { 1, sharedMutex, sharedCond, false, false };
464
465     EXPECT_TRUE(sharedMutex != NULL);
466     if (sharedMutex != NULL)
467     {
468         DBG_printf("test    : starting thread\n");
469         //start thread
470         EXPECT_EQ(CA_STATUS_OK,
471                   ca_thread_pool_add_task(mythreadpool, timedFunc, &pData1, NULL));
472
473         DBG_printf("test    : waiting for thread to timeout once.\n");
474
475         while (!pData1.thread_up)
476         {
477             // For test purposes only, use of condition variables is being
478             // avoided, so a minor sleep is used.
479             usleep(MINIMAL_LOOP_SLEEP * USECS_PER_MSEC);
480         }
481
482
483         DBG_printf("test    : signaling first thread\n");
484
485         oc_mutex_lock(sharedMutex);
486         oc_cond_signal(sharedCond);
487         oc_mutex_unlock(sharedMutex);
488
489         int waitCount = 0;
490         while (!pData1.finished
491                && ((waitCount * MINIMAL_EXTRA_SLEEP) < MAX_WAIT_MS))
492         {
493             usleep(MINIMAL_LOOP_SLEEP * USECS_PER_MSEC);
494             waitCount++;
495         }
496
497         EXPECT_TRUE(pData1.finished); // thread should finally be finished
498
499         // Cleanup Everything
500
501         oc_mutex_free(sharedMutex);
502     }
503
504     oc_cond_free(sharedCond);
505
506     ca_thread_pool_free(mythreadpool);
507 }
508
509 // Disabled because this should no longer be a valid test
510 TEST(ConditionTests, DISABLED_TC_06_INVALIDWAIT)
511 {
512
513     oc_mutex sharedMutex = oc_mutex_new();
514     oc_cond sharedCond = oc_cond_new();
515
516     oc_mutex_lock(sharedMutex);
517
518     int ret = oc_cond_wait_for(NULL, sharedMutex, 5000);
519     EXPECT_EQ(OC_WAIT_INVAL,ret);
520
521     ret = oc_cond_wait_for(sharedCond, NULL, 5000);
522     EXPECT_EQ(OC_WAIT_INVAL,ret);
523
524     ret = oc_cond_wait_for(NULL, NULL, 5000);
525     EXPECT_EQ(OC_WAIT_INVAL,ret);
526
527     oc_mutex_unlock(sharedMutex);
528
529     // Cleanup Everything
530
531     oc_mutex_free(sharedMutex);
532
533     oc_cond_free(sharedCond);
534 }
535
536 TEST(ConditionTests, TC_07_WAITDURATION)
537 {
538     const double TARGET_WAIT = 1.125;
539
540     oc_mutex sharedMutex = oc_mutex_new();
541     oc_cond sharedCond = oc_cond_new();
542
543     oc_mutex_lock(sharedMutex);
544
545     uint64_t beg = getAbsTime();
546
547     OCWaitResult_t ret = oc_cond_wait_for(sharedCond, sharedMutex,
548                                           TARGET_WAIT * USECS_PER_SEC);
549     EXPECT_EQ(OC_WAIT_TIMEDOUT,ret);
550
551     uint64_t end = getAbsTime();
552
553     double secondsDiff = (end - beg) / (double) USECS_PER_SEC;
554
555 #ifdef _WIN32
556     // Windows does not guarantee that the thread will resume execution from a
557     // yield within any given time frame. We will assume that the threads
558     // should have resumed within one second of the requested timeout value.
559     EXPECT_NEAR(TARGET_WAIT, secondsDiff, 1.00);
560 #else
561     EXPECT_NEAR(TARGET_WAIT, secondsDiff, 0.05);
562 #endif
563
564     oc_mutex_unlock(sharedMutex);
565
566     // Cleanup Everything
567
568     oc_mutex_free(sharedMutex);
569
570     oc_cond_free(sharedCond);
571 }