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