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 "stdio.h"
29
30 #include "py/mpconfig.h"
31 #include "py/mpstate.h"
32 #include "py/gc.h"
33 #include "py/mpthread.h"
34 #include "mpthreadport.h"
35 #include "mpsalport.h"
36
37 #include "aos/kernel.h"
38 #include "mphalport.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_sal_taskhandler_obj_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,uint32_t stack_len)64 void mp_thread_init(void *stack_addr, uint32_t stack_len) {
65 mp_thread_mutex_init(&thread_mutex);
66 // create the first entry in the linked list of all threads
67 thread = &thread_entry0;
68 thread->handler = mp_sal_get_taskhandler();
69 thread->ready = 1;
70 thread->arg = NULL;
71 thread->stack_addr = stack_addr;
72 thread->stack_len = stack_len;
73 thread->next = NULL;
74 thread->state = NULL;
75 mp_thread_set_state(&mp_state_ctx.thread);
76 }
77
mp_thread_gc_others(void)78 void mp_thread_gc_others(void) {
79 mp_thread_mutex_lock(&thread_mutex, 1);
80 for (thread_t *th = thread; th != NULL; th = th->next) {
81 gc_collect_root((void **)&th, 1);
82 gc_collect_root(&th->arg, 1);
83 if (th->handler == mp_sal_get_taskhandler()) {
84 continue;
85 }
86 if (!th->ready) {
87 continue;
88 }
89 gc_collect_root(th->stack_addr, th->stack_len);
90 }
91 mp_thread_mutex_unlock(&thread_mutex);
92 }
93
mp_thread_get_state(void)94 mp_state_thread_t *mp_thread_get_state(void) {
95 mp_state_thread_t *state = NULL;
96
97 mp_thread_mutex_lock(&thread_mutex, 1);
98 for (thread_t *th = thread; th != NULL; th = th->next) {
99 if (th->handler == mp_sal_get_taskhandler()) {
100 state = th->state;
101 break;
102 }
103 }
104 mp_thread_mutex_unlock(&thread_mutex);
105 return state;
106 }
107
mp_thread_set_state(mp_state_thread_t * state)108 void mp_thread_set_state(mp_state_thread_t *state) {
109 mp_thread_mutex_lock(&thread_mutex, 1);
110 for (thread_t *th = thread; th != NULL; th = th->next) {
111 if (th->handler == mp_sal_get_taskhandler()) {
112 th->state = state;
113 break;
114 }
115 }
116 mp_thread_mutex_unlock(&thread_mutex);
117 }
118
mp_thread_start(void)119 void mp_thread_start(void) {
120 mp_thread_mutex_lock(&thread_mutex, 1);
121 for (thread_t *th = thread; th != NULL; th = th->next) {
122 if (th->handler == mp_sal_get_taskhandler()) {
123 th->ready = 1;
124 break;
125 }
126 }
127 mp_thread_mutex_unlock(&thread_mutex);
128 }
129
mp_thread_create_ex(void (* entry)(void *),void * arg,size_t * stack_size,int priority,char * name)130 void mp_thread_create_ex(void (*entry)(void*), void *arg, size_t *stack_size, int priority, char *name) {
131
132 if (*stack_size == 0) {
133 *stack_size = MP_THREAD_DEFAULT_STACK_SIZE; // default stack size
134 } else if (*stack_size < MP_THREAD_MIN_STACK_SIZE) {
135 *stack_size = MP_THREAD_MIN_STACK_SIZE; // minimum stack size
136 }
137
138 // Allocate linked-list node (must be outside thread_mutex lock)
139 thread_t *th = m_new_obj(thread_t);
140 if (th == NULL) {
141 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "thread_t alloc fail"));
142 }
143
144 mp_thread_mutex_lock(&thread_mutex, 1);
145
146 // create thread
147 void *stack_addr = NULL;
148 int32_t result = mp_sal_task_create(th->handler, entry, arg, stack_addr, *stack_size, priority, name);
149 if (result != 0) {
150 mp_thread_mutex_unlock(&thread_mutex);
151 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread"));
152 }
153
154 // adjust the stack_size to provide room to recover from hitting the limit
155 *stack_size -= 1024;
156
157 // add thread to linked list of all threads
158 th->ready = 0;
159 th->arg = arg;
160 th->stack_addr = stack_addr;
161 th->stack_len = (*stack_size) / sizeof(cpu_stack_t);
162 th->next = thread;
163 thread = th;
164
165 mp_thread_mutex_unlock(&thread_mutex);
166 }
167
mp_thread_create(void * (* entry)(void *),void * arg,size_t * stack_size)168 void mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size) {
169 mp_thread_create_ex(entry, arg, stack_size, MP_THREAD_PRIORITY, "mp_thread");
170 }
171
mp_thread_finish(void)172 void mp_thread_finish(void) {
173 mp_thread_mutex_lock(&thread_mutex, 1);
174 for (thread_t *th = thread; th != NULL; th = th->next) {
175 if (th->handler == mp_sal_get_taskhandler()) {
176 th->ready = 0;
177 break;
178 }
179 }
180 mp_thread_mutex_unlock(&thread_mutex);
181 }
182
mp_thread_mutex_init(mp_thread_mutex_t * mutex)183 void mp_thread_mutex_init(mp_thread_mutex_t *mutex) {
184 mp_sal_mutex_create(&(mutex->k_mutex));
185 }
186
mp_thread_mutex_lock(mp_thread_mutex_t * mutex,int wait)187 int mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait) {
188 if((mutex->k_mutex) == NULL)
189 {
190 LOGE(LOG_TAG, "mpthread mutex lock error!!");
191 return 0;
192 }
193 return mp_sal_mutex_lock(&(mutex->k_mutex), wait ? AOS_WAIT_FOREVER : 0);
194 }
195
mp_thread_mutex_unlock(mp_thread_mutex_t * mutex)196 void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex) {
197 if((mutex->k_mutex) == NULL)
198 {
199 LOGE(LOG_TAG, "mpthread mutex unlock error!!");
200 return 0;
201 }
202 mp_sal_mutex_unlock(&(mutex->k_mutex));
203 }
204
mp_thread_deinit(void)205 void mp_thread_deinit(void) {
206 for (;;) {
207 // Find a task to delete
208 mp_sal_taskhandler_obj_t handler = NULL;
209 mp_thread_mutex_lock(&thread_mutex, 1);
210 for (thread_t *th = thread; th != NULL; th = th->next) {
211 // Don't delete the current task
212 if (th->handler != krhino_cur_task_get()) {
213 handler = th->handler;
214 break;
215 }
216 }
217 mp_thread_mutex_unlock(&thread_mutex);
218
219 if (handler == NULL) {
220 // No tasks left to delete
221 break;
222 } else {
223 int32_t status = -1;
224 mp_sal_task_delete(handler, &status);
225 if(status != 0) {
226 LOGE(LOG_TAG, "Failed to delete task[id = 0x%X]");
227 }
228 }
229 }
230 }
231
232 #else
233
234 #endif // MICROPY_PY_THREAD
235