From 7fd43e110fec2f1ab25a98566c853bd56e7d3470 Mon Sep 17 00:00:00 2001
From: Our Air Quality <info@ourairquality.org>
Date: Fri, 5 Jan 2018 00:42:30 +1100
Subject: [PATCH] freertos: misc fixes, core locking check support.

* sys_msleep - typo

* sys_jiffies - make it a macro

* sys_arch_protect - note and check the nesting.

* sys_mutex_lock - keep trying after a timeout

* sys_mbox_post - keep trying after a timeout

* sys_arch_mbox_fetch - handle msg being NULL; keep trying after a timeout.

* sys_arch_mbox_tryfetch - handle msg being NULL;

* sys_mbox_free - check that the queue is empty.

* Add support to check the core locking: sys_lock_tcpip_core, sys_unlock_tcpip_core, sys_mark_tcpip_thread, sys_check_core_locking.
---
 ports/freertos/include/arch/sys_arch.h |   4 +-
 ports/freertos/sys_arch.c              | 112 +++++++++++++++++++++++++--------
 2 files changed, 90 insertions(+), 26 deletions(-)

diff --git a/ports/freertos/include/arch/sys_arch.h b/ports/freertos/include/arch/sys_arch.h
index 4e7992b..456d120 100644
--- a/ports/freertos/include/arch/sys_arch.h
+++ b/ports/freertos/include/arch/sys_arch.h
@@ -41,7 +41,9 @@
  */
 
 void sys_arch_msleep(u32_t delay_ms);
-#define sys_mslee(ms) sys_arch_msleep(ms)
+#define sys_msleep(ms) sys_arch_msleep(ms)
+
+#define sys_jiffies() xTaskGetTickCount()
 
 #if SYS_LIGHTWEIGHT_PROT
 typedef u32_t sys_prot_t;
diff --git a/ports/freertos/sys_arch.c b/ports/freertos/sys_arch.c
index 7fcbdce..e010e0c 100644
--- a/ports/freertos/sys_arch.c
+++ b/ports/freertos/sys_arch.c
@@ -73,17 +73,13 @@ sys_now(void)
   return xTaskGetTickCount() * portTICK_PERIOD_MS;
 }
 
-u32_t
-sys_jiffies(void)
-{
-  return sys_now();
-}
-
 #if SYS_LIGHTWEIGHT_PROT
 
+static sys_prot_t critical_nesting;
 sys_prot_t
 sys_arch_protect(void)
 {
+  sys_prot_t prev;
 #if LWIP_FREERTOS_PROTECT_USES_MUTEX
   BaseType_t ret;
   LWIP_ASSERT("sys_arch_protect_mutex != NULL", sys_arch_protect_mutex != NULL);
@@ -93,7 +89,9 @@ sys_arch_protect(void)
 #else /* LWIP_FREERTOS_PROTECT_USES_MUTEX */
   taskENTER_CRITICAL();
 #endif /* LWIP_FREERTOS_PROTECT_USES_MUTEX */
-  return 1;
+  prev = critical_nesting;
+  critical_nesting++;
+  return prev;
 }
 
 void
@@ -102,13 +100,17 @@ sys_arch_unprotect(sys_prot_t pval)
 #if LWIP_FREERTOS_PROTECT_USES_MUTEX
   BaseType_t ret;
   LWIP_ASSERT("sys_arch_protect_mutex != NULL", sys_arch_protect_mutex != NULL);
+#endif /* LWIP_FREERTOS_PROTECT_USES_MUTEX */
 
+  critical_nesting--;
+  LWIP_ASSERT("unexpected critical_nestion", critical_nesting == pval);
+
+#if LWIP_FREERTOS_PROTECT_USES_MUTEX
   ret = xSemaphoreGiveRecursive(sys_arch_protect_mutex);
   LWIP_ASSERT("sys_arch_unprotect failed to give the mutex", ret == pdTRUE);
 #else /* LWIP_FREERTOS_PROTECT_USES_MUTEX */
   taskEXIT_CRITICAL();
 #endif /* LWIP_FREERTOS_PROTECT_USES_MUTEX */
-  LWIP_UNUSED_ARG(pval);
 }
 
 #endif /* SYS_LIGHTWEIGHT_PROT */
@@ -140,12 +142,10 @@ sys_mutex_new(sys_mutex_t *mutex)
 void
 sys_mutex_lock(sys_mutex_t *mutex)
 {
-  BaseType_t ret;
   LWIP_ASSERT("mutex != NULL", mutex != NULL);
   LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL);
 
-  ret = xSemaphoreTakeRecursive(mutex->mut, portMAX_DELAY);
-  LWIP_ASSERT("failed to take the mutex", ret == pdTRUE);
+  while (xSemaphoreTakeRecursive(mutex->mut, portMAX_DELAY) != pdTRUE);
 }
 
 void
@@ -213,8 +213,8 @@ sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout_ms)
   LWIP_ASSERT("sem != NULL", sem != NULL);
   LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL);
 
-  if(!timeout_ms) {
-    /* wait infinite */
+  if(timeout_ms == 0) {
+    /* Wait infinite */
     ret = xSemaphoreTake(sem->sem, portMAX_DELAY);
     LWIP_ASSERT("taking semaphore failed", ret == pdTRUE);
   } else {
@@ -262,12 +262,10 @@ sys_mbox_new(sys_mbox_t *mbox, int size)
 void
 sys_mbox_post(sys_mbox_t *mbox, void *msg)
 {
-  BaseType_t ret;
   LWIP_ASSERT("mbox != NULL", mbox != NULL);
   LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);
 
-  ret = xQueueSendToBack(mbox->mbx, &msg, portMAX_DELAY);
-  LWIP_ASSERT("mbox post failed", ret == pdTRUE);
+  while (xQueueSendToBack(mbox->mbx, &msg, portMAX_DELAY) != pdTRUE);
 }
 
 err_t
@@ -280,24 +278,28 @@ sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
   ret = xQueueSendToBack(mbox->mbx, &msg, 0);
   if (ret == pdTRUE) {
     return ERR_OK;
-  } else {
-    LWIP_ASSERT("mbox trypost failed", ret == errQUEUE_FULL);
-    SYS_STATS_INC(mbox.err);
-    return ERR_MEM;
   }
+
+  LWIP_ASSERT("mbox trypost failed", ret == errQUEUE_FULL);
+  SYS_STATS_INC(mbox.err);
+  return ERR_MEM;
 }
 
 u32_t
 sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout_ms)
 {
   BaseType_t ret;
+  void *msg_dummy;
   LWIP_ASSERT("mbox != NULL", mbox != NULL);
   LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);
 
-  if(!timeout_ms) {
+  if (msg == NULL) {
+    msg = &msg_dummy;
+  }
+
+  if(timeout_ms == 0) {
     /* wait infinite */
-    ret = xQueueReceive(mbox->mbx, &(*msg), portMAX_DELAY);
-    LWIP_ASSERT("mbox fetch failed", ret == pdTRUE);
+    while (xQueueReceive(mbox->mbx, &(*msg), portMAX_DELAY) != pdTRUE);
   } else {
     TickType_t timeout_ticks = timeout_ms / portTICK_RATE_MS;
     ret = xQueueReceive(mbox->mbx, &(*msg), timeout_ticks);
@@ -319,9 +321,14 @@ u32_t
 sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
 {
   BaseType_t ret;
+  void *msg_dummy;
   LWIP_ASSERT("mbox != NULL", mbox != NULL);
   LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);
 
+  if (msg == NULL) {
+    msg = &msg_dummy;
+  }
+
   ret = xQueueReceive(mbox->mbx, &(*msg), 0);
   if (ret == errQUEUE_EMPTY) {
     *msg = NULL;
@@ -339,18 +346,27 @@ void
 sys_mbox_free(sys_mbox_t *mbox)
 {
   BaseType_t ret;
+  UBaseType_t msgs_waiting;
   LWIP_ASSERT("mbox != NULL", mbox != NULL);
   LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);
 
-  vQueueDelete(mbox->mbx);
+  msgs_waiting = uxQueueMessagesWaiting(mbox->mbx);
+  LWIP_ASSERT("mbox quence not empty", msgs_waiting == 0);
 
+#if SYS_STATS
+  if (msgs_waiting != 0) {
+    SYS_STATS_INC(mbox.err);
+  }
   SYS_STATS_DEC(mbox.used);
+#endif /* SYS_STATS */
+
+  vQueueDelete(mbox->mbx);
 }
 
 sys_thread_t
 sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio)
 {
-  xTaskHandle rtos_task;
+  TaskHandle_t rtos_task;
   BaseType_t ret;
   sys_thread_t lwip_thread;
   size_t rtos_stacksize = stacksize / sizeof(StackType_t);
@@ -414,3 +430,49 @@ void sys_arch_netconn_sem_free(void)
 #endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 */
 
 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
+
+#if LWIP_TCPIP_CORE_LOCKING
+
+/** Flag the core lock held. A counter for recusive locks. */
+u8_t lwip_core_lock_count;
+TaskHandle_t lwip_core_lock_holder_thread;
+void sys_lock_tcpip_core(void)
+{
+   sys_mutex_lock(&lock_tcpip_core);
+   if (lwip_core_lock_count == 0) {
+     lwip_core_lock_holder_thread = xTaskGetCurrentTaskHandle();
+   }
+   lwip_core_lock_count++;
+}
+
+void sys_unlock_tcpip_core(void)
+{
+   lwip_core_lock_count--;
+   if (lwip_core_lock_count == 0) {
+       lwip_core_lock_holder_thread = 0;
+   }
+   sys_mutex_unlock(&lock_tcpip_core);
+}
+
+#endif /* LWIP_TCPIP_CORE_LOCKING */
+
+TaskHandle_t lwip_tcpip_thread;
+void sys_mark_tcpip_thread(void)
+{
+  lwip_tcpip_thread = xTaskGetCurrentTaskHandle();
+}
+
+void sys_check_core_locking(void)
+{
+  /* Embedded systems should check we are NOT in an interrupt context here */
+
+  if (lwip_tcpip_thread != 0) {
+    TaskHandle_t current_thread = xTaskGetCurrentTaskHandle();
+
+#if LWIP_TCPIP_CORE_LOCKING
+    LWIP_ASSERT("Function called without core lock", current_thread == lwip_core_lock_holder_thread && lwip_core_lock_count > 0);
+#else
+    LWIP_ASSERT("Function called from wrong thread", current_thread == lwip_tcpip_thread);
+#endif /* LWIP_TCPIP_CORE_LOCKING */
+  }
+}
-- 
2.14.3

