forked from xuos/xiuos
415 lines
12 KiB
C
415 lines
12 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: gatherblock.c
|
|
* @brief: block memory management file
|
|
* @version: 1.0
|
|
* @author: AIIT XUOS Lab
|
|
* @date: 2020/3/8
|
|
*
|
|
*/
|
|
|
|
#include <xizi.h>
|
|
#include <xs_hook.h>
|
|
|
|
#ifdef KERNEL_MEMBLOCK
|
|
|
|
/* a global list, which record all the gatherblocks*/
|
|
DoubleLinklistType xiaoshan_memgather_head = {&xiaoshan_memgather_head, &xiaoshan_memgather_head};
|
|
|
|
/**
|
|
* This function initializes a gather block memory structure.
|
|
*
|
|
* @param gm_handler the gatherblock structure
|
|
* @param gm_name the name of gatherblock
|
|
* @param begin_address the start address of gatherblock
|
|
* @param gm_size the total size of gatherblock
|
|
* @param one_block_size one block size in gatherblock
|
|
*
|
|
* @return EOK
|
|
*/
|
|
x_err_t InitMemGather(struct MemGather *gm_handler, const char *gm_name, void *begin_address, x_size_t gm_size, x_size_t one_block_size)
|
|
{
|
|
x_base lock = 0;
|
|
register x_size_t off_block = 0;
|
|
register x_base critical_value = 0;
|
|
uint8 *block_ptr = NONE;
|
|
struct SysDoubleLinklistNode *list_entry = NONE;
|
|
|
|
/* parameter detection */
|
|
NULL_PARAM_CHECK(gm_handler);
|
|
NULL_PARAM_CHECK(gm_name);
|
|
NULL_PARAM_CHECK(begin_address);
|
|
|
|
CHECK(gm_size >= 1 && one_block_size >= 1);
|
|
|
|
lock = CriticalAreaLock();
|
|
|
|
/* try to find gatherblock object */
|
|
for (list_entry = xiaoshan_memgather_head.node_next;
|
|
list_entry != &(xiaoshan_memgather_head);
|
|
list_entry = list_entry->node_next) {
|
|
GatherMemType gm;
|
|
|
|
gm = SYS_DOUBLE_LINKLIST_ENTRY(list_entry, struct MemGather, m_link);
|
|
if (gm) {
|
|
CHECK(gm != gm_handler);
|
|
}
|
|
}
|
|
CriticalAreaUnLock(lock);
|
|
|
|
/* set the type attribute of gatherblock object */
|
|
gm_handler->m_kind = Cmpt_KindN_Static;
|
|
/* set the name of gatherblock object */
|
|
strncpy(gm_handler->m_name, gm_name, NAME_NUM_MAX);
|
|
|
|
critical_value = CriticalAreaLock();
|
|
|
|
/* insert gatherblock object into the global list */
|
|
DoubleLinkListInsertNodeAfter(&xiaoshan_memgather_head, &(gm_handler->m_link));
|
|
|
|
CriticalAreaUnLock(critical_value);
|
|
|
|
/* initialize the other attributes of gatherblock object */
|
|
gm_handler->m_start_address = begin_address;
|
|
gm_handler->m_size = ALIGN_MEN_DOWN(gm_size, MEM_ALIGN_SIZE);
|
|
one_block_size = ALIGN_MEN_UP(one_block_size, MEM_ALIGN_SIZE);
|
|
gm_handler->one_block_size = one_block_size;
|
|
gm_handler->block_total_number = gm_handler->m_size / (gm_handler->one_block_size + sizeof(uint8 *));
|
|
gm_handler->block_free_number = gm_handler->block_total_number;
|
|
|
|
InitDoubleLinkList(&(gm_handler->wait_task));
|
|
|
|
/* links all the blocks in gatherblock object */
|
|
block_ptr = (uint8 *)gm_handler->m_start_address;
|
|
for (off_block = 0; off_block < gm_handler->block_total_number; off_block ++) {
|
|
*(uint8 **)(block_ptr + off_block * (one_block_size + sizeof(uint8 *))) =
|
|
(uint8 *)(block_ptr + (off_block + 1) * (one_block_size + sizeof(uint8 *)));
|
|
}
|
|
|
|
*(uint8 **)(block_ptr + (off_block - 1) * (one_block_size + sizeof(uint8 *))) =
|
|
NONE;
|
|
|
|
gm_handler->m_block_link = block_ptr;
|
|
|
|
return EOK;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* This function will remove the gatherblock from the global list, which is created by MemGatherInit function
|
|
*
|
|
* @param gm_handler the gatherblock to be removed
|
|
*
|
|
* @return EOK
|
|
*/
|
|
x_err_t RemoveMemGather(struct MemGather *gm_handler)
|
|
{
|
|
register x_ubase critical_value = 0;
|
|
struct TaskDescriptor *task = NONE;
|
|
|
|
/* parameter detection */
|
|
NULL_PARAM_CHECK(gm_handler);
|
|
|
|
CHECK((gm_handler->m_kind & Cmpt_KindN_Static)!=0);
|
|
|
|
/* resume all the suspend tasks on gatherblock object */
|
|
while (!IsDoubleLinkListEmpty(&(gm_handler->wait_task))) {
|
|
critical_value = CriticalAreaLock();
|
|
|
|
task = SYS_DOUBLE_LINKLIST_ENTRY(gm_handler->wait_task.node_next, struct TaskDescriptor, task_dync_sched_member.sched_link);
|
|
task->exstatus = -ERROR;
|
|
|
|
KTaskWakeup(task->id.id);
|
|
|
|
CriticalAreaUnLock(critical_value);
|
|
}
|
|
|
|
/* set the type attribute */
|
|
gm_handler->m_kind = 0;
|
|
|
|
critical_value = CriticalAreaLock();
|
|
|
|
/* remove the gatherblock object from the global links */
|
|
DoubleLinkListRmNode(&(gm_handler->m_link));
|
|
|
|
CriticalAreaUnLock(critical_value);
|
|
|
|
return EOK;
|
|
}
|
|
|
|
|
|
/**
|
|
* This function will create a gatherblock object.
|
|
*
|
|
* @param gm_name the name of gatherblock
|
|
* @param block_number the number of blocks in gatherblock
|
|
* @param one_block_size one block size
|
|
*
|
|
* @return EOK on success; NONE on failure
|
|
*/
|
|
GatherMemType CreateMemGather(const char *gm_name, x_size_t block_number, x_size_t one_block_size)
|
|
{
|
|
|
|
register x_size_t off_block = 0;
|
|
register x_base critical_value = 0;
|
|
uint8 *block_ptr = NONE;
|
|
struct MemGather *gm_handler = NONE;
|
|
|
|
KDEBUG_NOT_IN_INTERRUPT;
|
|
|
|
/* parameter detection */
|
|
NULL_PARAM_CHECK(gm_name);
|
|
CHECK(block_number >= 1 && one_block_size >= 1);
|
|
|
|
KDEBUG_NOT_IN_INTERRUPT;
|
|
|
|
/* allocate memory for gatherblock object */
|
|
gm_handler = (struct MemGather *)KERNEL_MALLOC(sizeof(struct MemGather));
|
|
|
|
if (NONE == gm_handler)
|
|
return NONE;
|
|
/* clear the gatherblock object */
|
|
memset(gm_handler, 0x0, sizeof(struct MemGather));
|
|
/* set the name attribute */
|
|
strncpy(gm_handler->m_name, gm_name, NAME_NUM_MAX);
|
|
/* set the flag attribute */
|
|
gm_handler->m_sign = 0;
|
|
|
|
critical_value = CriticalAreaLock();
|
|
|
|
/* insert gatherblock object into the global list */
|
|
DoubleLinkListInsertNodeAfter(&xiaoshan_memgather_head, &(gm_handler->m_link));
|
|
|
|
CriticalAreaUnLock(critical_value);
|
|
|
|
/* set the other attributes of gatherblock object */
|
|
one_block_size = ALIGN_MEN_UP(one_block_size, MEM_ALIGN_SIZE);
|
|
gm_handler->one_block_size = one_block_size;
|
|
gm_handler->m_size = (one_block_size + sizeof(uint8 *)) * block_number;
|
|
|
|
/* allocate memory for gather blocks */
|
|
gm_handler->m_start_address = x_malloc((one_block_size + sizeof(uint8 *)) * block_number);
|
|
if (NONE == gm_handler->m_start_address) {
|
|
gm_handler->m_kind = 0;
|
|
critical_value = CriticalAreaLock();
|
|
|
|
/* remove the gatherblock object from the global links */
|
|
DoubleLinkListRmNode(&(gm_handler->m_link));
|
|
|
|
CriticalAreaUnLock(critical_value);
|
|
|
|
/* release the memory for gather block structure */
|
|
KERNEL_FREE(gm_handler);
|
|
|
|
return NONE;
|
|
}
|
|
|
|
gm_handler->block_total_number = block_number;
|
|
gm_handler->block_free_number = gm_handler->block_total_number;
|
|
|
|
InitDoubleLinkList(&(gm_handler->wait_task));
|
|
|
|
/* links all the gather blocks */
|
|
block_ptr = (uint8 *)gm_handler->m_start_address;
|
|
for (off_block = 0; off_block < gm_handler->block_total_number; off_block ++) {
|
|
*(uint8 **)(block_ptr + off_block * (one_block_size + sizeof(uint8 *)))
|
|
= block_ptr + (off_block + 1) * (one_block_size + sizeof(uint8 *));
|
|
}
|
|
|
|
*(uint8 **)(block_ptr + (off_block - 1) * (one_block_size + sizeof(uint8 *)))
|
|
= NONE;
|
|
|
|
gm_handler->m_block_link = block_ptr;
|
|
|
|
return gm_handler;
|
|
}
|
|
|
|
/**
|
|
* This function will delete a gatherblock object, which is created by MemGatherCreate function.
|
|
*
|
|
* @param gm_handler the gatherblock object to be deleted
|
|
*
|
|
* @return EOK
|
|
*/
|
|
x_err_t DeleteMemGather(GatherMemType gm_handler)
|
|
{
|
|
register x_ubase critical_value = 0;
|
|
struct TaskDescriptor *task = NONE;
|
|
|
|
KDEBUG_NOT_IN_INTERRUPT;
|
|
|
|
/* parameter detection */
|
|
NULL_PARAM_CHECK(gm_handler);
|
|
CHECK(((gm_handler->m_kind & Cmpt_KindN_Static)==0));
|
|
|
|
/* resume all the suspend tasks on gatherblock object */
|
|
while (!IsDoubleLinkListEmpty(&(gm_handler->wait_task))) {
|
|
critical_value = CriticalAreaLock();
|
|
|
|
task = SYS_DOUBLE_LINKLIST_ENTRY(gm_handler->wait_task.node_next, struct TaskDescriptor, task_dync_sched_member.sched_link);
|
|
task->exstatus = -ERROR;
|
|
|
|
KTaskWakeup(task->id.id);
|
|
|
|
CriticalAreaUnLock(critical_value);
|
|
}
|
|
|
|
/* release the memory for gather blocks */
|
|
x_free(gm_handler->m_start_address);
|
|
|
|
gm_handler->m_kind = 0;
|
|
|
|
critical_value = CriticalAreaLock();
|
|
|
|
/* remove the gatherblock object from the global links */
|
|
DoubleLinkListRmNode(&(gm_handler->m_link));
|
|
|
|
CriticalAreaUnLock(critical_value);
|
|
|
|
/* release the memory for gather block structure */
|
|
KERNEL_FREE(gm_handler);
|
|
return EOK;
|
|
}
|
|
|
|
/**
|
|
* This function will allocate a data block from gatherblock object
|
|
*
|
|
* @param gm_handler the gatherblock object to get data block
|
|
* @param msec waiting time ,millisecond
|
|
*
|
|
* @return block pointer on success; NONE on failure
|
|
*/
|
|
void *AllocBlockMemGather(GatherMemType gm_handler, int32 msec)
|
|
{
|
|
int32 wait_time = 0;
|
|
uint32 before_sleep = 0;
|
|
register x_base critical_value = 0;
|
|
uint8 *block_ptr = NONE;
|
|
struct TaskDescriptor *task = NONE;
|
|
|
|
/* parameter detection */
|
|
NULL_PARAM_CHECK(gm_handler);
|
|
|
|
/* get descriptor of task */
|
|
task = GetKTaskDescriptor();
|
|
wait_time = CalculateTickFromTimeMs(msec);
|
|
|
|
critical_value = CriticalAreaLock();
|
|
/* no free gatherblock*/
|
|
while (0 == gm_handler->block_free_number) {
|
|
if (wait_time == 0) {
|
|
CriticalAreaUnLock(critical_value);
|
|
|
|
KUpdateExstatus(ETIMEOUT);
|
|
|
|
return NONE;
|
|
}
|
|
|
|
KDEBUG_NOT_IN_INTERRUPT;
|
|
|
|
task->exstatus = EOK;
|
|
|
|
/* suspend current task */
|
|
SuspendKTask(task->id.id);
|
|
DoubleLinkListInsertNodeAfter(&(gm_handler->wait_task), &(task->task_dync_sched_member.sched_link));
|
|
|
|
if (wait_time > 0) {
|
|
before_sleep = CurrentTicksGain();
|
|
/* start the timer */
|
|
KTaskSetDelay(task,wait_time);
|
|
}
|
|
|
|
CriticalAreaUnLock(critical_value);
|
|
|
|
/* schedule */
|
|
DO_KTASK_ASSIGN;
|
|
|
|
if (EOK != task->exstatus)
|
|
return NONE;
|
|
|
|
if (wait_time > 0) {
|
|
wait_time -= CurrentTicksGain() - before_sleep;
|
|
if (wait_time < 0)
|
|
wait_time = 0;
|
|
}
|
|
critical_value = CriticalAreaLock();
|
|
}
|
|
/* decrease the number of free gatherblocks */
|
|
gm_handler->block_free_number--;
|
|
|
|
block_ptr = gm_handler->m_block_link;
|
|
NULL_PARAM_CHECK(block_ptr);
|
|
|
|
/* set the block_list attribute of gather_block structure */
|
|
gm_handler->m_block_link = *(uint8 **)block_ptr;
|
|
|
|
*(uint8 **)block_ptr = (uint8 *)gm_handler;
|
|
|
|
CriticalAreaUnLock(critical_value);
|
|
|
|
HOOK(hook.mem.hook_GmAlloc, (gm_handler, (uint8 *)(block_ptr + sizeof(uint8 *))));
|
|
|
|
return (uint8 *)(block_ptr + sizeof(uint8 *));
|
|
}
|
|
|
|
/**
|
|
* This function will release a data block to gatherblock object
|
|
*
|
|
* @param data_block the data block to be released
|
|
*/
|
|
void FreeBlockMemGather(void *data_block)
|
|
{
|
|
uint8 **block_ptr;
|
|
register x_base critical_value = 0;
|
|
struct MemGather *gm_handler = NONE;
|
|
struct TaskDescriptor *task = NONE;
|
|
|
|
/* parameter detection */
|
|
NULL_PARAM_CHECK(data_block);
|
|
|
|
/* get gatherblock structure */
|
|
block_ptr = (uint8 **)((uint8 *)data_block - sizeof(uint8 *));
|
|
gm_handler = (struct MemGather *)*block_ptr;
|
|
|
|
HOOK(hook.mem.hook_GmFree, (gm_handler, data_block));
|
|
|
|
critical_value = CriticalAreaLock();
|
|
|
|
/* increase the number of gatherblocks */
|
|
gm_handler->block_free_number ++;
|
|
|
|
*block_ptr = gm_handler->m_block_link;
|
|
/* set the block_list attribute of gather_block object */
|
|
gm_handler->m_block_link = (uint8 *)block_ptr;
|
|
|
|
if (!IsDoubleLinkListEmpty(&(gm_handler->wait_task))) {
|
|
task = SYS_DOUBLE_LINKLIST_ENTRY(gm_handler->wait_task.node_next, struct TaskDescriptor, task_dync_sched_member.sched_link);
|
|
task->exstatus = EOK;
|
|
|
|
/* resume a suspend task */
|
|
KTaskWakeup(task->id.id);
|
|
|
|
CriticalAreaUnLock(critical_value);
|
|
|
|
DO_KTASK_ASSIGN;
|
|
|
|
return;
|
|
}
|
|
|
|
CriticalAreaUnLock(critical_value);
|
|
}
|
|
#endif
|
|
|