os_mutex.c
2026/7/19大约 9 分钟附录源码附录
os_mutex.c
路径: kernel\source\os_mutex.c
/**
***********************************************************************************************************************
* Copyright (c) 2020, China Mobile Communications Group Co.,Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* @file os_mutex.c
*
* @brief This file implements the mutex functions.
*
* @revision
* Date Author Notes
* 2020-12-24 OneOS team First Version
***********************************************************************************************************************
*/
#include <os_errno.h>
#include <os_mutex.h>
#include <arch_interrupt.h>
#include <string.h>
#include <os_spinlock.h>
#include "os_kernel_internal.h"
#ifdef OS_USING_MUTEX
#define MUTEX_TAG "MUTEX"
static os_list_node_t gs_os_mutex_resource_list_head = OS_LIST_INIT(gs_os_mutex_resource_list_head);
static OS_DEFINE_SPINLOCK(gs_os_mutex_resource_list_lock);
OS_INLINE os_bool_t _k_mutex_set_owner_priority(const os_mutex_t *mutex, uint8_t new_priority)
{
os_bool_t need_sched;
if ((mutex->owner->state & OS_TASK_STATE_READY) != 0)
{
k_readyq_remove(mutex->owner);
mutex->owner->current_priority = new_priority;
k_readyq_put(mutex->owner);
need_sched = OS_TRUE;
}
else
{
mutex->owner->current_priority = new_priority;
need_sched = OS_FALSE;
}
return need_sched;
}
OS_INLINE os_bool_t _k_mutex_restore_priority(const os_mutex_t *mutex)
{
const os_task_t *owner_task;
uint8_t new_priority;
os_bool_t need_sched;
const os_task_t *block_task;
const os_mutex_t *iter_mutex;
owner_task = mutex->owner;
need_sched = OS_FALSE;
if (owner_task->current_priority != mutex->original_priority)
{
new_priority = mutex->original_priority;
os_list_for_each_entry(iter_mutex, &owner_task->hold_mutex_list_head, os_mutex_t, hold_node)
{
if (!os_list_empty(&iter_mutex->task_list_head))
{
block_task = os_list_first_entry(&iter_mutex->task_list_head, os_task_t, task_node);
if (block_task->current_priority < new_priority)
{
new_priority = block_task->current_priority;
}
}
}
if (new_priority != owner_task->current_priority)
{
if ((mutex->owner->state & OS_TASK_STATE_READY) != 0)
{
k_readyq_remove(mutex->owner);
mutex->owner->current_priority = new_priority;
k_readyq_put(mutex->owner);
need_sched = OS_TRUE;
}
else
{
mutex->owner->current_priority = new_priority;
}
}
}
return need_sched;
}
OS_INLINE void _k_mutex_init(os_mutex_t *mutex, const char *name, os_bool_t recursive, uint8_t object_alloc_type)
{
os_list_init(&mutex->task_list_head);
mutex->owner = OS_NULL;
mutex->lock_count = 0U;
mutex->is_recursive = recursive;
mutex->object_alloc_type = object_alloc_type;
mutex->wake_type = OS_MUTEX_WAKE_TYPE_PRIO;
if (OS_NULL != name)
{
(void)strncpy(&mutex->name[0], name, OS_NAME_MAX);
mutex->name[OS_NAME_MAX] = '\0';
}
else
{
mutex->name[0] = '\0';
}
mutex->object_inited = OS_KOBJ_INITED;
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
os_spin_lock_init(&mutex->lock);
#endif
}
OS_INLINE void _k_mutex_deinit(os_mutex_t *mutex)
{
os_bool_t need_sched;
OS_KERNEL_INIT();
need_sched = OS_FALSE;
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
os_spin_lock_irq(&mutex->lock, &irq_save);
#else
OS_KERNEL_ENTER();
#endif
mutex->object_inited = OS_KOBJ_DEINITED;
if (OS_NULL == mutex->owner)
{
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
os_spin_unlock_irq(&mutex->lock, irq_save);
#else
OS_KERNEL_EXIT();
#endif
}
else
{
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
k_kernel_spin_lock();
#endif
if (mutex->owner->current_priority != mutex->owner->backup_priority)
{
if ((mutex->owner->state & OS_TASK_STATE_READY) != 0)
{
k_readyq_remove(mutex->owner);
mutex->owner->current_priority = mutex->owner->backup_priority;
k_readyq_put(mutex->owner);
need_sched = OS_TRUE;
}
else
{
mutex->owner->current_priority = mutex->owner->backup_priority;
}
}
os_list_del(&mutex->hold_node);
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
k_kernel_spin_unlock();
#endif
/* Wakeup all suspend tasks */
if (OS_TRUE == k_cancel_all_blocked_task(&mutex->task_list_head))
{
need_sched = OS_TRUE;
}
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
os_spin_unlock_irq(&mutex->lock, irq_save);
if (OS_TRUE == need_sched)
{
OS_KERNEL_ENTER();
OS_KERNEL_EXIT_SCHED();
}
#else
if (OS_TRUE == need_sched)
{
OS_KERNEL_EXIT_SCHED();
}
else
{
OS_KERNEL_EXIT();
}
#endif
}
os_spin_lock(&gs_os_mutex_resource_list_lock);
os_list_del(&mutex->resource_node);
os_spin_unlock(&gs_os_mutex_resource_list_lock);
return;
}
/**
***********************************************************************************************************************
* @brief This function to create a mutex object.
*
* @param[in] mutex_cb The static mutex cb to be create, NULL will dynamic create.
* @param[in] name The name of mutex.
* @param[in] recursive A recursive mutex or not.
*
* @return The ID of mutex.
* @retval The ID of mutex.
***********************************************************************************************************************
*/
os_mutex_id os_mutex_create(os_mutex_dummy_t *mutex_cb, const char *name, os_bool_t recursive)
{
os_bool_t flag;
const os_mutex_t *iter_mutex;
const os_list_node_t *pos;
os_mutex_t *mutex;
uint8_t alloc_type;
os_mutex_id mutex_id;
OS_ASSERT(OS_FALSE == os_is_irq_active());
#ifndef OS_USING_HEAP
OS_ASSERT(OS_NULL != mutex_cb);
#endif
flag = OS_TRUE;
if (OS_NULL != mutex_cb)
{
mutex = OS_TYPE_CONVERT(os_mutex_t *, mutex_cb);
alloc_type = OS_ALLOC_TYPE_STATIC;
os_spin_lock(&gs_os_mutex_resource_list_lock);
os_list_for_each(pos, &gs_os_mutex_resource_list_head)
{
iter_mutex = os_list_entry(pos, os_mutex_t, resource_node);
if (iter_mutex == mutex)
{
mutex = OS_NULL;
os_spin_unlock(&gs_os_mutex_resource_list_lock);
OS_KERN_LOG(KERN_ERROR, MUTEX_TAG, "%s", OS_KERNEL_ERR_INFO);
flag = OS_FALSE;
break;
}
}
}
#ifdef OS_USING_HEAP
else
{
/* Check context. */
alloc_type = OS_KOBJ_ALLOC_TYPE_DYNAMIC;
mutex = (os_mutex_t *)OS_KERNEL_MALLOC(sizeof(os_mutex_t));
if (OS_NULL == mutex)
{
OS_KERN_LOG(KERN_ERROR, MUTEX_TAG, "Malloc mutex memory failed");
flag = OS_FALSE;
}
}
#endif
if (OS_TRUE == flag)
{
_k_mutex_init(mutex, name, recursive, alloc_type);
if (OS_KOBJ_ALLOC_TYPE_DYNAMIC == (alloc_type & OS_KOBJ_ALLOC_TYPE_DYNAMIC))
{
os_spin_lock(&gs_os_mutex_resource_list_lock);
}
os_list_add_tail(&gs_os_mutex_resource_list_head, &mutex->resource_node);
os_spin_unlock(&gs_os_mutex_resource_list_lock);
}
mutex_id = OS_TYPE_CONVERT(os_mutex_id, mutex);
return mutex_id;
}
/**
***********************************************************************************************************************
* @brief Destory a mutex object created.
*
* @param[in] mutex_id The mutex id to destroy.
*
* @return The operation result.
* @retval OS_SUCCESS If the operation successful.
* @retval else Error code.
***********************************************************************************************************************
*/
os_err_t os_mutex_destroy(os_mutex_id mutex_id)
{
os_mutex_t *mutex;
os_err_t ret;
mutex = OS_TYPE_CONVERT(os_mutex_t *, mutex_id);
OS_ASSERT(OS_NULL != mutex);
OS_ASSERT(OS_FALSE == os_is_irq_active());
OS_ASSERT(OS_KOBJ_INITED == mutex->object_inited);
#ifndef OS_USING_HEAP
OS_ASSERT(OS_ALLOC_TYPE_STATIC == mutex->object_alloc_type);
#endif
ret = OS_SUCCESS;
if (OS_ALLOC_TYPE_STATIC == mutex->object_alloc_type)
{
_k_mutex_deinit(mutex);
}
else
{
_k_mutex_deinit(mutex);
OS_KERNEL_FREE(mutex);
}
return ret;
}
/**
***********************************************************************************************************************
* @brief This function locks a mutex. If the mutex is already locked by other task, the calling task will be
*blocked until either the mutex becomes available or waiting time expires. When mutex is locked multiple times by the
*same task, OS_ASSERT() will detect it.
*
* @param[in] mutex_id The id of mutex.
* @param[in] timeout Waitting time (in clock ticks).
*
* @return The operation result.
* @retval OS_SUCCESS If the operation successful.
* @retval else Error code.
***********************************************************************************************************************
*/
os_err_t os_mutex_lock(os_mutex_id mutex_id, os_tick_t timeout)
{
os_task_t *current_task;
os_bool_t need_sched;
os_err_t ret;
os_mutex_t *mutex;
OS_KERNEL_INIT();
mutex = OS_TYPE_CONVERT(os_mutex_t *, mutex_id);
OS_ASSERT(OS_NULL != mutex);
OS_ASSERT(OS_KOBJ_INITED == mutex->object_inited);
OS_ASSERT(OS_FALSE == mutex->is_recursive);
OS_ASSERT(OS_FALSE == os_is_irq_active());
OS_ASSERT((OS_FALSE == os_is_irq_disabled()) || (OS_NO_WAIT == timeout));
OS_ASSERT((OS_FALSE == os_is_schedule_locked()) || (OS_NO_WAIT == timeout));
OS_ASSERT((timeout < (OS_TICK_MAX / 2)) || (OS_WAIT_FOREVER == timeout));
ret = OS_SUCCESS;
need_sched = OS_FALSE;
current_task = k_task_self();
if (current_task == OS_NULL)
{
return OS_SUCCESS;
}
OS_ASSERT_EX(mutex->owner != current_task, "Task(%s) use mutex(%s) recursively!", current_task->name, mutex->name);
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
os_spin_lock_irq(&mutex->lock, &irq_save);
#else
OS_KERNEL_ENTER();
#endif
if (mutex->lock_count == 0U)
{
mutex->lock_count = 1U;
mutex->owner = current_task;
mutex->original_priority = current_task->current_priority;
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
k_kernel_spin_lock();
#endif
os_list_add_tail(¤t_task->hold_mutex_list_head, &mutex->hold_node);
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
k_kernel_spin_unlock();
os_spin_unlock_irq(&mutex->lock, irq_save);
#else
OS_KERNEL_EXIT();
#endif
}
else
{
if (timeout == OS_NO_WAIT)
{
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
os_spin_unlock_irq(&mutex->lock, irq_save);
#else
OS_KERNEL_EXIT();
#endif
ret = OS_BUSY;
}
else
{
/* Priority inherit */
if ((OS_MUTEX_WAKE_TYPE_PRIO == mutex->wake_type) &&
(current_task->current_priority < mutex->owner->current_priority))
{
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
k_kernel_spin_lock();
#endif
(void)_k_mutex_set_owner_priority(mutex, current_task->current_priority);
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
k_kernel_spin_unlock();
#endif
}
if (OS_MUTEX_WAKE_TYPE_PRIO == mutex->wake_type)
{
ret = k_block_task(&mutex->lock, irq_save, &mutex->task_list_head, timeout, OS_TRUE);
}
else
{
ret = k_block_task(&mutex->lock, irq_save, &mutex->task_list_head, timeout, OS_FALSE);
}
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
os_spin_lock_irq(&mutex->lock, &irq_save);
k_kernel_spin_lock();
#else
OS_KERNEL_ENTER();
#endif
if ((OS_SUCCESS != ret) && (OS_MUTEX_WAKE_TYPE_PRIO == mutex->wake_type))
{
need_sched = _k_mutex_restore_priority(mutex);
}
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
k_kernel_spin_unlock();
os_spin_unlock_irq(&mutex->lock, irq_save);
if (need_sched)
{
OS_KERNEL_ENTER();
OS_KERNEL_EXIT_SCHED();
}
#else
if (need_sched)
{
OS_KERNEL_EXIT_SCHED();
}
else
{
OS_KERNEL_EXIT();
}
#endif
}
}
return ret;
}
/**
***********************************************************************************************************************
* @brief This function unlocks a mutex. If there are tasks blocked on the mutex, the highest priority task
* will be woken up and aqcuire the mutex. When mutex is unlocked multiple times by the same task,
* OS_ASSERT() will detect it.
*
* @param[in] mutex_id The id of mutex.
*
* @return The operation result.
* @retval OS_SUCCESS If the operation successful.
* @retval else Error code.
***********************************************************************************************************************
*/
os_err_t os_mutex_unlock(os_mutex_id mutex_id)
{
os_task_t *current_task;
os_task_t *block_task;
os_bool_t need_sched;
os_mutex_t *mutex;
OS_KERNEL_INIT();
mutex = OS_TYPE_CONVERT(os_mutex_t *, mutex_id);
OS_ASSERT(OS_NULL != mutex);
OS_ASSERT(OS_KOBJ_INITED == mutex->object_inited);
OS_ASSERT(OS_FALSE == mutex->is_recursive);
OS_ASSERT(OS_FALSE == os_is_irq_active());
need_sched = OS_FALSE;
current_task = k_task_self();
if (current_task != OS_NULL)
{
/* Mutex only can be unlocked by owner */
OS_ASSERT_EX(mutex->owner == current_task,
"The mutex(addr: %p, name: %s, owner: %s) can't unlock by task(%s)",
mutex,
mutex->name,
mutex->owner->name,
current_task->name);
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
os_spin_lock_irq(&mutex->lock, &irq_save);
k_kernel_spin_lock();
#else
OS_KERNEL_ENTER();
#endif
os_list_del(&mutex->hold_node);
/* Restore task priority */
if (OS_MUTEX_WAKE_TYPE_PRIO == mutex->wake_type)
{
need_sched = _k_mutex_restore_priority(mutex);
}
/* Get the new owner, if any */
if (!os_list_empty(&mutex->task_list_head))
{
block_task = os_list_first_entry(&mutex->task_list_head, os_task_t, task_node);
need_sched = k_unblock_task(block_task);
mutex->owner = block_task;
mutex->original_priority = block_task->current_priority;
os_list_add_tail(&mutex->owner->hold_mutex_list_head, &mutex->hold_node);
}
else
{
mutex->owner = OS_NULL;
mutex->lock_count = 0;
}
if (os_list_empty(¤t_task->hold_mutex_list_head) &&
(current_task->current_priority != current_task->backup_priority))
{
OS_KERN_LOG(KERN_INFO,
MUTEX_TAG,
"New priority(%u) takes effect, old priority(%u)",
current_task->backup_priority,
current_task->current_priority);
k_readyq_remove(current_task);
current_task->current_priority = current_task->backup_priority;
k_readyq_put(current_task);
need_sched = OS_TRUE;
}
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
k_kernel_spin_unlock();
os_spin_unlock_irq(&mutex->lock, irq_save);
if (need_sched)
{
OS_KERNEL_ENTER();
OS_KERNEL_EXIT_SCHED();
}
#else
if (need_sched)
{
OS_KERNEL_EXIT_SCHED();
}
else
{
OS_KERNEL_EXIT();
}
#endif
}
return OS_SUCCESS;
}
/**
***********************************************************************************************************************
* @brief This function recursively locks a mutex and the increments it's nested count. If the mutex is
* already locked by other task, the calling task will block until either the mutex becomes available
* or waiting time expires. In contrast to os_mutex_lock(), it's ok to lock a mutex multiple times.
*
* @param[in] mutex_id The id of mutex.
* @param[in] timeout Waitting time (in clock ticks).
*
* @return The operation result.
* @retval OS_SUCCESS If the operation successful.
* @retval else Error code.
***********************************************************************************************************************
*/
os_err_t os_mutex_recursive_lock(os_mutex_id mutex_id, os_tick_t timeout)
{
os_task_t *current_task;
os_bool_t need_sched;
os_err_t ret;
os_mutex_t *mutex;
OS_KERNEL_INIT();
mutex = OS_TYPE_CONVERT(os_mutex_t *, mutex_id);
OS_ASSERT(OS_NULL != mutex);
OS_ASSERT(OS_KOBJ_INITED == mutex->object_inited);
OS_ASSERT(OS_TRUE == mutex->is_recursive);
OS_ASSERT(OS_FALSE == os_is_irq_active());
OS_ASSERT((OS_FALSE == os_is_irq_disabled()) || (OS_NO_WAIT == timeout));
OS_ASSERT((OS_FALSE == os_is_schedule_locked()) || (OS_NO_WAIT == timeout));
OS_ASSERT((timeout < (OS_TICK_MAX / 2)) || (OS_WAIT_FOREVER == timeout));
ret = OS_SUCCESS;
need_sched = OS_FALSE;
current_task = k_task_self();
if (current_task != OS_NULL)
{
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
os_spin_lock_irq(&mutex->lock, &irq_save);
#else
OS_KERNEL_ENTER();
#endif
if ((0U == mutex->lock_count) || (current_task == mutex->owner))
{
if (0U == mutex->lock_count)
{
mutex->original_priority = current_task->current_priority;
mutex->owner = current_task;
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
k_kernel_spin_lock();
#endif
os_list_add_tail(¤t_task->hold_mutex_list_head, &mutex->hold_node);
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
k_kernel_spin_unlock();
#endif
}
mutex->lock_count++;
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
os_spin_unlock_irq(&mutex->lock, irq_save);
#else
OS_KERNEL_EXIT();
#endif
}
else
{
if (timeout == OS_NO_WAIT)
{
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
os_spin_unlock_irq(&mutex->lock, irq_save);
#else
OS_KERNEL_EXIT();
#endif
ret = OS_BUSY;
}
else
{
if ((OS_MUTEX_WAKE_TYPE_PRIO == mutex->wake_type) &&
(current_task->current_priority < mutex->owner->current_priority))
{
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
k_kernel_spin_lock();
#endif
(void)_k_mutex_set_owner_priority(mutex, current_task->current_priority);
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
k_kernel_spin_unlock();
#endif
}
if (OS_MUTEX_WAKE_TYPE_PRIO == mutex->wake_type)
{
ret = k_block_task(&mutex->lock, irq_save, &mutex->task_list_head, timeout, OS_TRUE);
}
else
{
ret = k_block_task(&mutex->lock, irq_save, &mutex->task_list_head, timeout, OS_FALSE);
}
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
os_spin_lock_irq(&mutex->lock, &irq_save);
k_kernel_spin_lock();
#else
OS_KERNEL_ENTER();
#endif
if ((OS_SUCCESS != ret) && (OS_MUTEX_WAKE_TYPE_PRIO == mutex->wake_type))
{
need_sched = _k_mutex_restore_priority(mutex);
}
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
k_kernel_spin_unlock();
os_spin_unlock_irq(&mutex->lock, irq_save);
if (need_sched)
{
OS_KERNEL_ENTER();
OS_KERNEL_EXIT_SCHED();
}
#else
if (need_sched)
{
OS_KERNEL_EXIT_SCHED();
}
else
{
OS_KERNEL_EXIT();
}
#endif
}
}
}
return ret;
}
/**
***********************************************************************************************************************
* @brief This function recursively unlocks a mutex and decrements it's nested count. If the nested count is 0
* and there are tasks blocked on the mutex, the highest priority task will be woken up and
* aqcuire the mutex. In contrast to os_mutex_unlock(), it's ok to unlock a mutex multiple times.
*
* @param[in] mutex_id The id of mutex.
*
* @return The operation result.
* @retval OS_SUCCESS If the operation successful.
* @retval else Error code.
***********************************************************************************************************************
*/
os_err_t os_mutex_recursive_unlock(os_mutex_id mutex_id)
{
os_task_t *current_task;
os_task_t *block_task;
os_bool_t need_sched;
os_mutex_t *mutex;
OS_KERNEL_INIT();
mutex = OS_TYPE_CONVERT(os_mutex_t *, mutex_id);
OS_ASSERT(OS_NULL != mutex);
OS_ASSERT(OS_KOBJ_INITED == mutex->object_inited);
OS_ASSERT(OS_TRUE == mutex->is_recursive);
OS_ASSERT(OS_FALSE == os_is_irq_active());
need_sched = OS_FALSE;
current_task = k_task_self();
if (current_task != OS_NULL)
{
/* Mutex only can be unlocked by owner */
if (current_task != mutex->owner)
{
OS_KERN_LOG(KERN_ERROR,
MUTEX_TAG,
"The mutex(addr: %p, name: %s, owner: %s) can't unlock by task(%s)",
mutex,
mutex->name,
mutex->owner->name,
current_task->name);
OS_ASSERT((OS_FALSE));
}
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
os_spin_lock_irq(&mutex->lock, &irq_save);
k_kernel_spin_lock();
#else
OS_KERNEL_ENTER();
#endif
OS_ASSERT((mutex->lock_count > 0U));
if (mutex->lock_count > 1U)
{
mutex->lock_count--;
}
else
{
os_list_del(&mutex->hold_node);
/* Restore task priority */
if (OS_MUTEX_WAKE_TYPE_PRIO == mutex->wake_type)
{
need_sched = _k_mutex_restore_priority(mutex);
}
/* Get the new owner, if any */
if (!os_list_empty(&mutex->task_list_head))
{
block_task = os_list_first_entry(&mutex->task_list_head, os_task_t, task_node);
need_sched = k_unblock_task(block_task);
mutex->owner = block_task;
mutex->original_priority = block_task->current_priority;
os_list_add_tail(&mutex->owner->hold_mutex_list_head, &mutex->hold_node);
}
else
{
mutex->owner = OS_NULL;
mutex->lock_count = 0U;
}
}
if ((current_task->current_priority != current_task->backup_priority) &&
os_list_empty(¤t_task->hold_mutex_list_head))
{
OS_KERN_LOG(KERN_INFO,
MUTEX_TAG,
"New priority(%u) takes effect, old priority(%u)",
current_task->backup_priority,
current_task->current_priority);
k_readyq_remove(current_task);
current_task->current_priority = current_task->backup_priority;
k_readyq_put(current_task);
need_sched = OS_TRUE;
}
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
k_kernel_spin_unlock();
os_spin_unlock_irq(&mutex->lock, irq_save);
if (OS_TRUE == need_sched)
{
OS_KERNEL_ENTER();
OS_KERNEL_EXIT_SCHED();
}
#else
if (OS_TRUE == need_sched)
{
OS_KERNEL_EXIT_SCHED();
}
else
{
OS_KERNEL_EXIT();
}
#endif
}
return OS_SUCCESS;
}
/**
***********************************************************************************************************************
* @brief This function to set the mutex wake type(by prio or fifo)
*
* @param[in] mutex_id The mutex id to set.
* @param[in] wake_type The semaphore wake type to set.
*
* @return The operation result.
* @retval OS_SUCCESS If the operation successful.
* @retval else Error code.
***********************************************************************************************************************
*/
os_err_t os_mutex_set_wake_type(os_mutex_id mutex_id, uint8_t wake_type)
{
os_err_t ret;
os_mutex_t *mutex;
OS_KERNEL_INIT();
mutex = OS_TYPE_CONVERT(os_mutex_t *, mutex_id);
OS_ASSERT(OS_NULL != mutex);
OS_ASSERT(OS_KOBJ_INITED == mutex->object_inited);
OS_ASSERT((OS_MUTEX_WAKE_TYPE_PRIO == wake_type) || (OS_MUTEX_WAKE_TYPE_FIFO == wake_type));
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
os_spin_lock_irq(&mutex->lock, &irq_save);
#else
OS_KERNEL_ENTER();
#endif
if (OS_NULL == mutex->owner)
{
mutex->wake_type = wake_type;
ret = OS_SUCCESS;
}
else
{
ret = OS_BUSY;
}
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
os_spin_unlock_irq(&mutex->lock, irq_save);
#else
OS_KERNEL_EXIT();
#endif
return ret;
}
/**
***********************************************************************************************************************
* @brief This function to get the mutex owner
*
* @param[in] mutex_id The mutex id to get.
* @param[out] tid A pointer to return the owner task_id.
*
* @return The operation result.
* @retval OS_SUCCESS Get success.
* @retval else Error code.
***********************************************************************************************************************
*/
os_err_t os_mutex_get_owner(os_mutex_id mutex_id, os_task_id *tid)
{
os_mutex_t *mutex;
mutex = OS_TYPE_CONVERT(os_mutex_t *, mutex_id);
OS_ASSERT(OS_NULL != tid);
OS_ASSERT(OS_NULL != mutex);
OS_ASSERT(OS_KOBJ_INITED == mutex->object_inited);
*tid = (os_task_id)mutex->owner;
return OS_SUCCESS;
}
/**
***********************************************************************************************************************
* @brief Query whether the specified mutex exists.
*
* @param[in] mutex mutex control block.
*
* @return Whether the specified mutex exists.
* @retval OS_TRUE The specified mutex exists.
* @retval OS_FALSE The specified mutex doesn't exists.
***********************************************************************************************************************
*/
os_bool_t os_mutex_check_exist(os_mutex_id mutex_id)
{
os_mutex_t *iter_mutex;
os_list_node_t *node;
os_bool_t exist;
os_mutex_t *mutex;
mutex = OS_TYPE_CONVERT(os_mutex_t *, mutex_id);
OS_ASSERT(OS_NULL != mutex);
exist = OS_FALSE;
os_spin_lock(&gs_os_mutex_resource_list_lock);
os_list_for_each(node, &gs_os_mutex_resource_list_head)
{
iter_mutex = os_list_entry(node, os_mutex_t, resource_node);
if (mutex == iter_mutex)
{
exist = OS_TRUE;
break;
}
}
os_spin_unlock(&gs_os_mutex_resource_list_lock);
return exist;
}
/**
***********************************************************************************************************************
* @brief This function to return the "is_recursive" attribute of the specified mutex
*
* @param[in] mutex_id The id of mutex.
* @param[out] is_recursive A pointer to return the "is_recursive" attribute of the specified mutex.
*
* @return The operation result.
* @retval OS_SUCCESS Get success.
* @retval else Error code.
***********************************************************************************************************************
*/
os_err_t os_mutex_is_recursive(os_mutex_id mutex_id, os_bool_t *is_recursive)
{
os_mutex_t *mutex;
mutex = OS_TYPE_CONVERT(os_mutex_t *, mutex_id);
OS_ASSERT(OS_NULL != mutex);
OS_ASSERT(OS_KOBJ_INITED == mutex->object_inited);
OS_ASSERT(OS_NULL != is_recursive);
*is_recursive = mutex->is_recursive;
return OS_SUCCESS;
}
#if defined(OS_USING_SHELL)
#include <shell.h>
#define SH_SHOW_TASK_CNT_MAX 10
typedef struct
{
os_mutex_t *mutex;
os_task_t *owner;
uint32_t lock_count;
uint8_t owner_original_priority;
uint8_t owner_current_priority;
uint16_t block_task_count;
block_task_info_t block_info[SH_SHOW_TASK_CNT_MAX];
} sh_mutex_info_t;
static os_err_t os_mutex_show(os_mutex_t *mutex)
{
sh_mutex_info_t mutex_info;
os_task_t *iter_task;
uint16_t task_index;
OS_KERNEL_INIT();
if ((OS_NULL == mutex) || (OS_KOBJ_INITED != mutex->object_inited))
{
os_kprintf("The input parameter is an illegal mutex object.\r\n");
return OS_FAILURE;
}
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
os_spin_lock_irq(&mutex->lock, &irq_save);
k_kernel_spin_lock();
#else
OS_KERNEL_ENTER();
#endif
mutex_info.mutex = mutex;
mutex_info.owner = mutex->owner;
mutex_info.lock_count = mutex->lock_count;
mutex_info.block_task_count = os_list_len(&mutex->task_list_head);
if (OS_NULL != mutex->owner)
{
mutex_info.owner_original_priority = mutex->original_priority;
mutex_info.owner_current_priority = mutex->owner->current_priority;
}
else
{
mutex_info.owner_original_priority = 0U;
mutex_info.owner_current_priority = 0U;
}
task_index = 0;
os_list_for_each_entry(iter_task, &mutex->task_list_head, os_task_t, task_node)
{
mutex_info.block_info[task_index].current_priority = iter_task->current_priority;
mutex_info.block_info[task_index].name = iter_task->name;
task_index++;
if (task_index >= SH_SHOW_TASK_CNT_MAX)
{
break;
}
}
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
k_kernel_spin_unlock();
os_spin_unlock_irq(&mutex->lock, irq_save);
#else
OS_KERNEL_EXIT();
#endif
os_kprintf("%-*s %-*s 0x%-10x %11u/%-12u %-10u %-10s ",
OS_NAME_MAX,
(mutex_info.mutex->name[0] != '\0') ? mutex_info.mutex->name : "-",
OS_NAME_MAX,
((mutex_info.owner) && (mutex_info.owner->name[0] != '\0')) ? mutex_info.owner->name : "-",
mutex_info.mutex,
mutex_info.owner_original_priority,
mutex_info.owner_current_priority,
mutex_info.lock_count,
mutex_info.mutex->is_recursive ? "Yes" : "No");
if (mutex_info.block_task_count > 0)
{
os_kprintf("%-6u:", mutex_info.block_task_count);
k_show_blocked_task(mutex_info.block_info, task_index);
if (mutex_info.block_task_count > task_index)
{
os_kprintf("/...\r\n");
}
else
{
os_kprintf("\r\n");
}
}
else
{
os_kprintf("%-6u\r\n", 0);
}
return OS_SUCCESS;
}
/**
***********************************************************************************************************************
* @brief This function prints information about all the mutex and it's corresponding blokced tasks.
*
* @param[in]
*
* @return The operation result.
* @retval OS_SUCCESS If the operation successful.
* @retval else Error code.
***********************************************************************************************************************
*/
static os_err_t sh_show_mutex_info(int32_t argc, char *const *argv)
{
uint16_t len;
os_mutex_t *mutex_tmp;
os_mutex_t *iter_mutex;
OS_UNREFERENCE(argc);
OS_UNREFERENCE(argv);
os_kprintf("%-*s %-*s %-12s %-24s %-10s %-10s %-10s\r\n",
OS_NAME_MAX,
"Mutex",
OS_NAME_MAX,
"Owner name",
"Mutex ID",
"Owner priority(ori/cur)",
"Lock Count",
"Recursive",
"Block Task");
len = OS_NAME_MAX;
while ((len--) != 0)
{
os_kprintf("-");
}
os_kprintf(" ");
len = OS_NAME_MAX;
while ((len--) != 0)
{
os_kprintf("-");
}
os_kprintf(" ");
os_kprintf("%-12s %-24s %-10s %-10s %-10s\r\n",
"------------",
"-----------------------",
"----------",
"----------",
"----------");
if (argc >= 2)
{
if ((OS_NULL != argv[1]))
{
mutex_tmp = (os_mutex_t *)strtoul(argv[1], OS_NULL, 0);
os_spin_lock(&gs_os_mutex_resource_list_lock);
os_list_for_each_entry(iter_mutex, &gs_os_mutex_resource_list_head, os_mutex_t, resource_node)
{
if (mutex_tmp == iter_mutex)
{
os_mutex_show(mutex_tmp);
os_spin_unlock(&gs_os_mutex_resource_list_lock);
return OS_SUCCESS;
}
}
os_spin_unlock(&gs_os_mutex_resource_list_lock);
}
os_kprintf("Invalid Mutex Object.\r\n");
return OS_FAILURE;
}
os_spin_lock(&gs_os_mutex_resource_list_lock);
os_list_for_each_entry(iter_mutex, &gs_os_mutex_resource_list_head, os_mutex_t, resource_node)
{
os_mutex_show(iter_mutex);
}
os_spin_unlock(&gs_os_mutex_resource_list_lock);
return OS_SUCCESS;
}
SH_CMD_EXPORT(show_mutex, sh_show_mutex_info, "Show mutex information");
#endif /* defined(OS_USING_SHELL) */
#endif /* OS_USING_MUTEX */