main.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. /* This is a small demo of the high-performance ThreadX kernel. It includes examples of eight
  2. threads of different priorities, using a message queue, semaphore, mutex, event flags group,
  3. byte pool, and block pool. */
  4. #include "tx_api.h"
  5. #include <stdio.h>
  6. #define DEMO_STACK_SIZE 1024
  7. #define DEMO_BYTE_POOL_SIZE 10240
  8. #define DEMO_BLOCK_POOL_SIZE 100
  9. #define DEMO_QUEUE_SIZE 100
  10. // NOTE don't turn on all the debug, it really cost time
  11. // just turn on one and keep others close to see whether thread is running
  12. //#define DEBUG_THREAD_0
  13. //#define DEBUG_THREAD_1
  14. //#define DEBUG_THREAD_2
  15. //#define DEBUG_THREAD_3_4
  16. //#define DEBUG_THREAD_5
  17. #define DEBUG_THREAD_6_7
  18. /* Define the ThreadX object control blocks... */
  19. TX_THREAD thread_0;
  20. TX_THREAD thread_1;
  21. TX_THREAD thread_2;
  22. TX_THREAD thread_3;
  23. TX_THREAD thread_4;
  24. TX_THREAD thread_5;
  25. TX_THREAD thread_6;
  26. TX_THREAD thread_7;
  27. TX_QUEUE queue_0;
  28. TX_SEMAPHORE semaphore_0;
  29. TX_MUTEX mutex_0;
  30. TX_EVENT_FLAGS_GROUP event_flags_0;
  31. TX_BYTE_POOL byte_pool_0;
  32. TX_BLOCK_POOL block_pool_0;
  33. // This is an memory area used by ThreadX to allocate for task stacks and etc
  34. UCHAR memory_area[DEMO_BYTE_POOL_SIZE];
  35. /* Define the counters used in the demo application... */
  36. ULONG thread_0_counter;
  37. ULONG thread_1_counter;
  38. ULONG thread_1_messages_sent;
  39. ULONG thread_2_counter;
  40. ULONG thread_2_messages_received;
  41. ULONG thread_3_counter;
  42. ULONG thread_4_counter;
  43. ULONG thread_5_counter;
  44. ULONG thread_6_counter;
  45. ULONG thread_7_counter;
  46. /* Define thread prototypes. */
  47. void thread_0_entry(ULONG thread_input);
  48. void thread_1_entry(ULONG thread_input);
  49. void thread_2_entry(ULONG thread_input);
  50. void thread_3_and_4_entry(ULONG thread_input);
  51. void thread_5_entry(ULONG thread_input);
  52. void thread_6_and_7_entry(ULONG thread_input);
  53. /* Define main entry point. */
  54. int main()
  55. {
  56. /* Enter the ThreadX kernel. */
  57. tx_kernel_enter();
  58. }
  59. /* Define what the initial system looks like. */
  60. // NOTE: TODO: first_unused_memory is not used here, since our port don't create a memory for you, you need
  61. // to prepare it by yourself like memory_area here
  62. void tx_application_define(void *first_unused_memory)
  63. {
  64. CHAR *pointer = TX_NULL;
  65. /* Create a byte memory pool from which to allocate the thread stacks. */
  66. tx_byte_pool_create(&byte_pool_0, "byte pool 0", memory_area, DEMO_BYTE_POOL_SIZE);
  67. /* Put system definition stuff in here, e.g. thread creates and other assorted
  68. create information. */
  69. /* Allocate the stack for thread 0. */
  70. tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
  71. /* Create the main thread. */
  72. tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0,
  73. pointer, DEMO_STACK_SIZE,
  74. 1, 1, TX_NO_TIME_SLICE, TX_AUTO_START);
  75. /* Allocate the stack for thread 1. */
  76. tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
  77. /* Create threads 1 and 2. These threads pass information through a ThreadX
  78. message queue. It is also interesting to note that these threads have a time
  79. slice. */
  80. tx_thread_create(&thread_1, "thread 1", thread_1_entry, 1,
  81. pointer, DEMO_STACK_SIZE,
  82. 16, 16, 4, TX_AUTO_START);
  83. /* Allocate the stack for thread 2. */
  84. tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
  85. tx_thread_create(&thread_2, "thread 2", thread_2_entry, 2,
  86. pointer, DEMO_STACK_SIZE,
  87. 16, 16, 4, TX_AUTO_START);
  88. /* Allocate the stack for thread 3. */
  89. tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
  90. /* Create threads 3 and 4. These threads compete for a ThreadX counting semaphore.
  91. An interesting thing here is that both threads share the same instruction area. */
  92. tx_thread_create(&thread_3, "thread 3", thread_3_and_4_entry, 3,
  93. pointer, DEMO_STACK_SIZE,
  94. 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
  95. /* Allocate the stack for thread 4. */
  96. tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
  97. tx_thread_create(&thread_4, "thread 4", thread_3_and_4_entry, 4,
  98. pointer, DEMO_STACK_SIZE,
  99. 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
  100. /* Allocate the stack for thread 5. */
  101. tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
  102. /* Create thread 5. This thread simply pends on an event flag which will be set
  103. by thread_0. */
  104. tx_thread_create(&thread_5, "thread 5", thread_5_entry, 5,
  105. pointer, DEMO_STACK_SIZE,
  106. 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
  107. /* Allocate the stack for thread 6. */
  108. tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
  109. /* Create threads 6 and 7. These threads compete for a ThreadX mutex. */
  110. tx_thread_create(&thread_6, "thread 6", thread_6_and_7_entry, 6,
  111. pointer, DEMO_STACK_SIZE,
  112. 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
  113. /* Allocate the stack for thread 7. */
  114. tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
  115. tx_thread_create(&thread_7, "thread 7", thread_6_and_7_entry, 7,
  116. pointer, DEMO_STACK_SIZE,
  117. 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
  118. /* Allocate the message queue. */
  119. tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_QUEUE_SIZE*sizeof(ULONG), TX_NO_WAIT);
  120. /* Create the message queue shared by threads 1 and 2. */
  121. tx_queue_create(&queue_0, "queue 0", TX_1_ULONG, pointer, DEMO_QUEUE_SIZE*sizeof(ULONG));
  122. /* Create the semaphore used by threads 3 and 4. */
  123. tx_semaphore_create(&semaphore_0, "semaphore 0", 1);
  124. /* Create the event flags group used by threads 1 and 5. */
  125. tx_event_flags_create(&event_flags_0, "event flags 0");
  126. /* Create the mutex used by thread 6 and 7 without priority inheritance. */
  127. tx_mutex_create(&mutex_0, "mutex 0", TX_NO_INHERIT);
  128. /* Allocate the memory for a small block pool. */
  129. tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_BLOCK_POOL_SIZE, TX_NO_WAIT);
  130. /* Create a block memory pool to allocate a message buffer from. */
  131. tx_block_pool_create(&block_pool_0, "block pool 0", sizeof(ULONG), pointer, DEMO_BLOCK_POOL_SIZE);
  132. /* Allocate a block and release the block memory. */
  133. tx_block_allocate(&block_pool_0, (VOID **) &pointer, TX_NO_WAIT);
  134. /* Release the block back to the pool. */
  135. tx_block_release(pointer);
  136. }
  137. /* Define the test threads. */
  138. void thread_0_entry(ULONG thread_input)
  139. {
  140. UINT status;
  141. /* This thread simply sits in while-forever-sleep loop. */
  142. while(1)
  143. {
  144. /* Increment the thread counter. */
  145. thread_0_counter++;
  146. /* Sleep for 10 ticks. */
  147. tx_thread_sleep(10);
  148. /* Set event flag 0 to wakeup thread 5. */
  149. status = tx_event_flags_set(&event_flags_0, 0x1, TX_OR);
  150. #ifdef DEBUG_THREAD_0
  151. printf("thread 0 is running %lu\n", thread_0_counter);
  152. #endif
  153. /* Check status. */
  154. if (status != TX_SUCCESS)
  155. break;
  156. }
  157. }
  158. void thread_1_entry(ULONG thread_input)
  159. {
  160. UINT status;
  161. /* This thread simply sends messages to a queue shared by thread 2. */
  162. while(1)
  163. {
  164. /* Increment the thread counter. */
  165. thread_1_counter++;
  166. /* Send message to queue 0. */
  167. status = tx_queue_send(&queue_0, &thread_1_messages_sent, TX_WAIT_FOREVER);
  168. /* Check completion status. */
  169. if (status != TX_SUCCESS)
  170. break;
  171. /* Increment the message sent. */
  172. thread_1_messages_sent++;
  173. #ifdef DEBUG_THREAD_1
  174. printf("thread 1 is running %lu, msg sent %lu\n", thread_1_counter, thread_1_messages_sent);
  175. #endif
  176. }
  177. }
  178. void thread_2_entry(ULONG thread_input)
  179. {
  180. ULONG received_message;
  181. UINT status;
  182. /* This thread retrieves messages placed on the queue by thread 1. */
  183. while(1)
  184. {
  185. /* Increment the thread counter. */
  186. thread_2_counter++;
  187. /* Retrieve a message from the queue. */
  188. status = tx_queue_receive(&queue_0, &received_message, TX_WAIT_FOREVER);
  189. /* Check completion status and make sure the message is what we
  190. expected. */
  191. if ((status != TX_SUCCESS) || (received_message != thread_2_messages_received))
  192. break;
  193. /* Otherwise, all is okay. Increment the received message count. */
  194. thread_2_messages_received++;
  195. #ifdef DEBUG_THREAD_2
  196. printf("thread 2 is running %lu, msg recv %lu\n", thread_2_counter, thread_2_messages_received);
  197. #endif
  198. }
  199. }
  200. void thread_3_and_4_entry(ULONG thread_input)
  201. {
  202. UINT status;
  203. /* This function is executed from thread 3 and thread 4. As the loop
  204. below shows, these function compete for ownership of semaphore_0. */
  205. while(1)
  206. {
  207. /* Increment the thread counter. */
  208. if (thread_input == 3)
  209. thread_3_counter++;
  210. else
  211. thread_4_counter++;
  212. /* Get the semaphore with suspension. */
  213. status = tx_semaphore_get(&semaphore_0, TX_WAIT_FOREVER);
  214. /* Check status. */
  215. if (status != TX_SUCCESS)
  216. break;
  217. /* Sleep for 2 ticks to hold the semaphore. */
  218. tx_thread_sleep(2);
  219. /* Release the semaphore. */
  220. status = tx_semaphore_put(&semaphore_0);
  221. #ifdef DEBUG_THREAD_3_4
  222. printf("thread 3_4 is running, current is %lu, thread 3 counter %lu, thread 4 counter %lu\n", thread_input, thread_3_counter, thread_4_counter);
  223. #endif
  224. /* Check status. */
  225. if (status != TX_SUCCESS)
  226. break;
  227. }
  228. }
  229. void thread_5_entry(ULONG thread_input)
  230. {
  231. UINT status;
  232. ULONG actual_flags;
  233. /* This thread simply waits for an event in a forever loop. */
  234. while(1)
  235. {
  236. /* Increment the thread counter. */
  237. thread_5_counter++;
  238. /* Wait for event flag 0. */
  239. status = tx_event_flags_get(&event_flags_0, 0x1, TX_OR_CLEAR,
  240. &actual_flags, TX_WAIT_FOREVER);
  241. #ifdef DEBUG_THREAD_5
  242. printf("thread 5 is running %lu\n", thread_5_counter);
  243. #endif
  244. /* Check status. */
  245. if ((status != TX_SUCCESS) || (actual_flags != 0x1))
  246. break;
  247. }
  248. }
  249. void thread_6_and_7_entry(ULONG thread_input)
  250. {
  251. UINT status;
  252. /* This function is executed from thread 6 and thread 7. As the loop
  253. below shows, these function compete for ownership of mutex_0. */
  254. while(1)
  255. {
  256. /* Increment the thread counter. */
  257. if (thread_input == 6)
  258. thread_6_counter++;
  259. else
  260. thread_7_counter++;
  261. /* Get the mutex with suspension. */
  262. status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER);
  263. /* Check status. */
  264. if (status != TX_SUCCESS)
  265. break;
  266. /* Get the mutex again with suspension. This shows
  267. that an owning thread may retrieve the mutex it
  268. owns multiple times. */
  269. status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER);
  270. /* Check status. */
  271. if (status != TX_SUCCESS)
  272. break;
  273. /* Sleep for 2 ticks to hold the mutex. */
  274. tx_thread_sleep(2);
  275. /* Release the mutex. */
  276. status = tx_mutex_put(&mutex_0);
  277. /* Check status. */
  278. if (status != TX_SUCCESS)
  279. break;
  280. /* Release the mutex again. This will actually
  281. release ownership since it was obtained twice. */
  282. status = tx_mutex_put(&mutex_0);
  283. #ifdef DEBUG_THREAD_6_7
  284. printf("thread 6_7 is running, current is %lu, thread 6 counter %lu, thread 7 counter %lu\n", thread_input, thread_6_counter, thread_7_counter);
  285. #endif
  286. /* Check status. */
  287. if (status != TX_SUCCESS)
  288. break;
  289. #ifdef CFG_SIMULATION
  290. if (thread_7_counter > 2) {
  291. // directly exit if in nuclei internally simulation
  292. SIMULATION_EXIT(0);
  293. }
  294. #endif
  295. }
  296. }