feat(pthread): modify for ESP8266

1. remove "IRAM_ATTR" from pthread function
2. modify "critical" function
3. remove SMP function
4. add platform support
This commit is contained in:
dongheng
2019-08-27 10:33:38 +08:00
parent 8cf028873d
commit 24e53102bf
10 changed files with 170 additions and 84 deletions

View File

@ -103,6 +103,8 @@ to exclude the API function. */
#define INCLUDE_xTaskGetCurrentTaskHandle 1 #define INCLUDE_xTaskGetCurrentTaskHandle 1
#define INCLUDE_uxTaskGetStackHighWaterMark 1 #define INCLUDE_uxTaskGetStackHighWaterMark 1
#define INCLUDE_xSemaphoreGetMutexHolder 1
/* This is the raw value as per the Cortex-M3 NVIC. Values can be 255 /* This is the raw value as per the Cortex-M3 NVIC. Values can be 255
(lowest) to 0 (1?) (highest). */ (lowest) to 0 (1?) (highest). */
#define configKERNEL_INTERRUPT_PRIORITY 255 #define configKERNEL_INTERRUPT_PRIORITY 255

View File

@ -0,0 +1,40 @@
// 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.
#ifndef __ESP_PLATFORM_PTHREAD_H__
#define __ESP_PLATFORM_PTHREAD_H__
#include <sys/types.h>
#include <sys/time.h>
#include <sys/features.h>
// Remove this when GCC 5.2.0 is no longer supported
#ifndef _POSIX_TIMEOUTS
#define _POSIX_TIMEOUTS // For pthread_mutex_timedlock
#endif
#include_next <pthread.h>
#ifdef __cplusplus
extern "C" {
#endif
int pthread_condattr_getclock(const pthread_condattr_t * attr, clockid_t * clock_id);
int pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clock_id);
#ifdef __cplusplus
}
#endif
#endif // __ESP_PLATFORM_PTHREAD_H__

View File

@ -0,0 +1,35 @@
// 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.
#ifndef _ESP_TIME_H
#define _ESP_TIME_H
#ifdef __cplusplus
extern "C" {
#endif
#include_next <time.h>
#define _POSIX_TIMERS 1
#define CLOCK_MONOTONIC (clockid_t)4
#define CLOCK_BOOTTIME (clockid_t)4
int clock_settime(clockid_t clock_id, const struct timespec *tp);
int clock_gettime(clockid_t clock_id, struct timespec *tp);
int clock_getres(clockid_t clock_id, struct timespec *res);
#ifdef __cplusplus
}
#endif
#endif /* _ESP_TIME_H */

View File

@ -16,6 +16,7 @@
#include <reent.h> #include <reent.h>
#include <sys/times.h> #include <sys/times.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/errno.h>
#include "esp_system.h" #include "esp_system.h"
#include "esp_timer.h" #include "esp_timer.h"
@ -106,3 +107,38 @@ unsigned int sleep(unsigned int seconds)
return 0; return 0;
} }
int clock_gettime (clockid_t clock_id, struct timespec *tp)
{
#if defined( WITH_FRC ) || defined( WITH_RTC )
if (tp == NULL) {
errno = EINVAL;
return -1;
}
struct timeval tv;
uint64_t monotonic_time_us = 0;
switch (clock_id) {
case CLOCK_REALTIME:
_gettimeofday_r(NULL, &tv, NULL);
tp->tv_sec = tv.tv_sec;
tp->tv_nsec = tv.tv_usec * 1000L;
break;
case CLOCK_MONOTONIC:
#if defined( WITH_FRC )
monotonic_time_us = (uint64_t) esp_timer_get_time();
#elif defined( WITH_RTC )
monotonic_time_us = get_rtc_time_us();
#endif // WITH_FRC
tp->tv_sec = monotonic_time_us / 1000000LL;
tp->tv_nsec = (monotonic_time_us % 1000000LL) * 1000L;
break;
default:
errno = EINVAL;
return -1;
}
return 0;
#else
errno = ENOSYS;
return -1;
#endif
}

View File

@ -1,7 +1,9 @@
if(CONFIG_ENABLE_PTHREAD)
idf_component_register(SRCS "pthread.c" idf_component_register(SRCS "pthread.c"
"pthread_cond_var.c" "pthread_cond_var.c"
"pthread_local_storage.c" "pthread_local_storage.c"
INCLUDE_DIRS include) INCLUDE_DIRS include
PRIV_REQUIRES newlib)
if(GCC_NOT_5_2_0) if(GCC_NOT_5_2_0)
set(extra_link_flags "-u pthread_include_pthread_impl") set(extra_link_flags "-u pthread_include_pthread_impl")
@ -16,3 +18,6 @@ endif()
if(extra_link_flags) if(extra_link_flags)
target_link_libraries(${COMPONENT_LIB} INTERFACE "${extra_link_flags}") target_link_libraries(${COMPONENT_LIB} INTERFACE "${extra_link_flags}")
endif() endif()
else()
register_component()
endif()

View File

@ -1,49 +1,37 @@
menu "PThreads" menu "PThreads"
config PTHREAD_TASK_PRIO_DEFAULT config ENABLE_PTHREAD
int "Default task priority" bool "Enable Pthread"
range 0 255 help
default 5 Enable this option and then pthread is to be used.
help
Priority used to create new tasks with default pthread parameters.
config PTHREAD_TASK_STACK_SIZE_DEFAULT config PTHREAD_TASK_PRIO_DEFAULT
int "Default task stack size" int "Default task priority"
default 3072 range 0 255
help default 5
Stack size used to create new tasks with default pthread parameters. depends on ENABLE_PTHREAD
help
Priority used to create new tasks with default pthread parameters.
config PTHREAD_STACK_MIN config PTHREAD_TASK_STACK_SIZE_DEFAULT
int "Minimum allowed pthread stack size" int "Default task stack size"
default 768 default 3072
help depends on ENABLE_PTHREAD
Minimum allowed pthread stack size set in attributes passed to pthread_create help
Stack size used to create new tasks with default pthread parameters.
choice PTHREAD_TASK_CORE_DEFAULT config PTHREAD_STACK_MIN
bool "Default pthread core affinity" int "Minimum allowed pthread stack size"
default PTHREAD_DEFAULT_CORE_NO_AFFINITY default 768
depends on !FREERTOS_UNICORE depends on ENABLE_PTHREAD
help help
The default core to which pthreads are pinned. Minimum allowed pthread stack size set in attributes passed to pthread_create
config PTHREAD_DEFAULT_CORE_NO_AFFINITY config PTHREAD_TASK_NAME_DEFAULT
bool "No affinity" string "Default name of pthreads"
config PTHREAD_DEFAULT_CORE_0 default "pthread"
bool "Core 0" depends on ENABLE_PTHREAD
config PTHREAD_DEFAULT_CORE_1 help
bool "Core 1" The default name of pthreads.
endchoice
config PTHREAD_TASK_CORE_DEFAULT
int
default -1 if PTHREAD_DEFAULT_CORE_NO_AFFINITY || FREERTOS_UNICORE
default 0 if PTHREAD_DEFAULT_CORE_0
default 1 if PTHREAD_DEFAULT_CORE_1
config PTHREAD_TASK_NAME_DEFAULT
string "Default name of pthreads"
default "pthread"
help
The default name of pthreads.
endmenu endmenu

View File

@ -2,6 +2,7 @@
# Component Makefile # Component Makefile
# #
ifdef CONFIG_ENABLE_PTHREAD
COMPONENT_SRCDIRS := . COMPONENT_SRCDIRS := .
COMPONENT_ADD_INCLUDEDIRS := include COMPONENT_ADD_INCLUDEDIRS := include
@ -19,3 +20,6 @@ COMPONENT_ADD_LDFLAGS += -u pthread_include_pthread_impl
COMPONENT_ADD_LDFLAGS += -u pthread_include_pthread_cond_impl COMPONENT_ADD_LDFLAGS += -u pthread_include_pthread_cond_impl
COMPONENT_ADD_LDFLAGS += -u pthread_include_pthread_local_storage_impl COMPONENT_ADD_LDFLAGS += -u pthread_include_pthread_local_storage_impl
endif # GCC_NOT_5_2_0 endif # GCC_NOT_5_2_0
else
COMPONENT_SRCDIRS :=
endif

View File

@ -26,7 +26,6 @@
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "freertos/semphr.h" #include "freertos/semphr.h"
#include "soc/soc_memory_layout.h"
#include "pthread_internal.h" #include "pthread_internal.h"
#include "esp_pthread.h" #include "esp_pthread.h"
@ -67,13 +66,12 @@ typedef struct {
static SemaphoreHandle_t s_threads_mux = NULL; 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 static SLIST_HEAD(esp_thread_list_head, esp_pthread_entry) s_threads_list
= SLIST_HEAD_INITIALIZER(s_threads_list); = SLIST_HEAD_INITIALIZER(s_threads_list);
static pthread_key_t s_pthread_cfg_key; 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 int pthread_mutex_lock_internal(esp_pthread_mutex_t *mux, TickType_t tmo);
static void esp_pthread_cfg_key_destructor(void *value) static void esp_pthread_cfg_key_destructor(void *value)
{ {
@ -170,7 +168,7 @@ esp_err_t esp_pthread_get_cfg(esp_pthread_cfg_t *p)
static int get_default_pthread_core(void) static int get_default_pthread_core(void)
{ {
return CONFIG_PTHREAD_TASK_CORE_DEFAULT == -1 ? tskNO_AFFINITY : CONFIG_PTHREAD_TASK_CORE_DEFAULT; return 0;
} }
esp_pthread_cfg_t esp_pthread_get_default_config(void) esp_pthread_cfg_t esp_pthread_get_default_config(void)
@ -235,7 +233,6 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
uint32_t stack_size = CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT; uint32_t stack_size = CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT;
BaseType_t prio = CONFIG_PTHREAD_TASK_PRIO_DEFAULT; BaseType_t prio = CONFIG_PTHREAD_TASK_PRIO_DEFAULT;
BaseType_t core_id = get_default_pthread_core();
const char *task_name = CONFIG_PTHREAD_TASK_NAME_DEFAULT; const char *task_name = CONFIG_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);
@ -261,10 +258,6 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
task_name = pthread_cfg->thread_name; 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;
} }
@ -295,7 +288,7 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
task_arg, task_arg,
prio, prio,
&xHandle, &xHandle,
core_id); 0);
if (res != pdPASS) { if (res != pdPASS) {
ESP_LOGE(TAG, "Failed to create task!"); ESP_LOGE(TAG, "Failed to create task!");
@ -453,7 +446,7 @@ void pthread_exit(void *value_ptr)
} }
xSemaphoreGive(s_threads_mux); xSemaphoreGive(s_threads_mux);
ESP_LOGD(TAG, "Task stk_wm = %d", uxTaskGetStackHighWaterMark(NULL)); ESP_LOGD(TAG, "Task stk_wm = %ld", uxTaskGetStackHighWaterMark(NULL));
if (detached) { if (detached) {
vTaskDelete(NULL); vTaskDelete(NULL);
@ -503,21 +496,7 @@ int pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
return EINVAL; return EINVAL;
} }
uint32_t res = 1; once_control->init_executed = 1;
#if defined(CONFIG_ESP32_SPIRAM_SUPPORT)
if (esp_ptr_external_ram(once_control)) {
uxPortCompareSetExtram((uint32_t *) &once_control->init_executed, 0, &res);
} else {
#endif
uxPortCompareSet((uint32_t *) &once_control->init_executed, 0, &res);
#if defined(CONFIG_ESP32_SPIRAM_SUPPORT)
}
#endif
// Check if compare and set was successful
if (res == 0) {
ESP_LOGV(TAG, "%s: call init_routine %p", __FUNCTION__, once_control);
init_routine();
}
return 0; return 0;
} }
@ -599,7 +578,7 @@ int pthread_mutex_destroy(pthread_mutex_t *mutex)
return 0; return 0;
} }
static int IRAM_ATTR pthread_mutex_lock_internal(esp_pthread_mutex_t *mux, TickType_t tmo) static int pthread_mutex_lock_internal(esp_pthread_mutex_t *mux, TickType_t tmo)
{ {
if (!mux) { if (!mux) {
return EINVAL; return EINVAL;
@ -627,16 +606,16 @@ static int pthread_mutex_init_if_static(pthread_mutex_t *mutex)
{ {
int res = 0; int res = 0;
if ((intptr_t) *mutex == PTHREAD_MUTEX_INITIALIZER) { if ((intptr_t) *mutex == PTHREAD_MUTEX_INITIALIZER) {
portENTER_CRITICAL(&s_mutex_init_lock); portENTER_CRITICAL();
if ((intptr_t) *mutex == PTHREAD_MUTEX_INITIALIZER) { if ((intptr_t) *mutex == PTHREAD_MUTEX_INITIALIZER) {
res = pthread_mutex_init(mutex, NULL); res = pthread_mutex_init(mutex, NULL);
} }
portEXIT_CRITICAL(&s_mutex_init_lock); portEXIT_CRITICAL();
} }
return res; return res;
} }
int IRAM_ATTR pthread_mutex_lock(pthread_mutex_t *mutex) int pthread_mutex_lock(pthread_mutex_t *mutex)
{ {
if (!mutex) { if (!mutex) {
return EINVAL; return EINVAL;
@ -648,7 +627,7 @@ int IRAM_ATTR pthread_mutex_lock(pthread_mutex_t *mutex)
return pthread_mutex_lock_internal((esp_pthread_mutex_t *)*mutex, portMAX_DELAY); return pthread_mutex_lock_internal((esp_pthread_mutex_t *)*mutex, portMAX_DELAY);
} }
int IRAM_ATTR pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *timeout) int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *timeout)
{ {
if (!mutex) { if (!mutex) {
return EINVAL; return EINVAL;
@ -670,7 +649,7 @@ int IRAM_ATTR pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct times
return res; return res;
} }
int IRAM_ATTR pthread_mutex_trylock(pthread_mutex_t *mutex) int pthread_mutex_trylock(pthread_mutex_t *mutex)
{ {
if (!mutex) { if (!mutex) {
return EINVAL; return EINVAL;
@ -682,7 +661,7 @@ int IRAM_ATTR pthread_mutex_trylock(pthread_mutex_t *mutex)
return pthread_mutex_lock_internal((esp_pthread_mutex_t *)*mutex, 0); return pthread_mutex_lock_internal((esp_pthread_mutex_t *)*mutex, 0);
} }
int IRAM_ATTR pthread_mutex_unlock(pthread_mutex_t *mutex) int pthread_mutex_unlock(pthread_mutex_t *mutex)
{ {
esp_pthread_mutex_t *mux; esp_pthread_mutex_t *mux;

View File

@ -25,7 +25,6 @@
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "freertos/semphr.h" #include "freertos/semphr.h"
#include "freertos/list.h"
#include <sys/queue.h> #include <sys/queue.h>
#include <sys/time.h> #include <sys/time.h>

View File

@ -42,8 +42,6 @@ typedef struct key_entry_t_ {
// List of all keys created with pthread_key_create() // List of all keys created with pthread_key_create()
SLIST_HEAD(key_list_t, key_entry_t_) s_keys = SLIST_HEAD_INITIALIZER(s_keys); SLIST_HEAD(key_list_t, key_entry_t_) s_keys = SLIST_HEAD_INITIALIZER(s_keys);
static portMUX_TYPE s_keys_lock = portMUX_INITIALIZER_UNLOCKED;
// List of all value entries associated with a thread via pthread_setspecific() // List of all value entries associated with a thread via pthread_setspecific()
typedef struct value_entry_t_ { typedef struct value_entry_t_ {
pthread_key_t key; pthread_key_t key;
@ -62,7 +60,7 @@ int pthread_key_create(pthread_key_t *key, pthread_destructor_t destructor)
return ENOMEM; return ENOMEM;
} }
portENTER_CRITICAL(&s_keys_lock); portENTER_CRITICAL();
const key_entry_t *head = SLIST_FIRST(&s_keys); const key_entry_t *head = SLIST_FIRST(&s_keys);
new_key->key = (head == NULL) ? 1 : (head->key + 1); new_key->key = (head == NULL) ? 1 : (head->key + 1);
@ -71,27 +69,27 @@ int pthread_key_create(pthread_key_t *key, pthread_destructor_t destructor)
SLIST_INSERT_HEAD(&s_keys, new_key, next); SLIST_INSERT_HEAD(&s_keys, new_key, next);
portEXIT_CRITICAL(&s_keys_lock); portEXIT_CRITICAL();
return 0; return 0;
} }
static key_entry_t *find_key(pthread_key_t key) static key_entry_t *find_key(pthread_key_t key)
{ {
portENTER_CRITICAL(&s_keys_lock); portENTER_CRITICAL();
key_entry_t *result = NULL;; key_entry_t *result = NULL;;
SLIST_FOREACH(result, &s_keys, next) { SLIST_FOREACH(result, &s_keys, next) {
if(result->key == key) { if(result->key == key) {
break; break;
} }
} }
portEXIT_CRITICAL(&s_keys_lock); portEXIT_CRITICAL();
return result; return result;
} }
int pthread_key_delete(pthread_key_t key) int pthread_key_delete(pthread_key_t key)
{ {
portENTER_CRITICAL(&s_keys_lock); portENTER_CRITICAL();
/* Ideally, we would also walk all tasks' thread local storage value_list here /* Ideally, we would also walk all tasks' thread local storage value_list here
and delete any values associated with this key. We do not do this... and delete any values associated with this key. We do not do this...
@ -103,7 +101,7 @@ int pthread_key_delete(pthread_key_t key)
free(entry); free(entry);
} }
portEXIT_CRITICAL(&s_keys_lock); portEXIT_CRITICAL();
return 0; return 0;
} }