Merge branch 'refactor/lwip_port_layer' into 'master'

clean up TCPIP Stack  port layer

Closes IDFGH-1990 and IDFGH-2041

See merge request espressif/esp-idf!6230
This commit is contained in:
Angus Gratton 2019-10-30 11:58:49 +08:00
commit d0256a8867
5 changed files with 289 additions and 226 deletions

View file

@ -15,6 +15,7 @@ set(srcs
"lwip/src/api/api_lib.c" "lwip/src/api/api_lib.c"
"lwip/src/api/api_msg.c" "lwip/src/api/api_msg.c"
"lwip/src/api/err.c" "lwip/src/api/err.c"
"lwip/src/api/if_api.c"
"lwip/src/api/netbuf.c" "lwip/src/api/netbuf.c"
"lwip/src/api/netdb.c" "lwip/src/api/netdb.c"
"lwip/src/api/netifapi.c" "lwip/src/api/netifapi.c"

View file

@ -326,6 +326,15 @@ menu "LWIP"
IPv4 TCP_MSS Range: 576 <= TCP_MSS <= 1460 IPv4 TCP_MSS Range: 576 <= TCP_MSS <= 1460
IPv6 TCP_MSS Range: 1220<= TCP_mSS <= 1440 IPv6 TCP_MSS Range: 1220<= TCP_mSS <= 1440
config LWIP_TCP_TMR_INTERVAL
int "TCP timer interval(ms)"
default 250
help
Set TCP timer interval in milliseconds.
Can be used to speed connections on bad networks.
A lower value will redeliver unacked packets faster.
config LWIP_TCP_MSL config LWIP_TCP_MSL
int "Maximum segment lifetime (MSL)" int "Maximum segment lifetime (MSL)"
default 60000 default 60000

View file

@ -41,9 +41,7 @@
#include "lwip/stats.h" #include "lwip/stats.h"
#include "esp_log.h" #include "esp_log.h"
/* This is the number of threads that can be started with sys_thread_new() */ static const char* TAG = "lwip_arch";
#define SYS_THREAD_MAX 4
#define TAG "lwip_arch"
static sys_mutex_t g_lwip_protect_mutex = NULL; static sys_mutex_t g_lwip_protect_mutex = NULL;
@ -51,160 +49,167 @@ static pthread_key_t sys_thread_sem_key;
static void sys_thread_sem_free(void* data); static void sys_thread_sem_free(void* data);
#if !LWIP_COMPAT_MUTEX #if !LWIP_COMPAT_MUTEX
/** Create a new mutex
* @param mutex pointer to the mutex to create /**
* @return a new mutex */ * @brief Create a new mutex
*
* @param pxMutex pointer of the mutex to create
* @return ERR_OK on success, ERR_MEM when out of memory
*/
err_t err_t
sys_mutex_new(sys_mutex_t *pxMutex) sys_mutex_new(sys_mutex_t *pxMutex)
{ {
err_t xReturn = ERR_MEM;
*pxMutex = xSemaphoreCreateMutex(); *pxMutex = xSemaphoreCreateMutex();
if (*pxMutex == NULL) {
if (*pxMutex != NULL) { LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_mutex_new: out of mem\r\n"));
xReturn = ERR_OK; return ERR_MEM;
} }
LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_mutex_new: m=%p\n", *pxMutex)); LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_mutex_new: m=%p\n", *pxMutex));
return xReturn; return ERR_OK;
} }
/** Lock a mutex /**
* @param mutex the mutex to lock */ * @brief Lock a mutex
void ESP_IRAM_ATTR *
* @param pxMutex pointer of mutex to lock
*/
void
sys_mutex_lock(sys_mutex_t *pxMutex) sys_mutex_lock(sys_mutex_t *pxMutex)
{ {
while (xSemaphoreTake(*pxMutex, portMAX_DELAY) != pdPASS); BaseType_t ret = xSemaphoreTake(*pxMutex, portMAX_DELAY);
LWIP_ASSERT("failed to take the mutex", ret == pdTRUE);
} }
err_t /**
sys_mutex_trylock(sys_mutex_t *pxMutex) * @brief Unlock a mutex
{ *
if (xSemaphoreTake(*pxMutex, 0) == pdPASS) return 0; * @param pxMutex pointer of mutex to unlock
else return -1; */
} void
/** Unlock a mutex
* @param mutex the mutex to unlock */
void ESP_IRAM_ATTR
sys_mutex_unlock(sys_mutex_t *pxMutex) sys_mutex_unlock(sys_mutex_t *pxMutex)
{ {
xSemaphoreGive(*pxMutex); BaseType_t ret = xSemaphoreGive(*pxMutex);
LWIP_ASSERT("failed to give the mutex", ret == pdTRUE);
} }
/** Delete a semaphore /**
* @param mutex the mutex to delete */ * @brief Delete a mutex
*
* @param pxMutex pointer of mutex to delete
*/
void void
sys_mutex_free(sys_mutex_t *pxMutex) sys_mutex_free(sys_mutex_t *pxMutex)
{ {
LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_mutex_free: m=%p\n", *pxMutex)); LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_mutex_free: m=%p\n", *pxMutex));
vQueueDelete(*pxMutex); vSemaphoreDelete(*pxMutex);
*pxMutex = NULL;
} }
#endif
/*-----------------------------------------------------------------------------------*/ #endif /* !LWIP_COMPAT_MUTEX */
// Creates and returns a new semaphore. The "count" argument specifies
// the initial state of the semaphore. TBD finish and test /**
* @brief Creates a new semaphore
*
* @param sem pointer of the semaphore
* @param count initial state of the semaphore
* @return err_t
*/
err_t err_t
sys_sem_new(sys_sem_t *sem, u8_t count) sys_sem_new(sys_sem_t *sem, u8_t count)
{ {
err_t xReturn = ERR_MEM; LWIP_ASSERT("initial_count invalid (neither 0 nor 1)",
vSemaphoreCreateBinary(*sem); (count == 0) || (count == 1));
if ((*sem) != NULL) { *sem = xSemaphoreCreateBinary();
if (count == 0) { // Means it can't be taken if (*sem == NULL) {
xSemaphoreTake(*sem, 1); LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_sem_new: out of mem\r\n"));
} return ERR_MEM;
xReturn = ERR_OK;
} else {
; // TBD need assert
} }
return xReturn; if (count == 1) {
BaseType_t ret = xSemaphoreGive(*sem);
LWIP_ASSERT("sys_sem_new: initial give failed", ret == pdTRUE);
}
return ERR_OK;
} }
/*-----------------------------------------------------------------------------------*/ /**
// Signals a semaphore * @brief Signals a semaphore
void ESP_IRAM_ATTR *
* @param sem pointer of the semaphore
*/
void
sys_sem_signal(sys_sem_t *sem) sys_sem_signal(sys_sem_t *sem)
{ {
xSemaphoreGive(*sem); BaseType_t ret = xSemaphoreGive(*sem);
/* queue full is OK, this is a signal only... */
LWIP_ASSERT("sys_sem_signal: sane return value",
(ret == pdTRUE) || (ret == errQUEUE_FULL));
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
// Signals a semaphore (from ISR) // Signals a semaphore (from ISR)
int sys_sem_signal_isr(sys_sem_t *sem) int
sys_sem_signal_isr(sys_sem_t *sem)
{ {
BaseType_t woken = pdFALSE; BaseType_t woken = pdFALSE;
xSemaphoreGiveFromISR(*sem, &woken); xSemaphoreGiveFromISR(*sem, &woken);
return woken == pdTRUE; return woken == pdTRUE;
} }
/*-----------------------------------------------------------------------------------*/ /**
/* * @brief Wait for a semaphore to be signaled
Blocks the thread while waiting for the semaphore to be *
signaled. If the "timeout" argument is non-zero, the thread should * @param sem pointer of the semaphore
only be blocked for the specified time (measured in * @param timeout if zero, will wait infinitely, or will wait for milliseconds specify by this argument
milliseconds). * @return SYS_ARCH_TIMEOUT when timeout, 0 otherwise
*/
If the timeout argument is non-zero, the return value is the number of u32_t
milliseconds spent waiting for the semaphore to be signaled. If the
semaphore wasn't signaled within the specified time, the return value is
SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
(i.e., it was already signaled), the function may return zero.
Notice that lwIP implements a function with a similar name,
sys_sem_wait(), that uses the sys_arch_sem_wait() function.
*/
u32_t ESP_IRAM_ATTR
sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout) sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
{ {
portTickType StartTime, EndTime, Elapsed; BaseType_t ret;
unsigned long ulReturn;
StartTime = xTaskGetTickCount(); if (!timeout) {
/* wait infinite */
if (timeout != 0) { ret = xSemaphoreTake(*sem, portMAX_DELAY);
if (xSemaphoreTake(*sem, timeout / portTICK_PERIOD_MS) == pdTRUE) { LWIP_ASSERT("taking semaphore failed", ret == pdTRUE);
EndTime = xTaskGetTickCount(); } else {
Elapsed = (EndTime - StartTime) * portTICK_PERIOD_MS; TickType_t timeout_ticks = timeout / portTICK_RATE_MS;
ret = xSemaphoreTake(*sem, timeout_ticks);
if (Elapsed == 0) { if (ret == errQUEUE_EMPTY) {
Elapsed = 1; /* timed out */
} return SYS_ARCH_TIMEOUT;
ulReturn = Elapsed;
} else {
ulReturn = SYS_ARCH_TIMEOUT;
} }
} else { // must block without a timeout LWIP_ASSERT("taking semaphore failed", ret == pdTRUE);
while (xSemaphoreTake(*sem, portMAX_DELAY) != pdTRUE);
EndTime = xTaskGetTickCount();
Elapsed = (EndTime - StartTime) * portTICK_PERIOD_MS;
if (Elapsed == 0) {
Elapsed = 1;
}
ulReturn = Elapsed;
} }
return ulReturn ; // return time blocked return 0;
} }
/*-----------------------------------------------------------------------------------*/ /**
// Deallocates a semaphore * @brief Delete a semaphore
*
* @param sem pointer of the semaphore to delete
*/
void void
sys_sem_free(sys_sem_t *sem) sys_sem_free(sys_sem_t *sem)
{ {
vSemaphoreDelete(*sem); vSemaphoreDelete(*sem);
*sem = NULL;
} }
/*-----------------------------------------------------------------------------------*/ /**
// Creates an empty mailbox. * @brief Create an empty mailbox.
*
* @param mbox pointer of the mailbox
* @param size size of the mailbox
* @return ERR_OK on success, ERR_MEM when out of memory
*/
err_t err_t
sys_mbox_new(sys_mbox_t *mbox, int size) sys_mbox_new(sys_mbox_t *mbox, int size)
{ {
@ -217,7 +222,7 @@ sys_mbox_new(sys_mbox_t *mbox, int size)
(*mbox)->os_mbox = xQueueCreate(size, sizeof(void *)); (*mbox)->os_mbox = xQueueCreate(size, sizeof(void *));
if ((*mbox)->os_mbox == NULL) { if ((*mbox)->os_mbox == NULL) {
LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("fail to new *mbox->os_mbox\n")); LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("fail to new (*mbox)->os_mbox\n"));
free(*mbox); free(*mbox);
return ERR_MEM; return ERR_MEM;
} }
@ -230,21 +235,32 @@ sys_mbox_new(sys_mbox_t *mbox, int size)
return ERR_OK; return ERR_OK;
} }
/*-----------------------------------------------------------------------------------*/ /**
// Posts the "msg" to the mailbox. * @brief Send message to mailbox
void ESP_IRAM_ATTR *
* @param mbox pointer of the mailbox
* @param msg pointer of the message to send
*/
void
sys_mbox_post(sys_mbox_t *mbox, void *msg) sys_mbox_post(sys_mbox_t *mbox, void *msg)
{ {
while (xQueueSendToBack((*mbox)->os_mbox, &msg, portMAX_DELAY) != pdTRUE); BaseType_t ret = xQueueSendToBack((*mbox)->os_mbox, &msg, portMAX_DELAY);
LWIP_ASSERT("mbox post failed", ret == pdTRUE);
} }
/*-----------------------------------------------------------------------------------*/ /**
err_t ESP_IRAM_ATTR * @brief Try to post a message to mailbox
*
* @param mbox pointer of the mailbox
* @param msg pointer of the message to send
* @return ERR_OK on success, ERR_MEM when mailbox is full
*/
err_t
sys_mbox_trypost(sys_mbox_t *mbox, void *msg) sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
{ {
err_t xReturn; err_t xReturn;
if (xQueueSend((*mbox)->os_mbox, &msg, (portTickType)0) == pdPASS) { if (xQueueSend((*mbox)->os_mbox, &msg, 0) == pdTRUE) {
xReturn = ERR_OK; xReturn = ERR_OK;
} else { } else {
LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("trypost mbox=%p fail\n", (*mbox)->os_mbox)); LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("trypost mbox=%p fail\n", (*mbox)->os_mbox));
@ -254,83 +270,95 @@ sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
return xReturn; return xReturn;
} }
/*-----------------------------------------------------------------------------------*/ /**
/* * @brief Try to post a message to mailbox from ISR
Blocks the thread until a message arrives in the mailbox, but does *
not block the thread longer than "timeout" milliseconds (similar to * @param mbox pointer of the mailbox
the sys_arch_sem_wait() function). The "msg" argument is a result * @param msg pointer of the message to send
parameter that is set by the function (i.e., by doing "*msg = * @return ERR_OK on success
ptr"). The "msg" parameter maybe NULL to indicate that the message * ERR_MEM when mailbox is full
should be dropped. * ERR_NEED_SCHED when high priority task wakes up
*/
err_t
sys_mbox_trypost_fromisr(sys_mbox_t *mbox, void *msg)
{
BaseType_t ret;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
The return values are the same as for the sys_arch_sem_wait() function: ret = xQueueSendFromISR((*mbox)->os_mbox, &msg, &xHigherPriorityTaskWoken);
Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a if (ret == pdTRUE) {
timeout. if (xHigherPriorityTaskWoken == pdTRUE) {
return ERR_NEED_SCHED;
}
return ERR_OK;
} else {
LWIP_ASSERT("mbox trypost failed", ret == errQUEUE_FULL);
return ERR_MEM;
}
}
Note that a function with a similar name, sys_mbox_fetch(), is /**
implemented by lwIP. * @brief Fetch message from mailbox
*/ *
u32_t ESP_IRAM_ATTR * @param mbox pointer of mailbox
* @param msg pointer of the received message, could be NULL to indicate the message should be dropped
* @param timeout if zero, will wait infinitely; or will wait milliseconds specify by this argument
* @return SYS_ARCH_TIMEOUT when timeout, 0 otherwise
*/
u32_t
sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout) sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
{ {
void *dummyptr; BaseType_t ret;
portTickType StartTime, EndTime, Elapsed; void *msg_dummy;
unsigned long ulReturn;
StartTime = xTaskGetTickCount();
if (msg == NULL) { if (msg == NULL) {
msg = &dummyptr; msg = &msg_dummy;
}
if (*mbox == NULL){
*msg = NULL;
return -1;
} }
if (timeout == 0) { if (timeout == 0) {
timeout = portMAX_DELAY; /* wait infinite */
ret = xQueueReceive((*mbox)->os_mbox, &(*msg), portMAX_DELAY);
LWIP_ASSERT("mbox fetch failed", ret == pdTRUE);
} else { } else {
timeout = timeout / portTICK_PERIOD_MS; TickType_t timeout_ticks = timeout / portTICK_RATE_MS;
} ret = xQueueReceive((*mbox)->os_mbox, &(*msg), timeout_ticks);
if (ret == errQUEUE_EMPTY) {
*msg = NULL; /* timed out */
if (pdTRUE == xQueueReceive((*mbox)->os_mbox, &(*msg), timeout)) { *msg = NULL;
EndTime = xTaskGetTickCount(); return SYS_ARCH_TIMEOUT;
Elapsed = (EndTime - StartTime) * portTICK_PERIOD_MS;
if (Elapsed == 0) {
Elapsed = 1;
} }
LWIP_ASSERT("mbox fetch failed", ret == pdTRUE);
ulReturn = Elapsed;
} else { // timed out blocking for message
ulReturn = SYS_ARCH_TIMEOUT;
} }
return ulReturn ; // return time blocked TBD test return 0;
} }
/*-----------------------------------------------------------------------------------*/ /**
* @brief try to fetch message from mailbox
*
* @param mbox pointer of mailbox
* @param msg pointer of the received message
* @return SYS_MBOX_EMPTY if mailbox is empty, 1 otherwise
*/
u32_t u32_t
sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg) sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
{ {
void *pvDummy; BaseType_t ret;
unsigned long ulReturn; void *msg_dummy;
if (msg == NULL) { if (msg == NULL) {
msg = &pvDummy; msg = &msg_dummy;
} }
if (pdTRUE == xQueueReceive((*mbox)->os_mbox, &(*msg), 0)) { ret = xQueueReceive((*mbox)->os_mbox, &(*msg), 0);
ulReturn = ERR_OK; if (ret == errQUEUE_EMPTY) {
} else { *msg = NULL;
ulReturn = SYS_MBOX_EMPTY; return SYS_MBOX_EMPTY;
} }
LWIP_ASSERT("mbox fetch failed", ret == pdTRUE);
return ulReturn; return 0;
} }
/*-----------------------------------------------------------------------------------*/
void void
sys_mbox_set_owner(sys_mbox_t *mbox, void* owner) sys_mbox_set_owner(sys_mbox_t *mbox, void* owner)
{ {
@ -340,88 +368,99 @@ sys_mbox_set_owner(sys_mbox_t *mbox, void* owner)
} }
} }
/* /**
Deallocates a mailbox. If there are messages still present in the * @brief Delete a mailbox
mailbox when the mailbox is deallocated, it is an indication of a *
programming error in lwIP and the developer should be notified. * @param mbox pointer of the mailbox to delete
*/ */
void void
sys_mbox_free(sys_mbox_t *mbox) sys_mbox_free(sys_mbox_t *mbox)
{ {
if ( (NULL == mbox) || (NULL == *mbox) ) { if ((NULL == mbox) || (NULL == *mbox)) {
return; return;
} }
UBaseType_t msgs_waiting = uxQueueMessagesWaiting((*mbox)->os_mbox);
LWIP_ASSERT("mbox quence not empty", msgs_waiting == 0);
vQueueDelete((*mbox)->os_mbox); vQueueDelete((*mbox)->os_mbox);
free(*mbox); free(*mbox);
*mbox = NULL; *mbox = NULL;
} }
/*-----------------------------------------------------------------------------------*/ /**
/* * @brief Create a new thread
Starts a new thread with priority "prio" that will begin its execution in the *
function "thread()". The "arg" argument will be passed as an argument to the * @param name thread name
thread() function. The id of the new thread is returned. Both the id and * @param thread thread function
the priority are system dependent. * @param arg thread arguments
*/ * @param stacksize stacksize of the thread
* @param prio priority of the thread
* @return thread ID
*/
sys_thread_t sys_thread_t
sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio) sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio)
{ {
xTaskHandle created_task; TaskHandle_t rtos_task;
portBASE_TYPE result; BaseType_t ret;
result = xTaskCreatePinnedToCore(thread, name, stacksize, arg, prio, &created_task, /* LwIP's lwip_thread_fn matches FreeRTOS' TaskFunction_t, so we can pass the
thread function without adaption here. */
ret = xTaskCreatePinnedToCore(thread, name, stacksize, arg, prio, &rtos_task,
CONFIG_LWIP_TCPIP_TASK_AFFINITY); CONFIG_LWIP_TCPIP_TASK_AFFINITY);
if (result != pdPASS) { if (ret != pdTRUE) {
return NULL; return NULL;
} }
return created_task; return (sys_thread_t)rtos_task;
} }
/*-----------------------------------------------------------------------------------*/ /**
// Initialize sys arch * @brief Initialize the sys_arch layer
*
*/
void void
sys_init(void) sys_init(void)
{ {
if (ERR_OK != sys_mutex_new(&g_lwip_protect_mutex)) { if (ERR_OK != sys_mutex_new(&g_lwip_protect_mutex)) {
ESP_LOGE(TAG, "sys_init: failed to init lwip protect mutex\n"); ESP_LOGE(TAG, "sys_init: failed to init lwip protect mutex\n");
} }
// Create the pthreads key for the per-thread semaphore storage // Create the pthreads key for the per-thread semaphore storage
pthread_key_create(&sys_thread_sem_key, sys_thread_sem_free); pthread_key_create(&sys_thread_sem_key, sys_thread_sem_free);
esp_vfs_lwip_sockets_register(); esp_vfs_lwip_sockets_register();
} }
/*-----------------------------------------------------------------------------------*/ /**
* @brief Get system ticks
*
* @return system tick counts
*/
u32_t u32_t
sys_jiffies(void) sys_jiffies(void)
{ {
return xTaskGetTickCount(); return xTaskGetTickCount();
} }
/*-----------------------------------------------------------------------------------*/ /**
* @brief Get current time, in miliseconds
*
* @return current time
*/
u32_t u32_t
sys_now(void) sys_now(void)
{ {
return (xTaskGetTickCount()*portTICK_PERIOD_MS); return xTaskGetTickCount() * portTICK_PERIOD_MS;
} }
/* /**
This optional function does a "fast" critical region protection and returns * @brief Protect critical region
the previous protection level. This function is only called during very short *
critical regions. An embedded system which supports ISR-based drivers might * @note This function is only called during very short critical regions.
want to implement this function by disabling interrupts. Task-based systems *
might want to implement this by using a mutex or disabling tasking. This * @return previous protection level
function should support recursive calls from the same task or interrupt. In */
other words, sys_arch_protect() could be called while already protected. In
that case the return value indicates that it is already protected.
sys_arch_protect() is only required if your port is supporting an operating
system.
*/
sys_prot_t sys_prot_t
sys_arch_protect(void) sys_arch_protect(void)
{ {
@ -429,23 +468,23 @@ sys_arch_protect(void)
return (sys_prot_t) 1; return (sys_prot_t) 1;
} }
/*-----------------------------------------------------------------------------------*/ /**
/* * @brief Unprotect critical region
This optional function does a "fast" set of critical region protection to the *
value specified by pval. See the documentation for sys_arch_protect() for * @param pval protection level
more information. This function is only required if your port is supporting */
an operating system.
*/
void void
sys_arch_unprotect(sys_prot_t pval) sys_arch_unprotect(sys_prot_t pval)
{ {
LWIP_UNUSED_ARG(pval);
sys_mutex_unlock(&g_lwip_protect_mutex); sys_mutex_unlock(&g_lwip_protect_mutex);
} }
/* /*
* get per thread semphore * get per thread semaphore
*/ */
sys_sem_t* sys_thread_sem_get(void) sys_sem_t*
sys_thread_sem_get(void)
{ {
sys_sem_t *sem = pthread_getspecific(sys_thread_sem_key); sys_sem_t *sem = pthread_getspecific(sys_thread_sem_key);
@ -456,7 +495,8 @@ sys_sem_t* sys_thread_sem_get(void)
return sem; return sem;
} }
static void sys_thread_sem_free(void* data) // destructor for TLS semaphore static void
sys_thread_sem_free(void* data) // destructor for TLS semaphore
{ {
sys_sem_t *sem = (sys_sem_t*)(data); sys_sem_t *sem = (sys_sem_t*)(data);
@ -471,7 +511,8 @@ static void sys_thread_sem_free(void* data) // destructor for TLS semaphore
} }
} }
sys_sem_t* sys_thread_sem_init(void) sys_sem_t*
sys_thread_sem_init(void)
{ {
sys_sem_t *sem = (sys_sem_t*)mem_malloc(sizeof(sys_sem_t*)); sys_sem_t *sem = (sys_sem_t*)mem_malloc(sizeof(sys_sem_t*));
@ -491,7 +532,8 @@ sys_sem_t* sys_thread_sem_init(void)
return sem; return sem;
} }
void sys_thread_sem_deinit(void) void
sys_thread_sem_deinit(void)
{ {
sys_sem_t *sem = pthread_getspecific(sys_thread_sem_key); sys_sem_t *sem = pthread_getspecific(sys_thread_sem_key);
if (sem != NULL) { if (sem != NULL) {
@ -500,9 +542,8 @@ void sys_thread_sem_deinit(void)
} }
} }
void sys_delay_ms(uint32_t ms) void
sys_delay_ms(uint32_t ms)
{ {
vTaskDelay(ms / portTICK_PERIOD_MS); vTaskDelay(ms / portTICK_PERIOD_MS);
} }

View file

@ -29,7 +29,7 @@
* Author: Adam Dunkels <adam@sics.se> * Author: Adam Dunkels <adam@sics.se>
* *
*/ */
#ifndef __SYS_ARCH_H__ #ifndef __SYS_ARCH_H__
#define __SYS_ARCH_H__ #define __SYS_ARCH_H__
@ -44,15 +44,22 @@ extern "C" {
#endif #endif
typedef xSemaphoreHandle sys_sem_t; typedef SemaphoreHandle_t sys_sem_t;
typedef xSemaphoreHandle sys_mutex_t; typedef SemaphoreHandle_t sys_mutex_t;
typedef xTaskHandle sys_thread_t; typedef TaskHandle_t sys_thread_t;
typedef struct sys_mbox_s { typedef struct sys_mbox_s {
xQueueHandle os_mbox; QueueHandle_t os_mbox;
void *owner; void *owner;
}* sys_mbox_t; }* sys_mbox_t;
/** This is returned by _fromisr() sys functions to tell the outermost function
* that a higher priority task was woken and the scheduler needs to be invoked.
*/
#define ERR_NEED_SCHED 123
void sys_delay_ms(uint32_t ms);
#define sys_msleep(ms) sys_delay_ms(ms)
#define LWIP_COMPAT_MUTEX 0 #define LWIP_COMPAT_MUTEX 0
@ -64,7 +71,7 @@ typedef struct sys_mbox_s {
#define sys_mbox_valid( x ) ( ( ( *x ) == NULL) ? pdFALSE : pdTRUE ) #define sys_mbox_valid( x ) ( ( ( *x ) == NULL) ? pdFALSE : pdTRUE )
/* Define the sys_mbox_set_invalid() to empty to support lock-free mbox in ESP LWIP. /* Define the sys_mbox_set_invalid() to empty to support lock-free mbox in ESP LWIP.
* *
* The basic idea about the lock-free mbox is that the mbox should always be valid unless * The basic idea about the lock-free mbox is that the mbox should always be valid unless
* no socket APIs are using the socket and the socket is closed. ESP LWIP achieves this by * no socket APIs are using the socket and the socket is closed. ESP LWIP achieves this by
* following two changes to official LWIP: * following two changes to official LWIP:
@ -72,9 +79,9 @@ typedef struct sys_mbox_s {
* no one is using the socket. * no one is using the socket.
* 2. Define the sys_mbox_set_invalid() to empty if the mbox is not actually freed. * 2. Define the sys_mbox_set_invalid() to empty if the mbox is not actually freed.
* The second change is necessary. Consider a common scenario: the application task calls * The second change is necessary. Consider a common scenario: the application task calls
* recv() to receive packets from the socket, the sys_mbox_valid() returns true. Because there * recv() to receive packets from the socket, the sys_mbox_valid() returns true. Because there
* is no lock for the mbox, the LWIP CORE can call sys_mbox_set_invalid() to set the mbox at * is no lock for the mbox, the LWIP CORE can call sys_mbox_set_invalid() to set the mbox at
* anytime and the thread-safe issue may happen. * anytime and the thread-safe issue may happen.
* *
* However, if the sys_mbox_set_invalid() is not called after sys_mbox_free(), e.g. in netconn_alloc(), * However, if the sys_mbox_set_invalid() is not called after sys_mbox_free(), e.g. in netconn_alloc(),

View file

@ -325,6 +325,11 @@
*/ */
#define TCP_MSS CONFIG_LWIP_TCP_MSS #define TCP_MSS CONFIG_LWIP_TCP_MSS
/**
* TCP_TMR_INTERVAL: TCP timer interval
*/
#define TCP_TMR_INTERVAL CONFIG_LWIP_TCP_TMR_INTERVAL
/** /**
* TCP_MSL: The maximum segment lifetime in milliseconds * TCP_MSL: The maximum segment lifetime in milliseconds
*/ */