Итак так как проект LWIP HTTP SERVER RAW c FreeRTOS как-то работает , но виснет периодически (как и полагается).
Причины этому скорее всего связаны с тем , что FreeRTOS работает с памятью через свой так сказать диспетчер памяти, а LWIP работает через свой диспетчер с памятью. В общем вопросов много, надо разбираться.
Вопрос (я бы сказал) остается столько сколько не изученного кода LWIP остается .
LWIP предлагает другой вариант интеграции во FreeRTOS - через NETCONN и использование mailbox очередей для реализации потокобезопастности.
Хочу сказать "спасибо" сложившейся ситуации с реализацией NETCONN ибо не было до этого необходимости вникнуть в управление памятью кучи досконально.
Речь вообще говоря о malloc ,memp_malloc и pvPortMalloc . Все они встречаются в примерах с NETCONN и как-то не работают они вместе никак.
[sys_arch.c]
Не надо надеятся , что код в LWIP идеален. Особенно в более поздних версиях, где уже с трудом можно разобраться кто из последователей Адама Дункельса где что дописывал (дорабатывал).
Ниже пример , который меня откровенно разочаровал.
err_t sys_mbox_new(sys_mbox_t *mbox, int size)
{
int mboxsize = size;
LWIP_ASSERT("mbox != NULL", mbox != NULL);
LWIP_ASSERT("size >= 0", size >= 0);
if (size == 0)
{
mboxsize = 1024;
}
mbox->head = mbox->tail = 0;
mbox->sem = mbox; /* just point to something for sys_mbox_valid() */
mbox->q_mem = (void**)malloc(sizeof(void*)*mboxsize);
//mbox->q_mem = (void**)pvPortMalloc(sizeof(void*)*mboxsize);
mbox->size = mboxsize;
mbox->used = 0;
memset(mbox->q_mem, 0, sizeof(void*)*mboxsize);
return ERR_OK;
}
Почему здесь используется malloc? - в потоках FreeRTOS это не будет работать от слова совсем, даже если сделать потоки статическими (есть такая опция). И у нас malloc благополучно возвращает 0, то есть память не выделяется. Вот стек вызываемых функций под NETCONN для создания почтового ящика LWIP:
sys_mbox_new() at sys_arch.c:217 0x801a8e2
tcpip_init() at tcpip.c:607 0x801a432
StartDefaultTask() at http_server.c:115 0x80252b2
uxListRemove() at list.c:227 0x801379c
Дальнейшее изучение кода lwip 2.1.2 приводит к разочарованию. Я даже начала обращать внимание кто писал то или иной файл в заголовке.
Наибольшее удручение вызвал файл sys_arch.c помеченный как Copyright (c) 2017 Simon Goldschmidt .
Обратите внимание на the_waiting_fn , функцию которую вы должны якобы определить сами. По умолчанию ее нет, хотя из кода она вызывается. Но это мелочи.
Весь огород в sys_arch.c вокруг организации ожидания чего-то при получении из ehternet канала пакетов TCP (какой-то самописный семафор) . При чем у меня задача интегрировать lwip в FreeRTOS. Зачем мне какие-то еще выдуманные семафоры.
Вот злосчастная функция ожидания скидывания сефамора (не могу ее не привести):
u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
{
printf("sys_arch_sem_wait\n");
u32_t ret = 0;
LWIP_ASSERT("sem != NULL", sem != NULL);
LWIP_ASSERT("*sem > 0", *sem > 0);
if (*sem == 1)
{
/* need to wait */
if(!timeout)
{
/* wait infinite */
LWIP_ASSERT("cannot wait without waiting callback", the_waiting_fn != NULL);
// тут надо не забыть реализовать фукцию the_waiting_fn
// как она при этом нормально указанная ниже (но не реализованная нигде)
// компилируется нормально я не понял...
do
{
int expectSomething = the_waiting_fn(sem, NULL);
LWIP_ASSERT("*sem > 0", *sem > 0);
LWIP_ASSERT("expecting a semaphore count but it's 0", !expectSomething || (*sem > 1));
ret++;
if (ret == SYS_ARCH_TIMEOUT)
{
ret--;
}
} while(*sem == 1);
}
else
{
if (the_waiting_fn)
{
int expectSomething = the_waiting_fn(sem, NULL);
LWIP_ASSERT("expecting a semaphore count but it's 0", !expectSomething || (*sem > 1));
}
LWIP_ASSERT("*sem > 0", *sem > 0);
if (*sem == 1)
{
return SYS_ARCH_TIMEOUT;
}
ret = 1;
}
}
LWIP_ASSERT("*sem > 0", *sem > 0);
(*sem)--;
LWIP_ASSERT("*sem > 0", *sem > 0);
/* return the time we waited for the sem */
return ret;
}
Если в функцию передавать вторым параметром (timeout) 0, то функция крутится в бесконечном цикле. И выход возможен только , если кто-то где-то установит *sem !=1.
А теперь смотрим netconn_new / netconn_new_with_proto_and_callback / netconn_apimsg / tcpip_send_msg_wait_sem / sys_arch_sem_wait (sem, 0);
То есть netconn_new крутится в бесконечном цикле while(* sem == 1) и ждет чего-то.
В двух словах : при отладке в цепочке netconn_new / netconn_bind / netconn_accept все зависает уже на netconn_new .
Я очень хотел бы ошибаться, но складывается впечатление , что NETCONN не надо использовать от слова вообще.
Есть идея взять старый добрый RAW и использовать Static FreeRTOS вариант.