|
@@ -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.
|