1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** ThreadX Component */
16 /** */
17 /** Module Manager */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define TX_SOURCE_CODE
23
24 #include "tx_api.h"
25 #include "tx_initialize.h"
26 #include "tx_thread.h"
27 #include "tx_timer.h"
28 #include "tx_queue.h"
29 #include "tx_event_flags.h"
30 #include "tx_semaphore.h"
31 #include "tx_mutex.h"
32 #include "tx_block_pool.h"
33 #include "tx_byte_pool.h"
34 #include "txm_module.h"
35 #include "txm_module_manager_util.h"
36
37 #ifdef TX_ENABLE_EVENT_TRACE
38 #include "tx_trace.h"
39 #endif
40
41 #ifdef TXM_MODULE_ENABLE_FILEX
42 extern UINT _txm_module_manager_filex_stop(TXM_MODULE_INSTANCE *module_instance);
43 #endif
44
45 #ifdef TXM_MODULE_ENABLE_NETX
46 extern UINT _txm_module_manager_netx_stop(TXM_MODULE_INSTANCE *module_instance);
47 #endif
48
49 #ifdef TXM_MODULE_ENABLE_NETXDUO
50 extern UINT _txm_module_manager_netxduo_stop(TXM_MODULE_INSTANCE *module_instance);
51 #endif
52
53 #ifdef TXM_MODULE_ENABLE_GUIX
54 extern UINT _txm_module_manager_guix_stop(TXM_MODULE_INSTANCE *module_instance);
55 #endif
56
57 #ifdef TXM_MODULE_ENABLE_USBX
58 extern UINT _txm_module_manager_usbx_stop(TXM_MODULE_INSTANCE *module_instance);
59 #endif
60
61 /**************************************************************************/
62 /* */
63 /* FUNCTION RELEASE */
64 /* */
65 /* _txm_module_manager_stop PORTABLE C */
66 /* 6.2.1 */
67 /* AUTHOR */
68 /* */
69 /* Scott Larson, Microsoft Corporation */
70 /* */
71 /* DESCRIPTION */
72 /* */
73 /* This function stops execution of the specified module. */
74 /* */
75 /* INPUT */
76 /* */
77 /* module_instance Module instance pointer */
78 /* */
79 /* OUTPUT */
80 /* */
81 /* status Completion status */
82 /* */
83 /* CALLS */
84 /* */
85 /* _tx_block_pool_delete Block pool delete */
86 /* _tx_byte_pool_delete Byte pool delete */
87 /* _tx_event_flags_delete Event flags delete */
88 /* _tx_mutex_delete Mutex delete */
89 /* _tx_mutex_get Get protection mutex */
90 /* _tx_mutex_put Release protection mutex */
91 /* _tx_queue_delete Queue delete */
92 /* _tx_semaphore_delete Semaphore delete */
93 /* _tx_thread_delete Thread delete */
94 /* _tx_thread_sleep Thread sleep */
95 /* _tx_thread_system_preempt_check Check for preemption */
96 /* _tx_thread_terminate Thread terminate */
97 /* _tx_timer_delete Timer delete */
98 /* _txm_module_manager_callback_deactivate */
99 /* Deactivate callback */
100 /* _txm_module_manager_object_search Search for object in module's */
101 /* allocated object list */
102 /* _txm_module_manager_thread_create Module thread create */
103 /* [_txm_module_manager_*_stop] Optional external component */
104 /* stop functions */
105 /* */
106 /* CALLED BY */
107 /* */
108 /* Application code */
109 /* */
110 /* RELEASE HISTORY */
111 /* */
112 /* DATE NAME DESCRIPTION */
113 /* */
114 /* 09-30-2020 Scott Larson Initial Version 6.1 */
115 /* 03-02-2021 Scott Larson Modified comments, fix */
116 /* object delete underflow, */
117 /* resulting in version 6.1.5 */
118 /* 03-08-2023 Scott Larson Added tx_trace.h include, */
119 /* resulting in version 6.2.1 */
120 /* */
121 /**************************************************************************/
_txm_module_manager_stop(TXM_MODULE_INSTANCE * module_instance)122 UINT _txm_module_manager_stop(TXM_MODULE_INSTANCE *module_instance)
123 {
124
125 TX_INTERRUPT_SAVE_AREA
126
127 TX_THREAD *thread_ptr, *next_thread_ptr;
128 TX_TIMER *timer_ptr, *next_timer_ptr;
129 TX_QUEUE *queue_ptr, *next_queue_ptr;
130 TX_EVENT_FLAGS_GROUP *events_ptr, *next_events_ptr;
131 TX_SEMAPHORE *semaphore_ptr, *next_semaphore_ptr;
132 TX_MUTEX *mutex_ptr, *next_mutex_ptr;
133 TX_BLOCK_POOL *block_pool_ptr, *next_block_pool_ptr;
134 TX_BYTE_POOL *byte_pool_ptr, *next_byte_pool_ptr;
135 UCHAR created_by_module;
136 ULONG i;
137 TXM_MODULE_ALLOCATED_OBJECT *object_ptr;
138
139
140 /* Pickup thread pointer. */
141 TX_THREAD_GET_CURRENT(thread_ptr)
142
143 /* Determine if this is a legal request. */
144
145 /* Is there a current thread? */
146 if (thread_ptr == TX_NULL)
147 {
148
149 /* Illegal caller of this service. */
150 return(TX_CALLER_ERROR);
151 }
152
153 /* Is the caller an ISR or Initialization? */
154 if (TX_THREAD_GET_SYSTEM_STATE() != 0)
155 {
156
157 /* Illegal caller of this service. */
158 return(TX_CALLER_ERROR);
159 }
160
161 #ifndef TX_TIMER_PROCESS_IN_ISR
162
163 /* Check for invalid caller of this function. First check for a calling thread. */
164 if (thread_ptr == &_tx_timer_thread)
165 {
166
167 /* Invalid caller of this function, return appropriate error code. */
168 return(TX_CALLER_ERROR);
169 }
170 #endif
171
172 /* Determine if the module manager has not been initialized yet. */
173 if (_txm_module_manager_ready != TX_TRUE)
174 {
175
176 /* Module manager has not been initialized. */
177 return(TX_NOT_AVAILABLE);
178 }
179
180 /* Determine if the module is valid. */
181 if (module_instance == TX_NULL)
182 {
183
184 /* Invalid module pointer. */
185 return(TX_PTR_ERROR);
186 }
187
188 /* Get module manager protection mutex. */
189 _tx_mutex_get(&_txm_module_manager_mutex, TX_WAIT_FOREVER);
190
191 /* Determine if the module instance is valid. */
192 if (module_instance -> txm_module_instance_id != TXM_MODULE_ID)
193 {
194
195 /* Release the protection mutex. */
196 _tx_mutex_put(&_txm_module_manager_mutex);
197
198 /* Invalid module pointer. */
199 return(TX_PTR_ERROR);
200 }
201
202 /* Determine if the module instance is in the loaded state. */
203 if (module_instance -> txm_module_instance_state != TXM_MODULE_STARTED)
204 {
205
206 /* Release the protection mutex. */
207 _tx_mutex_put(&_txm_module_manager_mutex);
208
209 /* Return error if the module is not ready. */
210 return(TX_START_ERROR);
211 }
212
213 /* Set the module state to indicate the module is stopping. */
214 module_instance -> txm_module_instance_state = TXM_MODULE_STOPPING;
215
216 /* This thread was previously used as the start thread. So first, make sure it is terminated and deleted before doing anything else. */
217 _tx_thread_terminate(&(module_instance -> txm_module_instance_start_stop_thread));
218 _tx_thread_delete(&(module_instance -> txm_module_instance_start_stop_thread));
219
220 /* Determine if there is a module stop function. */
221 if (module_instance -> txm_module_instance_stop_thread_entry)
222 {
223
224 /* Yes, there is a stop function. Build a thread for executing the module stop function. */
225
226 /* Create the module stop thread. */
227 _txm_module_manager_thread_create(&(module_instance -> txm_module_instance_start_stop_thread),
228 "Module Stop Thread",
229 module_instance -> txm_module_instance_shell_entry_function,
230 module_instance -> txm_module_instance_stop_thread_entry,
231 module_instance -> txm_module_instance_application_module_id,
232 module_instance -> txm_module_instance_start_stop_stack_start_address,
233 module_instance -> txm_module_instance_start_stop_stack_size,
234 (UINT) module_instance -> txm_module_instance_start_stop_priority,
235 (UINT) module_instance -> txm_module_instance_start_stop_priority,
236 TXM_MODULE_TIME_SLICE,
237 TX_AUTO_START,
238 sizeof(TX_THREAD),
239 module_instance);
240
241 /* Wait for the stop thread to complete. */
242 i = 0;
243 while ((i < TXM_MODULE_TIMEOUT) && (module_instance -> txm_module_instance_start_stop_thread.tx_thread_state != TX_COMPLETED))
244 {
245
246 /* Sleep to let the module stop thread run. */
247 _tx_thread_sleep(1);
248
249 /* Increment the counter. */
250 i++;
251 }
252
253 /* At this point, we need to terminate and delete the stop thread. */
254 _tx_thread_terminate(&(module_instance -> txm_module_instance_start_stop_thread));
255 _tx_thread_delete(&(module_instance -> txm_module_instance_start_stop_thread));
256 }
257
258 /* Delete the module's callback thread and queue for the callback thread. */
259 _tx_thread_terminate(&(module_instance -> txm_module_instance_callback_request_thread));
260 _tx_thread_delete(&(module_instance -> txm_module_instance_callback_request_thread));
261 _tx_queue_delete(&(module_instance -> txm_module_instance_callback_request_queue));
262
263 /* Disable interrupts. */
264 TX_DISABLE
265
266 /* Temporarily disable preemption. This will keep other threads from creating and deleting threads. */
267 _tx_thread_preempt_disable++;
268
269 /* Restore interrupts. */
270 TX_RESTORE
271
272 /* Determine if any external component stop functions have been registered and
273 if so, call them to cleanup any module objects in that component. */
274
275 #ifdef TXM_MODULE_ENABLE_FILEX
276
277 /* Call the FileX stop function. */
278 _txm_module_manager_filex_stop(module_instance);
279 #endif
280
281 #ifdef TXM_MODULE_ENABLE_NETX
282
283 /* Call the NetX stop function. */
284 _txm_module_manager_netx_stop(module_instance);
285 #endif
286
287 #ifdef TXM_MODULE_ENABLE_NETXDUO
288
289 /* Call the NetX Duo stop function. */
290 _txm_module_manager_netxduo_stop(module_instance);
291 #endif
292
293 #ifdef TXM_MODULE_ENABLE_GUIX
294
295 /* Call the GUIX stop function. */
296 _txm_module_manager_guix_stop(module_instance);
297 #endif
298
299 #ifdef TXM_MODULE_ENABLE_USBX
300
301 /* Call the USBX stop function. */
302 _txm_module_manager_usbx_stop(module_instance);
303 #endif
304
305 /* Loop to delete any and all threads created by the module. */
306 i = _tx_thread_created_count;
307 thread_ptr = _tx_thread_created_ptr;
308 while (i--)
309 {
310
311 /* Pickup the next thread pointer. */
312 next_thread_ptr = thread_ptr -> tx_thread_created_next;
313
314 /* Determine if the thread control block is inside the module. */
315 if ( (((CHAR *) thread_ptr) >= ((CHAR *) module_instance -> txm_module_instance_data_start)) &&
316 (((CHAR *) thread_ptr) < ((CHAR *) module_instance -> txm_module_instance_data_end)))
317 {
318
319 /* Terminate and delete this thread, since it is part of this module. */
320 _tx_thread_terminate(thread_ptr);
321 _tx_thread_delete(thread_ptr);
322 }
323
324 /* Is this thread part of the module? */
325 else if (thread_ptr -> tx_thread_module_instance_ptr == module_instance)
326 {
327
328 /* Terminate and delete this thread, since it is part of this module. */
329 _tx_thread_terminate(thread_ptr);
330 _tx_thread_delete(thread_ptr);
331 }
332
333 /* Move to next thread. */
334 thread_ptr = next_thread_ptr;
335 }
336
337 /* Loop to delete any and all timers created by the module. */
338 i = _tx_timer_created_count;
339 timer_ptr = _tx_timer_created_ptr;
340 while (i--)
341 {
342
343 /* Pickup the next timer pointer. */
344 next_timer_ptr = timer_ptr -> tx_timer_created_next;
345
346 /* Check if this module created this timer. */
347 created_by_module = _txm_module_manager_created_object_check(module_instance, (VOID *) timer_ptr);
348 if (created_by_module == TX_TRUE)
349 {
350
351 /* Delete this timer, since it is part of this module. */
352 _tx_timer_delete(timer_ptr);
353 }
354
355 /* Move to next timer. */
356 timer_ptr = next_timer_ptr;
357 }
358
359 /* Loop to delete any and all queues created by the module. */
360 i = _tx_queue_created_count;
361 queue_ptr = _tx_queue_created_ptr;
362 while (i--)
363 {
364
365 /* Pickup the next queue pointer. */
366 next_queue_ptr = queue_ptr -> tx_queue_created_next;
367
368 #ifndef TX_DISABLE_NOTIFY_CALLBACKS
369
370 /* Determine if the queue callback function is associated with this module. */
371 if ((queue_ptr -> tx_queue_module_instance == module_instance) &&
372 (queue_ptr -> tx_queue_send_notify == _txm_module_manager_queue_notify_trampoline))
373 {
374
375 /* Clear the callback notification for this queue since it is no longer valid. */
376 queue_ptr -> tx_queue_send_notify = TX_NULL;
377 }
378 #endif
379
380 /* Check if this module created this queue. */
381 created_by_module = _txm_module_manager_created_object_check(module_instance, (VOID *) queue_ptr);
382 if (created_by_module == TX_TRUE)
383 {
384
385 /* Delete this queue, since it is part of this module. */
386 _tx_queue_delete(queue_ptr);
387 }
388
389 /* Move to next queue. */
390 queue_ptr = next_queue_ptr;
391 }
392
393 /* Loop to delete any and all event flag groups created by the module. */
394 i = _tx_event_flags_created_count;
395 events_ptr = _tx_event_flags_created_ptr;
396 while (i--)
397 {
398
399 /* Pickup the next event flags group pointer. */
400 next_events_ptr = events_ptr -> tx_event_flags_group_created_next;
401
402 #ifndef TX_DISABLE_NOTIFY_CALLBACKS
403
404 /* Determine if the event flags callback function is associated with this module. */
405 if ((events_ptr -> tx_event_flags_group_module_instance == module_instance) &&
406 (events_ptr -> tx_event_flags_group_set_notify == _txm_module_manager_event_flags_notify_trampoline))
407 {
408
409 /* Clear the callback notification for this event flag group since it is no longer valid. */
410 events_ptr -> tx_event_flags_group_set_notify = TX_NULL;
411 }
412 #endif
413
414 /* Check if this module created this event flags. */
415 created_by_module = _txm_module_manager_created_object_check(module_instance, (VOID *) events_ptr);
416 if (created_by_module == TX_TRUE)
417 {
418
419 /* Delete this event flags group, since it is part of this module. */
420 _tx_event_flags_delete(events_ptr);
421 }
422
423 /* Move to next event flags group. */
424 events_ptr = next_events_ptr;
425 }
426
427 /* Loop to delete any and all semaphores created by the module. */
428 i = _tx_semaphore_created_count;
429 semaphore_ptr = _tx_semaphore_created_ptr;
430 while (i--)
431 {
432
433 /* Pickup the next semaphore pointer. */
434 next_semaphore_ptr = semaphore_ptr -> tx_semaphore_created_next;
435
436 #ifndef TX_DISABLE_NOTIFY_CALLBACKS
437
438 /* Determine if the semaphore callback function is associated with this module. */
439 if ((semaphore_ptr -> tx_semaphore_module_instance == module_instance) &&
440 (semaphore_ptr -> tx_semaphore_put_notify == _txm_module_manager_semaphore_notify_trampoline))
441 {
442
443 /* Clear the callback notification for this semaphore since it is no longer valid. */
444 semaphore_ptr -> tx_semaphore_put_notify = TX_NULL;
445 }
446 #endif
447
448 /* Check if this module created this semaphore. */
449 created_by_module = _txm_module_manager_created_object_check(module_instance, (VOID *) semaphore_ptr);
450 if (created_by_module == TX_TRUE)
451 {
452
453 /* Delete this semaphore, since it is part of this module. */
454 _tx_semaphore_delete(semaphore_ptr);
455 }
456
457 /* Move to next semaphore. */
458 semaphore_ptr = next_semaphore_ptr;
459 }
460
461 /* Loop to delete any and all mutexes created by the module. */
462 i = _tx_mutex_created_count;
463 mutex_ptr = _tx_mutex_created_ptr;
464 while (i--)
465 {
466
467 /* Pickup the next mutex pointer. */
468 next_mutex_ptr = mutex_ptr -> tx_mutex_created_next;
469
470 /* Check if this module created this mutex. */
471 created_by_module = _txm_module_manager_created_object_check(module_instance, (VOID *) mutex_ptr);
472 if (created_by_module == TX_TRUE)
473 {
474
475 /* Delete this mutex, since it is part of this module. */
476 _tx_mutex_delete(mutex_ptr);
477 }
478
479 /* Move to next mutex. */
480 mutex_ptr = next_mutex_ptr;
481 }
482
483 /* Loop to delete any and all block pools created by the module. */
484 i = _tx_block_pool_created_count;
485 block_pool_ptr = _tx_block_pool_created_ptr;
486 while (i--)
487 {
488
489 /* Pickup the next block pool pointer. */
490 next_block_pool_ptr = block_pool_ptr -> tx_block_pool_created_next;
491
492 /* Check if this module created this block pool. */
493 created_by_module = _txm_module_manager_created_object_check(module_instance, (VOID *) block_pool_ptr);
494 if (created_by_module == TX_TRUE)
495 {
496
497 /* Delete this block pool, since it is part of this module. */
498 _tx_block_pool_delete(block_pool_ptr);
499 }
500
501 /* Move to next block pool. */
502 block_pool_ptr = next_block_pool_ptr;
503 }
504
505 /* Loop to delete any and all byte pools created by the module. */
506 i = _tx_byte_pool_created_count;
507 byte_pool_ptr = _tx_byte_pool_created_ptr;
508 while (i--)
509 {
510
511 /* Pickup the next byte pool pointer. */
512 next_byte_pool_ptr = byte_pool_ptr -> tx_byte_pool_created_next;
513
514 /* Check if this module created this byte pool. */
515 created_by_module = _txm_module_manager_created_object_check(module_instance, (VOID *) byte_pool_ptr);
516 if (created_by_module == TX_TRUE)
517 {
518
519 /* Delete this byte pool, since it is part of this module. */
520 _tx_byte_pool_delete(byte_pool_ptr);
521 }
522
523 /* Move to next byte pool. */
524 byte_pool_ptr = next_byte_pool_ptr;
525 }
526
527 #ifdef TX_ENABLE_EVENT_TRACE
528 /* Has trace been enabled? */
529 if (_tx_trace_buffer_current_ptr != TX_NULL)
530 {
531
532 /* Is the trace buffer located inside the module? */
533 if ((ULONG) _tx_trace_header_ptr -> tx_trace_header_buffer_start_pointer >= (ULONG) module_instance -> txm_module_instance_data_start &&
534 (ULONG) _tx_trace_header_ptr -> tx_trace_header_buffer_start_pointer < (ULONG) module_instance -> txm_module_instance_data_end)
535 {
536 _tx_trace_disable();
537 }
538 }
539 #endif
540
541 /* Delete the allocated objects for this module. */
542 while (module_instance -> txm_module_instance_object_list_count != 0)
543 {
544 /* Pickup the current object pointer. */
545 object_ptr = module_instance -> txm_module_instance_object_list_head;
546
547 /* Move the head pointer forward. */
548 module_instance -> txm_module_instance_object_list_head = object_ptr -> txm_module_allocated_object_next;
549
550 /* Release the object. */
551 _tx_byte_release((VOID *) object_ptr);
552
553 /* Decrement count. */
554 module_instance -> txm_module_instance_object_list_count--;
555 }
556
557 /* Set the allocated list head pointer to NULL. */
558 module_instance -> txm_module_instance_object_list_head = TX_NULL;
559
560 /* Disable interrupts. */
561 TX_DISABLE
562
563 /* Enable preemption again. */
564 _tx_thread_preempt_disable--;
565
566 /* Set the module state to indicate the module is stopped. */
567 module_instance -> txm_module_instance_state = TXM_MODULE_STOPPED;
568
569 /* Restore interrupts. */
570 TX_RESTORE
571
572 /* Release the protection mutex. */
573 _tx_mutex_put(&_txm_module_manager_mutex);
574
575 /* Check for preemption. */
576 _tx_thread_system_preempt_check();
577
578 /* Return success. */
579 return(TX_SUCCESS);
580 }
581
582