Browse Source

add rt_mb_urgent() and rt_mb_urgent_wait()

Meco Man 4 years ago
parent
commit
89cf5886aa
1 changed files with 164 additions and 0 deletions
  1. 164 0
      src/ipc.c

+ 164 - 0
src/ipc.c

@@ -37,6 +37,7 @@
  * 2020-07-29     Meco Man     fix thread->event_set/event_info when received an 
  *                             event without pending
  * 2020-10-11     Meco Man     add value overflow-check code
+ * 2021-01-03     Meco Man     add rt_mb_urgent() and rt_mb_urgent_wait()
  */
 
 #include <rtthread.h>
@@ -1654,6 +1655,169 @@ rt_err_t rt_mb_send(rt_mailbox_t mb, rt_ubase_t value)
 }
 RTM_EXPORT(rt_mb_send);
 
+/**
+ * This function will send an urgent mail to mailbox object. If the mailbox is full,
+ * current thread will be suspended until timeout.
+ *
+ * @param mb the mailbox object
+ * @param value the mail
+ * @param timeout the waiting time
+ *
+ * @return the error code
+ */
+rt_err_t rt_mb_urgent_wait(rt_mailbox_t mb,
+                           rt_ubase_t   value,
+                           rt_int32_t   timeout)
+{
+    struct rt_thread *thread;
+    register rt_ubase_t temp;
+    rt_uint32_t tick_delta;
+
+    /* parameter check */
+    RT_ASSERT(mb != RT_NULL);
+    RT_ASSERT(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox);
+
+    /* initialize delta tick */
+    tick_delta = 0;
+    /* get current thread */
+    thread = rt_thread_self();
+
+    RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mb->parent.parent)));
+
+    /* disable interrupt */
+    temp = rt_hw_interrupt_disable();
+
+    /* for non-blocking call */
+    if (mb->entry == mb->size && timeout == 0)
+    {
+        rt_hw_interrupt_enable(temp);
+
+        return -RT_EFULL;
+    }
+
+    /* mailbox is full */
+    while (mb->entry == mb->size)
+    {
+        /* reset error number in thread */
+        thread->error = RT_EOK;
+
+        /* no waiting, return timeout */
+        if (timeout == 0)
+        {
+            /* enable interrupt */
+            rt_hw_interrupt_enable(temp);
+
+            return -RT_EFULL;
+        }
+
+        RT_DEBUG_IN_THREAD_CONTEXT;
+        /* suspend current thread */
+        rt_ipc_list_suspend(&(mb->suspend_sender_thread),
+                            thread,
+                            mb->parent.parent.flag);
+
+        /* has waiting time, start thread timer */
+        if (timeout > 0)
+        {
+            /* get the start tick of timer */
+            tick_delta = rt_tick_get();
+
+            RT_DEBUG_LOG(RT_DEBUG_IPC, ("mb_send_wait: start timer of thread:%s\n",
+                                        thread->name));
+
+            /* reset the timeout of thread timer and start it */
+            rt_timer_control(&(thread->thread_timer),
+                             RT_TIMER_CTRL_SET_TIME,
+                             &timeout);
+            rt_timer_start(&(thread->thread_timer));
+        }
+
+        /* enable interrupt */
+        rt_hw_interrupt_enable(temp);
+
+        /* re-schedule */
+        rt_schedule();
+
+        /* resume from suspend state */
+        if (thread->error != RT_EOK)
+        {
+            /* return error */
+            return thread->error;
+        }
+
+        /* disable interrupt */
+        temp = rt_hw_interrupt_disable();
+
+        /* if it's not waiting forever and then re-calculate timeout tick */
+        if (timeout > 0)
+        {
+            tick_delta = rt_tick_get() - tick_delta;
+            timeout -= tick_delta;
+            if (timeout < 0)
+                timeout = 0;
+        }
+    }
+
+    /* rewind to the previous position */
+    if(mb->out_offset > 0)
+    {
+        mb->out_offset --;
+    }
+    else
+    {
+        mb->out_offset = mb->size - 1;
+    }
+
+    /* set ptr */
+    mb->msg_pool[mb->out_offset] = value;
+
+    if(mb->entry < RT_MB_ENTRY_MAX)
+    {
+        /* increase message entry */
+        mb->entry ++;
+    }
+    else
+    {
+        rt_hw_interrupt_enable(temp); /* enable interrupt */
+        return -RT_EFULL; /* value overflowed */
+    }
+
+    /* resume suspended thread */
+    if (!rt_list_isempty(&mb->parent.suspend_thread))
+    {
+        rt_ipc_list_resume(&(mb->parent.suspend_thread));
+
+        /* enable interrupt */
+        rt_hw_interrupt_enable(temp);
+
+        rt_schedule();
+
+        return RT_EOK;
+    }
+
+    /* enable interrupt */
+    rt_hw_interrupt_enable(temp);
+
+    return RT_EOK;
+}
+RTM_EXPORT(rt_mb_urgent_wait);
+
+/**
+ * This function will send an urgent mail to mailbox object, if there are threads
+ * suspended on mailbox object, it will be waked up. This function will return
+ * immediately, if you want blocking send, use rt_mb_urgent_wait instead.
+ *
+ * @param mb the mailbox object
+ * @param value the mail
+ *
+ * @return the error code
+ */
+rt_err_t rt_mb_urgent(rt_mailbox_t mb, rt_ubase_t value)
+{
+    return rt_mb_urgent_wait(mb, value, 0);
+}
+RTM_EXPORT(rt_mb_urgent);
+
 /**
  * This function will receive a mail from mailbox object, if there is no mail
  * in mailbox object, the thread shall wait for a specified time.