add rt_mb_urgent() and rt_mb_urgent_wait()

This commit is contained in:
Meco Man 2021-01-03 06:19:14 +08:00
parent b315c36a5c
commit 89cf5886aa
1 changed files with 164 additions and 0 deletions

164
src/ipc.c
View File

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