ChibiOS/RT Architecture - Reference Manual - Guides |
00001 /* 00002 ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio. 00003 00004 This file is part of ChibiOS/RT. 00005 00006 ChibiOS/RT is free software; you can redistribute it and/or modify 00007 it under the terms of the GNU General Public License as published by 00008 the Free Software Foundation; either version 3 of the License, or 00009 (at your option) any later version. 00010 00011 ChibiOS/RT is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU General Public License for more details. 00015 00016 You should have received a copy of the GNU General Public License 00017 along with this program. If not, see <http://www.gnu.org/licenses/>. 00018 00019 --- 00020 00021 A special exception to the GPL can be applied should you wish to distribute 00022 a combined work that includes ChibiOS/RT, without being obliged to provide 00023 the source code for any proprietary components. See the file exception.txt 00024 for full details of how and when the exception can be applied. 00025 */ 00026 00027 #include "ch.h" 00028 #include "test.h" 00029 00030 /** 00031 * @page test_dynamic Dynamic APIs test 00032 * 00033 * File: @ref testdyn.c 00034 * 00035 * <h2>Description</h2> 00036 * This module implements the test sequence for the dynamic thread creation 00037 * APIs. 00038 * 00039 * <h2>Objective</h2> 00040 * Objective of the test module is to cover 100% of the dynamic APIs code. 00041 * 00042 * <h2>Preconditions</h2> 00043 * The module requires the following kernel options: 00044 * - @p CH_USE_DYNAMIC 00045 * - @p CH_USE_HEAP 00046 * - @p CH_USE_MEMPOOLS 00047 * . 00048 * In case some of the required options are not enabled then some or all tests 00049 * may be skipped. 00050 * 00051 * <h2>Test Cases</h2> 00052 * - @subpage test_dynamic_001 00053 * - @subpage test_dynamic_002 00054 * - @subpage test_dynamic_003 00055 * . 00056 * @file testdyn.c 00057 * @brief Dynamic thread APIs test source file 00058 * @file testdyn.h 00059 * @brief Dynamic thread APIs test header file 00060 */ 00061 00062 #if CH_USE_DYNAMIC 00063 #if CH_USE_HEAP 00064 static MemoryHeap heap1; 00065 #endif 00066 #if CH_USE_MEMPOOLS 00067 static MemoryPool mp1; 00068 #endif 00069 00070 /** 00071 * @page test_dynamic_001 Threads creation from Memory Heap 00072 * 00073 * <h2>Description</h2> 00074 * Two threads are started by allocating the memory from the Memory Heap then 00075 * the remaining heap space is arbitrarily allocated and a third tread startup 00076 * is attempted.<br> 00077 * The test expects the first two threads to successfully start and the last 00078 * one to fail. 00079 */ 00080 00081 static msg_t thread(void *p) { 00082 00083 test_emit_token(*(char *)p); 00084 return 0; 00085 } 00086 00087 #if CH_USE_HEAP 00088 static char *dyn1_gettest(void) { 00089 00090 return "Dynamic APIs, threads creation from heap"; 00091 } 00092 00093 static void dyn1_setup(void) { 00094 00095 chHeapInit(&heap1, test.buffer, sizeof(union test_buffers)); 00096 } 00097 00098 static void dyn1_execute(void) { 00099 size_t n, sz; 00100 void *p1; 00101 tprio_t prio = chThdGetPriority(); 00102 00103 (void)chHeapStatus(&heap1, &sz); 00104 /* Starting threads from the heap. */ 00105 threads[0] = chThdCreateFromHeap(&heap1, THD_WA_SIZE(THREADS_STACK_SIZE), 00106 prio-1, thread, "A"); 00107 threads[1] = chThdCreateFromHeap(&heap1, THD_WA_SIZE(THREADS_STACK_SIZE), 00108 prio-2, thread, "B"); 00109 /* Allocating the whole heap in order to make the thread creation fail.*/ 00110 (void)chHeapStatus(&heap1, &n); 00111 p1 = chHeapAlloc(&heap1, n); 00112 threads[2] = chThdCreateFromHeap(&heap1, THD_WA_SIZE(THREADS_STACK_SIZE), 00113 prio-3, thread, "C"); 00114 chHeapFree(p1); 00115 00116 test_assert(1, (threads[0] != NULL) && 00117 (threads[1] != NULL) && 00118 (threads[2] == NULL) && 00119 (threads[3] == NULL) && 00120 (threads[4] == NULL), 00121 "thread creation failed"); 00122 00123 /* Claiming the memory from terminated threads. */ 00124 test_wait_threads(); 00125 test_assert_sequence(2, "AB"); 00126 00127 /* Heap status checked again.*/ 00128 test_assert(3, chHeapStatus(&heap1, &n) == 1, "heap fragmented"); 00129 test_assert(4, n == sz, "heap size changed"); 00130 } 00131 00132 const struct testcase testdyn1 = { 00133 dyn1_gettest, 00134 dyn1_setup, 00135 NULL, 00136 dyn1_execute 00137 }; 00138 #endif /* CH_USE_HEAP */ 00139 00140 #if CH_USE_MEMPOOLS 00141 /** 00142 * @page test_dynamic_002 Threads creation from Memory Pool 00143 * 00144 * <h2>Description</h2> 00145 * Five thread creation are attempted from a pool containing only four 00146 * elements.<br> 00147 * The test expects the first four threads to successfully start and the last 00148 * one to fail. 00149 */ 00150 00151 static char *dyn2_gettest(void) { 00152 00153 return "Dynamic APIs, threads creation from memory pool"; 00154 } 00155 00156 static void dyn2_setup(void) { 00157 00158 chPoolInit(&mp1, THD_WA_SIZE(THREADS_STACK_SIZE), NULL); 00159 } 00160 00161 static void dyn2_execute(void) { 00162 int i; 00163 tprio_t prio = chThdGetPriority(); 00164 00165 /* Adding the WAs to the pool. */ 00166 for (i = 0; i < 4; i++) 00167 chPoolFree(&mp1, wa[i]); 00168 00169 /* Starting threads from the memory pool. */ 00170 threads[0] = chThdCreateFromMemoryPool(&mp1, prio-1, thread, "A"); 00171 threads[1] = chThdCreateFromMemoryPool(&mp1, prio-2, thread, "B"); 00172 threads[2] = chThdCreateFromMemoryPool(&mp1, prio-3, thread, "C"); 00173 threads[3] = chThdCreateFromMemoryPool(&mp1, prio-4, thread, "D"); 00174 threads[4] = chThdCreateFromMemoryPool(&mp1, prio-5, thread, "E"); 00175 00176 test_assert(1, (threads[0] != NULL) && 00177 (threads[1] != NULL) && 00178 (threads[2] != NULL) && 00179 (threads[3] != NULL) && 00180 (threads[4] == NULL), 00181 "thread creation failed"); 00182 00183 /* Claiming the memory from terminated threads. */ 00184 test_wait_threads(); 00185 test_assert_sequence(2, "ABCD"); 00186 00187 /* Now the pool must be full again. */ 00188 for (i = 0; i < 4; i++) 00189 test_assert(3, chPoolAlloc(&mp1) != NULL, "pool list empty"); 00190 test_assert(4, chPoolAlloc(&mp1) == NULL, "pool list not empty"); 00191 } 00192 00193 const struct testcase testdyn2 = { 00194 dyn2_gettest, 00195 dyn2_setup, 00196 NULL, 00197 dyn2_execute 00198 }; 00199 #endif /* CH_USE_MEMPOOLS */ 00200 00201 #if CH_USE_HEAP && CH_USE_REGISTRY 00202 /** 00203 * @page test_dynamic_003 Registry and References test 00204 * 00205 * <h2>Description</h2> 00206 * Registry and Thread References APIs are tested for functionality and 00207 * coverage. 00208 */ 00209 00210 static unsigned regscan(void) { 00211 Thread *tp; 00212 unsigned i = 0; 00213 00214 tp = chRegFirstThread(); 00215 do { 00216 i++; 00217 tp = chRegNextThread(tp); 00218 } while (tp != NULL); 00219 return i; 00220 } 00221 00222 static char *dyn3_gettest(void) { 00223 00224 return "Dynamic APIs, registry and references"; 00225 } 00226 00227 static void dyn3_setup(void) { 00228 00229 chHeapInit(&heap1, test.buffer, sizeof(union test_buffers)); 00230 } 00231 00232 static void dyn3_execute(void) { 00233 unsigned n1, n2, n3; 00234 Thread *tp; 00235 tprio_t prio = chThdGetPriority(); 00236 00237 /* Current number of threads in the system, two times just in case some 00238 external detached thread terminated.*/ 00239 (void)regscan(); 00240 n1 = regscan(); 00241 00242 /* Testing references increase/decrease and final detach.*/ 00243 tp = chThdCreateFromHeap(&heap1, WA_SIZE, prio-1, thread, "A"); 00244 test_assert(1, tp->p_refs == 1, "wrong initial reference counter"); 00245 chThdAddRef(tp); 00246 test_assert(2, tp->p_refs == 2, "references increase failure"); 00247 chThdRelease(tp); 00248 test_assert(3, tp->p_refs == 1, "references decrease failure"); 00249 00250 /* Verify the new threads count.*/ 00251 n2 = regscan(); 00252 test_assert(4, n1 == n2 - 1, "unexpected threads count"); 00253 00254 /* Detach and let the thread execute and terminate.*/ 00255 chThdRelease(tp); 00256 test_assert(5, tp->p_refs == 0, "detach failure"); 00257 chThdSleepMilliseconds(50); /* The thread just terminates. */ 00258 test_assert(6, tp->p_state == THD_STATE_FINAL, "invalid state"); 00259 00260 /* Clearing the zombie by scanning the registry.*/ 00261 n3 = regscan(); 00262 test_assert(7, n1 == n3, "unexpected threads count"); 00263 } 00264 00265 const struct testcase testdyn3 = { 00266 dyn3_gettest, 00267 dyn3_setup, 00268 NULL, 00269 dyn3_execute 00270 }; 00271 #endif /* CH_USE_HEAP && CH_USE_REGISTRY */ 00272 #endif /* CH_USE_DYNAMIC */ 00273 00274 /** 00275 * @brief Test sequence for dynamic APIs. 00276 */ 00277 const struct testcase * const patterndyn[] = { 00278 #if CH_USE_DYNAMIC 00279 #if CH_USE_HEAP 00280 &testdyn1, 00281 #endif 00282 #if CH_USE_MEMPOOLS 00283 &testdyn2, 00284 #endif 00285 #if CH_USE_HEAP && CH_USE_REGISTRY 00286 &testdyn3, 00287 #endif 00288 #endif 00289 NULL 00290 };