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