test_initialization.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. #include <vector>
  2. #include <numeric>
  3. #include <stdexcept>
  4. #include <string>
  5. #include "unity.h"
  6. #include "esp_log.h"
  7. #include "freertos/FreeRTOS.h"
  8. #include "freertos/task.h"
  9. #include "freertos/semphr.h"
  10. #include "soc/soc.h"
  11. static const char* TAG = "cxx";
  12. class NonPOD
  13. {
  14. public:
  15. NonPOD(int a_) : a(a_) { }
  16. int a;
  17. };
  18. static int non_pod_test_helper(int new_val)
  19. {
  20. static NonPOD non_pod(42);
  21. int ret = non_pod.a;
  22. non_pod.a = new_val;
  23. return ret;
  24. }
  25. TEST_CASE("can use static initializers for non-POD types", "[cxx]")
  26. {
  27. TEST_ASSERT_EQUAL(42, non_pod_test_helper(1));
  28. TEST_ASSERT_EQUAL(1, non_pod_test_helper(0));
  29. }
  30. /*
  31. * This test exercises static initialization guards for two objects.
  32. * For each object, 4 tasks are created which attempt to perform static initialization.
  33. * We check that constructor runs only once for each object.
  34. */
  35. static SemaphoreHandle_t s_slow_init_sem = NULL;
  36. template<int obj>
  37. class SlowInit
  38. {
  39. public:
  40. SlowInit(int arg) {
  41. ESP_LOGD(TAG, "init obj=%d start, arg=%d\n", obj, arg);
  42. vTaskDelay(300/portTICK_PERIOD_MS);
  43. TEST_ASSERT_EQUAL(-1, mInitBy);
  44. TEST_ASSERT_EQUAL(0, mInitCount);
  45. mInitBy = arg;
  46. ++mInitCount;
  47. ESP_LOGD(TAG, "init obj=%d done\n", obj);
  48. }
  49. static void task(void* arg) {
  50. int taskId = reinterpret_cast<int>(arg);
  51. ESP_LOGD(TAG, "obj=%d before static init, task=%d\n", obj, taskId);
  52. static SlowInit slowinit(taskId);
  53. ESP_LOGD(TAG, "obj=%d after static init, task=%d\n", obj, taskId);
  54. xSemaphoreGive(s_slow_init_sem);
  55. vTaskDelete(NULL);
  56. }
  57. private:
  58. static int mInitBy;
  59. static int mInitCount;
  60. };
  61. template<> int SlowInit<1>::mInitBy = -1;
  62. template<> int SlowInit<1>::mInitCount = 0;
  63. template<> int SlowInit<2>::mInitBy = -1;
  64. template<> int SlowInit<2>::mInitCount = 0;
  65. template<int obj>
  66. static int start_slow_init_task(int id, int affinity)
  67. {
  68. return xTaskCreatePinnedToCore(&SlowInit<obj>::task, "slow_init", 2048,
  69. reinterpret_cast<void*>(id), 3, NULL, affinity) ? 1 : 0;
  70. }
  71. TEST_CASE("static initialization guards work as expected", "[cxx]")
  72. {
  73. s_slow_init_sem = xSemaphoreCreateCounting(10, 0);
  74. TEST_ASSERT_NOT_NULL(s_slow_init_sem);
  75. int task_count = 0;
  76. // four tasks competing for static initialization of one object
  77. task_count += start_slow_init_task<1>(0, PRO_CPU_NUM);
  78. #if portNUM_PROCESSORS == 2
  79. task_count += start_slow_init_task<1>(1, APP_CPU_NUM);
  80. #endif
  81. task_count += start_slow_init_task<1>(2, PRO_CPU_NUM);
  82. task_count += start_slow_init_task<1>(3, tskNO_AFFINITY);
  83. // four tasks competing for static initialization of another object
  84. task_count += start_slow_init_task<2>(0, PRO_CPU_NUM);
  85. #if portNUM_PROCESSORS == 2
  86. task_count += start_slow_init_task<2>(1, APP_CPU_NUM);
  87. #endif
  88. task_count += start_slow_init_task<2>(2, PRO_CPU_NUM);
  89. task_count += start_slow_init_task<2>(3, tskNO_AFFINITY);
  90. // All tasks should
  91. for (int i = 0; i < task_count; ++i) {
  92. TEST_ASSERT_TRUE(xSemaphoreTake(s_slow_init_sem, 500/portTICK_PERIOD_MS));
  93. }
  94. vSemaphoreDelete(s_slow_init_sem);
  95. vTaskDelay(10); // Allow tasks to clean up, avoids race with leak detector
  96. }
  97. struct GlobalInitTest
  98. {
  99. GlobalInitTest() : index(order++) {
  100. }
  101. int index;
  102. static int order;
  103. };
  104. int GlobalInitTest::order = 0;
  105. GlobalInitTest g_init_test1;
  106. GlobalInitTest g_init_test2;
  107. GlobalInitTest g_init_test3;
  108. TEST_CASE("global initializers run in the correct order", "[cxx]")
  109. {
  110. TEST_ASSERT_EQUAL(0, g_init_test1.index);
  111. TEST_ASSERT_EQUAL(1, g_init_test2.index);
  112. TEST_ASSERT_EQUAL(2, g_init_test3.index);
  113. }
  114. struct StaticInitTestBeforeScheduler
  115. {
  116. StaticInitTestBeforeScheduler()
  117. {
  118. static int first_init_order = getOrder();
  119. index = first_init_order;
  120. }
  121. int getOrder()
  122. {
  123. return order++;
  124. }
  125. int index;
  126. static int order;
  127. };
  128. int StaticInitTestBeforeScheduler::order = 1;
  129. StaticInitTestBeforeScheduler g_static_init_test1;
  130. StaticInitTestBeforeScheduler g_static_init_test2;
  131. StaticInitTestBeforeScheduler g_static_init_test3;
  132. TEST_CASE("before scheduler has started, static initializers work correctly", "[cxx]")
  133. {
  134. TEST_ASSERT_EQUAL(1, g_static_init_test1.index);
  135. TEST_ASSERT_EQUAL(1, g_static_init_test2.index);
  136. TEST_ASSERT_EQUAL(1, g_static_init_test3.index);
  137. TEST_ASSERT_EQUAL(2, StaticInitTestBeforeScheduler::order);
  138. }
  139. struct PriorityInitTest
  140. {
  141. PriorityInitTest()
  142. {
  143. index = getOrder();
  144. }
  145. int getOrder()
  146. {
  147. return order++;
  148. }
  149. int index;
  150. static int order;
  151. };
  152. int PriorityInitTest::order = 0;
  153. // init_priority objects are initialized from the lowest to the heighest priority number
  154. // Default init_priority is always the lowest
  155. PriorityInitTest g_static_init_priority_test3;
  156. PriorityInitTest g_static_init_priority_test2 __attribute__((init_priority(1000)));
  157. PriorityInitTest g_static_init_priority_test1 __attribute__((init_priority(999)));
  158. TEST_CASE("init_priority extension works", "[cxx]")
  159. {
  160. TEST_ASSERT_EQUAL(0, g_static_init_priority_test1.index);
  161. TEST_ASSERT_EQUAL(1, g_static_init_priority_test2.index);
  162. TEST_ASSERT_EQUAL(2, g_static_init_priority_test3.index);
  163. }