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