From 6739d5b99f3343be192556e1e71c586a0d03aa43 Mon Sep 17 00:00:00 2001
From: Jeroen Domburg <jeroen@espressif.com>
Date: Mon, 27 Feb 2017 16:34:19 +0800
Subject: [PATCH] Add xPortInIsrContext function + unit test. This function
 returns true when the current CPU runs in an interrupt handler context.

---
 components/esp32/include/soc/cpu.h            | 10 ----
 .../freertos/include/freertos/portable.h      |  6 +++
 components/freertos/port.c                    | 19 ++++++-
 .../test/test_freertos_isinisrcontext.c       | 51 +++++++++++++++++++
 components/newlib/locks.c                     |  5 +-
 5 files changed, 77 insertions(+), 14 deletions(-)
 create mode 100644 components/freertos/test/test_freertos_isinisrcontext.c

diff --git a/components/esp32/include/soc/cpu.h b/components/esp32/include/soc/cpu.h
index 2e0ac7de80..7e1301345b 100644
--- a/components/esp32/include/soc/cpu.h
+++ b/components/esp32/include/soc/cpu.h
@@ -36,16 +36,6 @@ static inline void *get_sp()
     return sp;
 }
 
-/* Return true if the CPU is in an interrupt context
-   (PS.UM == 0)
-*/
-static inline bool cpu_in_interrupt_context(void)
-{
-    uint32_t ps;
-    RSR(PS, ps);
-    return (ps & PS_UM) == 0;
-}
-
 /* Functions to set page attributes for Region Protection option in the CPU.
  * See Xtensa ISA Reference manual for explanation of arguments (section 4.6.3.2).
  */
diff --git a/components/freertos/include/freertos/portable.h b/components/freertos/include/freertos/portable.h
index 0c10ac36eb..e46ec17fb6 100644
--- a/components/freertos/include/freertos/portable.h
+++ b/components/freertos/include/freertos/portable.h
@@ -194,6 +194,12 @@ void vPortYieldOtherCore( BaseType_t coreid) PRIVILEGED_FUNCTION;
  */
 void vPortSetStackWatchpoint( void* pxStackStart );
 
+/*
+ * Returns true if the current core is in ISR context; low prio ISR, med prio ISR or timer tick ISR. High prio ISRs
+ * aren't detected here, but they normally cannot call C code, so that should not be an issue anyway.
+ */
+BaseType_t xPortInIsrContext();
+
 /*
  * The structures and methods of manipulating the MPU are contained within the
  * port layer.
diff --git a/components/freertos/port.c b/components/freertos/port.c
index 3c26edfabf..756e14295d 100644
--- a/components/freertos/port.c
+++ b/components/freertos/port.c
@@ -115,7 +115,7 @@ extern void _xt_coproc_init(void);
 /*-----------------------------------------------------------*/
 
 unsigned port_xSchedulerRunning[portNUM_PROCESSORS] = {0}; // Duplicate of inaccessible xSchedulerRunning; needed at startup to avoid counting nesting
-unsigned port_interruptNesting[portNUM_PROCESSORS] = {0};  // Interrupt nesting level
+unsigned port_interruptNesting[portNUM_PROCESSORS] = {0};  // Interrupt nesting level. Increased/decreased in portasm.c, _frxt_int_enter/_frxt_int_exit
 
 /*-----------------------------------------------------------*/
 
@@ -256,9 +256,24 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMOR
 #endif
 
 
+/*
+ * Returns true if the current core is in ISR context; low prio ISR, med prio ISR or timer tick ISR. High prio ISRs
+ * aren't detected here, but they normally cannot call C code, so that should not be an issue anyway.
+ */
+BaseType_t xPortInIsrContext()
+{
+	unsigned int irqStatus;
+	BaseType_t ret;
+	irqStatus=portENTER_CRITICAL_NESTED();
+	ret=(port_interruptNesting[xPortGetCoreID()] != 0);
+	portEXIT_CRITICAL_NESTED(irqStatus);
+	return ret;
+}
+
+
 void vPortAssertIfInISR()
 {
-	configASSERT(port_interruptNesting[xPortGetCoreID()]==0)
+	configASSERT(xPortInIsrContext());
 }
 
 /*
diff --git a/components/freertos/test/test_freertos_isinisrcontext.c b/components/freertos/test/test_freertos_isinisrcontext.c
new file mode 100644
index 0000000000..9c7d31c270
--- /dev/null
+++ b/components/freertos/test/test_freertos_isinisrcontext.c
@@ -0,0 +1,51 @@
+/*
+ See if xPortInIsrContext works
+*/
+
+#include <esp_types.h>
+#include <stdio.h>
+#include "rom/ets_sys.h"
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+#include "freertos/queue.h"
+#include "freertos/xtensa_api.h"
+#include "unity.h"
+#include "esp_intr_alloc.h"
+#include "xtensa/hal.h"
+
+static volatile int in_int_context, int_handled;
+
+
+static void testint(void *arg) {
+    xthal_set_ccompare(1, xthal_get_ccount()+8000000000);
+    ets_printf("INT!\n");
+    if (xPortInIsrContext()) in_int_context++;
+    int_handled++;
+}
+
+
+static void testthread(void *arg) {
+    intr_handle_t handle;
+    in_int_context=0;
+    int_handled=0;
+    TEST_ASSERT(!xPortInIsrContext());
+    xthal_set_ccompare(2, xthal_get_ccount()+8000000);
+    esp_intr_alloc(ETS_INTERNAL_TIMER1_INTR_SOURCE, 0, &testint, NULL, &handle);
+    vTaskDelay(100 / portTICK_PERIOD_MS);
+    TEST_ASSERT(int_handled);
+    TEST_ASSERT(in_int_context);
+    esp_intr_free(handle);
+    vTaskDelete(NULL);
+}
+
+
+TEST_CASE("xPortInIsrContext test", "[freertos]")
+{
+    xTaskCreatePinnedToCore(testthread, "tst" , 4096, NULL, 3, NULL, 0);
+    vTaskDelay(150 / portTICK_PERIOD_MS);
+    xTaskCreatePinnedToCore(testthread, "tst" , 4096, NULL, 3, NULL, 1);
+    vTaskDelay(150 / portTICK_PERIOD_MS);
+}
+
diff --git a/components/newlib/locks.c b/components/newlib/locks.c
index 21b974a1f1..c143e3a3dd 100644
--- a/components/newlib/locks.c
+++ b/components/newlib/locks.c
@@ -21,6 +21,7 @@
 #include "freertos/semphr.h"
 #include "freertos/portmacro.h"
 #include "freertos/task.h"
+#include "freertos/portable.h"
 
 /* Notes on our newlib lock implementation:
  *
@@ -126,7 +127,7 @@ static int IRAM_ATTR lock_acquire_generic(_lock_t *lock, uint32_t delay, uint8_t
     }
 
     BaseType_t success;
-    if (cpu_in_interrupt_context()) {
+    if (xPortInIsrContext()) {
         /* In ISR Context */
         if (mutex_type == queueQUEUE_TYPE_RECURSIVE_MUTEX) {
             abort(); /* recursive mutexes make no sense in ISR context */
@@ -180,7 +181,7 @@ static void IRAM_ATTR lock_release_generic(_lock_t *lock, uint8_t mutex_type) {
         return;
     }
 
-    if (cpu_in_interrupt_context()) {
+    if (xPortInIsrContext()) {
         if (mutex_type == queueQUEUE_TYPE_RECURSIVE_MUTEX) {
             abort(); /* indicates logic bug, it shouldn't be possible to lock recursively in ISR */
         }