main.c 14 KB

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