Skip to content

Commit dc82def

Browse files
Daniel Camporadpgeorge
authored andcommitted
esp32: Add threading implementation, disabled for the time being.
1 parent 747cbbc commit dc82def

File tree

4 files changed

+275
-1
lines changed

4 files changed

+275
-1
lines changed

esp32/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ SRC_C = \
128128
modesp.c \
129129
espneopixel.c \
130130
machine_hw_spi.c \
131+
mpthreadport.c \
131132
$(SRC_MOD)
132133

133134
STM_SRC_C = $(addprefix stmhal/,\

esp32/mpthreadport.c

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
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+
36+
#include "esp_task.h"
37+
38+
#if MICROPY_PY_THREAD
39+
40+
#define MP_THREAD_MIN_STACK_SIZE (4 * 1024)
41+
#define MP_THREAD_DEFAULT_STACK_SIZE (MP_THREAD_MIN_STACK_SIZE + 1024)
42+
#define MP_THREAD_PRIORITY (ESP_TASK_PRIO_MIN + 1)
43+
44+
// this structure forms a linked list, one node per active thread
45+
typedef struct _thread_t {
46+
TaskHandle_t id; // system id of thread
47+
int ready; // whether the thread is ready and running
48+
void *arg; // thread Python args, a GC root pointer
49+
void *stack; // pointer to the stack
50+
StaticTask_t *tcb; // pointer to the Task Control Block
51+
size_t stack_len; // number of words in the stack
52+
struct _thread_t *next;
53+
} thread_t;
54+
55+
// the mutex controls access to the linked list
56+
STATIC mp_thread_mutex_t thread_mutex;
57+
STATIC thread_t thread_entry0;
58+
STATIC thread_t *thread; // root pointer, handled by mp_thread_gc_others
59+
60+
void mp_thread_init(void *stack, uint32_t stack_len) {
61+
mp_thread_set_state(&mp_state_ctx.thread);
62+
// create the first entry in the linked list of all threads
63+
thread = &thread_entry0;
64+
thread->id = xTaskGetCurrentTaskHandle();
65+
thread->ready = 1;
66+
thread->arg = NULL;
67+
thread->stack = stack;
68+
thread->stack_len = stack_len;
69+
thread->next = NULL;
70+
mp_thread_mutex_init(&thread_mutex);
71+
}
72+
73+
void mp_thread_gc_others(void) {
74+
mp_thread_mutex_lock(&thread_mutex, 1);
75+
for (thread_t *th = thread; th != NULL; th = th->next) {
76+
gc_collect_root((void**)&th, 1);
77+
gc_collect_root(&th->arg, 1); // probably not needed
78+
if (th->id == xTaskGetCurrentTaskHandle()) {
79+
continue;
80+
}
81+
if (!th->ready) {
82+
continue;
83+
}
84+
gc_collect_root(th->stack, th->stack_len); // probably not needed
85+
}
86+
mp_thread_mutex_unlock(&thread_mutex);
87+
}
88+
89+
mp_state_thread_t *mp_thread_get_state(void) {
90+
return pvTaskGetThreadLocalStoragePointer(NULL, 1);
91+
}
92+
93+
void mp_thread_set_state(void *state) {
94+
vTaskSetThreadLocalStoragePointer(NULL, 1, state);
95+
}
96+
97+
void mp_thread_start(void) {
98+
mp_thread_mutex_lock(&thread_mutex, 1);
99+
for (thread_t *th = thread; th != NULL; th = th->next) {
100+
if (th->id == xTaskGetCurrentTaskHandle()) {
101+
th->ready = 1;
102+
break;
103+
}
104+
}
105+
mp_thread_mutex_unlock(&thread_mutex);
106+
}
107+
108+
STATIC void *(*ext_thread_entry)(void*) = NULL;
109+
110+
STATIC void freertos_entry(void *arg) {
111+
if (ext_thread_entry) {
112+
ext_thread_entry(arg);
113+
}
114+
vTaskDelete(NULL);
115+
for (;;);
116+
}
117+
118+
void mp_thread_create_ex(void *(*entry)(void*), void *arg, size_t *stack_size, int priority, char *name) {
119+
// store thread entry function into a global variable so we can access it
120+
ext_thread_entry = entry;
121+
122+
if (*stack_size == 0) {
123+
*stack_size = MP_THREAD_DEFAULT_STACK_SIZE; // default stack size
124+
} else if (*stack_size < MP_THREAD_MIN_STACK_SIZE) {
125+
*stack_size = MP_THREAD_MIN_STACK_SIZE; // minimum stack size
126+
}
127+
128+
// allocate TCB, stack and linked-list node (must be outside thread_mutex lock)
129+
StaticTask_t *tcb = m_new(StaticTask_t, 1);
130+
StackType_t *stack = m_new(StackType_t, *stack_size / sizeof(StackType_t));
131+
thread_t *th = m_new_obj(thread_t);
132+
133+
mp_thread_mutex_lock(&thread_mutex, 1);
134+
135+
// create thread
136+
TaskHandle_t id = xTaskCreateStaticPinnedToCore(freertos_entry, name, *stack_size / sizeof(StackType_t), arg, priority, stack, tcb, 0);
137+
if (id == NULL) {
138+
mp_thread_mutex_unlock(&thread_mutex);
139+
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread"));
140+
}
141+
142+
// adjust the stack_size to provide room to recover from hitting the limit
143+
*stack_size -= 1024;
144+
145+
// add thread to linked list of all threads
146+
th->id = id;
147+
th->ready = 0;
148+
th->arg = arg;
149+
th->stack = stack;
150+
th->tcb = tcb;
151+
th->stack_len = *stack_size / sizeof(StackType_t);
152+
th->next = thread;
153+
thread = th;
154+
155+
mp_thread_mutex_unlock(&thread_mutex);
156+
}
157+
158+
void mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size) {
159+
mp_thread_create_ex(entry, arg, stack_size, MP_THREAD_PRIORITY, "mp_thread");
160+
}
161+
162+
void mp_thread_finish(void) {
163+
mp_thread_mutex_lock(&thread_mutex, 1);
164+
for (thread_t *th = thread; th != NULL; th = th->next) {
165+
if (th->id == xTaskGetCurrentTaskHandle()) {
166+
th->ready = 0;
167+
break;
168+
}
169+
}
170+
mp_thread_mutex_unlock(&thread_mutex);
171+
}
172+
173+
void vPortCleanUpTCB(void *tcb) {
174+
thread_t *prev = NULL;
175+
mp_thread_mutex_lock(&thread_mutex, 1);
176+
for (thread_t *th = thread; th != NULL; prev = th, th = th->next) {
177+
// unlink the node from the list
178+
if (th->tcb == tcb) {
179+
if (prev != NULL) {
180+
prev->next = th->next;
181+
} else {
182+
// move the start pointer
183+
thread = th->next;
184+
}
185+
// explicitly release all its memory
186+
m_del(StaticTask_t, th->tcb, 1);
187+
m_del(StackType_t, th->stack, th->stack_len);
188+
m_del(thread_t, th, 1);
189+
break;
190+
}
191+
}
192+
mp_thread_mutex_unlock(&thread_mutex);
193+
}
194+
195+
void mp_thread_mutex_init(mp_thread_mutex_t *mutex) {
196+
mutex->handle = xSemaphoreCreateMutexStatic(&mutex->buffer);
197+
}
198+
199+
int mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait) {
200+
return (pdTRUE == xSemaphoreTake(mutex->handle, wait ? portMAX_DELAY : 0));
201+
}
202+
203+
void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex) {
204+
xSemaphoreGive(mutex->handle);
205+
}
206+
207+
void mp_thread_deinit(void) {
208+
mp_thread_mutex_lock(&thread_mutex, 1);
209+
for (thread_t *th = thread; th != NULL; th = th->next) {
210+
// don't delete the current task
211+
if (th->id == xTaskGetCurrentTaskHandle()) {
212+
continue;
213+
}
214+
vTaskDelete(th->id);
215+
}
216+
mp_thread_mutex_unlock(&thread_mutex);
217+
// allow FreeRTOS to clean-up the threads
218+
vTaskDelay(2);
219+
}
220+
221+
#else
222+
223+
void vPortCleanUpTCB(void *tcb) {
224+
}
225+
226+
#endif // MICROPY_PY_THREAD

esp32/mpthreadport.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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+
#ifndef MICROPY_INCLUDED_ESP32_MPTHREADPORT_H
29+
#define MICROPY_INCLUDED_ESP32_MPTHREADPORT_H
30+
31+
#include "freertos/FreeRTOS.h"
32+
#include "freertos/task.h"
33+
#include "freertos/semphr.h"
34+
#include "freertos/queue.h"
35+
36+
typedef struct _mp_thread_mutex_t {
37+
SemaphoreHandle_t handle;
38+
StaticSemaphore_t buffer;
39+
} mp_thread_mutex_t;
40+
41+
void mp_thread_init(void *stack, uint32_t stack_len);
42+
void mp_thread_gc_others(void);
43+
void mp_thread_deinit(void);
44+
45+
#endif // MICROPY_INCLUDED_ESP32_MPTHREADPORT_H

esp32/sdkconfig.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@
3636
#define CONFIG_FREERTOS_ASSERT_FAIL_ABORT 1
3737
#define CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION 1
3838
#define CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE 1
39-
#define CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS 1
39+
#define CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS 2
4040
#define CONFIG_FREERTOS_ISR_STACKSIZE 1536
4141
#define CONFIG_FREERTOS_BREAK_ON_SCHEDULER_START_JTAG 1
4242
#define CONFIG_FREERTOS_MAX_TASK_NAME_LEN 16
43+
#define CONFIG_SUPPORT_STATIC_ALLOCATION 1
44+
#define CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK 1
4345

4446
#define CONFIG_MAIN_TASK_STACK_SIZE 4096
4547
#define CONFIG_BTC_TASK_STACK_SIZE 3072

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy