Explorar o código

Furi: make `furi_is_irq_context` public (#2276)

* Furi: make `furi_is_irq_context` public
* Furi: proper name and documentation for furi_kernel_is_irq_or_masked.
* Target: bump symbol table version
* Furi: proper doxygen context for warnings

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
Petr Portnov | PROgrm_JARvis %!s(int64=3) %!d(string=hai) anos
pai
achega
f5fe0ff694

+ 1 - 0
firmware/targets/f7/api_symbols.csv

@@ -1389,6 +1389,7 @@ Function,+,furi_hal_version_uid_size,size_t,
 Function,-,furi_hal_vibro_init,void,
 Function,+,furi_hal_vibro_on,void,_Bool
 Function,-,furi_init,void,
+Function,+,furi_kernel_is_irq_or_masked,_Bool,
 Function,+,furi_kernel_get_tick_frequency,uint32_t,
 Function,+,furi_kernel_lock,int32_t,
 Function,+,furi_kernel_restore_lock,int32_t,int32_t

+ 0 - 24
furi/core/common_defines.h

@@ -52,30 +52,6 @@ extern "C" {
     }
 #endif
 
-static inline bool furi_is_irq_context() {
-    bool irq = false;
-    BaseType_t state;
-
-    if(FURI_IS_IRQ_MODE()) {
-        /* Called from interrupt context */
-        irq = true;
-    } else {
-        /* Get FreeRTOS scheduler state */
-        state = xTaskGetSchedulerState();
-
-        if(state != taskSCHEDULER_NOT_STARTED) {
-            /* Scheduler was started */
-            if(FURI_IS_IRQ_MASKED()) {
-                /* Interrupts are masked */
-                irq = true;
-            }
-        }
-    }
-
-    /* Return context, 0: thread context, 1: IRQ context */
-    return (irq);
-}
-
 #ifdef __cplusplus
 }
 #endif

+ 30 - 6
furi/core/kernel.c

@@ -7,8 +7,32 @@
 
 #include CMSIS_device_header
 
+bool furi_kernel_is_irq_or_masked() {
+    bool irq = false;
+    BaseType_t state;
+
+    if(FURI_IS_IRQ_MODE()) {
+        /* Called from interrupt context */
+        irq = true;
+    } else {
+        /* Get FreeRTOS scheduler state */
+        state = xTaskGetSchedulerState();
+
+        if(state != taskSCHEDULER_NOT_STARTED) {
+            /* Scheduler was started */
+            if(FURI_IS_IRQ_MASKED()) {
+                /* Interrupts are masked */
+                irq = true;
+            }
+        }
+    }
+
+    /* Return context, 0: thread context, 1: IRQ context */
+    return (irq);
+}
+
 int32_t furi_kernel_lock() {
-    furi_assert(!furi_is_irq_context());
+    furi_assert(!furi_kernel_is_irq_or_masked());
 
     int32_t lock;
 
@@ -33,7 +57,7 @@ int32_t furi_kernel_lock() {
 }
 
 int32_t furi_kernel_unlock() {
-    furi_assert(!furi_is_irq_context());
+    furi_assert(!furi_kernel_is_irq_or_masked());
 
     int32_t lock;
 
@@ -63,7 +87,7 @@ int32_t furi_kernel_unlock() {
 }
 
 int32_t furi_kernel_restore_lock(int32_t lock) {
-    furi_assert(!furi_is_irq_context());
+    furi_assert(!furi_kernel_is_irq_or_masked());
 
     switch(xTaskGetSchedulerState()) {
     case taskSCHEDULER_SUSPENDED:
@@ -99,7 +123,7 @@ uint32_t furi_kernel_get_tick_frequency() {
 }
 
 void furi_delay_tick(uint32_t ticks) {
-    furi_assert(!furi_is_irq_context());
+    furi_assert(!furi_kernel_is_irq_or_masked());
     if(ticks == 0U) {
         taskYIELD();
     } else {
@@ -108,7 +132,7 @@ void furi_delay_tick(uint32_t ticks) {
 }
 
 FuriStatus furi_delay_until_tick(uint32_t tick) {
-    furi_assert(!furi_is_irq_context());
+    furi_assert(!furi_kernel_is_irq_or_masked());
 
     TickType_t tcnt, delay;
     FuriStatus stat;
@@ -137,7 +161,7 @@ FuriStatus furi_delay_until_tick(uint32_t tick) {
 uint32_t furi_get_tick() {
     TickType_t ticks;
 
-    if(furi_is_irq_context() != 0U) {
+    if(furi_kernel_is_irq_or_masked() != 0U) {
         ticks = xTaskGetTickCountFromISR();
     } else {
         ticks = xTaskGetTickCount();

+ 28 - 1
furi/core/kernel.h

@@ -10,19 +10,42 @@
 extern "C" {
 #endif
 
+/** Check if CPU is in IRQ or kernel running and IRQ is masked
+ * 
+ * Originally this primitive was born as a workaround for FreeRTOS kernel primitives shenanigans with PRIMASK.
+ * 
+ * Meaningful use cases are:
+ * 
+ * - When kernel is started and you want to ensure that you are not in IRQ or IRQ is not masked(like in critical section)
+ * - When kernel is not started and you want to make sure that you are not in IRQ mode, ignoring PRIMASK.
+ * 
+ * As you can see there will be edge case when kernel is not started and PRIMASK is not 0 that may cause some funky behavior.
+ * Most likely it will happen after kernel primitives being used, but control not yet passed to kernel.
+ * It's up to you to figure out if it is safe for your code or not.
+ * 
+ * @return     true if CPU is in IRQ or kernel running and IRQ is masked
+ */
+bool furi_kernel_is_irq_or_masked();
+
 /** Lock kernel, pause process scheduling
+ *
+ * @warning This should never be called in interrupt request context.
  *
  * @return     previous lock state(0 - unlocked, 1 - locked)
  */
 int32_t furi_kernel_lock();
 
 /** Unlock kernel, resume process scheduling
+ *
+ * @warning This should never be called in interrupt request context.
  *
  * @return     previous lock state(0 - unlocked, 1 - locked)
  */
 int32_t furi_kernel_unlock();
 
 /** Restore kernel lock state
+ *
+ * @warning This should never be called in interrupt request context.
  *
  * @param[in]  lock  The lock state
  *
@@ -37,7 +60,9 @@ int32_t furi_kernel_restore_lock(int32_t lock);
 uint32_t furi_kernel_get_tick_frequency();
 
 /** Delay execution
- * 
+ *
+ * @warning This should never be called in interrupt request context.
+ *
  * Also keep in mind delay is aliased to scheduler timer intervals.
  *
  * @param[in]  ticks  The ticks count to pause
@@ -45,6 +70,8 @@ uint32_t furi_kernel_get_tick_frequency();
 void furi_delay_tick(uint32_t ticks);
 
 /** Delay until tick
+ *
+ * @warning This should never be called in interrupt request context.
  *
  * @param[in]  ticks  The tick until which kerel should delay task execution
  *

+ 8 - 8
furi/core/message_queue.c

@@ -1,11 +1,11 @@
+#include "kernel.h"
 #include "message_queue.h"
-#include "core/common_defines.h"
 #include <FreeRTOS.h>
 #include <queue.h>
 #include "check.h"
 
 FuriMessageQueue* furi_message_queue_alloc(uint32_t msg_count, uint32_t msg_size) {
-    furi_assert((furi_is_irq_context() == 0U) && (msg_count > 0U) && (msg_size > 0U));
+    furi_assert((furi_kernel_is_irq_or_masked() == 0U) && (msg_count > 0U) && (msg_size > 0U));
 
     QueueHandle_t handle = xQueueCreate(msg_count, msg_size);
     furi_check(handle);
@@ -14,7 +14,7 @@ FuriMessageQueue* furi_message_queue_alloc(uint32_t msg_count, uint32_t msg_size
 }
 
 void furi_message_queue_free(FuriMessageQueue* instance) {
-    furi_assert(furi_is_irq_context() == 0U);
+    furi_assert(furi_kernel_is_irq_or_masked() == 0U);
     furi_assert(instance);
 
     vQueueDelete((QueueHandle_t)instance);
@@ -28,7 +28,7 @@ FuriStatus
 
     stat = FuriStatusOk;
 
-    if(furi_is_irq_context() != 0U) {
+    if(furi_kernel_is_irq_or_masked() != 0U) {
         if((hQueue == NULL) || (msg_ptr == NULL) || (timeout != 0U)) {
             stat = FuriStatusErrorParameter;
         } else {
@@ -65,7 +65,7 @@ FuriStatus furi_message_queue_get(FuriMessageQueue* instance, void* msg_ptr, uin
 
     stat = FuriStatusOk;
 
-    if(furi_is_irq_context() != 0U) {
+    if(furi_kernel_is_irq_or_masked() != 0U) {
         if((hQueue == NULL) || (msg_ptr == NULL) || (timeout != 0U)) {
             stat = FuriStatusErrorParameter;
         } else {
@@ -131,7 +131,7 @@ uint32_t furi_message_queue_get_count(FuriMessageQueue* instance) {
 
     if(hQueue == NULL) {
         count = 0U;
-    } else if(furi_is_irq_context() != 0U) {
+    } else if(furi_kernel_is_irq_or_masked() != 0U) {
         count = uxQueueMessagesWaitingFromISR(hQueue);
     } else {
         count = uxQueueMessagesWaiting(hQueue);
@@ -148,7 +148,7 @@ uint32_t furi_message_queue_get_space(FuriMessageQueue* instance) {
 
     if(mq == NULL) {
         space = 0U;
-    } else if(furi_is_irq_context() != 0U) {
+    } else if(furi_kernel_is_irq_or_masked() != 0U) {
         isrm = taskENTER_CRITICAL_FROM_ISR();
 
         /* space = pxQueue->uxLength - pxQueue->uxMessagesWaiting; */
@@ -167,7 +167,7 @@ FuriStatus furi_message_queue_reset(FuriMessageQueue* instance) {
     QueueHandle_t hQueue = (QueueHandle_t)instance;
     FuriStatus stat;
 
-    if(furi_is_irq_context() != 0U) {
+    if(furi_kernel_is_irq_or_masked() != 0U) {
         stat = FuriStatusErrorISR;
     } else if(hQueue == NULL) {
         stat = FuriStatusErrorParameter;

+ 5 - 6
furi/core/timer.c

@@ -3,7 +3,6 @@
 #include "memmgr.h"
 #include "kernel.h"
 
-#include "core/common_defines.h"
 #include <FreeRTOS.h>
 #include <timers.h>
 
@@ -27,7 +26,7 @@ static void TimerCallback(TimerHandle_t hTimer) {
 }
 
 FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* context) {
-    furi_assert((furi_is_irq_context() == 0U) && (func != NULL));
+    furi_assert((furi_kernel_is_irq_or_masked() == 0U) && (func != NULL));
 
     TimerHandle_t hTimer;
     TimerCallback_t* callb;
@@ -60,7 +59,7 @@ FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* co
 }
 
 void furi_timer_free(FuriTimer* instance) {
-    furi_assert(!furi_is_irq_context());
+    furi_assert(!furi_kernel_is_irq_or_masked());
     furi_assert(instance);
 
     TimerHandle_t hTimer = (TimerHandle_t)instance;
@@ -82,7 +81,7 @@ void furi_timer_free(FuriTimer* instance) {
 }
 
 FuriStatus furi_timer_start(FuriTimer* instance, uint32_t ticks) {
-    furi_assert(!furi_is_irq_context());
+    furi_assert(!furi_kernel_is_irq_or_masked());
     furi_assert(instance);
 
     TimerHandle_t hTimer = (TimerHandle_t)instance;
@@ -99,7 +98,7 @@ FuriStatus furi_timer_start(FuriTimer* instance, uint32_t ticks) {
 }
 
 FuriStatus furi_timer_stop(FuriTimer* instance) {
-    furi_assert(!furi_is_irq_context());
+    furi_assert(!furi_kernel_is_irq_or_masked());
     furi_assert(instance);
 
     TimerHandle_t hTimer = (TimerHandle_t)instance;
@@ -117,7 +116,7 @@ FuriStatus furi_timer_stop(FuriTimer* instance) {
 }
 
 uint32_t furi_timer_is_running(FuriTimer* instance) {
-    furi_assert(!furi_is_irq_context());
+    furi_assert(!furi_kernel_is_irq_or_masked());
     furi_assert(instance);
 
     TimerHandle_t hTimer = (TimerHandle_t)instance;

+ 2 - 2
furi/furi.c

@@ -3,7 +3,7 @@
 #include "queue.h"
 
 void furi_init() {
-    furi_assert(!furi_is_irq_context());
+    furi_assert(!furi_kernel_is_irq_or_masked());
     furi_assert(xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED);
 
     furi_log_init();
@@ -11,7 +11,7 @@ void furi_init() {
 }
 
 void furi_run() {
-    furi_assert(!furi_is_irq_context());
+    furi_assert(!furi_kernel_is_irq_or_masked());
     furi_assert(xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED);
 
 #if(__ARM_ARCH_7A__ == 0U)