mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/pthread_name_affinity_config' into 'master'
pthread: make affinity and task name configurable See merge request idf/esp-idf!3878
This commit is contained in:
commit
37975c186d
@ -19,4 +19,31 @@ config PTHREAD_STACK_MIN
|
|||||||
help
|
help
|
||||||
Minimum allowed pthread stack size set in attributes passed to pthread_create
|
Minimum allowed pthread stack size set in attributes passed to pthread_create
|
||||||
|
|
||||||
|
choice ESP32_PTHREAD_TASK_CORE_DEFAULT
|
||||||
|
bool "Default pthread core affinity"
|
||||||
|
default ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY
|
||||||
|
depends on !FREERTOS_UNICORE
|
||||||
|
help
|
||||||
|
The default core to which pthreads are pinned.
|
||||||
|
|
||||||
|
config ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY
|
||||||
|
bool "No affinity"
|
||||||
|
config ESP32_DEFAULT_PTHREAD_CORE_0
|
||||||
|
bool "Core 0"
|
||||||
|
config ESP32_DEFAULT_PTHREAD_CORE_1
|
||||||
|
bool "Core 1"
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
config ESP32_PTHREAD_TASK_CORE_DEFAULT
|
||||||
|
int
|
||||||
|
default -1 if ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY || FREERTOS_UNICORE
|
||||||
|
default 0 if ESP32_DEFAULT_PTHREAD_CORE_0
|
||||||
|
default 1 if ESP32_DEFAULT_PTHREAD_CORE_1
|
||||||
|
|
||||||
|
config ESP32_PTHREAD_TASK_NAME_DEFAULT
|
||||||
|
string "Default name of pthreads"
|
||||||
|
default "pthread"
|
||||||
|
help
|
||||||
|
The default name of pthreads.
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
@ -14,6 +14,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include <freertos/FreeRTOSConfig.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@ -24,11 +27,22 @@ extern "C" {
|
|||||||
|
|
||||||
/** pthread configuration structure that influences pthread creation */
|
/** pthread configuration structure that influences pthread creation */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
size_t stack_size; ///< the stack size of the pthread
|
size_t stack_size; ///< The stack size of the pthread
|
||||||
size_t prio; ///< the thread's priority
|
size_t prio; ///< The thread's priority
|
||||||
bool inherit_cfg; ///< inherit this configuration further
|
bool inherit_cfg; ///< Inherit this configuration further
|
||||||
|
const char* thread_name; ///< The thread name.
|
||||||
|
int pin_to_core; ///< The core id to pin the thread to. Has the same value range as xCoreId argument of xTaskCreatePinnedToCore.
|
||||||
} esp_pthread_cfg_t;
|
} esp_pthread_cfg_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a default pthread configuration based
|
||||||
|
* on the values set via menuconfig.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* A default configuration structure.
|
||||||
|
*/
|
||||||
|
esp_pthread_cfg_t esp_pthread_get_default_config();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Configure parameters for creating pthread
|
* @brief Configure parameters for creating pthread
|
||||||
*
|
*
|
||||||
|
@ -136,7 +136,6 @@ static void pthread_delete(esp_pthread_t *pthread)
|
|||||||
free(pthread);
|
free(pthread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Call this function to configure pthread stacks in Pthreads */
|
/* Call this function to configure pthread stacks in Pthreads */
|
||||||
esp_err_t esp_pthread_set_cfg(const esp_pthread_cfg_t *cfg)
|
esp_err_t esp_pthread_set_cfg(const esp_pthread_cfg_t *cfg)
|
||||||
{
|
{
|
||||||
@ -168,6 +167,24 @@ esp_err_t esp_pthread_get_cfg(esp_pthread_cfg_t *p)
|
|||||||
return ESP_ERR_NOT_FOUND;
|
return ESP_ERR_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int get_default_pthread_core()
|
||||||
|
{
|
||||||
|
return CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT == -1 ? tskNO_AFFINITY : CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_pthread_cfg_t esp_pthread_get_default_config()
|
||||||
|
{
|
||||||
|
esp_pthread_cfg_t cfg = {
|
||||||
|
.stack_size = CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT,
|
||||||
|
.prio = CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT,
|
||||||
|
.inherit_cfg = false,
|
||||||
|
.thread_name = NULL,
|
||||||
|
.pin_to_core = get_default_pthread_core()
|
||||||
|
};
|
||||||
|
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
|
||||||
static void pthread_task_func(void *arg)
|
static void pthread_task_func(void *arg)
|
||||||
{
|
{
|
||||||
void *rval = NULL;
|
void *rval = NULL;
|
||||||
@ -179,8 +196,13 @@ static void pthread_task_func(void *arg)
|
|||||||
xTaskNotifyWait(0, 0, NULL, portMAX_DELAY);
|
xTaskNotifyWait(0, 0, NULL, portMAX_DELAY);
|
||||||
|
|
||||||
if (task_arg->cfg.inherit_cfg) {
|
if (task_arg->cfg.inherit_cfg) {
|
||||||
/* If inherit option is set, then do a set_cfg() ourselves for future forks */
|
/* If inherit option is set, then do a set_cfg() ourselves for future forks,
|
||||||
esp_pthread_set_cfg(&task_arg->cfg);
|
but first set thread_name to NULL to enable inheritance of the name too.
|
||||||
|
(This also to prevents dangling pointers to name of tasks that might
|
||||||
|
possibly have been deleted when we use the configuration).*/
|
||||||
|
esp_pthread_cfg_t *cfg = &task_arg->cfg;
|
||||||
|
cfg->thread_name = NULL;
|
||||||
|
esp_pthread_set_cfg(cfg);
|
||||||
}
|
}
|
||||||
ESP_LOGV(TAG, "%s START %p", __FUNCTION__, task_arg->func);
|
ESP_LOGV(TAG, "%s START %p", __FUNCTION__, task_arg->func);
|
||||||
rval = task_arg->func(task_arg->arg);
|
rval = task_arg->func(task_arg->arg);
|
||||||
@ -212,6 +234,8 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
|||||||
|
|
||||||
uint32_t stack_size = CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT;
|
uint32_t stack_size = CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT;
|
||||||
BaseType_t prio = CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT;
|
BaseType_t prio = CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT;
|
||||||
|
BaseType_t core_id = get_default_pthread_core();
|
||||||
|
const char *task_name = CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT;
|
||||||
|
|
||||||
esp_pthread_cfg_t *pthread_cfg = pthread_getspecific(s_pthread_cfg_key);
|
esp_pthread_cfg_t *pthread_cfg = pthread_getspecific(s_pthread_cfg_key);
|
||||||
if (pthread_cfg) {
|
if (pthread_cfg) {
|
||||||
@ -221,6 +245,25 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
|||||||
if (pthread_cfg->prio && pthread_cfg->prio < configMAX_PRIORITIES) {
|
if (pthread_cfg->prio && pthread_cfg->prio < configMAX_PRIORITIES) {
|
||||||
prio = pthread_cfg->prio;
|
prio = pthread_cfg->prio;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pthread_cfg->inherit_cfg) {
|
||||||
|
if (pthread_cfg->thread_name == NULL) {
|
||||||
|
// Inherit task name from current task.
|
||||||
|
task_name = pcTaskGetTaskName(NULL);
|
||||||
|
} else {
|
||||||
|
// Inheriting, but new task name.
|
||||||
|
task_name = pthread_cfg->thread_name;
|
||||||
|
}
|
||||||
|
} else if (pthread_cfg->thread_name == NULL) {
|
||||||
|
task_name = CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT;
|
||||||
|
} else {
|
||||||
|
task_name = pthread_cfg->thread_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pthread_cfg->pin_to_core >= 0 && pthread_cfg->pin_to_core < portNUM_PROCESSORS) {
|
||||||
|
core_id = pthread_cfg->pin_to_core;
|
||||||
|
}
|
||||||
|
|
||||||
task_arg->cfg = *pthread_cfg;
|
task_arg->cfg = *pthread_cfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,9 +284,15 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
|||||||
task_arg->func = start_routine;
|
task_arg->func = start_routine;
|
||||||
task_arg->arg = arg;
|
task_arg->arg = arg;
|
||||||
pthread->task_arg = task_arg;
|
pthread->task_arg = task_arg;
|
||||||
BaseType_t res = xTaskCreate(&pthread_task_func, "pthread", stack_size,
|
BaseType_t res = xTaskCreatePinnedToCore(&pthread_task_func,
|
||||||
task_arg, prio, &xHandle);
|
task_name,
|
||||||
if(res != pdPASS) {
|
stack_size,
|
||||||
|
task_arg,
|
||||||
|
prio,
|
||||||
|
&xHandle,
|
||||||
|
core_id);
|
||||||
|
|
||||||
|
if (res != pdPASS) {
|
||||||
ESP_LOGE(TAG, "Failed to create task!");
|
ESP_LOGE(TAG, "Failed to create task!");
|
||||||
free(pthread);
|
free(pthread);
|
||||||
free(task_arg);
|
free(task_arg);
|
||||||
|
@ -8,6 +8,8 @@ This module offers Espressif specific extensions to the pthread library that can
|
|||||||
* Stack size of the pthreads
|
* Stack size of the pthreads
|
||||||
* Priority of the created pthreads
|
* Priority of the created pthreads
|
||||||
* Inheriting this configuration across threads
|
* Inheriting this configuration across threads
|
||||||
|
* Thread name
|
||||||
|
* Core affinity / core pinning.
|
||||||
|
|
||||||
Example to tune the stack size of the pthread:
|
Example to tune the stack size of the pthread:
|
||||||
|
|
||||||
@ -19,7 +21,7 @@ Example to tune the stack size of the pthread:
|
|||||||
{
|
{
|
||||||
pthread_t t1;
|
pthread_t t1;
|
||||||
|
|
||||||
esp_pthread_cfg_t cfg;
|
esp_pthread_cfg_t cfg = esp_create_default_pthread_config();
|
||||||
cfg.stack_size = (4 * 1024);
|
cfg.stack_size = (4 * 1024);
|
||||||
esp_pthread_set_cfg(&cfg);
|
esp_pthread_set_cfg(&cfg);
|
||||||
|
|
||||||
@ -50,7 +52,7 @@ The API can also be used for inheriting the settings across threads. For example
|
|||||||
|
|
||||||
pthread_t t1;
|
pthread_t t1;
|
||||||
|
|
||||||
esp_pthread_cfg_t cfg;
|
esp_pthread_cfg_t cfg = esp_create_default_pthread_config();
|
||||||
cfg.stack_size = (4 * 1024);
|
cfg.stack_size = (4 * 1024);
|
||||||
cfg.inherit_cfg = true;
|
cfg.inherit_cfg = true;
|
||||||
esp_pthread_set_cfg(&cfg);
|
esp_pthread_set_cfg(&cfg);
|
||||||
|
6
examples/system/cpp_pthread/CMakeLists.txt
Normal file
6
examples/system/cpp_pthread/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||||
|
# in this exact order for cmake to work correctly
|
||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
project(cpp_pthread)
|
9
examples/system/cpp_pthread/Makefile
Normal file
9
examples/system/cpp_pthread/Makefile
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#
|
||||||
|
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||||
|
# project subdirectory.
|
||||||
|
#
|
||||||
|
|
||||||
|
PROJECT_NAME := cpp_pthread
|
||||||
|
|
||||||
|
include $(IDF_PATH)/make/project.mk
|
||||||
|
|
5
examples/system/cpp_pthread/README.md
Normal file
5
examples/system/cpp_pthread/README.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# pthread examples
|
||||||
|
|
||||||
|
This example shows how to use the pthread API to create std::threads with different stack sizes, names, priorities and pinned to certain cores.
|
||||||
|
|
||||||
|
This example is in C++, contrary to the the normal standard of pure C.
|
4
examples/system/cpp_pthread/main/CMakeLists.txt
Normal file
4
examples/system/cpp_pthread/main/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
set(COMPONENT_SRCS "cpp_pthread.cpp")
|
||||||
|
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||||
|
|
||||||
|
register_component()
|
3
examples/system/cpp_pthread/main/component.mk
Normal file
3
examples/system/cpp_pthread/main/component.mk
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#
|
||||||
|
# Main Makefile. This is basically the same as a component makefile.
|
||||||
|
#
|
112
examples/system/cpp_pthread/main/cpp_pthread.cpp
Normal file
112
examples/system/cpp_pthread/main/cpp_pthread.cpp
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/* pthread/std::thread example
|
||||||
|
|
||||||
|
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, this
|
||||||
|
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
#include <chrono>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <esp_pthread.h>
|
||||||
|
#include <freertos/FreeRTOS.h>
|
||||||
|
#include <freertos/task.h>
|
||||||
|
#include <esp_log.h>
|
||||||
|
|
||||||
|
using namespace std::chrono;
|
||||||
|
|
||||||
|
const auto sleep_time = seconds
|
||||||
|
{
|
||||||
|
5
|
||||||
|
};
|
||||||
|
|
||||||
|
void print_thread_info(const char *extra = nullptr)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
if (extra) {
|
||||||
|
ss << extra;
|
||||||
|
}
|
||||||
|
ss << "Core id: " << xPortGetCoreID()
|
||||||
|
<< ", prio: " << uxTaskPriorityGet(nullptr)
|
||||||
|
<< ", minimum free stack: " << uxTaskGetStackHighWaterMark(nullptr) << " bytes.";
|
||||||
|
ESP_LOGI(pcTaskGetTaskName(nullptr), "%s", ss.str().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread_func_inherited()
|
||||||
|
{
|
||||||
|
while (true) {
|
||||||
|
print_thread_info("This is the INHERITING thread with the same parameters as our parent, including name. ");
|
||||||
|
std::this_thread::sleep_for(sleep_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void spawn_another_thread()
|
||||||
|
{
|
||||||
|
// Create a new thread, it will inherit our configuration
|
||||||
|
std::thread inherits(thread_func_inherited);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
print_thread_info();
|
||||||
|
std::this_thread::sleep_for(sleep_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread_func_any_core()
|
||||||
|
{
|
||||||
|
while (true) {
|
||||||
|
print_thread_info("This thread (with the default name) may run on any core.");
|
||||||
|
std::this_thread::sleep_for(sleep_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread_func()
|
||||||
|
{
|
||||||
|
while (true) {
|
||||||
|
print_thread_info();
|
||||||
|
std::this_thread::sleep_for(sleep_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_pthread_cfg_t create_config(const char *name, int core_id, int stack, int prio)
|
||||||
|
{
|
||||||
|
auto cfg = esp_pthread_get_default_config();
|
||||||
|
cfg.thread_name = name;
|
||||||
|
cfg.pin_to_core = core_id;
|
||||||
|
cfg.stack_size = stack;
|
||||||
|
cfg.prio = prio;
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void app_main()
|
||||||
|
{
|
||||||
|
// Create a thread using deafult values that can run on any core
|
||||||
|
auto cfg = esp_pthread_get_default_config();
|
||||||
|
esp_pthread_set_cfg(&cfg);
|
||||||
|
std::thread any_core(thread_func_any_core);
|
||||||
|
|
||||||
|
// Create a thread on core 0 that spawns another thread, they will both have the same name etc.
|
||||||
|
cfg = create_config("Thread 1", 0, 3 * 1024, 5);
|
||||||
|
cfg.inherit_cfg = true;
|
||||||
|
esp_pthread_set_cfg(&cfg);
|
||||||
|
std::thread thread_1(spawn_another_thread);
|
||||||
|
|
||||||
|
// Create a thread on core 1.
|
||||||
|
cfg = create_config("Thread 2", 1, 3 * 1024, 5);
|
||||||
|
esp_pthread_set_cfg(&cfg);
|
||||||
|
std::thread thread_2(thread_func);
|
||||||
|
|
||||||
|
// Let the main task do something too
|
||||||
|
while (true) {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "core id: " << xPortGetCoreID()
|
||||||
|
<< ", prio: " << uxTaskPriorityGet(nullptr)
|
||||||
|
<< ", minimum free stack: " << uxTaskGetStackHighWaterMark(nullptr) << " bytes.";
|
||||||
|
ESP_LOGI(pcTaskGetTaskName(nullptr), "%s", ss.str().c_str());
|
||||||
|
std::this_thread::sleep_for(sleep_time);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user