Skip to content

Commit 938a737

Browse files
Felipe Nevesespressif-bot
authored andcommitted
esp_common/shared_stack: modifed the stack switch procedure to a simpler way
esp_common/shared_stack: refactored the implemenation of shared stack function (still not working properly) esp_expression_with_stack: refactored the shared stack function calling mechanism and updated the documentation
1 parent 1fa7454 commit 938a737

File tree

8 files changed

+109
-103
lines changed

8 files changed

+109
-103
lines changed

components/esp_common/include/esp_expression_with_stack.h

Lines changed: 12 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
// limitations under the License.
1414
#pragma once
1515

16+
#include <stdbool.h>
1617
#include "freertos/FreeRTOS.h"
1718
#include "freertos/semphr.h"
1819
#include "freertos/task.h"
@@ -23,56 +24,25 @@
2324
extern "C" {
2425
#endif
2526

27+
typedef void (*shared_stack_function)(void);
28+
29+
#define ESP_EXECUTE_EXPRESSION_WITH_STACK(lock, stack, stack_size, expression) \
30+
esp_execute_shared_stack_function(lock, stack, stack_size, expression)
31+
2632
/**
27-
* @brief Executes a 1-line expression with a application alocated stack
33+
* @brief Calls user defined shared stack space function
2834
* @param lock Mutex object to protect in case of shared stack
2935
* @param stack Pointer to user alocated stack
3036
* @param stack_size Size of current stack in bytes
31-
* @param expression Expression or function to be executed using the stack
37+
* @param function pointer to the shared stack function to be executed
3238
* @note if either lock, stack or stack size is invalid, the expression will
3339
* be called using the current stack.
3440
*/
35-
#define ESP_EXECUTE_EXPRESSION_WITH_STACK(lock, stack, stack_size, expression) \
36-
({ \
37-
assert(lock && stack && (stack_size >= CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE)); \
38-
uint32_t backup; \
39-
xSemaphoreTake(lock, portMAX_DELAY); \
40-
StackType_t *top_of_stack = esp_switch_stack_setup(stack, stack_size); \
41-
esp_switch_stack_enter(top_of_stack, &backup); \
42-
{ \
43-
expression; \
44-
} \
45-
esp_switch_stack_exit(&backup); \
46-
StaticTask_t *current = (StaticTask_t *)xTaskGetCurrentTaskHandle(); \
47-
/* pxDummy6 is the stack base of current thread defined in TCB_t */ \
48-
/* place the watchpoint on current task stack after function execution*/ \
49-
vPortSetStackWatchpoint(current->pxDummy6); \
50-
xSemaphoreGive(lock); \
51-
})
52-
53-
/**
54-
* @brief Fill stack frame with CPU-specifics value before use
55-
* @param stack Caller allocated stack pointer
56-
* @param stack_size Size of stack in bytes
57-
* @return New pointer to the top of stack
58-
* @note Application must not call this function directly
59-
*/
60-
StackType_t * esp_switch_stack_setup(StackType_t *stack, size_t stack_size);
41+
void esp_execute_shared_stack_function(SemaphoreHandle_t lock,
42+
void *stack,
43+
size_t stack_size,
44+
shared_stack_function function);
6145

62-
/**
63-
* @brief Changes CPU sp-register to use another stack space and save the previous one
64-
* @param stack Caller allocated stack pointer
65-
* @param backup_stack Pointer to a place to save the current stack
66-
* @note Application must not call this function directly
67-
*/
68-
extern void esp_switch_stack_enter(StackType_t *stack, uint32_t *backup_stack);
69-
70-
/**
71-
* @brief Restores the previous CPU sp-register
72-
* @param backup_stack Pointer to the place where stack was saved
73-
* @note Application must not call this function directly
74-
*/
75-
extern void esp_switch_stack_exit(uint32_t *backup_stack);
7646

7747
#ifdef __cplusplus
7848
}

components/newlib/test/test_shared_stack_printf.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,32 @@
88
#include "test_utils.h"
99
#include "esp_expression_with_stack.h"
1010

11-
//makes sure this is not the task stack...
11+
void external_stack_function(void)
12+
{
13+
printf("Executing this printf from external stack! sp=%p\n", get_sp());
14+
}
15+
1216
void another_external_stack_function(void)
1317
{
1418
//We can even use Freertos resources inside of this context.
19+
printf("We can even use FreeRTOS resources delaying..., sp=%p\n", get_sp());
1520
vTaskDelay(100);
16-
printf("Executing this another printf inside a function with external stack");
21+
printf("Done!, sp=%p\n", get_sp());
1722
}
1823

1924
TEST_CASE("test printf using shared buffer stack", "[newlib]")
2025
{
21-
portSTACK_TYPE *shared_stack = malloc(8192 * sizeof(portSTACK_TYPE));
26+
portSTACK_TYPE *shared_stack = malloc(8192);
2227

2328
TEST_ASSERT(shared_stack != NULL);
2429

2530
SemaphoreHandle_t printf_lock = xSemaphoreCreateMutex();
2631
TEST_ASSERT_NOT_NULL(printf_lock);
32+
printf("SP: %p\n", get_sp());
33+
printf("shared_stack: %p\n", (void *)shared_stack);
2734

28-
ESP_EXECUTE_EXPRESSION_WITH_STACK(printf_lock, shared_stack,8192,printf("Executing this printf from external stack! \n"));
29-
ESP_EXECUTE_EXPRESSION_WITH_STACK(printf_lock, shared_stack,8192,another_external_stack_function());
35+
esp_execute_shared_stack_function(printf_lock, shared_stack,8192,external_stack_function);
36+
esp_execute_shared_stack_function(printf_lock, shared_stack,8192,another_external_stack_function);
3037
vSemaphoreDelete(printf_lock);
3138
free(shared_stack);
3239
}

components/xtensa/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ else()
77
set(priv_requires soc freertos)
88
set(srcs "debug_helpers.c"
99
"debug_helpers_asm.S"
10-
"expression_with_stack_xtensa_asm.S"
1110
"expression_with_stack_xtensa.c"
11+
"expression_with_stack_xtensa_asm.S"
1212
"eri.c"
1313
"trax.c"
1414
"${target}/trax_init.c"

components/xtensa/expression_with_stack_xtensa.c

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,29 +15,58 @@
1515
#include <esp_expression_with_stack.h>
1616
#include <freertos/xtensa_rtos.h>
1717
#include <freertos/xtensa_context.h>
18+
#include <setjmp.h>
1819

19-
StackType_t * esp_switch_stack_setup(StackType_t *stack, size_t stack_size)
20+
StackType_t *shared_stack;
21+
shared_stack_function shared_stack_callback;
22+
jmp_buf shared_stack_env;
23+
bool shared_stack_function_done = false;
24+
portMUX_TYPE shared_stack_spinlock = portMUX_INITIALIZER_UNLOCKED;
25+
26+
extern void esp_shared_stack_invoke_function(void);
27+
28+
static void esp_switch_stack_setup(StackType_t *stack, size_t stack_size)
2029
{
2130
#if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
2231
esp_clear_watchpoint(1);
23-
uint32_t watchpoint_place = ((uint32_t)stack + 32) & 0x1f ;
32+
uint32_t watchpoint_place = ((uint32_t)stack + 32) & ~0x1f ;
2433
#endif
25-
StackType_t *top_of_stack = (StackType_t *)&stack[0] +
26-
((stack_size * sizeof(StackType_t)) / sizeof(StackType_t));
34+
StackType_t *top_of_stack = stack + stack_size;
2735

2836
//Align stack to a 16byte boundary, as required by CPU specific:
29-
top_of_stack = (StackType_t *)(((UBaseType_t)(top_of_stack - 31) -
30-
ALIGNUP(0x10, sizeof(XtSolFrame) )) &
31-
~0xf);
32-
33-
//Fake stack frame to do not break the backtrace
34-
XtSolFrame *frame = (XtSolFrame *)top_of_stack;
35-
frame->a0 = 0;
36-
frame->a1 = (UBaseType_t)top_of_stack;
37+
top_of_stack = (StackType_t *)(((UBaseType_t)(top_of_stack - 16) & ~0xf));
3738

3839
#if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
3940
esp_set_watchpoint(1, (uint8_t *)watchpoint_place, 32, ESP_WATCHPOINT_STORE);
4041
#endif
4142

42-
return top_of_stack;
43+
shared_stack = top_of_stack;
44+
}
45+
46+
47+
void esp_execute_shared_stack_function(SemaphoreHandle_t lock, void *stack, size_t stack_size, shared_stack_function function)
48+
{
49+
assert(lock);
50+
assert(stack);
51+
assert(stack_size > 0 && stack_size >= CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE);
52+
assert(function);
53+
54+
xSemaphoreTake(lock, portMAX_DELAY);
55+
portENTER_CRITICAL(&shared_stack_spinlock);
56+
shared_stack_function_done = false;
57+
esp_switch_stack_setup(stack, stack_size);
58+
shared_stack_callback = function;
59+
portEXIT_CRITICAL(&shared_stack_spinlock);
60+
61+
setjmp(shared_stack_env);
62+
if(!shared_stack_function_done) {
63+
esp_shared_stack_invoke_function();
64+
}
65+
66+
portENTER_CRITICAL(&shared_stack_spinlock);
67+
StaticTask_t *current = (StaticTask_t *)xTaskGetCurrentTaskHandle();
68+
vPortSetStackWatchpoint(current->pxDummy6);
69+
portEXIT_CRITICAL(&shared_stack_spinlock);
70+
71+
xSemaphoreGive(lock);
4372
}

components/xtensa/expression_with_stack_xtensa_asm.S

Lines changed: 22 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -14,43 +14,34 @@
1414

1515
#include <freertos/xtensa_context.h>
1616

17-
.extern esp_clear_watchpoint
17+
.extern shared_stack
18+
.extern shared_stack_callback
19+
.extern shared_stack_function_done
20+
.extern longjmp
1821
.text
1922

20-
/**
21-
* extern void switch_stack_enter(portSTACK_TYPE *stack, portSTACK_TYPE *backup_stack);
22-
*/
23-
.globl esp_switch_stack_enter
24-
.type esp_switch_stack_enter,@function
25-
.align 4
26-
esp_switch_stack_enter:
2723

28-
#ifndef __XTENSA_CALL0_ABI__
29-
entry sp, 0x10
30-
mov a4, a1
31-
s32i a4, a3, 0 /* on a3 there is a safe place to save the current stack */
32-
l32i a4, a2, 0 /* obtains the user allocated stack buffer */
33-
mov a1, a4 /* sp register now contains caller specified stack */
34-
retw
35-
#else
36-
#error "this code is written for Window ABI"
37-
#endif
24+
/* extern void esp_shared_stack_invoke_function(void) */
3825

39-
/**
40-
* extern void switch_stack_exit(portSTACK_TYPE *backup_stack);
41-
*/
42-
.globl esp_switch_stack_exit
43-
.type esp_switch_stack_exit,@function
44-
.align 4
45-
esp_switch_stack_exit:
26+
.globl esp_shared_stack_invoke_function
27+
.type esp_shared_stack_invoke_function,@function
28+
.align 4
29+
esp_shared_stack_invoke_function:
4630

4731
#ifndef __XTENSA_CALL0_ABI__
48-
entry sp, 0x10
49-
50-
l32i a4, a2, 0 /* recover the original task stack */
51-
mov a1, a4 /* put it on sp register again */
52-
retw
53-
32+
movi a0, 0 /* no need to rotate window, it will be destroyed anyway */
33+
movi a6, shared_stack
34+
l32i sp, a6, 0 /* load shared stack pointer */
35+
movi a12, shared_stack_callback
36+
l32i a12, a12, 0
37+
callx4 a12 /* call user function */
38+
movi a6, shared_stack_function_done
39+
movi a7, 1
40+
s32i a7, a6, 0 /* hint the function was finished */
41+
movi a6, shared_stack_env
42+
movi a7, 0
43+
call4 longjmp /* jump to last clean state previously saved */
44+
ret
5445
#else
5546
#error "this code is written for Window ABI"
5647
#endif

docs/en/api-reference/system/esp_expression_with_stack.rst renamed to docs/en/api-reference/system/esp_function_with_shared_stack.rst

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,31 @@ A given function can be executed with a user allocated stack space
88
which is independent of current task stack, this mechanism can be
99
used to save stack space wasted by tasks which call a common function
1010
with intensive stack usage such as `printf`. The given function can
11-
be called inside the macro :cpp:func:`ESP_EXECUTE_EXPRESSION_WITH_STACK`
12-
it will redirect the target function to be executed using the space
13-
allocated by the user.
11+
be called inside the shared stack space which is a callback function
12+
deferred by calling :cpp:func:`esp_execute_shared_stack_function`,
13+
passing that function as parameter
1414

1515
Usage
1616
-----
1717

18-
:cpp:func:`ESP_EXECUTE_EXPRESSION_WITH_STACK` takes three arguments,
18+
:cpp:func:`esp_execute_shared_stack_function` takes four arguments,
1919
a mutex object allocated by the caller, which is used to protect if
2020
the same function shares its allocated stack, a pointer to the top
21-
of stack used to that fuction, and the function itself, note the
22-
function is passed exactly in the same way as do when you call
23-
it on a regular way.
21+
of stack used to that fuction, the size in bytes of stack and, a pointer
22+
to a user function where the shared stack space will reside, after calling
23+
the function, the user defined function will be deferred as a callback
24+
where functions can be called using the user allocated space without
25+
taking space from current task stack.
2426

2527
The usage may looks like the code below:
2628

2729
.. code-block:: c
2830
31+
void external_stack_function(void)
32+
{
33+
printf("Executing this printf from external stack! \n");
34+
}
35+
2936
//Let's suppose we wanting to call printf using a separated stack space
3037
//allowing app to reduce its stack size.
3138
void app_main()
@@ -39,9 +46,11 @@ The usage may looks like the code below:
3946
assert(printf_lock != NULL);
4047
4148
//Call the desired function using the macro helper:
42-
ESP_EXECUTE_EXPRESSION_WITH_STACK(printf_lock,
43-
shared_stack,
44-
printf("Executing this from external stack! \n"));
49+
esp_execute_shared_stack_function(printf_lock,
50+
shared_stack,
51+
8192,
52+
external_stack_function);
53+
4554
vSemaphoreDelete(printf_lock);
4655
free(shared_stack);
4756
}

docs/zh_CN/api-reference/system/esp_expression_with_stack.rst

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.. include:: ../../../en/api-reference/system/esp_function_with_shared_stack.rst

0 commit comments

Comments
 (0)