summaryrefslogtreecommitdiff
path: root/src/ipc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ipc.c')
-rwxr-xr-x[-rw-r--r--]src/ipc.c249
1 files changed, 226 insertions, 23 deletions
diff --git a/src/ipc.c b/src/ipc.c
index 8e8c4db842..37b05b9ae3 100644..100755
--- a/src/ipc.c
+++ b/src/ipc.c
@@ -34,6 +34,11 @@
* 2013-09-14 Grissiom add an option check in rt_event_recv
* 2018-10-02 Bernard add 64bit support for mailbox
* 2019-09-16 tyx add send wait support for message queue
+ * 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()
+ * 2021-01-20 hupu fix priority inversion bug of mutex
*/
#include <rtthread.h>
@@ -117,6 +122,9 @@ rt_inline rt_err_t rt_ipc_list_suspend(rt_list_t *list,
rt_list_insert_before(list, &(thread->tlist));
}
break;
+
+ default:
+ break;
}
return RT_EOK;
@@ -184,6 +192,31 @@ rt_inline rt_err_t rt_ipc_list_resume_all(rt_list_t *list)
return RT_EOK;
}
+/**
+ * This function will get the highest priority from the specified
+ * list of threads
+ *
+ * @param list of the threads
+ *
+ * @return the highest priority
+ */
+rt_uint8_t rt_ipc_get_highest_priority(rt_list_t *list)
+{
+ struct rt_list_node *n;
+ struct rt_thread *sthread;
+ rt_uint8_t priority = RT_THREAD_PRIORITY_MAX - 1;
+
+ for (n = list->next; n != list; n = n->next)
+ {
+ sthread = rt_list_entry(n, struct rt_thread, tlist);
+
+ priority = priority < sthread->current_priority ?
+ priority :
+ sthread->current_priority;
+ }
+ return priority;
+}
+
#ifdef RT_USING_SEMAPHORE
/**
* This function will initialize a semaphore and put it under control of
@@ -458,7 +491,17 @@ rt_err_t rt_sem_release(rt_sem_t sem)
need_schedule = RT_TRUE;
}
else
- sem->value ++; /* increase value */
+ {
+ if(sem->value < RT_SEM_VALUE_MAX)
+ {
+ sem->value ++; /* increase value */
+ }
+ else
+ {
+ rt_hw_interrupt_enable(temp); /* enable interrupt */
+ return -RT_EFULL; /* value overflowed */
+ }
+ }
/* enable interrupt */
rt_hw_interrupt_enable(temp);
@@ -680,12 +723,22 @@ rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t time)
if (mutex->owner == thread)
{
- /* it's the same thread */
- mutex->hold ++;
+ if(mutex->hold < RT_MUTEX_HOLD_MAX)
+ {
+ /* it's the same thread */
+ mutex->hold ++;
+ }
+ else
+ {
+ rt_hw_interrupt_enable(temp); /* enable interrupt */
+ return -RT_EFULL; /* value overflowed */
+ }
}
else
{
+#ifdef RT_USING_SIGNALS
__again:
+#endif /* end of RT_USING_SIGNALS */
/* The value of mutex is 1 in initial status. Therefore, if the
* value is great than 0, it indicates the mutex is avaible.
*/
@@ -697,7 +750,15 @@ __again:
/* set mutex owner and original priority */
mutex->owner = thread;
mutex->original_priority = thread->current_priority;
- mutex->hold ++;
+ if(mutex->hold < RT_MUTEX_HOLD_MAX)
+ {
+ mutex->hold ++;
+ }
+ else
+ {
+ rt_hw_interrupt_enable(temp); /* enable interrupt */
+ return -RT_EFULL; /* value overflowed */
+ }
}
else
{
@@ -754,8 +815,10 @@ __again:
if (thread->error != RT_EOK)
{
+#ifdef RT_USING_SIGNALS
/* interrupt by signal, try it again */
if (thread->error == -RT_EINTR) goto __again;
+#endif /* end of RT_USING_SIGNALS */
/* return error */
return thread->error;
@@ -792,6 +855,7 @@ rt_err_t rt_mutex_release(rt_mutex_t mutex)
register rt_base_t temp;
struct rt_thread *thread;
rt_bool_t need_schedule;
+ rt_uint8_t max_priority_in_queue = RT_THREAD_PRIORITY_MAX - 1;
/* parameter check */
RT_ASSERT(mutex != RT_NULL);
@@ -852,7 +916,31 @@ rt_err_t rt_mutex_release(rt_mutex_t mutex)
/* set new owner and priority */
mutex->owner = thread;
mutex->original_priority = thread->current_priority;
- mutex->hold ++;
+
+ /* Priority adjustment occurs only when the following conditions
+ * are met simultaneously:
+ * 1.The type of mutex is RT_IPC_FLAG_FIFO;
+ * 2.The priority of the thread to be resumed is not equal to the
+ * highest priority in the queue;
+ */
+ max_priority_in_queue = rt_ipc_get_highest_priority(&mutex->parent.suspend_thread);
+ if (mutex->parent.parent.flag == RT_IPC_FLAG_FIFO &&
+ thread->current_priority != max_priority_in_queue)
+ {
+ rt_thread_control(thread,
+ RT_THREAD_CTRL_CHANGE_PRIORITY,
+ &(max_priority_in_queue));
+ }
+
+ if(mutex->hold < RT_MUTEX_HOLD_MAX)
+ {
+ mutex->hold ++;
+ }
+ else
+ {
+ rt_hw_interrupt_enable(temp); /* enable interrupt */
+ return -RT_EFULL; /* value overflowed */
+ }
/* resume thread */
rt_ipc_list_resume(&(mutex->parent.suspend_thread));
@@ -861,9 +949,17 @@ rt_err_t rt_mutex_release(rt_mutex_t mutex)
}
else
{
- /* increase value */
- mutex->value ++;
-
+ if(mutex->value < RT_MUTEX_VALUE_MAX)
+ {
+ /* increase value */
+ mutex->value ++;
+ }
+ else
+ {
+ rt_hw_interrupt_enable(temp); /* enable interrupt */
+ return -RT_EFULL; /* value overflowed */
+ }
+
/* clear owner */
mutex->owner = RT_NULL;
mutex->original_priority = 0xff;
@@ -1080,6 +1176,13 @@ rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set)
status = RT_EOK;
}
}
+ else
+ {
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+
+ return -RT_EINVAL;
+ }
/* move node to the next */
n = n->next;
@@ -1177,7 +1280,11 @@ rt_err_t rt_event_recv(rt_event_t event,
/* set received event */
if (recved)
*recved = (event->set & set);
-
+
+ /* fill thread event info */
+ thread->event_set = (event->set & set);
+ thread->event_info = option;
+
/* received event */
if (option & RT_EVENT_FLAG_CLEAR)
event->set &= ~set;
@@ -1186,10 +1293,10 @@ rt_err_t rt_event_recv(rt_event_t event,
{
/* no waiting */
thread->error = -RT_ETIMEOUT;
-
+
/* enable interrupt */
rt_hw_interrupt_enable(level);
-
+
return -RT_ETIMEOUT;
}
else
@@ -1470,7 +1577,6 @@ rt_err_t rt_mb_send_wait(rt_mailbox_t mb,
if (mb->entry == mb->size && timeout == 0)
{
rt_hw_interrupt_enable(temp);
-
return -RT_EFULL;
}
@@ -1543,9 +1649,18 @@ rt_err_t rt_mb_send_wait(rt_mailbox_t mb,
++ mb->in_offset;
if (mb->in_offset >= mb->size)
mb->in_offset = 0;
- /* increase message entry */
- mb->entry ++;
-
+
+ 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))
{
@@ -1583,6 +1698,71 @@ 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 there are threads
+ * suspended on mailbox object, it will be waked up. This function will return
+ * immediately.
+ *
+ * @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)
+{
+ register rt_ubase_t temp;
+
+ /* parameter check */
+ RT_ASSERT(mb != RT_NULL);
+ RT_ASSERT(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox);
+
+ RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mb->parent.parent)));
+
+ /* disable interrupt */
+ temp = rt_hw_interrupt_disable();
+
+ if (mb->entry == mb->size)
+ {
+ rt_hw_interrupt_enable(temp);
+ return -RT_EFULL;
+ }
+
+ /* 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;
+
+ /* increase message entry */
+ mb->entry ++;
+
+ /* 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);
+
+/**
* 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.
*
@@ -1692,8 +1872,12 @@ rt_err_t rt_mb_recv(rt_mailbox_t mb, rt_ubase_t *value, rt_int32_t timeout)
++ mb->out_offset;
if (mb->out_offset >= mb->size)
mb->out_offset = 0;
+
/* decrease message entry */
- mb->entry --;
+ if(mb->entry > 0)
+ {
+ mb->entry --;
+ }
/* resume suspended thread */
if (!rt_list_isempty(&(mb->suspend_sender_thread)))
@@ -2019,7 +2203,7 @@ rt_err_t rt_mq_send_wait(rt_mq_t mq,
}
/* message queue is full */
- while ((msg = mq->msg_queue_free) == RT_NULL)
+ while ((msg = (struct rt_mq_message *)mq->msg_queue_free) == RT_NULL)
{
/* reset error number in thread */
thread->error = RT_EOK;
@@ -2107,8 +2291,16 @@ rt_err_t rt_mq_send_wait(rt_mq_t mq,
if (mq->msg_queue_head == RT_NULL)
mq->msg_queue_head = msg;
- /* increase message entry */
- mq->entry ++;
+ if(mq->entry < RT_MQ_ENTRY_MAX)
+ {
+ /* increase message entry */
+ mq->entry ++;
+ }
+ else
+ {
+ rt_hw_interrupt_enable(temp); /* enable interrupt */
+ return -RT_EFULL; /* value overflowed */
+ }
/* resume suspended thread */
if (!rt_list_isempty(&mq->parent.suspend_thread))
@@ -2207,9 +2399,17 @@ rt_err_t rt_mq_urgent(rt_mq_t mq, const void *buffer, rt_size_t size)
if (mq->msg_queue_tail == RT_NULL)
mq->msg_queue_tail = msg;
- /* increase message entry */
- mq->entry ++;
-
+ if(mq->entry < RT_MQ_ENTRY_MAX)
+ {
+ /* increase message entry */
+ mq->entry ++;
+ }
+ else
+ {
+ rt_hw_interrupt_enable(temp); /* enable interrupt */
+ return -RT_EFULL; /* value overflowed */
+ }
+
/* resume suspended thread */
if (!rt_list_isempty(&mq->parent.suspend_thread))
{
@@ -2351,7 +2551,10 @@ rt_err_t rt_mq_recv(rt_mq_t mq,
mq->msg_queue_tail = RT_NULL;
/* decrease message entry */
- mq->entry --;
+ if(mq->entry > 0)
+ {
+ mq->entry --;
+ }
/* enable interrupt */
rt_hw_interrupt_enable(temp);