316 lines
7.6 KiB
C
316 lines
7.6 KiB
C
/*
|
|
* Copyright (c) 2020 AIIT XUOS Lab
|
|
* XiUOS is licensed under Mulan PSL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
* You may obtain a copy of Mulan PSL v2 at:
|
|
* http://license.coscl.org.cn/MulanPSL2
|
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
* See the Mulan PSL v2 for more details.
|
|
*/
|
|
|
|
/**
|
|
* @file: mutex.c
|
|
* @brief: mutex file
|
|
* @version: 1.0
|
|
* @author: AIIT XUOS Lab
|
|
* @date: 2020/3/15
|
|
*
|
|
*/
|
|
|
|
#include <xiuos.h>
|
|
|
|
DECLARE_ID_MANAGER(k_mutex_id_manager, ID_NUM_MAX);
|
|
DoubleLinklistType k_mutex_list ={&k_mutex_list, &k_mutex_list}; ///< global mutex manage list
|
|
|
|
static int32 _MutexCreate()
|
|
{
|
|
int32 id = 0;
|
|
x_base lock = 0;
|
|
struct Mutex *mutex = NONE;
|
|
|
|
mutex = x_malloc(sizeof(struct Mutex));
|
|
if (mutex == NONE) {
|
|
return -ENOMEMORY;
|
|
}
|
|
|
|
memset(mutex, 0x0, sizeof(struct Mutex));
|
|
lock = CriticalAreaLock();
|
|
|
|
id = IdInsertObj(&k_mutex_id_manager, &mutex->id);
|
|
if (id < 0) {
|
|
CriticalAreaUnLock(lock);
|
|
x_free(mutex);
|
|
return -ENOMEMORY;
|
|
}
|
|
|
|
InitDoubleLinkList(&mutex->pend_list);
|
|
|
|
mutex->val = 1;
|
|
mutex->holder = NONE;
|
|
mutex->origin_prio = 0xFF;
|
|
mutex->recursive_cnt = 0;
|
|
|
|
DoubleLinkListInsertNodeAfter(&k_mutex_list, &mutex->link);
|
|
|
|
CriticalAreaUnLock(lock);
|
|
|
|
return id;
|
|
}
|
|
|
|
static void _MutexDelete(struct Mutex *mutex)
|
|
{
|
|
x_base lock = 0;
|
|
|
|
NULL_PARAM_CHECK(mutex);
|
|
|
|
LinklistResumeAll(&mutex->pend_list);
|
|
lock = CriticalAreaLock();
|
|
IdRemoveObj(&k_mutex_id_manager, mutex->id.id);
|
|
|
|
DoubleLinkListRmNode(&(mutex->link));
|
|
CriticalAreaUnLock(lock);
|
|
x_free(mutex);
|
|
}
|
|
|
|
static int32 _MutexObtain(struct Mutex *mutex, int32 msec)
|
|
{
|
|
x_base lock = 0;
|
|
int32 wait_time = 0;
|
|
struct TaskDescriptor *task = NONE;
|
|
|
|
NULL_PARAM_CHECK(mutex);
|
|
|
|
task = GetKTaskDescriptor();
|
|
wait_time = CalculteTickFromTimeMs(msec);
|
|
lock = CriticalAreaLock();
|
|
|
|
SYS_KDEBUG_LOG(KDBG_IPC,
|
|
("mutex_take: current task %s, mutex value: %d, hold: %d\n",
|
|
task->task_base_info.name, mutex->val, mutex->recursive_cnt));
|
|
|
|
task->exstatus = EOK;
|
|
|
|
if (mutex->holder == task) {
|
|
mutex->recursive_cnt++;
|
|
} else {
|
|
if (mutex->val > 0) {
|
|
mutex->val--;
|
|
mutex->holder = task;
|
|
mutex->origin_prio = task->task_dync_sched_member.cur_prio;
|
|
mutex->recursive_cnt++;
|
|
} else {
|
|
if (wait_time == 0) {
|
|
task->exstatus = -ETIMEOUT;
|
|
CriticalAreaUnLock(lock);
|
|
return -ETIMEOUT;
|
|
} else {
|
|
SYS_KDEBUG_LOG(KDBG_IPC, ("mutex_take: suspend task: %s\n",
|
|
task->task_base_info.name));
|
|
|
|
if (task->task_dync_sched_member.cur_prio > mutex->holder->task_dync_sched_member.cur_prio)
|
|
{
|
|
KTaskPrioSet(mutex->holder->id.id, task->task_dync_sched_member.cur_prio);
|
|
}
|
|
|
|
LinklistSuspend(&(mutex->pend_list), task, LINKLIST_FLAG_PRIO);
|
|
|
|
if (wait_time > 0) {
|
|
SYS_KDEBUG_LOG(KDBG_IPC,
|
|
("mutex_take: start the timer of task:%s\n",
|
|
task->task_base_info.name));
|
|
KTaskSetDelay(task,wait_time);
|
|
}
|
|
|
|
CriticalAreaUnLock(lock);
|
|
|
|
DO_KTASK_ASSIGN;
|
|
|
|
if (task->exstatus != EOK) {
|
|
return task->exstatus;
|
|
} else {
|
|
lock = CriticalAreaLock();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CriticalAreaUnLock(lock);
|
|
|
|
return EOK;
|
|
}
|
|
|
|
static int32 _MutexAbandon(struct Mutex *mutex)
|
|
{
|
|
int resched = 0;
|
|
x_base lock = 0;
|
|
struct TaskDescriptor *task = NONE;
|
|
|
|
NULL_PARAM_CHECK(mutex);
|
|
|
|
task = GetKTaskDescriptor();
|
|
lock = CriticalAreaLock();
|
|
|
|
SYS_KDEBUG_LOG(KDBG_IPC,
|
|
("mutex_release:current task %s, mutex value: %d, hold: %d\n",
|
|
task->task_base_info.name, mutex->val, mutex->recursive_cnt));
|
|
|
|
if (task != mutex->holder) {
|
|
task->exstatus = -ERROR;
|
|
CriticalAreaUnLock(lock);
|
|
return -ERROR;
|
|
}
|
|
|
|
mutex->recursive_cnt --;
|
|
if (mutex->recursive_cnt == 0) {
|
|
if (mutex->origin_prio != mutex->holder->task_dync_sched_member.cur_prio)
|
|
{
|
|
KTaskPrioSet(mutex->holder->id.id, mutex->origin_prio);
|
|
}
|
|
|
|
if (!IsDoubleLinkListEmpty(&mutex->pend_list)) {
|
|
task = SYS_DOUBLE_LINKLIST_ENTRY(mutex->pend_list.node_next, struct TaskDescriptor, task_dync_sched_member.sched_link);
|
|
SYS_KDEBUG_LOG(KDBG_IPC, ("mutex_release: resume task: %s\n",
|
|
task->task_base_info.name));
|
|
|
|
mutex->holder = task;
|
|
mutex->origin_prio = task->task_dync_sched_member.cur_prio;
|
|
mutex->recursive_cnt++;
|
|
|
|
LinklistResume(&(mutex->pend_list));
|
|
|
|
resched = RET_TRUE;
|
|
} else {
|
|
mutex->val++;
|
|
mutex->holder = NONE;
|
|
mutex->origin_prio = 0xff;
|
|
}
|
|
}
|
|
|
|
CriticalAreaUnLock(lock);
|
|
|
|
if (resched == RET_TRUE)
|
|
DO_KTASK_ASSIGN;
|
|
|
|
return EOK;
|
|
}
|
|
|
|
static MutexDoneType done = {
|
|
.MutexCreate = _MutexCreate,
|
|
.MutexDelete = _MutexDelete,
|
|
.MutexObtain = _MutexObtain,
|
|
.MutexAbandon = _MutexAbandon,
|
|
};
|
|
|
|
/**
|
|
* a mutex will be inited in static way,then this mutex will be inserted to the manage list
|
|
*
|
|
* @param mutex the mutex descriptor
|
|
* @param name mutex name
|
|
* @param flag mutex flag
|
|
*
|
|
* @return EOK on success
|
|
*
|
|
*/
|
|
int32 KMutexCreate()
|
|
{
|
|
KDEBUG_NOT_IN_INTERRUPT;
|
|
|
|
return done.MutexCreate();
|
|
}
|
|
|
|
/**
|
|
* a dynamic mutex will be deleted from the manage list
|
|
*
|
|
* @param mutex mutex descriptor
|
|
*
|
|
*/
|
|
void KMutexDelete(int32 id)
|
|
{
|
|
KDEBUG_NOT_IN_INTERRUPT;
|
|
|
|
x_base lock = 0;
|
|
struct Mutex *mutex = NONE;
|
|
struct IdNode *idnode = NONE;
|
|
|
|
if (id < 0)
|
|
return;
|
|
|
|
lock = CriticalAreaLock();
|
|
idnode = IdGetObj(&k_mutex_id_manager, id);
|
|
if (idnode == NONE) {
|
|
CriticalAreaUnLock(lock);
|
|
return;
|
|
}
|
|
|
|
mutex =CONTAINER_OF(idnode, struct Mutex, id);
|
|
CriticalAreaUnLock(lock);
|
|
|
|
done.MutexDelete(mutex);
|
|
}
|
|
|
|
/**
|
|
* a mutex will be taken when mutex is available
|
|
*
|
|
* @param mutex mutex descriptor
|
|
* @param msec the time needed waiting
|
|
*
|
|
* @return EOK on success;ERROR on failure
|
|
*
|
|
*/
|
|
int32 KMutexObtain(int32 id, int32 msec)
|
|
{
|
|
KDEBUG_IN_KTASK_CONTEXT;
|
|
|
|
x_base lock = 0;
|
|
struct Mutex *mutex = NONE;
|
|
struct IdNode *idnode = NONE;
|
|
|
|
if (id < 0)
|
|
return -ERROR;
|
|
|
|
lock = CriticalAreaLock();
|
|
idnode = IdGetObj(&k_mutex_id_manager, id);
|
|
if (idnode == NONE){
|
|
CriticalAreaUnLock(lock);
|
|
return -ERROR;
|
|
}
|
|
|
|
|
|
mutex =CONTAINER_OF(idnode, struct Mutex, id);
|
|
CriticalAreaUnLock(lock);
|
|
|
|
return done.MutexObtain(mutex, msec);
|
|
}
|
|
|
|
/**
|
|
* release the mutex and resume corresponding suspended task
|
|
*
|
|
* @param mutex mutex descriptor
|
|
*
|
|
* @return EOK on success;ERROR on failure
|
|
*/
|
|
int32 KMutexAbandon(int32 id)
|
|
{
|
|
KDEBUG_IN_KTASK_CONTEXT;
|
|
|
|
x_base lock = 0;
|
|
struct Mutex *mutex = NONE;
|
|
struct IdNode *idnode = NONE;
|
|
|
|
if (id < 0)
|
|
return -ERROR;
|
|
|
|
lock = CriticalAreaLock();
|
|
idnode = IdGetObj(&k_mutex_id_manager, id);
|
|
if (idnode == NONE) {
|
|
CriticalAreaUnLock(lock);
|
|
return -ERROR;
|
|
}
|
|
|
|
mutex = CONTAINER_OF(idnode, struct Mutex, id);
|
|
CriticalAreaUnLock(lock);
|
|
return done.MutexAbandon(mutex);
|
|
}
|