From 7a0cab0a5b3d2c7208892655eb8ac41cc78bd9cc Mon Sep 17 00:00:00 2001 From: Kedar Sovani Date: Sun, 25 Feb 2018 14:56:04 +0530 Subject: [PATCH] pthread: Allow configuration of priority and stacksize The expected usage is: esp_pthread_set_cfg(cfg); pthread_create() If the inherit flag is set, then all subsequent threads forked by this thread will also inherit this configuration. This avoids having to change/prefix this for each and every pthread_create() call. --- components/pthread/component.mk | 2 +- components/pthread/include/esp_pthread.h | 57 ++++++++++++++++ components/pthread/pthread.c | 61 ++++++++++++++++- docs/Doxyfile | 2 + docs/en/api-reference/system/esp_pthread.rst | 65 +++++++++++++++++++ docs/en/api-reference/system/index.rst | 1 + .../api-reference/system/esp_pthread.rst | 1 + 7 files changed, 185 insertions(+), 4 deletions(-) create mode 100644 components/pthread/include/esp_pthread.h create mode 100644 docs/en/api-reference/system/esp_pthread.rst create mode 100644 docs/zh_CN/api-reference/system/esp_pthread.rst diff --git a/components/pthread/component.mk b/components/pthread/component.mk index cd69bb330..97ace4b78 100644 --- a/components/pthread/component.mk +++ b/components/pthread/component.mk @@ -4,6 +4,6 @@ COMPONENT_SRCDIRS := . -#COMPONENT_ADD_INCLUDEDIRS := include +COMPONENT_ADD_INCLUDEDIRS := include COMPONENT_ADD_LDFLAGS := -lpthread diff --git a/components/pthread/include/esp_pthread.h b/components/pthread/include/esp_pthread.h new file mode 100644 index 000000000..ae3c2d68f --- /dev/null +++ b/components/pthread/include/esp_pthread.h @@ -0,0 +1,57 @@ +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include + +/** pthread configuration structure that influences pthread creation */ +typedef struct { + size_t stack_size; ///< the stack size of the pthread + size_t prio; ///< the thread's priority + bool inherit_cfg; ///< inherit this configuration further +} esp_pthread_cfg_t; + +/** + * @brief Configure parameters for creating pthread + * + * This API allows you to configure how the subsequent + * pthread_create() call will behave. This call can be used to setup + * configuration parameters like stack size, priority, configuration + * inheritance etc. + * + * If the 'inherit' flag in the configuration structure is enabled, + * then the same configuration is also inherited in the thread + * subtree. + * + * @param cfg The pthread config parameters + * + * @return + * - ESP_OK if configuration was successfully set + * - ESP_ERR_NO_MEM if out of memory + */ +esp_err_t esp_pthread_set_cfg(const esp_pthread_cfg_t *cfg); + +/** + * @brief Get current pthread creation configuration + * + * This will retrieve the current configuration that will be used for + * creating threads. + * + * @param p Pointer to the pthread config structure that will be + * updated with the currently configured parameters + * + * @return + * - ESP_OK if the configuration was available + * - ESP_ERR_NOT_FOUND if a configuration wasn't previously set + */ +esp_err_t esp_pthread_get_cfg(esp_pthread_cfg_t *p); + diff --git a/components/pthread/pthread.c b/components/pthread/pthread.c index 0ce185425..9d7822b86 100644 --- a/components/pthread/pthread.c +++ b/components/pthread/pthread.c @@ -29,6 +29,7 @@ #include "freertos/semphr.h" #include "pthread_internal.h" +#include "esp_pthread.h" #define LOG_LOCAL_LEVEL CONFIG_LOG_DEFAULT_LEVEL #include "esp_log.h" @@ -53,6 +54,7 @@ typedef struct esp_pthread_entry { typedef struct { void *(*func)(void *); ///< user task entry void *arg; ///< user task argument + esp_pthread_cfg_t cfg; ///< pthread configuration } esp_pthread_task_arg_t; /** pthread mutex FreeRTOS wrapper */ @@ -66,14 +68,24 @@ static SemaphoreHandle_t s_threads_mux = NULL; static portMUX_TYPE s_mutex_init_lock = portMUX_INITIALIZER_UNLOCKED; static SLIST_HEAD(esp_thread_list_head, esp_pthread_entry) s_threads_list = SLIST_HEAD_INITIALIZER(s_threads_list); +static pthread_key_t s_pthread_cfg_key; static int IRAM_ATTR pthread_mutex_lock_internal(esp_pthread_mutex_t *mux, TickType_t tmo); +static void esp_pthread_cfg_key_destructor(void *value) +{ + free(value); +} + esp_err_t esp_pthread_init(void) { + if (pthread_key_create(&s_pthread_cfg_key, esp_pthread_cfg_key_destructor) != 0) { + return ESP_ERR_NO_MEM; + } s_threads_mux = xSemaphoreCreateMutex(); if (s_threads_mux == NULL) { + pthread_key_delete(s_pthread_cfg_key); return ESP_ERR_NO_MEM; } return ESP_OK; @@ -123,15 +135,46 @@ static void pthread_delete(esp_pthread_t *pthread) free(pthread); } + +/* Call this function to configure pthread stacks in Pthreads */ +esp_err_t esp_pthread_set_cfg(const esp_pthread_cfg_t *cfg) +{ + /* If a value is already set, update that value */ + esp_pthread_cfg_t *p = pthread_getspecific(s_pthread_cfg_key); + if (!p) { + p = malloc(sizeof(esp_pthread_cfg_t)); + if (!p) { + return ESP_ERR_NO_MEM; + } + } + *p = *cfg; + pthread_setspecific(s_pthread_cfg_key, p); + return 0; +} + +esp_err_t esp_pthread_get_cfg(esp_pthread_cfg_t *p) +{ + esp_pthread_cfg_t *cfg = pthread_getspecific(s_pthread_cfg_key); + if (cfg) { + *p = *cfg; + return ESP_OK; + } + memset(p, 0, sizeof(*p)); + return ESP_ERR_NOT_FOUND; +} + static void pthread_task_func(void *arg) { esp_pthread_task_arg_t *task_arg = (esp_pthread_task_arg_t *)arg; ESP_LOGV(TAG, "%s ENTER %p", __FUNCTION__, task_arg->func); - // wait for start xTaskNotifyWait(0, 0, NULL, portMAX_DELAY); + if (task_arg->cfg.inherit_cfg) { + /* If inherit option is set, then do a set_cfg() ourselves for future forks */ + esp_pthread_set_cfg(&task_arg->cfg); + } ESP_LOGV(TAG, "%s START %p", __FUNCTION__, task_arg->func); task_arg->func(task_arg->arg); ESP_LOGV(TAG, "%s END %p", __FUNCTION__, task_arg->func); @@ -190,11 +233,23 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr, free(task_arg); return ENOMEM; } + uint32_t stack_size = CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT; + BaseType_t prio = CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT; + esp_pthread_cfg_t *pthread_cfg = pthread_getspecific(s_pthread_cfg_key); + if (pthread_cfg) { + if (pthread_cfg->stack_size) { + stack_size = pthread_cfg->stack_size; + } + if (pthread_cfg->prio && pthread_cfg->prio < configMAX_PRIORITIES) { + prio = pthread_cfg->prio; + } + task_arg->cfg = *pthread_cfg; + } memset(pthread, 0, sizeof(esp_pthread_t)); task_arg->func = start_routine; task_arg->arg = arg; - BaseType_t res = xTaskCreate(&pthread_task_func, "pthread", CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT, - task_arg, CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT, &xHandle); + BaseType_t res = xTaskCreate(&pthread_task_func, "pthread", stack_size, + task_arg, prio, &xHandle); if(res != pdPASS) { ESP_LOGE(TAG, "Failed to create task!"); free(pthread); diff --git a/docs/Doxyfile b/docs/Doxyfile index 0eb592737..3cfb49d37 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -155,6 +155,8 @@ INPUT = \ ../../components/esp32/include/esp32/pm.h \ ### esp_timer, High Resolution Timer ../../components/esp32/include/esp_timer.h \ + ### ESP Pthread parameters + ../../components/pthread/include/esp_pthread.h \ ### ### FreeRTOS ### diff --git a/docs/en/api-reference/system/esp_pthread.rst b/docs/en/api-reference/system/esp_pthread.rst new file mode 100644 index 000000000..7e43ce365 --- /dev/null +++ b/docs/en/api-reference/system/esp_pthread.rst @@ -0,0 +1,65 @@ +ESP-pthread +=========== + +Overview +-------- + +This module offers Espressif specific extensions to the pthread library that can be used to influence the behaviour of pthreads. Currently the following configuration can be tuned: + * Stack size of the pthreads + * Priority of the created pthreads + * Inheriting this configuration across threads + +Example to tune the stack size of the pthread: + +.. highlight:: c + +:: + + main() + { + pthread_t t1; + + esp_pthread_cfg_t cfg; + cfg.stack_size = (4 * 1024); + esp_pthread_set_cfg(&cfg); + + pthread_create(&t1, NULL, thread_func); + } + +The API can also be used for inheriting the settings across threads. For example: + +.. highlight:: c + +:: + + void * my_thread2(void * p) + { + /* This thread will inherit the stack size of 4K */ + printf("In my_thread2\n"); + } + + void * my_thread1(void * p) + { + printf("In my_thread1\n"); + pthread_t t2; + pthread_create(&t2, NULL, my_thread2); + } + + main() + { + + pthread_t t1; + + esp_pthread_cfg_t cfg; + cfg.stack_size = (4 * 1024); + cfg.inherit_cfg = true; + esp_pthread_set_cfg(&cfg); + + pthread_create(&t1, NULL, my_thread1); + } + +API Reference +------------- + +.. include:: /_build/inc/esp_pthread.inc + diff --git a/docs/en/api-reference/system/index.rst b/docs/en/api-reference/system/index.rst index 593fcc3d6..7dd9991c4 100644 --- a/docs/en/api-reference/system/index.rst +++ b/docs/en/api-reference/system/index.rst @@ -18,6 +18,7 @@ System API Sleep Modes Base MAC address Over The Air Updates (OTA) + ESP pthread Example code for this API section is provided in :example:`system` directory of ESP-IDF examples. diff --git a/docs/zh_CN/api-reference/system/esp_pthread.rst b/docs/zh_CN/api-reference/system/esp_pthread.rst new file mode 100644 index 000000000..274bc26cb --- /dev/null +++ b/docs/zh_CN/api-reference/system/esp_pthread.rst @@ -0,0 +1 @@ +.. include:: ../../../en/api-reference/system/esp_pthread.rst