Merge pull request #6523 from BernardXiong/nested_mutex
[Kernel] Add nested mutex feature
This commit is contained in:
commit
79e298147b
|
@ -411,9 +411,9 @@ long list_mutex(void)
|
|||
|
||||
maxlen = RT_NAME_MAX;
|
||||
|
||||
rt_kprintf("%-*.s owner hold suspend thread\n", maxlen, item_title);
|
||||
rt_kprintf("%-*.s owner hold suspend thread priority\n", maxlen, item_title);
|
||||
object_split(maxlen);
|
||||
rt_kprintf(" -------- ---- --------------\n");
|
||||
rt_kprintf(" -------- ---- -------------- --------\n");
|
||||
|
||||
do
|
||||
{
|
||||
|
@ -436,13 +436,14 @@ long list_mutex(void)
|
|||
rt_hw_interrupt_enable(level);
|
||||
|
||||
m = (struct rt_mutex *)obj;
|
||||
rt_kprintf("%-*.*s %-8.*s %04d %d\n",
|
||||
rt_kprintf("%-*.*s %-8.*s %04d %d %d\n",
|
||||
maxlen, RT_NAME_MAX,
|
||||
m->parent.parent.name,
|
||||
RT_NAME_MAX,
|
||||
m->owner->name,
|
||||
m->hold,
|
||||
rt_list_len(&m->parent.suspend_thread));
|
||||
rt_list_len(&m->parent.suspend_thread),
|
||||
m->priority);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -673,12 +673,19 @@ struct rt_thread
|
|||
|
||||
/* priority */
|
||||
rt_uint8_t current_priority; /**< current priority */
|
||||
rt_uint8_t init_priority; /**< initialized priority */
|
||||
#if RT_THREAD_PRIORITY_MAX > 32
|
||||
rt_uint8_t number;
|
||||
rt_uint8_t high_mask;
|
||||
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
|
||||
rt_uint32_t number_mask;
|
||||
|
||||
#ifdef RT_USING_MUTEX
|
||||
/* object for IPC */
|
||||
rt_list_t taken_object_list;
|
||||
rt_object_t pending_object;
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_EVENT
|
||||
/* thread event */
|
||||
rt_uint32_t event_set;
|
||||
|
@ -772,12 +779,13 @@ struct rt_mutex
|
|||
{
|
||||
struct rt_ipc_object parent; /**< inherit from ipc_object */
|
||||
|
||||
rt_uint16_t value; /**< value of mutex */
|
||||
|
||||
rt_uint8_t original_priority; /**< priority of last thread hold the mutex */
|
||||
rt_uint8_t ceiling_priority; /**< the priority ceiling of mutexe */
|
||||
rt_uint8_t priority; /**< the maximal priority for pending thread */
|
||||
rt_uint8_t hold; /**< numbers of thread hold the mutex */
|
||||
rt_uint8_t reserved; /**< reserved field */
|
||||
|
||||
struct rt_thread *owner; /**< current owner of mutex */
|
||||
rt_list_t taken_list; /**< the object list taken by thread */
|
||||
};
|
||||
typedef struct rt_mutex *rt_mutex_t;
|
||||
#endif /* RT_USING_MUTEX */
|
||||
|
|
|
@ -368,6 +368,9 @@ rt_err_t rt_mutex_detach(rt_mutex_t mutex);
|
|||
rt_mutex_t rt_mutex_create(const char *name, rt_uint8_t flag);
|
||||
rt_err_t rt_mutex_delete(rt_mutex_t mutex);
|
||||
#endif
|
||||
void rt_mutex_drop_thread(rt_mutex_t mutex, rt_thread_t thread);
|
||||
rt_uint8_t rt_mutex_setprioceiling(rt_mutex_t mutex, rt_uint8_t priority);
|
||||
rt_uint8_t rt_mutex_getprioceiling(rt_mutex_t mutex);
|
||||
|
||||
rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout);
|
||||
rt_err_t rt_mutex_trytake(rt_mutex_t mutex);
|
||||
|
|
386
src/ipc.c
386
src/ipc.c
|
@ -42,6 +42,8 @@
|
|||
* 2022-01-07 Gabriel Moving __on_rt_xxxxx_hook to ipc.c
|
||||
* 2022-01-24 THEWON let rt_mutex_take return thread->error when using signal
|
||||
* 2022-04-08 Stanley Correct descriptions
|
||||
* 2022-10-15 Bernard add nested mutex feature
|
||||
* 2022-10-16 Bernard add prioceiling feature in mutex
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
@ -708,6 +710,83 @@ RTM_EXPORT(rt_sem_control);
|
|||
#endif /* RT_USING_SEMAPHORE */
|
||||
|
||||
#ifdef RT_USING_MUTEX
|
||||
rt_inline rt_uint8_t _mutex_update_priority(struct rt_mutex *mutex)
|
||||
{
|
||||
struct rt_thread *thread;
|
||||
|
||||
if (!rt_list_isempty(&mutex->parent.suspend_thread))
|
||||
{
|
||||
thread = rt_list_entry(mutex->parent.suspend_thread.next, struct rt_thread, tlist);
|
||||
mutex->priority = thread->current_priority;
|
||||
}
|
||||
else
|
||||
{
|
||||
mutex->priority = 0xff;
|
||||
}
|
||||
|
||||
return mutex->priority;
|
||||
}
|
||||
|
||||
rt_inline rt_uint8_t _thread_get_mutex_priority(struct rt_thread* thread)
|
||||
{
|
||||
rt_list_t *node = RT_NULL;
|
||||
struct rt_mutex *mutex = RT_NULL;
|
||||
rt_uint8_t priority = thread->init_priority;
|
||||
|
||||
rt_list_for_each(node, &(thread->taken_object_list))
|
||||
{
|
||||
mutex = rt_list_entry(node, struct rt_mutex, taken_list);
|
||||
if (priority > mutex->priority)
|
||||
{
|
||||
priority = mutex->priority;
|
||||
}
|
||||
}
|
||||
|
||||
return priority;
|
||||
}
|
||||
|
||||
rt_inline void _thread_update_priority(struct rt_thread *thread, rt_uint8_t priority)
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_IPC,
|
||||
("thread:%s priority -> %d\n", thread->name, priority));
|
||||
|
||||
/* change priority of the thread */
|
||||
rt_thread_control(thread,
|
||||
RT_THREAD_CTRL_CHANGE_PRIORITY,
|
||||
&priority);
|
||||
|
||||
if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND)
|
||||
{
|
||||
/* whether change the priority of taken mutex */
|
||||
struct rt_object* pending_obj = thread->pending_object;
|
||||
|
||||
if (pending_obj && rt_object_get_type(pending_obj) == RT_Object_Class_Mutex)
|
||||
{
|
||||
rt_uint8_t mutex_priority;
|
||||
struct rt_mutex* pending_mutex = (struct rt_mutex *)pending_obj;
|
||||
|
||||
/* re-insert thread to suspended thread list */
|
||||
rt_list_remove(&(thread->tlist));
|
||||
_ipc_list_suspend(&(pending_mutex->parent.suspend_thread),
|
||||
thread,
|
||||
pending_mutex->parent.parent.flag);
|
||||
|
||||
/* update priority */
|
||||
_mutex_update_priority(pending_mutex);
|
||||
/* change the priority of mutex owner thread */
|
||||
RT_DEBUG_LOG(RT_DEBUG_IPC,
|
||||
("mutex: %s priority -> %d\n", pending_mutex->parent.parent.name,
|
||||
pending_mutex->priority));
|
||||
|
||||
mutex_priority = _thread_get_mutex_priority(pending_mutex->owner);
|
||||
if (mutex_priority != pending_mutex->owner->current_priority)
|
||||
{
|
||||
_thread_update_priority(pending_mutex->owner, mutex_priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @addtogroup mutex
|
||||
*/
|
||||
|
@ -752,10 +831,11 @@ rt_err_t rt_mutex_init(rt_mutex_t mutex, const char *name, rt_uint8_t flag)
|
|||
/* initialize ipc object */
|
||||
_ipc_object_init(&(mutex->parent));
|
||||
|
||||
mutex->value = 1;
|
||||
mutex->owner = RT_NULL;
|
||||
mutex->original_priority = 0xFF;
|
||||
mutex->hold = 0;
|
||||
mutex->owner = RT_NULL;
|
||||
mutex->priority = 0xFF;
|
||||
mutex->hold = 0;
|
||||
mutex->ceiling_priority = 0xFF;
|
||||
rt_list_init(&(mutex->taken_list));
|
||||
|
||||
/* flag can only be RT_IPC_FLAG_PRIO. RT_IPC_FLAG_FIFO cannot solve the unbounded priority inversion problem */
|
||||
mutex->parent.parent.flag = RT_IPC_FLAG_PRIO;
|
||||
|
@ -785,13 +865,19 @@ RTM_EXPORT(rt_mutex_init);
|
|||
*/
|
||||
rt_err_t rt_mutex_detach(rt_mutex_t mutex)
|
||||
{
|
||||
rt_ubase_t level;
|
||||
|
||||
/* parameter check */
|
||||
RT_ASSERT(mutex != RT_NULL);
|
||||
RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex);
|
||||
RT_ASSERT(rt_object_is_systemobject(&mutex->parent.parent));
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
/* wakeup all suspended threads */
|
||||
_ipc_list_resume_all(&(mutex->parent.suspend_thread));
|
||||
/* remove mutex from thread's taken list */
|
||||
rt_list_remove(&mutex->taken_list);
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
/* detach mutex object */
|
||||
rt_object_detach(&(mutex->parent.parent));
|
||||
|
@ -800,6 +886,104 @@ rt_err_t rt_mutex_detach(rt_mutex_t mutex)
|
|||
}
|
||||
RTM_EXPORT(rt_mutex_detach);
|
||||
|
||||
/* drop a thread from the suspend list of mutex */
|
||||
|
||||
/**
|
||||
* @brief drop a thread from the suspend list of mutex
|
||||
*
|
||||
* @param mutex is a pointer to a mutex object.
|
||||
* @param thread is the thread should be dropped from mutex.
|
||||
*/
|
||||
void rt_mutex_drop_thread(rt_mutex_t mutex, rt_thread_t thread)
|
||||
{
|
||||
rt_uint8_t priority;
|
||||
rt_bool_t need_update = RT_FALSE;
|
||||
|
||||
rt_list_remove(&(thread->tlist));
|
||||
|
||||
/* should change the priority of mutex owner thread */
|
||||
if (mutex->owner->current_priority == thread->current_priority)
|
||||
need_update = RT_TRUE;
|
||||
|
||||
/* update the priority of mutex */
|
||||
if (!rt_list_isempty(&mutex->parent.suspend_thread))
|
||||
{
|
||||
/* more thread suspended in the list */
|
||||
struct rt_thread *th;
|
||||
|
||||
th = rt_list_entry(mutex->parent.suspend_thread.next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
/* update the priority of mutex */
|
||||
mutex->priority = th->current_priority;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* set mutex priority to maximal priority */
|
||||
mutex->priority = 0xff;
|
||||
}
|
||||
|
||||
/* try to change the priority of mutex owner thread */
|
||||
if (need_update)
|
||||
{
|
||||
/* get the maximal priority of mutex in thread */
|
||||
priority = _thread_get_mutex_priority(mutex->owner);
|
||||
if (priority != mutex->owner->current_priority)
|
||||
{
|
||||
_thread_update_priority(mutex->owner, priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief set the prioceiling attribute of the mutex.
|
||||
*
|
||||
* @param mutex is a pointer to a mutex object.
|
||||
* @param priority is the priority should be set to mutex.
|
||||
*
|
||||
* @return return the old priority ceiling
|
||||
*/
|
||||
rt_uint8_t rt_mutex_setprioceiling(rt_mutex_t mutex, rt_uint8_t priority)
|
||||
{
|
||||
rt_uint8_t ret_priority = 0xFF;
|
||||
|
||||
if ((mutex) && (priority < RT_THREAD_PRIORITY_MAX))
|
||||
{
|
||||
ret_priority = mutex->ceiling_priority;
|
||||
mutex->ceiling_priority = priority;
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_set_errno(-RT_EINVAL);
|
||||
}
|
||||
|
||||
return ret_priority;
|
||||
}
|
||||
RTM_EXPORT(rt_mutex_setprioceiling);
|
||||
|
||||
|
||||
/**
|
||||
* @brief set the prioceiling attribute of the mutex.
|
||||
*
|
||||
* @param mutex is a pointer to a mutex object.
|
||||
*
|
||||
* @return return the current priority ceiling of the mutex.
|
||||
*/
|
||||
rt_uint8_t rt_mutex_getprioceiling(rt_mutex_t mutex)
|
||||
{
|
||||
rt_uint8_t prio = 0xFF;
|
||||
|
||||
if (mutex)
|
||||
{
|
||||
prio = mutex->ceiling_priority;
|
||||
}
|
||||
|
||||
return prio;
|
||||
}
|
||||
RTM_EXPORT(rt_mutex_getprioceiling);
|
||||
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
/**
|
||||
* @brief This function will create a mutex object.
|
||||
|
@ -836,10 +1020,11 @@ rt_mutex_t rt_mutex_create(const char *name, rt_uint8_t flag)
|
|||
/* initialize ipc object */
|
||||
_ipc_object_init(&(mutex->parent));
|
||||
|
||||
mutex->value = 1;
|
||||
mutex->owner = RT_NULL;
|
||||
mutex->original_priority = 0xFF;
|
||||
mutex->hold = 0;
|
||||
mutex->owner = RT_NULL;
|
||||
mutex->priority = 0xFF;
|
||||
mutex->hold = 0;
|
||||
mutex->ceiling_priority = 0xFF;
|
||||
rt_list_init(&(mutex->taken_list));
|
||||
|
||||
/* flag can only be RT_IPC_FLAG_PRIO. RT_IPC_FLAG_FIFO cannot solve the unbounded priority inversion problem */
|
||||
mutex->parent.parent.flag = RT_IPC_FLAG_PRIO;
|
||||
|
@ -869,6 +1054,8 @@ RTM_EXPORT(rt_mutex_create);
|
|||
*/
|
||||
rt_err_t rt_mutex_delete(rt_mutex_t mutex)
|
||||
{
|
||||
rt_ubase_t level;
|
||||
|
||||
/* parameter check */
|
||||
RT_ASSERT(mutex != RT_NULL);
|
||||
RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex);
|
||||
|
@ -876,8 +1063,12 @@ rt_err_t rt_mutex_delete(rt_mutex_t mutex)
|
|||
|
||||
RT_DEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
/* wakeup all suspended threads */
|
||||
_ipc_list_resume_all(&(mutex->parent.suspend_thread));
|
||||
/* remove mutex from thread's taken list */
|
||||
rt_list_remove(&mutex->taken_list);
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
/* delete mutex object */
|
||||
rt_object_delete(&(mutex->parent.parent));
|
||||
|
@ -933,8 +1124,8 @@ rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout)
|
|||
RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(mutex->parent.parent)));
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_IPC,
|
||||
("mutex_take: current thread %s, mutex value: %d, hold: %d\n",
|
||||
thread->name, mutex->value, mutex->hold));
|
||||
("mutex_take: current thread %s, hold: %d\n",
|
||||
thread->name, mutex->hold));
|
||||
|
||||
/* reset thread error */
|
||||
thread->error = RT_EOK;
|
||||
|
@ -954,25 +1145,24 @@ rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout)
|
|||
}
|
||||
else
|
||||
{
|
||||
/* The value of mutex is 1 in initial status. Therefore, if the
|
||||
* value is great than 0, it indicates the mutex is avaible.
|
||||
*/
|
||||
if (mutex->value > 0)
|
||||
/* whether the mutex has owner thread. */
|
||||
if (mutex->owner == RT_NULL)
|
||||
{
|
||||
/* mutex is available */
|
||||
mutex->value --;
|
||||
|
||||
/* set mutex owner and original priority */
|
||||
mutex->owner = thread;
|
||||
mutex->original_priority = thread->current_priority;
|
||||
if(mutex->hold < RT_MUTEX_HOLD_MAX)
|
||||
mutex->owner = thread;
|
||||
mutex->priority = 0xff;
|
||||
mutex->hold = 1;
|
||||
|
||||
if (mutex->ceiling_priority != 0xFF)
|
||||
{
|
||||
mutex->hold ++;
|
||||
/* set the priority of thread to the ceiling priority */
|
||||
if (mutex->ceiling_priority < mutex->owner->current_priority)
|
||||
_thread_update_priority(mutex->owner, mutex->ceiling_priority);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_hw_interrupt_enable(level); /* enable interrupt */
|
||||
return -RT_EFULL; /* value overflowed */
|
||||
/* insert mutex to thread's taken object list */
|
||||
rt_list_insert_after(&thread->taken_object_list, &mutex->taken_list);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -990,23 +1180,28 @@ rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout)
|
|||
}
|
||||
else
|
||||
{
|
||||
rt_uint8_t priority = thread->current_priority;
|
||||
|
||||
/* mutex is unavailable, push to suspend list */
|
||||
RT_DEBUG_LOG(RT_DEBUG_IPC, ("mutex_take: suspend thread: %s\n",
|
||||
thread->name));
|
||||
|
||||
/* change the owner thread priority of mutex */
|
||||
if (thread->current_priority < mutex->owner->current_priority)
|
||||
{
|
||||
/* change the owner thread priority */
|
||||
rt_thread_control(mutex->owner,
|
||||
RT_THREAD_CTRL_CHANGE_PRIORITY,
|
||||
&thread->current_priority);
|
||||
}
|
||||
|
||||
/* suspend current thread */
|
||||
_ipc_list_suspend(&(mutex->parent.suspend_thread),
|
||||
thread,
|
||||
mutex->parent.parent.flag);
|
||||
/* set pending object in thread to this mutex */
|
||||
thread->pending_object = &(mutex->parent.parent);
|
||||
|
||||
/* update the priority level of mutex */
|
||||
if (priority < mutex->priority)
|
||||
{
|
||||
mutex->priority = priority;
|
||||
if (mutex->priority < mutex->owner->current_priority)
|
||||
{
|
||||
_thread_update_priority(mutex->owner, priority);
|
||||
}
|
||||
}
|
||||
|
||||
/* has waiting time, start thread timer */
|
||||
if (timeout > 0)
|
||||
|
@ -1028,16 +1223,57 @@ rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout)
|
|||
/* do schedule */
|
||||
rt_schedule();
|
||||
|
||||
if (thread->error != RT_EOK)
|
||||
/* disable interrupt */
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
if (thread->error == RT_EOK)
|
||||
{
|
||||
/* return error */
|
||||
return thread->error;
|
||||
/* get mutex successfully */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* the mutex is taken successfully. */
|
||||
/* disable interrupt */
|
||||
level = rt_hw_interrupt_disable();
|
||||
/* the mutex has not been taken and thread has detach from the pending list. */
|
||||
|
||||
rt_bool_t need_update = RT_FALSE;
|
||||
|
||||
/* should change the priority of mutex owner thread */
|
||||
if (mutex->owner->current_priority == thread->current_priority)
|
||||
need_update = RT_TRUE;
|
||||
|
||||
/* update the priority of mutex */
|
||||
if (!rt_list_isempty(&mutex->parent.suspend_thread))
|
||||
{
|
||||
/* more thread suspended in the list */
|
||||
struct rt_thread *th;
|
||||
|
||||
th = rt_list_entry(mutex->parent.suspend_thread.next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
/* update the priority of mutex */
|
||||
mutex->priority = th->current_priority;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* set mutex priority to maximal priority */
|
||||
mutex->priority = 0xff;
|
||||
}
|
||||
|
||||
/* try to change the priority of mutex owner thread */
|
||||
if (need_update)
|
||||
{
|
||||
/* get the maximal priority of mutex in thread */
|
||||
priority = _thread_get_mutex_priority(mutex->owner);
|
||||
if (priority != mutex->owner->current_priority)
|
||||
{
|
||||
_thread_update_priority(mutex->owner, priority);
|
||||
}
|
||||
}
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
/* return error */
|
||||
return thread->error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1109,8 +1345,8 @@ rt_err_t rt_mutex_release(rt_mutex_t mutex)
|
|||
level = rt_hw_interrupt_disable();
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_IPC,
|
||||
("mutex_release:current thread %s, mutex value: %d, hold: %d\n",
|
||||
thread->name, mutex->value, mutex->hold));
|
||||
("mutex_release:current thread %s, hold: %d\n",
|
||||
thread->name, mutex->hold));
|
||||
|
||||
RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mutex->parent.parent)));
|
||||
|
||||
|
@ -1130,60 +1366,70 @@ rt_err_t rt_mutex_release(rt_mutex_t mutex)
|
|||
/* if no hold */
|
||||
if (mutex->hold == 0)
|
||||
{
|
||||
/* change the owner thread to original priority */
|
||||
if (mutex->original_priority != mutex->owner->current_priority)
|
||||
/* remove mutex from thread's taken list */
|
||||
rt_list_remove(&mutex->taken_list);
|
||||
|
||||
/* whether change the thread priority */
|
||||
if ((mutex->ceiling_priority != 0xFF) || (thread->current_priority == mutex->priority))
|
||||
{
|
||||
rt_thread_control(mutex->owner,
|
||||
rt_uint8_t priority = 0xff;
|
||||
|
||||
/* get the highest priority in the taken list of thread */
|
||||
priority = _thread_get_mutex_priority(thread);
|
||||
|
||||
rt_thread_control(thread,
|
||||
RT_THREAD_CTRL_CHANGE_PRIORITY,
|
||||
&(mutex->original_priority));
|
||||
&priority);
|
||||
|
||||
need_schedule = RT_TRUE;
|
||||
}
|
||||
|
||||
/* wakeup suspended thread */
|
||||
if (!rt_list_isempty(&mutex->parent.suspend_thread))
|
||||
{
|
||||
/* get suspended thread */
|
||||
thread = rt_list_entry(mutex->parent.suspend_thread.next,
|
||||
/* get the first suspended thread */
|
||||
struct rt_thread *next_thread = rt_list_entry(mutex->parent.suspend_thread.next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_IPC, ("mutex_release: resume thread: %s\n",
|
||||
thread->name));
|
||||
next_thread->name));
|
||||
|
||||
/* set new owner and priority */
|
||||
mutex->owner = thread;
|
||||
mutex->original_priority = thread->current_priority;
|
||||
/* remove the thread from the suspended list of mutex */
|
||||
rt_list_remove(&(next_thread->tlist));
|
||||
|
||||
if(mutex->hold < RT_MUTEX_HOLD_MAX)
|
||||
/* set new owner and put mutex into taken list of thread */
|
||||
mutex->owner = next_thread;
|
||||
mutex->hold = 1;
|
||||
rt_list_insert_after(&next_thread->taken_object_list, &mutex->taken_list);
|
||||
/* cleanup pending object */
|
||||
next_thread->pending_object = RT_NULL;
|
||||
|
||||
/* resume thread */
|
||||
rt_thread_resume(next_thread);
|
||||
|
||||
/* update mutex priority */
|
||||
if (!rt_list_isempty(&(mutex->parent.suspend_thread)))
|
||||
{
|
||||
mutex->hold ++;
|
||||
struct rt_thread *th;
|
||||
|
||||
th = rt_list_entry(mutex->parent.suspend_thread.next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
mutex->priority = th->current_priority;
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_hw_interrupt_enable(level); /* enable interrupt */
|
||||
return -RT_EFULL; /* value overflowed */
|
||||
mutex->priority = 0xff;
|
||||
}
|
||||
|
||||
/* resume thread */
|
||||
_ipc_list_resume(&(mutex->parent.suspend_thread));
|
||||
|
||||
need_schedule = RT_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(mutex->value < RT_MUTEX_VALUE_MAX)
|
||||
{
|
||||
/* increase value */
|
||||
mutex->value ++;
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_hw_interrupt_enable(level); /* enable interrupt */
|
||||
return -RT_EFULL; /* value overflowed */
|
||||
}
|
||||
|
||||
/* clear owner */
|
||||
mutex->owner = RT_NULL;
|
||||
mutex->original_priority = 0xff;
|
||||
mutex->owner = RT_NULL;
|
||||
mutex->priority = 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
27
src/thread.c
27
src/thread.c
|
@ -31,6 +31,7 @@
|
|||
* 2021-12-27 Meco Man remove .init_priority
|
||||
* 2022-01-07 Gabriel Moving __on_rt_xxxxx_hook to thread.c
|
||||
* 2022-01-24 THEWON let rt_thread_sleep return thread->error when using signal
|
||||
* 2022-10-15 Bernard add nested mutex feature
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
|
@ -187,10 +188,16 @@ static rt_err_t _thread_init(struct rt_thread *thread,
|
|||
|
||||
/* priority init */
|
||||
RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX);
|
||||
thread->init_priority = priority;
|
||||
thread->current_priority = priority;
|
||||
|
||||
thread->number_mask = 0;
|
||||
|
||||
#ifdef RT_USING_MUTEX
|
||||
rt_list_init(&thread->taken_object_list);
|
||||
thread->pending_object = RT_NULL;
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_EVENT
|
||||
thread->event_set = 0;
|
||||
thread->event_info = 0;
|
||||
|
@ -420,6 +427,16 @@ rt_err_t rt_thread_detach(rt_thread_t thread)
|
|||
/* change stat */
|
||||
thread->stat = RT_THREAD_CLOSE;
|
||||
|
||||
#ifdef RT_USING_MUTEX
|
||||
if ((thread->pending_object) &&
|
||||
(rt_object_get_type(thread->pending_object) == RT_Object_Class_Mutex))
|
||||
{
|
||||
struct rt_mutex *mutex = (struct rt_mutex*)thread->pending_object;
|
||||
rt_mutex_drop_thread(mutex, thread);
|
||||
thread->pending_object = RT_NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* insert to defunct thread list */
|
||||
rt_thread_defunct_enqueue(thread);
|
||||
|
||||
|
@ -523,6 +540,16 @@ rt_err_t rt_thread_delete(rt_thread_t thread)
|
|||
/* change stat */
|
||||
thread->stat = RT_THREAD_CLOSE;
|
||||
|
||||
#ifdef RT_USING_MUTEX
|
||||
if ((thread->pending_object) &&
|
||||
(rt_object_get_type(thread->pending_object) == RT_Object_Class_Mutex))
|
||||
{
|
||||
struct rt_mutex *mutex = (struct rt_mutex*)thread->pending_object;
|
||||
rt_mutex_drop_thread(mutex, thread);
|
||||
thread->pending_object = RT_NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* insert to defunct thread list */
|
||||
rt_thread_defunct_enqueue(thread);
|
||||
|
||||
|
|
Loading…
Reference in New Issue