1 /*
2 * This file is part of the MicroPython project, http://micropython.org/
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
7 * Copyright (c) 2017 Pycom Limited
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28 #include "mpthreadport.h"
29
30 #include "aos/kernel.h"
31 #include "mphalport.h"
32 #include "mpsalport.h"
33 #include "py/gc.h"
34 #include "py/mpconfig.h"
35 #include "py/mperrno.h"
36 #include "py/mpstate.h"
37 #include "py/mpthread.h"
38 #include "stdio.h"
39
40 #if MICROPY_PY_THREAD
41
42 #define LOG_TAG "MP_THREAD"
43
44 #define MP_THREAD_MIN_STACK_SIZE MP_SAL_THREAD_MIN_STACK_SIZE
45 #define MP_THREAD_DEFAULT_STACK_SIZE MP_SAL_THREAD_DEFAULT_STACK_SIZE
46 #define MP_THREAD_PRIORITY MP_SAL_THREAD_PRIORITY
47
48 // this structure forms a linked list, one node per active thread
49 typedef struct _thread_t {
50 mp_task_t handler; // task handler of thread
51 int ready; // whether the thread is ready and running
52 void *arg; // thread Python args, a GC root pointer
53 void *stack_addr; // pointer to the stack
54 size_t stack_len; // number of bytes in the stack
55 struct _thread_t *next;
56 mp_state_thread_t *state; // state
57 } thread_t;
58
59 // the mutex controls access to the linked list
60 STATIC mp_thread_mutex_t thread_mutex;
61 STATIC thread_t thread_entry0;
62 STATIC thread_t *thread = NULL; // root pointer, handled by mp_thread_gc_others
63
mp_thread_init(void * stack_addr,mp_uint_t stack_len)64 void mp_thread_init(void *stack_addr, mp_uint_t stack_len)
65 {
66 mp_thread_mutex_init(&thread_mutex);
67 // create the first entry in the linked list of all threads
68 thread = &thread_entry0;
69 thread->handler = aos_task_self();
70 thread->ready = 1;
71 thread->arg = NULL;
72 thread->stack_addr = stack_addr;
73 thread->stack_len = stack_len;
74 thread->next = NULL;
75 thread->state = NULL;
76 mp_thread_set_state(&mp_state_ctx.thread);
77 }
78
mp_thread_gc_others(void)79 void mp_thread_gc_others(void)
80 {
81 mp_thread_mutex_lock(&thread_mutex, 1);
82 for (thread_t *th = thread; th != NULL; th = th->next) {
83 gc_collect_root((void **)&th, 1);
84 gc_collect_root(&th->arg, 1);
85 if (th->handler == aos_task_self()) {
86 continue;
87 }
88 if (!th->ready) {
89 continue;
90 }
91 gc_collect_root(th->stack_addr, th->stack_len);
92 }
93 mp_thread_mutex_unlock(&thread_mutex);
94 }
95
mp_thread_get_state(void)96 mp_state_thread_t *mp_thread_get_state(void)
97 {
98 mp_state_thread_t *state = NULL;
99
100 mp_thread_mutex_lock(&thread_mutex, 1);
101 for (thread_t *th = thread; th != NULL; th = th->next) {
102 if (th->handler == aos_task_self()) {
103 state = th->state;
104 break;
105 }
106 }
107 mp_thread_mutex_unlock(&thread_mutex);
108
109 return state;
110 }
111
mp_thread_set_state(mp_state_thread_t * state)112 void mp_thread_set_state(mp_state_thread_t *state)
113 {
114 mp_thread_mutex_lock(&thread_mutex, 1);
115 for (thread_t *th = thread; th != NULL; th = th->next) {
116 if (th->handler == aos_task_self()) {
117 th->state = state;
118 break;
119 }
120 }
121 mp_thread_mutex_unlock(&thread_mutex);
122 }
123
mp_thread_start(void)124 void mp_thread_start(void)
125 {
126 mp_thread_mutex_lock(&thread_mutex, 1);
127 for (thread_t *th = thread; th != NULL; th = th->next) {
128 if (th->handler == aos_task_self()) {
129 th->ready = 1;
130 break;
131 }
132 }
133 mp_thread_mutex_unlock(&thread_mutex);
134 }
135
mp_thread_create_ex(void * (* entry)(void *),void * arg,size_t * stack_size,int priority,char * name)136 void mp_thread_create_ex(void *(*entry)(void *), void *arg, size_t *stack_size, int priority, char *name)
137 {
138 if (*stack_size == 0) {
139 *stack_size = MP_THREAD_DEFAULT_STACK_SIZE; // default stack size
140 } else if (*stack_size < MP_THREAD_MIN_STACK_SIZE) {
141 *stack_size = MP_THREAD_MIN_STACK_SIZE; // minimum stack size
142 }
143
144 // Allocate linked-list node (must be outside thread_mutex lock)
145 thread_t *th = m_new_obj(thread_t);
146 if (th == NULL) {
147 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "thread_t alloc fail"));
148 }
149
150 mp_task_t _task = (mp_task_t)aos_malloc(mp_task_struct_size);
151 if (!_task) {
152 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "task alloc fail"));
153 }
154
155 // Allocate stack buffer
156 void *stack_addr = m_new(uint8_t, *stack_size);
157 if (stack_addr == NULL) {
158 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "stack alloc fail"));
159 }
160
161 mp_thread_mutex_lock(&thread_mutex, 1);
162 #ifdef AOS_BOARD_HAAS700
163 mp_int_t result = aos_task_create(_task, name, entry, arg, stack_addr, *stack_size, priority, 1);
164 #else
165 mp_int_t result = aos_task_create(&_task, name, entry, arg, stack_addr, *stack_size, priority, 1);
166 #endif
167 if (result != 0) {
168 mp_thread_mutex_unlock(&thread_mutex);
169 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread"));
170 }
171
172 // adjust the stack_size to provide room to recover from hitting the limit
173 *stack_size -= 1024;
174
175 // add thread to linked list of all threads
176 th->handler = _task;
177 th->ready = 0;
178 th->arg = arg;
179 th->stack_addr = stack_addr;
180 th->stack_len = (*stack_size) / sizeof(cpu_stack_t);
181 th->next = thread;
182 thread = th;
183
184 mp_thread_mutex_unlock(&thread_mutex);
185 }
186
mp_thread_create(void * (* entry)(void *),void * arg,size_t * stack_size)187 void mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size)
188 {
189 mp_thread_create_ex(entry, arg, stack_size, MP_THREAD_PRIORITY, "mp_thread");
190 }
191
mp_thread_finish(void)192 void mp_thread_finish(void)
193 {
194 mp_thread_mutex_lock(&thread_mutex, 1);
195 for (thread_t *th = thread; th != NULL; th = th->next) {
196 if (th->handler == aos_task_self()) {
197 th->ready = 0;
198 break;
199 }
200 }
201 mp_thread_mutex_unlock(&thread_mutex);
202 }
203
mp_thread_mutex_init(mp_thread_mutex_t * mutex)204 void mp_thread_mutex_init(mp_thread_mutex_t *mutex)
205 {
206 aos_mutex_new((aos_mutex_t *)&(mutex->k_mutex));
207 }
208
mp_thread_mutex_lock(mp_thread_mutex_t * mutex,int wait)209 int mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait)
210 {
211 if (mutex->k_mutex == NULL) {
212 LOGE(LOG_TAG, "mp_thread_mutex_lock with k_mutex NULL!!");
213 return MP_EINVAL;
214 }
215
216 int status = aos_mutex_lock(&(mutex->k_mutex), wait ? AOS_WAIT_FOREVER : 0);
217 return (status == 0);
218 }
219
mp_thread_mutex_unlock(mp_thread_mutex_t * mutex)220 void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex)
221 {
222 if ((mutex->k_mutex) == NULL) {
223 LOGE(LOG_TAG, "mpthread mutex unlock error!!");
224 return;
225 }
226 mp_sal_mutex_unlock(&(mutex->k_mutex));
227 }
228
mp_thread_deinit(void)229 void mp_thread_deinit(void)
230 {
231 for (;;) {
232 // Find a task to delete
233 thread_t *th = NULL;
234 aos_task_t *handler = NULL;
235 mp_thread_mutex_lock(&thread_mutex, 1);
236 for (th = thread; th != NULL; th = th->next) {
237 // Don't delete the current task
238 if (th->handler != aos_task_self()) {
239 handler = th->handler;
240 break;
241 }
242 }
243 mp_thread_mutex_unlock(&thread_mutex);
244
245 if (handler == NULL) {
246 // No tasks left to delete
247 break;
248 } else {
249 mp_int_t status = -1;
250 mp_sal_task_delete(handler, &status);
251 if (status != 0) {
252 LOGE(LOG_TAG, "Failed to delete task[id = 0x%X]");
253 }
254 aos_free(handler);
255 m_del(uint8_t, th->stack_addr, th->stack_len * sizeof(cpu_stack_t));
256 m_del_obj(thread_t, th);
257 }
258 }
259 }
260
261 #else
262
263 #endif // MICROPY_PY_THREAD
264