forked from xuos/xiuos
First commit XiUOS
This commit is contained in:
315
kernel/thread/mutex.c
Normal file
315
kernel/thread/mutex.c
Normal file
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
Reference in New Issue
Block a user