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