1 /*
2 * Copyright (c) 2006-2022, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2024-08-30 heyuanjie87 the first version
9 *
10 */
11
12 #include <rthw.h>
13 #include <rtthread.h>
14
15 #ifndef SYSTEM_THREAD_STACK_SIZE
16 #define SYSTEM_THREAD_STACK_SIZE IDLE_THREAD_STACK_SIZE
17 #endif
18 static rt_list_t _rt_thread_defunct = RT_LIST_OBJECT_INIT(_rt_thread_defunct);
19 static struct rt_spinlock _defunct_spinlock;
20 #if defined(RT_USING_SMP) || defined(RT_USING_SMART)
21 static struct rt_thread rt_system_thread;
22 rt_align(RT_ALIGN_SIZE) static rt_uint8_t rt_system_stack[SYSTEM_THREAD_STACK_SIZE];
23 static struct rt_semaphore system_sem;
24 #endif
25
26 /**
27 * @brief Enqueue a thread to defunct queue.
28 *
29 * @param thread the thread to be enqueued.
30 *
31 * @note It must be called between rt_hw_interrupt_disable and rt_hw_interrupt_enable
32 */
rt_thread_defunct_enqueue(rt_thread_t thread)33 void rt_thread_defunct_enqueue(rt_thread_t thread)
34 {
35 rt_base_t level;
36 level = rt_spin_lock_irqsave(&_defunct_spinlock);
37 rt_list_insert_after(&_rt_thread_defunct, &RT_THREAD_LIST_NODE(thread));
38 rt_spin_unlock_irqrestore(&_defunct_spinlock, level);
39 #if defined(RT_USING_SMP) || defined(RT_USING_SMART)
40 rt_sem_release(&system_sem);
41 #endif
42 }
43
44 /**
45 * @brief Dequeue a thread from defunct queue.
46 */
rt_thread_defunct_dequeue(void)47 rt_thread_t rt_thread_defunct_dequeue(void)
48 {
49 rt_base_t level;
50 rt_thread_t thread = RT_NULL;
51 rt_list_t *l = &_rt_thread_defunct;
52
53 level = rt_spin_lock_irqsave(&_defunct_spinlock);
54 if (!rt_list_isempty(l))
55 {
56 thread = RT_THREAD_LIST_NODE_ENTRY(l->next);
57 rt_list_remove(&RT_THREAD_LIST_NODE(thread));
58 }
59 rt_spin_unlock_irqrestore(&_defunct_spinlock, level);
60
61 return thread;
62 }
63
64 /**
65 * @brief This function will perform system background job when system idle.
66 */
rt_defunct_execute(void)67 void rt_defunct_execute(void)
68 {
69 /* Loop until there is no dead thread. So one call to rt_defunct_execute
70 * will do all the cleanups. */
71 while (1)
72 {
73 rt_thread_t thread;
74 rt_bool_t object_is_systemobject;
75 void (*cleanup)(struct rt_thread *tid);
76
77 #ifdef RT_USING_MODULE
78 struct rt_dlmodule *module = RT_NULL;
79 #endif
80 /* get defunct thread */
81 thread = rt_thread_defunct_dequeue();
82 if (thread == RT_NULL)
83 {
84 break;
85 }
86
87 #ifdef RT_USING_MODULE
88 module = (struct rt_dlmodule *)thread->parent.module_id;
89 if (module)
90 {
91 dlmodule_destroy(module);
92 }
93 #endif
94
95 #ifdef RT_USING_SIGNALS
96 rt_thread_free_sig(thread);
97 #endif
98
99 /* store the point of "thread->cleanup" avoid to lose */
100 cleanup = thread->cleanup;
101
102 /* if it's a system object, detach it */
103 object_is_systemobject = rt_object_is_systemobject((rt_object_t)thread);
104 if (object_is_systemobject == RT_TRUE)
105 {
106 /* detach this object */
107 rt_object_detach((rt_object_t)thread);
108 }
109
110 /* invoke thread cleanup */
111 if (cleanup != RT_NULL)
112 {
113 cleanup(thread);
114 }
115
116 #ifdef RT_USING_HEAP
117 #ifdef RT_USING_MEM_PROTECTION
118 if (thread->mem_regions != RT_NULL)
119 {
120 RT_KERNEL_FREE(thread->mem_regions);
121 }
122 #endif
123 /* if need free, delete it */
124 if (object_is_systemobject == RT_FALSE)
125 {
126 /* release thread's stack */
127 #ifdef RT_USING_HW_STACK_GUARD
128 RT_KERNEL_FREE(thread->stack_buf);
129 #else
130 RT_KERNEL_FREE(thread->stack_addr);
131 #endif
132 /* delete thread object */
133 rt_object_delete((rt_object_t)thread);
134 }
135 #endif
136 }
137 }
138
139 #if defined(RT_USING_SMP) || defined(RT_USING_SMART)
rt_thread_system_entry(void * parameter)140 static void rt_thread_system_entry(void *parameter)
141 {
142 RT_UNUSED(parameter);
143
144 while (1)
145 {
146 int ret = rt_sem_take(&system_sem, RT_WAITING_FOREVER);
147 if (ret != RT_EOK)
148 {
149 rt_kprintf("failed to sem_take() error %d\n", ret);
150 RT_ASSERT(0);
151 }
152 rt_defunct_execute();
153 }
154 }
155 #endif
156
rt_thread_defunct_init(void)157 void rt_thread_defunct_init(void)
158 {
159 RT_ASSERT(RT_THREAD_PRIORITY_MAX > 2);
160
161 rt_spin_lock_init(&_defunct_spinlock);
162
163 #if defined(RT_USING_SMP) || defined(RT_USING_SMART)
164 rt_sem_init(&system_sem, "defunct", 0, RT_IPC_FLAG_FIFO);
165
166 /* create defunct thread */
167 rt_thread_init(&rt_system_thread,
168 "tsystem",
169 rt_thread_system_entry,
170 RT_NULL,
171 rt_system_stack,
172 sizeof(rt_system_stack),
173 RT_THREAD_PRIORITY_MAX - 2,
174 32);
175 /* startup */
176 rt_thread_startup(&rt_system_thread);
177 #endif
178 }
179