zhoujin_branch
niehaoquan 1 year ago
commit 3a2996d289

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
@ -31,54 +31,78 @@
#include "los_bitmap.h"
#include "los_printf.h"
#include "los_toolchain.h"
#define OS_BITMAP_MASK 0x1FU
#include "los_toolchain.h" //GCC 编译器的内置函数
/**
* @brief
* @verbatim
bit
bit
使
10
1
https://www.geeksforgeeks.org/builtin-functions-gcc-compiler/
* @endverbatim
*/
#define OS_BITMAP_MASK 0x1FU //
#define OS_BITMAP_WORD_MASK ~0UL
/* find first zero bit starting from LSB */
/*! find first zero bit starting from LSB */
STATIC INLINE UINT16 Ffz(UINTPTR x)
{
return __builtin_ffsl(~x) - 1;
{//__builtin_ffsl: 返回右起第一个1的位置函数来自 glibc
return __builtin_ffsl(~x) - 1;//从LSB开始查找第一个零位 LSB(最低有效位) 对应 最高有效位(MSB)
}
///对状态字的某一标志位进行置1操作
VOID LOS_BitmapSet(UINT32 *bitmap, UINT16 pos)
{
if (bitmap == NULL) {
return;
}
*bitmap |= 1U << (pos & OS_BITMAP_MASK);
*bitmap |= 1U << (pos & OS_BITMAP_MASK);//在对应位上置1
}
///对状态字的某一标志位进行清0操作
VOID LOS_BitmapClr(UINT32 *bitmap, UINT16 pos)
{
if (bitmap == NULL) {
return;
}
*bitmap &= ~(1U << (pos & OS_BITMAP_MASK));
*bitmap &= ~(1U << (pos & OS_BITMAP_MASK));//在对应位上置0
}
/**
* @brief 1 : 00110110 5
* @verbatim
CLZ 0
  1.使1
  2.
* @endverbatim
* @param bitmap
* @return UINT16
*/
UINT16 LOS_HighBitGet(UINT32 bitmap)
{
if (bitmap == 0) {
return LOS_INVALID_BIT_INDEX;
}
return (OS_BITMAP_MASK - CLZ(bitmap));
return (OS_BITMAP_MASK - CLZ(bitmap));//CLZ = count leading zeros 用于计算整数的前导零
}
/// 获取参数位图中最低位为1的索引位 例如: 00110110 返回 1
UINT16 LOS_LowBitGet(UINT32 bitmap)
{
if (bitmap == 0) {
return LOS_INVALID_BIT_INDEX;
}
return CTZ(bitmap);
return CTZ(bitmap);// CTZ = count trailing zeros 用于计算给定整数的尾随零
}
/// 从start位置开始设置numsSet个bit位 置1
VOID LOS_BitmapSetNBits(UINTPTR *bitmap, UINT32 start, UINT32 numsSet)
{
UINTPTR *p = bitmap + BITMAP_WORD(start);
@ -98,7 +122,7 @@ VOID LOS_BitmapSetNBits(UINTPTR *bitmap, UINT32 start, UINT32 numsSet)
*p |= maskToSet;
}
}
///从start位置开始 清除numsSet个bit位置0 ,对状态字的连续标志位进行清0操作
VOID LOS_BitmapClrNBits(UINTPTR *bitmap, UINT32 start, UINT32 numsClear)
{
UINTPTR *p = bitmap + BITMAP_WORD(start);
@ -118,7 +142,7 @@ VOID LOS_BitmapClrNBits(UINTPTR *bitmap, UINT32 start, UINT32 numsClear)
*p &= ~maskToClear;
}
}
///从numBits位置开始找到第一个0位
INT32 LOS_BitmapFfz(UINTPTR *bitmap, UINT32 numBits)
{
INT32 bit, i;

@ -31,15 +31,15 @@
#include "los_info_pri.h"
#include "los_task_pri.h"
#include "los_vm_dump.h"
//获取当前进程的父进程ID
STATIC UINT32 GetCurrParentPid(UINT32 pid, const LosProcessCB *processCB)
{
if (processCB->parentProcess == NULL) {
return 0;
}
#ifdef LOSCFG_PID_CONTAINER
if (pid == OS_USER_ROOT_PROCESS_ID) {
#ifdef LOSCFG_PID_CONTAINER //从容器中获取
if (pid == OS_USER_ROOT_PROCESS_ID) {//从这里可以看出 0号进程kidle1,2号进程的父进程
return 0;
}
@ -49,7 +49,7 @@ STATIC UINT32 GetCurrParentPid(UINT32 pid, const LosProcessCB *processCB)
#endif
return processCB->parentProcess->processID;
}
//获取当前任务ID
STATIC INLINE UINT32 GetCurrTid(const LosTaskCB *taskCB)
{
#ifdef LOSCFG_PID_CONTAINER

File diff suppressed because it is too large Load Diff

@ -1,6 +1,6 @@
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2023 Huawei Device Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
@ -40,7 +40,7 @@
#ifdef LOSCFG_KERNEL_SMP
STATIC struct SmpOps *g_smpOps = NULL;
/// 多核中次级CPU核初始化,每个核都会调用一次
STATIC VOID OsSmpSecondaryInit(VOID *arg)
{
UNUSED(arg);
@ -56,7 +56,7 @@ STATIC VOID OsSmpSecondaryInit(VOID *arg)
OsSchedStart();
}
/// 设置多核操作接口, 通过外部注册
VOID LOS_SmpOpsSet(struct SmpOps *ops)
{
g_smpOps = ops;

@ -1,6 +1,70 @@
/*!
* @file los_swtmr.c
* @brief
* @details
* @attention @verbatim
TickTick
Tick
使
TickHuawei LiteOS
TickTick
TickTick
Tick
OS_SWTMR_STATUS_UNUSED使
OS_SWTMR_STATUS_TICKING
LOS_SwtmrStart
OS_SWTMR_STATUS_CREATED
使
make menuconfig
LOS_SwtmrCreate
LOS_SwtmrStart
TickLOS_SwtmrTimeGet
LOS_SwtmrStop
LOS_SwtmrDelete
使
使
使0
使使
使
Tick
@endverbatim
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2023 Huawei Device Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
@ -45,20 +109,19 @@
STATIC INLINE VOID SwtmrDelete(SWTMR_CTRL_S *swtmr);
STATIC INLINE UINT64 SwtmrToStart(SWTMR_CTRL_S *swtmr, UINT16 cpuid);
LITE_OS_SEC_BSS SWTMR_CTRL_S *g_swtmrCBArray = NULL; /* First address in Timer memory space */
LITE_OS_SEC_BSS UINT8 *g_swtmrHandlerPool = NULL; /* Pool of Swtmr Handler */
LITE_OS_SEC_BSS LOS_DL_LIST g_swtmrFreeList; /* Free list of Software Timer */
LITE_OS_SEC_BSS SWTMR_CTRL_S *g_swtmrCBArray = NULL; /**< First address in Timer memory space \n 定时器池 */
LITE_OS_SEC_BSS UINT8 *g_swtmrHandlerPool = NULL; /**< Pool of Swtmr Handler \n 用于注册软时钟的回调函数 */
LITE_OS_SEC_BSS LOS_DL_LIST g_swtmrFreeList; /**< Free list of Software Timer \n 空闲定时器链表 */
/* spinlock for swtmr module, only available on SMP mode */
LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_swtmrSpin);
#define SWTMR_LOCK(state) LOS_SpinLockSave(&g_swtmrSpin, &(state))
#define SWTMR_UNLOCK(state) LOS_SpinUnlockRestore(&g_swtmrSpin, (state))
LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_swtmrSpin);///< 初始化软时钟自旋锁,只有SMP情况才需要,只要是自旋锁都是用于CPU多核的同步
#define SWTMR_LOCK(state) LOS_SpinLockSave(&g_swtmrSpin, &(state))///< 持有软时钟自旋锁
#define SWTMR_UNLOCK(state) LOS_SpinUnlockRestore(&g_swtmrSpin, (state))///< 释放软时钟自旋锁
typedef struct {
SortLinkAttribute swtmrSortLink;
LosTaskCB *swtmrTask; /* software timer task id */
LOS_DL_LIST swtmrHandlerQueue; /* software timer timeout queue id */
LosTaskCB *swtmrTask; /* software timer task id | 定时器任务ID */
LOS_DL_LIST swtmrHandlerQueue; /* software timer timeout queue id | 定时器超时队列*/
} SwtmrRunqueue;
STATIC SwtmrRunqueue g_swtmrRunqueue[LOSCFG_KERNEL_CORE_NUM];
@ -254,7 +317,11 @@ STATIC INLINE VOID ScanSwtmrTimeList(SwtmrRunqueue *srq)
LOS_SpinUnlockRestore(&swtmrSortLink->spinLock, intSave);
return;
}
/**
* @brief , 0 !
*
* @return LITE_OS_SEC_TEXT
*/
STATIC VOID SwtmrTask(VOID)
{
SwtmrHandlerItem swtmrHandle;
@ -263,7 +330,7 @@ STATIC VOID SwtmrTask(VOID)
SwtmrRunqueue *srq = &g_swtmrRunqueue[ArchCurrCpuid()];
LOS_DL_LIST *head = &srq->swtmrHandlerQueue;
for (;;) {
for (;;) {//死循环获取队列item,一直读干净为止
waitTime = OsSortLinkGetNextExpireTime(OsGetCurrSchedTimeCycle(), &srq->swtmrSortLink);
if (waitTime != 0) {
SCHEDULER_LOCK(intSave);
@ -279,29 +346,30 @@ STATIC VOID SwtmrTask(VOID)
LOS_ListDelete(&swtmrHandlePtr->node);
(VOID)memcpy_s(&swtmrHandle, sizeof(SwtmrHandlerItem), swtmrHandlePtr, sizeof(SwtmrHandlerItem));
(VOID)LOS_MemboxFree(g_swtmrHandlerPool, swtmrHandlePtr);
(VOID)LOS_MemboxFree(g_swtmrHandlerPool, swtmrHandlePtr);//静态释放内存,注意在鸿蒙内核只有软时钟注册用到了静态内存
SwtmrHandler(&swtmrHandle);
}
}
}
}
///创建软时钟任务,每个cpu core都可以拥有自己的软时钟任务
STATIC UINT32 SwtmrTaskCreate(UINT16 cpuid, UINT32 *swtmrTaskID)
{
UINT32 ret;
TSK_INIT_PARAM_S swtmrTask;
(VOID)memset_s(&swtmrTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
swtmrTask.pfnTaskEntry = (TSK_ENTRY_FUNC)SwtmrTask;
swtmrTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
swtmrTask.pcName = "Swt_Task";
swtmrTask.usTaskPrio = 0;
swtmrTask.uwResved = LOS_TASK_STATUS_DETACHED;
(VOID)memset_s(&swtmrTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));//清0
swtmrTask.pfnTaskEntry = (TSK_ENTRY_FUNC)SwtmrTask;//入口函数
swtmrTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;//16K默认内核任务栈
swtmrTask.pcName = "Swt_Task";//任务名称
swtmrTask.usTaskPrio = 0;//哇塞! 逮到一个最高优先级的任务 @note_thinking 这里应该用 OS_TASK_PRIORITY_HIGHEST 表示
swtmrTask.uwResved = LOS_TASK_STATUS_DETACHED;//分离模式
#ifdef LOSCFG_KERNEL_SMP
swtmrTask.usCpuAffiMask = CPUID_TO_AFFI_MASK(cpuid);
swtmrTask.usCpuAffiMask = CPUID_TO_AFFI_MASK(cpuid);//交给当前CPU执行这个任务
#endif
ret = LOS_TaskCreate(swtmrTaskID, &swtmrTask);
ret = LOS_TaskCreate(swtmrTaskID, &swtmrTask);//创建任务并申请调度
if (ret == LOS_OK) {
OS_TCB_FROM_TID(*swtmrTaskID)->taskStatus |= OS_TASK_FLAG_SYSTEM_TASK;
OS_TCB_FROM_TID(*swtmrTaskID)->taskStatus |= OS_TASK_FLAG_SYSTEM_TASK;//告知这是一个系统任务
}
return ret;
@ -319,16 +387,16 @@ BOOL OsIsSwtmrTask(const LosTaskCB *taskCB)
}
return FALSE;
}
///回收指定进程的软时钟
LITE_OS_SEC_TEXT_INIT VOID OsSwtmrRecycle(UINTPTR ownerID)
{
for (UINT16 index = 0; index < LOSCFG_BASE_CORE_SWTMR_LIMIT; index++) {
for (UINT16 index = 0; index < LOSCFG_BASE_CORE_SWTMR_LIMIT; index++) {//一个进程往往会有多个定时器
if (g_swtmrCBArray[index].uwOwnerPid == ownerID) {
LOS_SwtmrDelete(index);
LOS_SwtmrDelete(index);//删除定时器
}
}
}
///软时钟初始化 ,注意函数在多CPU情况下会执行多次
STATIC UINT32 SwtmrBaseInit(VOID)
{
UINT32 ret;
@ -338,15 +406,15 @@ STATIC UINT32 SwtmrBaseInit(VOID)
return LOS_ERRNO_SWTMR_NO_MEMORY;
}
(VOID)memset_s(swtmr, size, 0, size);
g_swtmrCBArray = swtmr;
LOS_ListInit(&g_swtmrFreeList);
(VOID)memset_s(swtmr, size, 0, size);//清0
g_swtmrCBArray = swtmr;//软时钟
LOS_ListInit(&g_swtmrFreeList);//初始化空闲链表
for (UINT16 index = 0; index < LOSCFG_BASE_CORE_SWTMR_LIMIT; index++, swtmr++) {
swtmr->usTimerID = index;
LOS_ListTailInsert(&g_swtmrFreeList, &swtmr->stSortList.sortLinkNode);
swtmr->usTimerID = index;//按顺序赋值
LOS_ListTailInsert(&g_swtmrFreeList, &swtmr->stSortList.sortLinkNode);//通过sortLinkNode将节点挂到空闲链表
}
size = LOS_MEMBOX_SIZE(sizeof(SwtmrHandlerItem), OS_SWTMR_HANDLE_QUEUE_SIZE);
//想要用静态内存池管理,就必须要使用LOS_MEMBOX_SIZE来计算申请的内存大小,因为需要点前缀内存承载头部信息.
size = LOS_MEMBOX_SIZE(sizeof(SwtmrHandlerItem), OS_SWTMR_HANDLE_QUEUE_SIZE);//规划一片内存区域作为软时钟处理函数的静态内存池。
g_swtmrHandlerPool = (UINT8 *)LOS_MemAlloc(m_aucSysMem1, size); /* system resident resource */
if (g_swtmrHandlerPool == NULL) {
return LOS_ERRNO_SWTMR_NO_MEMORY;
@ -474,12 +542,12 @@ STATIC UINT64 SwtmrToStart(SWTMR_CTRL_S *swtmr, UINT16 cpuid)
if ((swtmr->uwOverrun == 0) && ((swtmr->ucMode == LOS_SWTMR_MODE_ONCE) ||
(swtmr->ucMode == LOS_SWTMR_MODE_OPP) ||
(swtmr->ucMode == LOS_SWTMR_MODE_NO_SELFDELETE))) {
ticks = swtmr->uwExpiry;
(swtmr->ucMode == LOS_SWTMR_MODE_NO_SELFDELETE))) {//如果是一次性的定时器
ticks = swtmr->uwExpiry; //获取时间间隔
} else {
ticks = swtmr->uwInterval;
ticks = swtmr->uwInterval;//获取周期性定时器时间间隔
}
swtmr->ucState = OS_SWTMR_STATUS_TICKING;
swtmr->ucState = OS_SWTMR_STATUS_TICKING;//计数状态
UINT64 period = (UINT64)ticks * OS_CYCLE_PER_TICK;
UINT64 responseTime = swtmr->startTime + period;
@ -522,10 +590,9 @@ STATIC INLINE VOID SwtmrStart(SWTMR_CTRL_S *swtmr)
STATIC INLINE VOID SwtmrDelete(SWTMR_CTRL_S *swtmr)
{
/* insert to free list */
LOS_ListTailInsert(&g_swtmrFreeList, &swtmr->stSortList.sortLinkNode);
swtmr->ucState = OS_SWTMR_STATUS_UNUSED;
LOS_ListTailInsert(&g_swtmrFreeList, &swtmr->stSortList.sortLinkNode);//直接插入空闲链表中,回收再利用
swtmr->ucState = OS_SWTMR_STATUS_UNUSED;//又干净着呢
swtmr->uwOwnerPid = OS_INVALID_VALUE;
SwtmrDebugDataClear(swtmr->usTimerID);
}
@ -641,7 +708,7 @@ LITE_OS_SEC_TEXT STATIC UINT32 OsSwtmrTimeGet(const SWTMR_CTRL_S *swtmr)
}
return (UINT32)time;
}
///创建定时器设置定时器的定时时长、定时器模式、回调函数并返回定时器ID
LITE_OS_SEC_TEXT_INIT UINT32 LOS_SwtmrCreate(UINT32 interval,
UINT8 mode,
SWTMR_PROC_FUNC handler,
@ -670,30 +737,30 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_SwtmrCreate(UINT32 interval,
}
SWTMR_LOCK(intSave);
if (LOS_ListEmpty(&g_swtmrFreeList)) {
if (LOS_ListEmpty(&g_swtmrFreeList)) {//空闲链表不能为空
SWTMR_UNLOCK(intSave);
return LOS_ERRNO_SWTMR_MAXSIZE;
}
sortList = LOS_DL_LIST_ENTRY(g_swtmrFreeList.pstNext, SortLinkList, sortLinkNode);
swtmr = LOS_DL_LIST_ENTRY(sortList, SWTMR_CTRL_S, stSortList);
LOS_ListDelete(LOS_DL_LIST_FIRST(&g_swtmrFreeList));
LOS_ListDelete(LOS_DL_LIST_FIRST(&g_swtmrFreeList));//
SWTMR_UNLOCK(intSave);
swtmr->uwOwnerPid = (UINTPTR)OsCurrProcessGet();
swtmr->pfnHandler = handler;
swtmr->ucMode = mode;
swtmr->pfnHandler = handler;//时间到了的回调函数
swtmr->ucMode = mode; //定时器模式
swtmr->uwOverrun = 0;
swtmr->uwInterval = interval;
swtmr->uwExpiry = interval;
swtmr->uwArg = arg;
swtmr->ucState = OS_SWTMR_STATUS_CREATED;
swtmr->uwInterval = interval; //周期性超时间隔
swtmr->uwExpiry = interval; //一次性超时间隔
swtmr->uwArg = arg; //回调函数的参数
swtmr->ucState = OS_SWTMR_STATUS_CREATED; //已创建状态
SET_SORTLIST_VALUE(&swtmr->stSortList, OS_SORT_LINK_INVALID_TIME);
*swtmrID = swtmr->usTimerID;
OsHookCall(LOS_HOOK_TYPE_SWTMR_CREATE, swtmr);
return LOS_OK;
}
///接口函数 启动定时器 参数定时任务ID
LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStart(UINT16 swtmrID)
{
SWTMR_CTRL_S *swtmr = NULL;
@ -705,27 +772,27 @@ LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStart(UINT16 swtmrID)
return LOS_ERRNO_SWTMR_ID_INVALID;
}
swtmrCBID = swtmrID % LOSCFG_BASE_CORE_SWTMR_LIMIT;
swtmr = g_swtmrCBArray + swtmrCBID;
swtmrCBID = swtmrID % LOSCFG_BASE_CORE_SWTMR_LIMIT;//取模
swtmr = g_swtmrCBArray + swtmrCBID;//获取定时器控制结构体
SWTMR_LOCK(intSave);
if (swtmr->usTimerID != swtmrID) {
if (swtmr->usTimerID != swtmrID) {//ID必须一样
SWTMR_UNLOCK(intSave);
return LOS_ERRNO_SWTMR_ID_INVALID;
}
switch (swtmr->ucState) {
switch (swtmr->ucState) {//判断定时器状态
case OS_SWTMR_STATUS_UNUSED:
ret = LOS_ERRNO_SWTMR_NOT_CREATED;
break;
/*
/* 如果定时器的状态为启动中,应先停止定时器再重新启动
* If the status of swtmr is timing, it should stop the swtmr first,
* then start the swtmr again.
*/
case OS_SWTMR_STATUS_TICKING:
SwtmrStop(swtmr);
case OS_SWTMR_STATUS_TICKING://正在计数的定时器
SwtmrStop(swtmr);//先停止定时器,注意这里没有break;,在OsSwtmrStop中状态将会回到了OS_SWTMR_STATUS_CREATED 接下来就是执行启动了
/* fall-through */
case OS_SWTMR_STATUS_CREATED:
case OS_SWTMR_STATUS_CREATED://已经创建好了
SwtmrStart(swtmr);
break;
default:
@ -737,7 +804,7 @@ LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStart(UINT16 swtmrID)
OsHookCall(LOS_HOOK_TYPE_SWTMR_START, swtmr);
return ret;
}
///接口函数 停止定时器 参数定时任务ID
LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStop(UINT16 swtmrID)
{
SWTMR_CTRL_S *swtmr = NULL;
@ -749,24 +816,24 @@ LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStop(UINT16 swtmrID)
return LOS_ERRNO_SWTMR_ID_INVALID;
}
swtmrCBID = swtmrID % LOSCFG_BASE_CORE_SWTMR_LIMIT;
swtmr = g_swtmrCBArray + swtmrCBID;
swtmrCBID = swtmrID % LOSCFG_BASE_CORE_SWTMR_LIMIT;//取模
swtmr = g_swtmrCBArray + swtmrCBID;//获取定时器控制结构体
SWTMR_LOCK(intSave);
if (swtmr->usTimerID != swtmrID) {
if (swtmr->usTimerID != swtmrID) {//ID必须一样
SWTMR_UNLOCK(intSave);
return LOS_ERRNO_SWTMR_ID_INVALID;
}
switch (swtmr->ucState) {
switch (swtmr->ucState) {//判断定时器状态
case OS_SWTMR_STATUS_UNUSED:
ret = LOS_ERRNO_SWTMR_NOT_CREATED;
ret = LOS_ERRNO_SWTMR_NOT_CREATED;//返回没有创建
break;
case OS_SWTMR_STATUS_CREATED:
ret = LOS_ERRNO_SWTMR_NOT_STARTED;
ret = LOS_ERRNO_SWTMR_NOT_STARTED;//返回没有开始
break;
case OS_SWTMR_STATUS_TICKING:
SwtmrStop(swtmr);
case OS_SWTMR_STATUS_TICKING://正在计数
SwtmrStop(swtmr);//执行正在停止定时器操作
break;
default:
ret = LOS_ERRNO_SWTMR_STATUS_INVALID;
@ -777,7 +844,7 @@ LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStop(UINT16 swtmrID)
OsHookCall(LOS_HOOK_TYPE_SWTMR_STOP, swtmr);
return ret;
}
///接口函数 获得软件定时器剩余Tick数 通过 *tick 带走
LITE_OS_SEC_TEXT UINT32 LOS_SwtmrTimeGet(UINT16 swtmrID, UINT32 *tick)
{
SWTMR_CTRL_S *swtmr = NULL;
@ -793,11 +860,11 @@ LITE_OS_SEC_TEXT UINT32 LOS_SwtmrTimeGet(UINT16 swtmrID, UINT32 *tick)
return LOS_ERRNO_SWTMR_TICK_PTR_NULL;
}
swtmrCBID = swtmrID % LOSCFG_BASE_CORE_SWTMR_LIMIT;
swtmr = g_swtmrCBArray + swtmrCBID;
swtmrCBID = swtmrID % LOSCFG_BASE_CORE_SWTMR_LIMIT;//取模
swtmr = g_swtmrCBArray + swtmrCBID;//获取定时器控制结构体
SWTMR_LOCK(intSave);
if (swtmr->usTimerID != swtmrID) {
if (swtmr->usTimerID != swtmrID) {//ID必须一样
SWTMR_UNLOCK(intSave);
return LOS_ERRNO_SWTMR_ID_INVALID;
}
@ -808,8 +875,8 @@ LITE_OS_SEC_TEXT UINT32 LOS_SwtmrTimeGet(UINT16 swtmrID, UINT32 *tick)
case OS_SWTMR_STATUS_CREATED:
ret = LOS_ERRNO_SWTMR_NOT_STARTED;
break;
case OS_SWTMR_STATUS_TICKING:
*tick = OsSwtmrTimeGet(swtmr);
case OS_SWTMR_STATUS_TICKING://正在计数的定时器
*tick = OsSwtmrTimeGet(swtmr);//获取
break;
default:
ret = LOS_ERRNO_SWTMR_STATUS_INVALID;
@ -818,7 +885,7 @@ LITE_OS_SEC_TEXT UINT32 LOS_SwtmrTimeGet(UINT16 swtmrID, UINT32 *tick)
SWTMR_UNLOCK(intSave);
return ret;
}
///接口函数 删除定时器
LITE_OS_SEC_TEXT UINT32 LOS_SwtmrDelete(UINT16 swtmrID)
{
SWTMR_CTRL_S *swtmr = NULL;
@ -830,11 +897,11 @@ LITE_OS_SEC_TEXT UINT32 LOS_SwtmrDelete(UINT16 swtmrID)
return LOS_ERRNO_SWTMR_ID_INVALID;
}
swtmrCBID = swtmrID % LOSCFG_BASE_CORE_SWTMR_LIMIT;
swtmr = g_swtmrCBArray + swtmrCBID;
swtmrCBID = swtmrID % LOSCFG_BASE_CORE_SWTMR_LIMIT;//取模
swtmr = g_swtmrCBArray + swtmrCBID;//获取定时器控制结构体
SWTMR_LOCK(intSave);
if (swtmr->usTimerID != swtmrID) {
if (swtmr->usTimerID != swtmrID) {//ID必须一样
SWTMR_UNLOCK(intSave);
return LOS_ERRNO_SWTMR_ID_INVALID;
}
@ -843,10 +910,10 @@ LITE_OS_SEC_TEXT UINT32 LOS_SwtmrDelete(UINT16 swtmrID)
case OS_SWTMR_STATUS_UNUSED:
ret = LOS_ERRNO_SWTMR_NOT_CREATED;
break;
case OS_SWTMR_STATUS_TICKING:
case OS_SWTMR_STATUS_TICKING://正在计数就先停止再删除,这里没有break;
SwtmrStop(swtmr);
/* fall-through */
case OS_SWTMR_STATUS_CREATED:
case OS_SWTMR_STATUS_CREATED://再删除定时器
SwtmrDelete(swtmr);
break;
default:
@ -860,3 +927,4 @@ LITE_OS_SEC_TEXT UINT32 LOS_SwtmrDelete(UINT16 swtmrID)
}
#endif /* LOSCFG_BASE_CORE_SWTMR_ENABLE */

@ -1,6 +1,6 @@
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
* Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020, Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
@ -32,19 +32,72 @@
#include "los_sys_pri.h"
#include "los_sched_pri.h"
/*!
* @file los_sys.c
* @brief
* @details
* @link kernel-small-basic-time http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-basic-time.html @endlink
* @verbatim
/
Tick
Tick
Tick/
Cycle
CycleCycle
Tick
TickTick
使
Tick
使LOSCFG_BASE_CORE_TICK_HW_TIME
OS_SYS_CLOCKHzOS_SYS_CLOCK
make menuconfigLOSCFG_BASE_CORE_TICK_PER_SECOND
http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-basic-time.html
@endverbatim
* @attention
Tick使
los_config.hOS_SYS_CLOCKLOSCFG_BASE_CORE_TICK_PER_SECOND
TickTick
*/
#define OS_MAX_VALUE 0xFFFFFFFFUL
/**
* @brief Tick
*
* @return LITE_OS_SEC_TEXT_MINOR
*/
LITE_OS_SEC_TEXT_MINOR UINT64 LOS_TickCountGet(VOID)
{
return OsGetCurrSchedTimeCycle() / OS_CYCLE_PER_TICK;
}
/**
* @brief TickCycle
*
* @return LITE_OS_SEC_TEXT_MINOR
*/
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_CyclePerTickGet(VOID)
{
return g_sysClock / LOSCFG_BASE_CORE_TICK_PER_SECOND;
}
/**
* @brief Tick
*
* @param millisec
* @return LITE_OS_SEC_TEXT_MINOR
*/
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MS2Tick(UINT32 millisec)
{
if (millisec == OS_MAX_VALUE) {
@ -53,12 +106,22 @@ LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MS2Tick(UINT32 millisec)
return ((UINT64)millisec * LOSCFG_BASE_CORE_TICK_PER_SECOND) / OS_SYS_MS_PER_SECOND;
}
/**
* @brief Tick
*
* @param tick
* @return LITE_OS_SEC_TEXT_MINOR
*/
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_Tick2MS(UINT32 tick)
{
return ((UINT64)tick * OS_SYS_MS_PER_SECOND) / LOSCFG_BASE_CORE_TICK_PER_SECOND;
}
/**
* @brief tick
*
* @param nanoseconds
* @return LITE_OS_SEC_TEXT_MINOR
*/
LITE_OS_SEC_TEXT_MINOR UINT32 OsNS2Tick(UINT64 nanoseconds)
{
const UINT32 nsPerTick = OS_SYS_NS_PER_SECOND / LOSCFG_BASE_CORE_TICK_PER_SECOND;

File diff suppressed because it is too large Load Diff

@ -37,30 +37,30 @@
#endif
LITE_OS_SEC_DATA_INIT UINT32 g_sysClock;
LITE_OS_SEC_DATA_INIT UINT32 g_tickPerSecond;
LITE_OS_SEC_BSS DOUBLE g_cycle2NsScale;
LITE_OS_SEC_DATA_INIT UINT32 g_sysClock; ///< 系统时钟,是绝大部分部件工作的时钟源,也是其他所有外设的时钟的来源
LITE_OS_SEC_DATA_INIT UINT32 g_tickPerSecond; ///< 每秒Tick数,鸿蒙默认是每秒100次,即:10ms
LITE_OS_SEC_BSS DOUBLE g_cycle2NsScale; ///< 周期转纳秒级
/* spinlock for task module */
LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_tickSpin);
LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_tickSpin); ///< 节拍器自旋锁
/*
* Description : Tick interruption handler
* Description : Tick interruption handler | ,鸿1ms
*/
LITE_OS_SEC_TEXT VOID OsTickHandler(VOID)
{
#ifdef LOSCFG_SCHED_TICK_DEBUG
#ifdef LOSCFG_SCHED_TICK_DEBUG
OsSchedDebugRecordData();
#endif
#ifdef LOSCFG_KERNEL_VDSO
OsVdsoTimevalUpdate();
OsVdsoTimevalUpdate();//更新vdso数据页时间,vdso可以直接在用户进程空间绕过系统调用获取系统时间(例如:gettimeofday)
#endif
#ifdef LOSCFG_BASE_CORE_TICK_HW_TIME
HalClockIrqClear(); /* diff from every platform */
#endif
OsSchedTick();
OsSchedTick();//由时钟发起的调度
}

@ -57,10 +57,10 @@
typedef enum {
CONTAINER = 0,
PID_CONTAINER,
PID_CHILD_CONTAINER,
UTS_CONTAINER,
MNT_CONTAINER,
PID_CONTAINER, //进程容器
PID_CHILD_CONTAINER, //子进程容器
UTS_CONTAINER, //
MNT_CONTAINER, //挂载容器
IPC_CONTAINER,
USER_CONTAINER,
TIME_CONTAINER,
@ -70,29 +70,29 @@ typedef enum {
} ContainerType;
typedef struct Container {
Atomic rc;
Atomic rc; //原子操作
#ifdef LOSCFG_PID_CONTAINER
struct PidContainer *pidContainer;
struct PidContainer *pidForChildContainer;
struct PidContainer *pidContainer; //进程容器
struct PidContainer *pidForChildContainer;//进程的孩子容器
#endif
#ifdef LOSCFG_UTS_CONTAINER
struct UtsContainer *utsContainer;
struct UtsContainer *utsContainer; //
#endif
#ifdef LOSCFG_MNT_CONTAINER
struct MntContainer *mntContainer;
struct MntContainer *mntContainer; //挂载容器
#endif
#ifdef LOSCFG_IPC_CONTAINER
struct IpcContainer *ipcContainer;
struct IpcContainer *ipcContainer; //IPC容器
#endif
#ifdef LOSCFG_TIME_CONTAINER
struct TimeContainer *timeContainer;
struct TimeContainer *timeForChildContainer;
struct TimeContainer *timeContainer; //时间容器
struct TimeContainer *timeForChildContainer;
#endif
#ifdef LOSCFG_NET_CONTAINER
struct NetContainer *netContainer;
struct NetContainer *netContainer; //网络容器
#endif
} Container;
//容器数量上限
typedef struct TagContainerLimit {
#ifdef LOSCFG_PID_CONTAINER
UINT32 pidLimit;

@ -1,3 +1,31 @@
/*!
* @file los_futex_pri.h
* @brief
* @link
@verbatim
FUTEX_WAIT
uaddrfutexvalsleepFUTEX_WAKE
futexsleep
futex线线sleepwaiterfutex
futexEAGAIN
线
线FUTEX_WAITFUTEX_WAKE线
FUTEX_WAIT
FUTEX_WAIT
线FUTEX_WAKE线FUTEX_WAKEFUTEX_WAIT线
timeoutNULL使
CLOCK_MONOTONICLinux 4.5futex_op
FUTEX_CLOCK_REALTIME使CLOCK_REALTIMEtimeoutNULL
FUTEX_WAITtimeoutfutextimeout
使FUTEX_BITSET_MATCH_ANYval3FUTEX_WAIT_BITSETtimeoutFUTEX_WAIT
@endverbatim
* @version
* @author weharmonyos.com | 鸿 |
* @date 2021-11-24
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
@ -33,25 +61,27 @@
#define _LOS_FUTEX_PRI_H
#include "los_list.h"
#define FUTEX_WAIT 0
#define FUTEX_WAKE 1
#define FUTEX_REQUEUE 3
#define FUTEX_WAKE_OP 5
#define FUTEX_WAIT 0 ///< 原子性的检查 uaddr 中计数器的值是否为 val如果是则让任务休眠直到 FUTEX_WAKE 或者超时time-out
//也就是把任务挂到 uaddr 相对应的等待队列上去。
#define FUTEX_WAKE 1 ///< 最多唤醒 val 个等待在 uaddr 上任务。
#define FUTEX_REQUEUE 3 ///< 调整指定锁在Futex表中的位置
#define FUTEX_WAKE_OP 5
#define FUTEX_LOCK_PI 6
#define FUTEX_UNLOCK_PI 7
#define FUTEX_TRYLOCK_PI 8
#define FUTEX_WAIT_BITSET 9
#define FUTEX_PRIVATE 128
#define FUTEX_PRIVATE 128 //私有快锁(以虚拟地址进行哈希)
#define FUTEX_MASK 0x3U
/// 每个futex node对应一个被挂起的task key值唯一标识一把用户态锁具有相同key值的node被queue_list串联起来表示被同一把锁阻塞的task队列。
typedef struct {
UINTPTR key; /* private:uvaddr shared:paddr */
UINT32 index; /* hash bucket index */
UINT32 pid; /* private:process id shared:OS_INVALID(-1) */
LOS_DL_LIST pendList; /* point to pendList in TCB struct */
LOS_DL_LIST queueList; /* thread list blocked by this lock */
LOS_DL_LIST futexList; /* point to the next FutexNode */
UINTPTR key; /* private:uvaddr | 私有锁,用虚拟地址 shared:paddr | 共享锁,用物理地址*/
UINT32 index; /* hash bucket index | 哈希桶索引 OsFutexKeyToIndex */
UINT32 pid; /* private:process id shared:OS_INVALID(-1) | 私有锁:进程ID , 共享锁为 -1 */
LOS_DL_LIST pendList; /* point to pendList in TCB struct | 指向 TCB 结构中的 pendList, 通过它找到任务*/
LOS_DL_LIST queueList; /* thread list blocked by this lock | 挂等待这把锁的任务其实这里挂到是FutexNode.queueList ,
queueList pendList , pendList*/
LOS_DL_LIST futexList; /* point to the next FutexNode | 下一把Futex锁*/
} FutexNode;
extern UINT32 OsFutexInit(VOID);

@ -42,13 +42,13 @@ typedef struct TagQueueCB LosQueueCB;
typedef struct OsMux LosMux;
typedef LosMux pthread_mutex_t;
typedef struct ProcessCB LosProcessCB;
//IPC容器
typedef struct IpcContainer {
Atomic rc;
LosQueueCB *allQueue;
LOS_DL_LIST freeQueueList;
LosQueueCB *allQueue; //队列控制块(读写分离模式)
LOS_DL_LIST freeQueueList;//空闲队列链表
fd_set queueFdSet;
struct mqarray queueTable[LOSCFG_BASE_IPC_QUEUE_LIMIT];
struct mqarray queueTable[LOSCFG_BASE_IPC_QUEUE_LIMIT];//队列池
pthread_mutex_t mqueueMutex;
struct mqpersonal *mqPrivBuf[MAX_MQ_FD];
struct shminfo shmInfo;

@ -42,7 +42,7 @@ extern "C" {
#endif /* __cplusplus */
typedef struct {
UINT32 memUsed;
UINT32 memUsed; ///< 记录任务内存使用量
} TskMemUsedInfo;
extern VOID OsTaskMemUsedInc(UINT32 usedSize, UINT32 taskID);
@ -53,7 +53,7 @@ extern VOID OsTaskMemClear(UINT32 taskID);
#ifdef LOS_MEM_SLAB
typedef struct {
UINT32 slabUsed;
UINT32 slabUsed; ///< 任务占用以slab分配方式内存量
} TskSlabUsedInfo;
extern VOID OsTaskSlabUsedInc(UINT32 usedSize, UINT32 taskID);

@ -1,6 +1,6 @@
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2022 Huawei Device Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:

@ -43,9 +43,9 @@ extern "C" {
#ifdef LOSCFG_KERNEL_SMP
typedef enum {
CPU_RUNNING = 0, /* cpu is running */
CPU_HALT, /* cpu in the halt */
CPU_EXC /* cpu in the exc */
CPU_RUNNING = 0, ///< cpu is running | CPU正在运行状态
CPU_HALT, ///< cpu in the halt | CPU处于暂停状态
CPU_EXC ///< cpu in the exc | CPU处于异常状态
} ExcFlag;
typedef struct {
@ -55,14 +55,14 @@ typedef struct {
#endif
} Percpu;
/* the kernel per-cpu structure */
/*! the kernel per-cpu structure | 每个cpu的内核描述符 */
extern Percpu g_percpu[LOSCFG_KERNEL_CORE_NUM];
/*! 获得当前运行CPU的信息 */
STATIC INLINE Percpu *OsPercpuGet(VOID)
{
return &g_percpu[ArchCurrCpuid()];
return &g_percpu[ArchCurrCpuid()];
}
/*! 获得参数CPU的信息 */
STATIC INLINE Percpu *OsPercpuGetByID(UINT32 cpuid)
{
return &g_percpu[cpuid];

@ -38,29 +38,29 @@ typedef struct TagTaskCB LosTaskCB;
typedef struct ProcessCB LosProcessCB;
struct ProcessGroup;
struct Container;
//虚拟进程/任务 信息
typedef struct {
UINT32 vid; /* Virtual ID */
UINT32 vpid; /* Virtual parent ID */
UINTPTR cb; /* Control block */
LosProcessCB *realParent; /* process real parent */
LOS_DL_LIST node;
UINT32 vid; /* Virtual ID | 虚拟ID*/
UINT32 vpid; /* Virtual parent ID | 父进程虚拟ID*/
UINTPTR cb; /* Control block | 控制块*/
LosProcessCB *realParent; /* process real parent | 进程真实的父进程 */
LOS_DL_LIST node;//用于挂入 PidContainer.pidFreeList | tidFreeList
} ProcessVid;
#define PID_CONTAINER_LEVEL_LIMIT 3
//进程容器
typedef struct PidContainer {
Atomic rc;
Atomic level;
Atomic lock;
BOOL referenced;
UINT32 containerID;
struct PidContainer *parent;
struct ProcessGroup *rootPGroup;
LOS_DL_LIST tidFreeList;
ProcessVid tidArray[LOSCFG_BASE_CORE_TSK_LIMIT];
LOS_DL_LIST pidFreeList;
ProcessVid pidArray[LOSCFG_BASE_CORE_PROCESS_LIMIT];
Atomic rc; //原子操作
Atomic level; //等级0为最高级父比子高一级
Atomic lock; //锁
BOOL referenced; //是否被引用
UINT32 containerID; //容器ID
struct PidContainer *parent; //父进程容器
struct ProcessGroup *rootPGroup; //进程组
LOS_DL_LIST tidFreeList; //任务空闲链表
ProcessVid tidArray[LOSCFG_BASE_CORE_TSK_LIMIT];//虚拟任务池
LOS_DL_LIST pidFreeList; //进程空闲链表
ProcessVid pidArray[LOSCFG_BASE_CORE_PROCESS_LIMIT];//虚拟进程池
} PidContainer;
#define OS_PID_CONTAINER_FROM_PCB(processCB) ((processCB)->container->pidContainer)

@ -1,6 +1,6 @@
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2023 Huawei Device Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
@ -65,82 +65,86 @@ extern "C" {
#ifdef LOSCFG_SECURITY_CAPABILITY
#define OS_GROUPS_NUMBER_MAX 256
/*! 用户描述体*/
typedef struct {
UINT32 userID;
UINT32 userID; ///<用户ID [0,60000],0为root用户
UINT32 effUserID;
UINT32 gid;
UINT32 gid; ///<用户组ID [0,60000],0为root用户组
UINT32 effGid;
UINT32 groupNumber;
UINT32 groups[1];
UINT32 groupNumber;///< 用户组数量
UINT32 groups[1]; //所属用户组列表,一个用户可属多个用户组
} User;
#endif
/*! 进程组结构体*/
typedef struct ProcessGroup {
UINTPTR pgroupLeader; /**< Process group leader is the the process that created the group */
LOS_DL_LIST processList; /**< List of processes under this process group */
LOS_DL_LIST exitProcessList; /**< List of closed processes (zombie processes) under this group */
LOS_DL_LIST groupList; /**< Process group list */
UINTPTR pgroupLeader; /**< Process group leader is the the process that created the group | 负责创建进程组的进程首地址*/
LOS_DL_LIST processList; /**< List of processes under this process group | 属于该进程组的进程链表*/
LOS_DL_LIST exitProcessList; /**< List of closed processes (zombie processes) under this group | 进程组的僵死进程链表*/
LOS_DL_LIST groupList; /**< Process group list | 进程组链表,上面挂的都是进程组*/
} ProcessGroup;
/**
* .
*/
typedef struct ProcessCB {
CHAR processName[OS_PCB_NAME_LEN]; /**< Process name */
UINT32 processID; /**< Process ID */
CHAR processName[OS_PCB_NAME_LEN]; /**< Process name | 进程名称 */
UINT32 processID; /**< Process ID = leader thread ID | 进程ID,由进程池分配,范围[0,64] */
UINT16 processStatus; /**< [15:4] Process Status; [3:0] The number of threads currently
running in the process */
UINT16 consoleID; /**< The console id of task belongs */
UINT16 processMode; /**< Kernel Mode:0; User Mode:1; */
running in the process | . ,! @note_good */
UINT16 consoleID; /**< The console id of task belongs | 任务的控制台id归属 */
UINT16 processMode; /**< Kernel Mode:0; User Mode:1; | 模式指定为内核还是用户进程 */
struct ProcessCB *parentProcess; /**< Parent process */
UINT32 exitCode; /**< Process exit status */
LOS_DL_LIST pendList; /**< Block list to which the process belongs */
LOS_DL_LIST childrenList; /**< Children process list */
LOS_DL_LIST exitChildList; /**< Exit children process list */
LOS_DL_LIST siblingList; /**< Linkage in parent's children list */
ProcessGroup *pgroup; /**< Process group to which a process belongs */
LOS_DL_LIST subordinateGroupList; /**< Linkage in group list */
UINT32 exitCode; /**< Process exit status | 进程退出状态码*/
LOS_DL_LIST pendList; /**< Block list to which the process belongs | 进程所在的阻塞列表,进程因阻塞挂入相应的链表.*/
LOS_DL_LIST childrenList; /**< Children process list | 孩子进程都挂到这里,形成双循环链表*/
LOS_DL_LIST exitChildList; /**< Exit children process list | 要退出的孩子进程链表,白发人要送黑发人.*/
LOS_DL_LIST siblingList; /**< Linkage in parent's children list | 兄弟进程链表, 56个民族是一家,来自同一个父进程.*/
ProcessGroup *pgroup; /**< Process group to which a process belongs | 所属进程组*/
LOS_DL_LIST subordinateGroupList; /**< Linkage in group list | 进程组员链表*/
LosTaskCB *threadGroup;
LOS_DL_LIST threadSiblingList; /**< List of threads under this process */
volatile UINT32 threadNumber; /**< Number of threads alive under this process */
UINT32 threadCount; /**< Total number of threads created under this process */
LOS_DL_LIST waitList; /**< The process holds the waitLits to support wait/waitpid */
LOS_DL_LIST threadSiblingList; /**< List of threads under this process | 进程的线程(任务)列表 */
volatile UINT32 threadNumber; /**< Number of threads alive under this process | 此进程下的活动线程数*/
UINT32 threadCount; /**< Total number of threads created under this process | 在此进程下创建的线程总数*/ //
LOS_DL_LIST waitList; /**< The process holds the waitLits to support wait/waitpid | 父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息*/
#ifdef LOSCFG_KERNEL_SMP
UINT32 timerCpu; /**< CPU core number of this task is delayed or pended */
UINT32 timerCpu; /**< CPU core number of this task is delayed or pended | 统计各线程被延期或阻塞的时间*/
#endif
UINTPTR sigHandler; /**< Signal handler */
sigset_t sigShare; /**< Signal share bit */
UINTPTR sigHandler; /**< Signal handler | 信号处理函数,处理如 SIGSYS 等信号*/
sigset_t sigShare; /**< Signal share bit | 信号共享位 sigset_t是个64位的变量,对应64种信号*/
#ifdef LOSCFG_KERNEL_LITEIPC
ProcIpcInfo *ipcInfo; /**< Memory pool for lite ipc */
ProcIpcInfo *ipcInfo; /**< Memory pool for lite ipc | 用于进程间通讯的虚拟设备文件系统,设备装载点为 /dev/lite_ipc*/
#endif
#ifdef LOSCFG_KERNEL_VM
LosVmSpace *vmSpace; /**< VMM space for processes */
LosVmSpace *vmSpace; /**< VMM space for processes | 虚拟空间,描述进程虚拟内存的数据结构linux称为内存描述符 */
#endif
#ifdef LOSCFG_FS_VFS
struct files_struct *files; /**< Files held by the process */
#endif
timer_t timerID; /**< ITimer */
struct files_struct *files; /**< Files held by the process | 进程所持有的所有文件,注者称之为进程的文件管理器*/
#endif //每个进程都有属于自己的文件管理器,记录对文件的操作. 注意:一个文件可以被多个进程操作
timer_t timerID; /**< iTimer */
#ifdef LOSCFG_SECURITY_CAPABILITY
User *user;
UINT32 capability;
#ifdef LOSCFG_SECURITY_CAPABILITY //安全能力
User *user; ///< 进程的拥有者
UINT32 capability; ///< 安全能力范围 对应 CAP_SETGID
#endif
#ifdef LOSCFG_SECURITY_VID
TimerIdMap timerIdMap;
#ifdef LOSCFG_SECURITY_VID //虚拟ID映射功能
TimerIdMap timerIdMap;
#endif
#ifdef LOSCFG_DRIVERS_TZDRIVER
struct Vnode *execVnode; /**< Exec bin of the process */
struct Vnode *execVnode; /**< Exec bin of the process | 进程的可执行文件 */
#endif
mode_t umask;
mode_t umask; ///< umask(user file-creatiopn mode mask)为用户文件创建掩码,是创建文件或文件夹时默认权限的基础。
#ifdef LOSCFG_KERNEL_CPUP
OsCpupBase *processCpup; /**< Process cpu usage */
OsCpupBase *processCpup; /**< Process cpu usage | 进程占用CPU情况统计*/
#endif
struct rlimit *resourceLimit;
struct rlimit *resourceLimit; ///< 每个进程在运行时系统不会无限制的允许单个进程不断的消耗资源,因此都会设置资源限制。
#ifdef LOSCFG_KERNEL_CONTAINER
Container *container;
Container *container; ///< 内核容器
#ifdef LOSCFG_USER_CONTAINER
struct Credentials *credentials;
struct Credentials *credentials; ///< 用户身份证
#endif
#endif
#ifdef LOSCFG_PROC_PROCESS_DIR
struct ProcDirEntry *procDir;
struct ProcDirEntry *procDir; ///< 目录文件项
#endif
#ifdef LOSCFG_KERNEL_PLIMITS
ProcLimiterSet *plimits;
@ -161,8 +165,8 @@ extern UINT32 g_processMaxNum;
#define OS_PCB_FROM_TCB(taskCB) ((LosProcessCB *)((taskCB)->processCB))
#define OS_PCB_FROM_TID(taskID) ((LosProcessCB *)(OS_TCB_FROM_TID(taskID)->processCB))
#define OS_GET_PGROUP_LEADER(pgroup) ((LosProcessCB *)((pgroup)->pgroupLeader))
#define OS_PCB_FROM_SIBLIST(ptr) LOS_DL_LIST_ENTRY((ptr), LosProcessCB, siblingList)
#define OS_PCB_FROM_PENDLIST(ptr) LOS_DL_LIST_ENTRY((ptr), LosProcessCB, pendList)
#define OS_PCB_FROM_SIBLIST(ptr) LOS_DL_LIST_ENTRY((ptr), LosProcessCB, siblingList)///< 通过siblingList节点找到 LosProcessCB
#define OS_PCB_FROM_PENDLIST(ptr) LOS_DL_LIST_ENTRY((ptr), LosProcessCB, pendList) ///< 通过pendlist节点找到 LosProcessCB
/**
* @ingroup los_process
@ -202,7 +206,7 @@ extern UINT32 g_processMaxNum;
*
* The process is run out but the resources occupied by the process are not recovered.
*/
#define OS_PROCESS_STATUS_ZOMBIES 0x0100U
#define OS_PROCESS_STATUS_ZOMBIES 0x0100U ///< 进程状态: 僵死
/**
* @ingroup los_process
@ -211,7 +215,7 @@ extern UINT32 g_processMaxNum;
* The process status equal this is process control block unused,
* coexisting with OS_PROCESS_STATUS_ZOMBIES means that the control block is not recovered.
*/
#define OS_PROCESS_FLAG_UNUSED 0x0200U
#define OS_PROCESS_FLAG_UNUSED 0x0200U ///< 进程未使用标签,一般用于进程的初始状态 freelist里面都是这种标签
/**
* @ingroup los_process
@ -219,7 +223,7 @@ extern UINT32 g_processMaxNum;
*
* The process has been call exit, it only works with multiple cores.
*/
#define OS_PROCESS_FLAG_EXIT 0x0400U
#define OS_PROCESS_FLAG_EXIT 0x0400U ///< 进程退出标签,退出的进程进入回收链表等待回收资源
/**
* @ingroup los_process
@ -227,7 +231,7 @@ extern UINT32 g_processMaxNum;
*
* The process is the leader of the process group.
*/
#define OS_PROCESS_FLAG_GROUP_LEADER 0x0800U
#define OS_PROCESS_FLAG_GROUP_LEADER 0x0800U ///< 进程当了进程组领导标签
/**
* @ingroup los_process
@ -235,21 +239,21 @@ extern UINT32 g_processMaxNum;
*
* The process has performed the exec operation.
*/
#define OS_PROCESS_FLAG_ALREADY_EXEC 0x1000U
#define OS_PROCESS_FLAG_ALREADY_EXEC 0x1000U ///< 进程已执行exec操作 load elf时使用
/**
* @ingroup los_process
* Flag that indicates the process or process control block status.
*
* The process is dying or already dying.
*/
#define OS_PROCESS_STATUS_INACTIVE (OS_PROCESS_FLAG_EXIT | OS_PROCESS_STATUS_ZOMBIES)
*/ /// 进程不活跃状态定义: 身上贴有退出便签且状态为僵死的进程
#define OS_PROCESS_STATUS_INACTIVE (OS_PROCESS_FLAG_EXIT | OS_PROCESS_STATUS_ZOMBIES)
/**
* @ingroup los_process
* Used to check if the process control block is unused.
*/
STATIC INLINE BOOL OsProcessIsUnused(const LosProcessCB *processCB)
STATIC INLINE BOOL OsProcessIsUnused(const LosProcessCB *processCB)//查下进程是否还在使用?
{
return ((processCB->processStatus & OS_PROCESS_FLAG_UNUSED) != 0);
}
@ -257,8 +261,8 @@ STATIC INLINE BOOL OsProcessIsUnused(const LosProcessCB *processCB)
/**
* @ingroup los_process
* Used to check if the process is inactive.
*/
STATIC INLINE BOOL OsProcessIsInactive(const LosProcessCB *processCB)
*/ /// 进程不活跃函数定义:身上贴有不使用且不活跃标签的进程
STATIC INLINE BOOL OsProcessIsInactive(const LosProcessCB *processCB)//查下进程是否不活跃?
{
return ((processCB->processStatus & (OS_PROCESS_FLAG_UNUSED | OS_PROCESS_STATUS_INACTIVE)) != 0);
}
@ -266,8 +270,8 @@ STATIC INLINE BOOL OsProcessIsInactive(const LosProcessCB *processCB)
/**
* @ingroup los_process
* Used to check if the process is dead.
*/
STATIC INLINE BOOL OsProcessIsDead(const LosProcessCB *processCB)
*/ /// 进程死啦死啦的定义: 身上贴有不使用且状态为僵死的进程
STATIC INLINE BOOL OsProcessIsDead(const LosProcessCB *processCB)//查下进程是否死啦死啦滴?
{
return ((processCB->processStatus & OS_PROCESS_STATUS_ZOMBIES) != 0);
}
@ -286,64 +290,64 @@ STATIC INLINE BOOL OsProcessIsPGroupLeader(const LosProcessCB *processCB)
* @ingroup los_process
* The highest priority of a kernel mode process.
*/
#define OS_PROCESS_PRIORITY_HIGHEST 0
#define OS_PROCESS_PRIORITY_HIGHEST 0 ///< 进程最高优先级
/**
* @ingroup los_process
* The lowest priority of a kernel mode process
*/
#define OS_PROCESS_PRIORITY_LOWEST 31
#define OS_PROCESS_PRIORITY_LOWEST 31 ///< 进程最低优先级
/**
* @ingroup los_process
* The highest priority of a user mode process.
*/
#define OS_USER_PROCESS_PRIORITY_HIGHEST 10
#define OS_USER_PROCESS_PRIORITY_HIGHEST 10 ///< 内核模式和用户模式的优先级分割线 10-31 用户级, 0-9内核级
/**
* @ingroup los_process
* The lowest priority of a user mode process
*/
#define OS_USER_PROCESS_PRIORITY_LOWEST OS_PROCESS_PRIORITY_LOWEST
#define OS_USER_PROCESS_PRIORITY_LOWEST OS_PROCESS_PRIORITY_LOWEST ///< 用户进程的最低优先级
/**
* @ingroup los_process
* User state root process default priority
*/
#define OS_PROCESS_USERINIT_PRIORITY 28
#define OS_PROCESS_USERINIT_PRIORITY 28 ///< 用户进程默认的优先级,28级好低啊
/**
* @ingroup los_process
* ID of the kernel idle process
*/
#define OS_KERNEL_IDLE_PROCESS_ID 0U
#define OS_KERNEL_IDLE_PROCESS_ID 0U //0号进程为空闲进程
/**
* @ingroup los_process
* ID of the user root process
*/
#define OS_USER_ROOT_PROCESS_ID 1U
#define OS_USER_ROOT_PROCESS_ID 1U //1号为用户态根进程
/**
* @ingroup los_process
* ID of the kernel root process
*/
#define OS_KERNEL_ROOT_PROCESS_ID 2U
#define OS_KERNEL_ROOT_PROCESS_ID 2U //1号为内核态根进程
#define OS_TASK_DEFAULT_STACK_SIZE 0x2000 ///< task默认栈大小 8K
#define OS_USER_TASK_SYSCALL_STACK_SIZE 0x3000 ///< 用户通过系统调用的栈大小 12K ,这时是运行在内核模式下
#define OS_USER_TASK_STACK_SIZE 0x100000 ///< 用户任务运行在用户空间的栈大小 1M
#define OS_TASK_DEFAULT_STACK_SIZE 0x2000
#define OS_USER_TASK_SYSCALL_STACK_SIZE 0x3000
#define OS_USER_TASK_STACK_SIZE 0x100000
#define OS_KERNEL_MODE 0x0U
#define OS_USER_MODE 0x1U
#define OS_KERNEL_MODE 0x0U ///< 内核态
#define OS_USER_MODE 0x1U ///< 用户态
/*! 用户态进程*/
STATIC INLINE BOOL OsProcessIsUserMode(const LosProcessCB *processCB)
{
return (processCB->processMode == OS_USER_MODE);
}
#define LOS_PRIO_PROCESS 0U
#define LOS_PRIO_PGRP 1U
#define LOS_PRIO_USER 2U
#define LOS_PRIO_PROCESS 0U ///< 进程标识
#define LOS_PRIO_PGRP 1U ///< 进程组标识
#define LOS_PRIO_USER 2U ///< 用户标识
#define OS_USER_PRIVILEGE_PROCESS_GROUP ((UINTPTR)OsGetUserInitProcess())
#define OS_KERNEL_PROCESS_GROUP ((UINTPTR)OsGetKernelInitProcess())
@ -353,40 +357,40 @@ STATIC INLINE BOOL OsProcessIsUserMode(const LosProcessCB *processCB)
* 31 15 8 7 0
* | | exit code | core dump | signal |
*/
#define OS_PRO_EXIT_OK 0
#define OS_PRO_EXIT_OK 0 ///< 进程正常退出
/// 置进程退出码第七位为1
STATIC INLINE VOID OsProcessExitCodeCoreDumpSet(LosProcessCB *processCB)
{
processCB->exitCode |= 0x80U;
processCB->exitCode |= 0x80U; // 0b10000000
}
/// 设置进程退出信号(0 ~ 7)
STATIC INLINE VOID OsProcessExitCodeSignalSet(LosProcessCB *processCB, UINT32 signal)
{
processCB->exitCode |= signal & 0x7FU;
processCB->exitCode |= signal & 0x7FU;// 0b01111111
}
/// 清除进程退出信号(0 ~ 7)
STATIC INLINE VOID OsProcessExitCodeSignalClear(LosProcessCB *processCB)
{
processCB->exitCode &= (~0x7FU);
processCB->exitCode &= (~0x7FU);// 低7位全部清0
}
/// 进程退出码是否被设置过,默认是 0 ,如果 & 0x7FU 还是 0 ,说明没有被设置过.
STATIC INLINE BOOL OsProcessExitCodeSignalIsSet(LosProcessCB *processCB)
{
return (processCB->exitCode) & 0x7FU;
}
/// 设置进程退出号(8 ~ 15)
STATIC INLINE VOID OsProcessExitCodeSet(LosProcessCB *processCB, UINT32 code)
{
processCB->exitCode |= ((code & 0x000000FFU) << 8U) & 0x0000FF00U; /* 8: Move 8 bits to the left, exitCode */
}
#define OS_PID_CHECK_INVALID(pid) (((UINT32)(pid)) >= g_processMaxNum)
/*! 内联函数 进程ID是否有效 */
STATIC INLINE BOOL OsProcessIDUserCheckInvalid(UINT32 pid)
{
return ((pid >= g_processMaxNum) || (pid == 0));
}
/*! 获取当前进程PCB */
STATIC INLINE LosProcessCB *OsCurrProcessGet(VOID)
{
UINT32 intSave;
@ -398,6 +402,7 @@ STATIC INLINE LosProcessCB *OsCurrProcessGet(VOID)
}
#ifdef LOSCFG_SECURITY_CAPABILITY
/*! 获取当前进程的所属用户 */
STATIC INLINE User *OsCurrUserGet(VOID)
{
User *user = NULL;
@ -469,14 +474,14 @@ STATIC INLINE UINT32 OsGetRootPid(const LosProcessCB *processCB)
/*
* return immediately if no child has exited.
*/
#define LOS_WAIT_WNOHANG (1 << 0U)
#define LOS_WAIT_WNOHANG (1 << 0U) ///< 如果没有孩子进程退出,则立即返回,而不是阻塞在这个函数上等待;如果结束了,则返回该子进程的进程号。
/*
* return if a child has stopped (but not traced via ptrace(2)).
* Status for traced children which have stopped is provided even
* if this option is not specified.
*/
#define LOS_WAIT_WUNTRACED (1 << 1U)
#define LOS_WAIT_WUNTRACED (1 << 1U) ///< 如果子进程进入暂停情况则马上返回不予以理会结束状态。untraced
#define LOS_WAIT_WSTOPPED (1 << 1U)
/*
@ -488,7 +493,7 @@ STATIC INLINE UINT32 OsGetRootPid(const LosProcessCB *processCB)
* return if a stopped child has been resumed by delivery of SIGCONT.
* (For Linux-only options, see below.)
*/
#define LOS_WAIT_WCONTINUED (1 << 3U)
#define LOS_WAIT_WCONTINUED (1 << 3U) ///< 可获取子进程恢复执行的状态也就是可获取continued状态 continued
/*
* Leave the child in a waitable state;
@ -499,30 +504,30 @@ STATIC INLINE UINT32 OsGetRootPid(const LosProcessCB *processCB)
/*
* Indicates that you are already in a wait state
*/
#define OS_PROCESS_WAIT (1 << 15U)
#define OS_PROCESS_WAIT (1 << 15U) ///< 表示已经处于等待状态
/*
* Wait for any child process to finish
*/
#define OS_PROCESS_WAIT_ANY OS_TASK_WAIT_ANYPROCESS
#define OS_PROCESS_WAIT_ANY OS_TASK_WAIT_ANYPROCESS ///< 等待任意子进程完成
/*
* Wait for the child process specified by the pid to finish
*/
#define OS_PROCESS_WAIT_PRO OS_TASK_WAIT_PROCESS
#define OS_PROCESS_WAIT_PRO OS_TASK_WAIT_PROCESS ///< 等待pid指定的子进程完成
/*
* Waits for any child process in the specified process group to finish.
*/
#define OS_PROCESS_WAIT_GID OS_TASK_WAIT_GID
#define OS_PROCESS_WAIT_GID OS_TASK_WAIT_GID ///< 等待指定进程组中的任意子进程完成
#define OS_PROCESS_INFO_ALL 1
#define OS_PROCESS_DEFAULT_UMASK 0022
extern UINTPTR __user_init_entry;
extern UINTPTR __user_init_bss;
extern UINTPTR __user_init_end;
extern UINTPTR __user_init_load_addr;
#define OS_PROCESS_DEFAULT_UMASK 0022 ///< 系统默认的用户掩码(umask),大多数的Linux系统的默认掩码为022。
//用户掩码的作用是用户在创建文件时从文件的默认权限中去除掩码中的权限。所以文件创建之后的权限实际为:创建文件的权限为0666-0022=0644。创建文件夹的权限为0777-0022=0755
extern UINTPTR __user_init_entry; ///< 第一个用户态进程(init)的入口地址 查看 LITE_USER_SEC_ENTRY
extern UINTPTR __user_init_bss; ///< 查看 LITE_USER_SEC_BSS ,赋值由liteos.ld完成
extern UINTPTR __user_init_end; ///< init 进程的用户空间初始化结束地址
extern UINTPTR __user_init_load_addr;///< init 进程的加载地址 ,由链接器赋值
extern UINT32 OsProcessInit(VOID);
extern UINT32 OsSystemProcessCreate(VOID);
extern VOID OsProcessNaturalExit(LosProcessCB *processCB, UINT32 status);

@ -39,16 +39,35 @@
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
/**
* @brief @note_pic
* @verbatim
鸿
|<-----,2---->|
+------------+------------------------------------------------------------+
| | |---------------|---------------| |
| | |---------------|---------------| |
| | |---------------|---------------| |
+-------------------------------------------------------------------------+
| | ^ ^ |
|<> | | | |
| | |head |tail |
| + + + |
| |
| |
+<-------------+ ,, +------------->+
* @endverbatim
*/
typedef enum {
OS_QUEUE_READ = 0,
OS_QUEUE_WRITE = 1,
OS_QUEUE_READ = 0, ///< 读队列
OS_QUEUE_WRITE = 1, ///< 写队列
OS_QUEUE_N_RW = 2
} QueueReadWrite;
typedef enum {
OS_QUEUE_HEAD = 0,
OS_QUEUE_TAIL = 1
OS_QUEUE_HEAD = 0, ///< 队列头部标识
OS_QUEUE_TAIL = 1 ///< 队列尾部标识
} QueueHeadTail;
#define OS_QUEUE_OPERATE_TYPE(ReadOrWrite, HeadOrTail) (((UINT32)(HeadOrTail) << 1) | (ReadOrWrite))
@ -64,18 +83,21 @@ typedef enum {
/**
* @ingroup los_queue
* Queue information block structure
* @attention
*/
typedef struct TagQueueCB {
UINT8 *queueHandle; /**< Pointer to a queue handle */
UINT16 queueState; /**< Queue state */
UINT16 queueLen; /**< Queue length */
UINT16 queueSize; /**< Node size */
UINT32 queueID; /**< queueID */
UINT16 queueHead; /**< Node head */
UINT16 queueTail; /**< Node tail */
UINT16 readWriteableCnt[OS_QUEUE_N_RW]; /**< Count of readable or writable resources, 0:readable, 1:writable */
LOS_DL_LIST readWriteList[OS_QUEUE_N_RW]; /**< the linked list to be read or written, 0:readlist, 1:writelist */
LOS_DL_LIST memList; /**< Pointer to the memory linked list */
typedef struct TagQueueCB{
UINT8 *queueHandle; /**< Pointer to a queue handle | 队列消息内存空间的指针*/
UINT16 queueState; /**< Queue state | 队列状态*/
UINT16 queueLen; /**< Queue length | 队列中消息节点个数,即队列长度,由创建时确定,不再改变*/
UINT16 queueSize; /**< Node size | 消息节点大小,由创建时确定,不再改变,即定义了每个消息长度的上限.*/
UINT32 queueID; /**< queueID | 队列ID*/
UINT16 queueHead; /**< Node head | 消息头节点位置(数组下标)*/
UINT16 queueTail; /**< Node tail | 消息尾节点位置(数组下标)*/
UINT16 readWriteableCnt[OS_QUEUE_N_RW]; /**< Count of readable or writable resources, 0:readable, 1:writable
| 01*/
LOS_DL_LIST readWriteList[OS_QUEUE_N_RW]; /**< the linked list to be read or written, 0:readlist, 1:writelist
| /01*/
LOS_DL_LIST memList; /**< Pointer to the memory linked list | 内存块链表*/
} LosQueueCB;
/* queue state */
@ -83,13 +105,13 @@ typedef struct TagQueueCB {
* @ingroup los_queue
* Message queue state: not in use.
*/
#define OS_QUEUE_UNUSED 0
#define OS_QUEUE_UNUSED 0 ///< 队列没有使用
/**
* @ingroup los_queue
* Message queue state: used.
*/
#define OS_QUEUE_INUSED 1
#define OS_QUEUE_INUSED 1 ///< 队列被使用
/**
* @ingroup los_queue

@ -1,6 +1,6 @@
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2022 Huawei Device Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
@ -41,14 +41,14 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
#define OS_RWLOCK_MAGIC 0xEFDCAU
#define OS_RWLOCK_MAGIC 0xEFDCAU ///< 读写锁魔法数字
enum RwlockMode {
RWLOCK_NONE_MODE,
RWLOCK_READ_MODE,
RWLOCK_WRITE_MODE,
RWLOCK_READFIRST_MODE,
RWLOCK_WRITEFIRST_MODE
RWLOCK_NONE_MODE, ///< 自由模式: 读写链表都没有内容
RWLOCK_READ_MODE, ///< 读模式: 读链表有数据,写链表没有数据
RWLOCK_WRITE_MODE, ///< 写模式: 写链表有数据,读链表没有数据
RWLOCK_READFIRST_MODE, ///< 读优先模式: 读链表中的任务最高优先级高于写链表中任务最高优先级
RWLOCK_WRITEFIRST_MODE ///< 写优先模式: 写链表中的任务最高优先级高于读链表中任务最高优先级
};
extern UINT32 OsRwlockRdUnsafe(LosRwlock *rwlock, UINT32 timeout);

@ -1,6 +1,6 @@
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2023 Huawei Device Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
@ -62,8 +62,8 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
#define OS_SCHED_MINI_PERIOD (OS_SYS_CLOCK / LOSCFG_BASE_CORE_TICK_PER_SECOND_MINI)
#define OS_TICK_RESPONSE_PRECISION (UINT32)((OS_SCHED_MINI_PERIOD * 75) / 100)
#define OS_SCHED_MINI_PERIOD (OS_SYS_CLOCK / LOSCFG_BASE_CORE_TICK_PER_SECOND_MINI) ///< 1毫秒的时钟周期
#define OS_TICK_RESPONSE_PRECISION (UINT32)((OS_SCHED_MINI_PERIOD * 75) / 100) ///< 不明白为啥是 * 75 就精确了??? @note_thinking
#define OS_SCHED_MAX_RESPONSE_TIME OS_SORT_LINK_INVALID_TIME
#define OS_SCHED_TICK_TO_CYCLE(ticks) ((UINT64)ticks * OS_CYCLE_PER_TICK)
#define AFFI_MASK_TO_CPUID(mask) ((UINT16)((mask) - 1))
@ -78,30 +78,30 @@ extern UINT32 g_taskScheduled;
typedef struct TagTaskCB LosTaskCB;
typedef BOOL (*SCHED_TL_FIND_FUNC)(UINTPTR, UINTPTR);
//获取当前调度经历了多少个时间周期
STATIC INLINE UINT64 OsGetCurrSchedTimeCycle(VOID)
{
return HalClockGetCycles();
}
typedef enum {
INT_NO_RESCH = 0x0, /* no needs to schedule */
INT_PEND_RESCH = 0x1, /* pending schedule flag */
INT_PEND_TICK = 0x2, /* pending tick */
INT_NO_RESCH = 0x0, /* no needs to schedule | 无需调度*/
INT_PEND_RESCH = 0x1, /* pending schedule flag | 因阻塞而引起的调度*/
INT_PEND_TICK = 0x2, /* pending tick | 因Tick而引起的调度*/
} SchedFlag;
#define OS_PRIORITY_QUEUE_NUM 32
#define OS_PRIORITY_QUEUE_NUM 32 //队列优先级
typedef struct {
LOS_DL_LIST priQueList[OS_PRIORITY_QUEUE_NUM];
UINT32 readyTasks[OS_PRIORITY_QUEUE_NUM];
UINT32 queueBitmap;
LOS_DL_LIST priQueList[OS_PRIORITY_QUEUE_NUM]; //任务
UINT32 readyTasks[OS_PRIORITY_QUEUE_NUM]; //已就绪任务
UINT32 queueBitmap; //位图
} HPFQueue;
typedef struct {
HPFQueue queueList[OS_PRIORITY_QUEUE_NUM];
HPFQueue queueList[OS_PRIORITY_QUEUE_NUM]; //
UINT32 queueBitmap;
} HPFRunqueue;
//调度运行队列
typedef struct {
LOS_DL_LIST root;
LOS_DL_LIST waitList;
@ -119,10 +119,10 @@ typedef struct {
UINT32 schedFlag; /* pending scheduler flag */
} SchedRunqueue;
extern SchedRunqueue g_schedRunqueue[LOSCFG_KERNEL_CORE_NUM];
extern SchedRunqueue g_schedRunqueue[LOSCFG_KERNEL_CORE_NUM];//每个CPU核都有一个属于自己的调度队列
VOID OsSchedExpireTimeUpdate(VOID);
//获取当前CPU
STATIC INLINE SchedRunqueue *OsSchedRunqueue(VOID)
{
return &g_schedRunqueue[ArchCurrCpuid()];
@ -223,10 +223,10 @@ STATIC INLINE VOID OsSchedRunqueuePendingSet(VOID)
OsSchedRunqueue()->schedFlag |= INT_PEND_RESCH;
}
#define LOS_SCHED_NORMAL 0U
#define LOS_SCHED_FIFO 1U
#define LOS_SCHED_RR 2U
#define LOS_SCHED_IDLE 3U
#define LOS_SCHED_NORMAL 0U
#define LOS_SCHED_FIFO 1U
#define LOS_SCHED_RR 2U
#define LOS_SCHED_IDLE 3U
#define LOS_SCHED_DEADLINE 6U
typedef struct {
@ -242,19 +242,21 @@ typedef struct {
UINT32 periodUs;
} SchedParam;
typedef struct {
UINT16 policy; /* This field must be present for all scheduling policies and must be the first in the structure */
UINT16 basePrio;
UINT16 priority;
UINT32 initTimeSlice; /* cycle */
UINT32 priBitmap; /* Bitmap for recording the change of task priority, the priority can not be greater than 31 */
typedef struct {//记录任务调度信息
UINT16 policy; /* This field must be present for all scheduling policies and must be the first in the structure
| */
UINT16 basePrio; ///< 起始优先级
UINT16 priority; ///< 当前优先级
UINT32 initTimeSlice;///< 初始化时间片
UINT32 priBitmap; /**< Bitmap for recording the change of task priority, the priority can not be greater than 31
| 31 */
} SchedHPF;
#define EDF_UNUSED 0
#define EDF_NEXT_PERIOD 1
#define EDF_WAIT_FOREVER 2
#define EDF_INIT 3
typedef struct {
typedef struct { //调度策略
UINT16 policy;
UINT16 cpuid;
UINT32 flags;
@ -267,29 +269,29 @@ typedef struct {
typedef struct {
union {
SchedEDF edf;
SchedHPF hpf;
SchedHPF hpf; // 目前只支持 优先级策略Highest-Priority-FirstHPF
};
} SchedPolicy;
typedef struct {
VOID (*dequeue)(SchedRunqueue *rq, LosTaskCB *taskCB);
VOID (*enqueue)(SchedRunqueue *rq, LosTaskCB *taskCB);
VOID (*start)(SchedRunqueue *rq, LosTaskCB *taskCB);
VOID (*exit)(LosTaskCB *taskCB);
typedef struct {//调度接口函数
VOID (*dequeue)(SchedRunqueue *rq, LosTaskCB *taskCB); ///< 出队列
VOID (*enqueue)(SchedRunqueue *rq, LosTaskCB *taskCB); ///< 入队列
VOID (*start)(SchedRunqueue *rq, LosTaskCB *taskCB); ///< 开始执行任务
VOID (*exit)(LosTaskCB *taskCB); ///< 任务退出
UINT64 (*waitTimeGet)(LosTaskCB *taskCB);
UINT32 (*wait)(LosTaskCB *runTask, LOS_DL_LIST *list, UINT32 timeout);
VOID (*wake)(LosTaskCB *taskCB);
BOOL (*schedParamModify)(LosTaskCB *taskCB, const SchedParam *param);
UINT32 (*schedParamGet)(const LosTaskCB *taskCB, SchedParam *param);
UINT32 (*delay)(LosTaskCB *taskCB, UINT64 waitTime);
VOID (*yield)(LosTaskCB *taskCB);
UINT32 (*suspend)(LosTaskCB *taskCB);
UINT32 (*resume)(LosTaskCB *taskCB, BOOL *needSched);
UINT64 (*deadlineGet)(const LosTaskCB *taskCB);
VOID (*timeSliceUpdate)(SchedRunqueue *rq, LosTaskCB *taskCB, UINT64 currTime);
INT32 (*schedParamCompare)(const SchedPolicy *sp1, const SchedPolicy *sp2);
VOID (*priorityInheritance)(LosTaskCB *owner, const SchedParam *param);
VOID (*priorityRestore)(LosTaskCB *owner, const LOS_DL_LIST *list, const SchedParam *param);
UINT32 (*wait)(LosTaskCB *runTask, LOS_DL_LIST *list, UINT32 timeout); ///< 任务等待
VOID (*wake)(LosTaskCB *taskCB);///< 任务唤醒
BOOL (*schedParamModify)(LosTaskCB *taskCB, const SchedParam *param);///< 修改调度参数
UINT32 (*schedParamGet)(const LosTaskCB *taskCB, SchedParam *param);///< 获取调度参数
UINT32 (*delay)(LosTaskCB *taskCB, UINT64 waitTime);///< 延时执行
VOID (*yield)(LosTaskCB *taskCB);///< 让出控制权
UINT32 (*suspend)(LosTaskCB *taskCB);///< 挂起任务
UINT32 (*resume)(LosTaskCB *taskCB, BOOL *needSched);///< 恢复任务
UINT64 (*deadlineGet)(const LosTaskCB *taskCB);///< 获取最后期限
VOID (*timeSliceUpdate)(SchedRunqueue *rq, LosTaskCB *taskCB, UINT64 currTime);///< 更新时间片
INT32 (*schedParamCompare)(const SchedPolicy *sp1, const SchedPolicy *sp2); ///< 比较调度参数
VOID (*priorityInheritance)(LosTaskCB *owner, const SchedParam *param);//继承调度参数
VOID (*priorityRestore)(LosTaskCB *owner, const LOS_DL_LIST *list, const SchedParam *param);///< 恢复调度参数
} SchedOps;
/**
@ -298,7 +300,7 @@ typedef struct {
*
* Highest task priority.
*/
#define OS_TASK_PRIORITY_HIGHEST 0
#define OS_TASK_PRIORITY_HIGHEST 0 /// 任务最高优先级
/**
* @ingroup los_sched
@ -306,7 +308,7 @@ typedef struct {
*
* Lowest task priority.
*/
#define OS_TASK_PRIORITY_LOWEST 31
#define OS_TASK_PRIORITY_LOWEST 31 /// 任务最低优先级
/**
* @ingroup los_sched
@ -314,7 +316,7 @@ typedef struct {
*
* The task is init.
*/
#define OS_TASK_STATUS_INIT 0x0001U
#define OS_TASK_STATUS_INIT 0x0001U /// 任务初始状态
/**
* @ingroup los_sched
@ -390,80 +392,80 @@ typedef struct {
* The delayed operation of this task is frozen.
*/
#define OS_TASK_STATUS_FROZEN 0x0200U
#define OS_TCB_NAME_LEN 32
typedef struct TagTaskCB {
VOID *stackPointer; /**< Task stack pointer */
UINT16 taskStatus; /**< Task status */
UINT64 startTime; /**< The start time of each phase of task */
UINT64 waitTime; /**< Task delay time, tick number */
UINT64 irqStartTime; /**< Interrupt start time */
UINT32 irqUsedTime; /**< Interrupt consumption time */
INT32 timeSlice; /**< Task remaining time slice */
SortLinkList sortList; /**< Task sortlink node */
VOID *stackPointer; /**< Task stack pointer | 内核栈指针位置(SP) */
UINT16 taskStatus; /**< Task status | 各种状态标签,可以拥有多种标签,按位标识 */
UINT64 startTime; /**< The start time of each phase of task | 任务开始时间 */
UINT64 waitTime; /**< Task delay time, tick number | 设置任务调度延期时间 */
UINT64 irqStartTime; /**< Interrupt start time | 任务中断开始时间 */
UINT32 irqUsedTime; /**< Interrupt consumption time | 任务中断消耗时间 */
INT32 timeSlice; /**< Task remaining time slice | 任务剩余时间片 */
SortLinkList sortList; /**< Task sortlink node | 跟CPU捆绑的任务排序链表节点,上面挂的是就绪队列的下一个阶段,进入CPU要执行的任务队列 */
const SchedOps *ops;
SchedPolicy sp;
UINT32 stackSize; /**< Task stack size */
UINTPTR topOfStack; /**< Task stack top */
UINT32 taskID; /**< Task ID */
TSK_ENTRY_FUNC taskEntry; /**< Task entrance function */
VOID *joinRetval; /**< pthread adaption */
VOID *taskMux; /**< Task-held mutex */
VOID *taskEvent; /**< Task-held event */
UINTPTR args[4]; /**< Parameter, of which the maximum number is 4 */
CHAR taskName[OS_TCB_NAME_LEN]; /**< Task name */
LOS_DL_LIST pendList; /**< Task pend node */
LOS_DL_LIST threadList; /**< thread list */
UINT32 eventMask; /**< Event mask */
UINT32 eventMode; /**< Event mode */
UINT32 stackSize; /**< Task stack size | 内核态栈大小,内存来自内核空间 */
UINTPTR topOfStack; /**< Task stack top | 内核态栈顶 bottom = top + size */
UINT32 taskID; /**< Task ID | 任务ID任务池本质是一个大数组ID就是数组的索引默认 < 128 */
TSK_ENTRY_FUNC taskEntry; /**< Task entrance function | 任务执行入口地址 */
VOID *joinRetval; /**< pthread adaption | 用来存储join线程的入口地址 */
VOID *taskMux; /**< Task-held mutex | task在等哪把锁 */
VOID *taskEvent; /**< Task-held event | task在等哪个事件 */
UINTPTR args[4]; /**< Parameter, of which the maximum number is 4 | 入口函数的参数 例如 main (int argc,char *argv[]) */
CHAR taskName[OS_TCB_NAME_LEN]; /**< Task name | 任务的名称 */
LOS_DL_LIST pendList; /**< Task pend node | 如果任务阻塞时就通过它挂到各种阻塞情况的链表上,比如OsTaskWait时 */
LOS_DL_LIST threadList; /**< thread list | 挂到所属进程的线程链表上 */
UINT32 eventMask; /**< Event mask | 任务对哪些事件进行屏蔽 */
UINT32 eventMode; /**< Event mode | 事件三种模式(LOS_WAITMODE_AND,LOS_WAITMODE_OR,LOS_WAITMODE_CLR) */
#ifdef LOSCFG_KERNEL_CPUP
OsCpupBase taskCpup; /**< task cpu usage */
OsCpupBase taskCpup; /**< task cpu usage | CPU 使用统计 */
#endif
INT32 errorNo; /**< Error Num */
UINT32 signal; /**< Task signal */
sig_cb sig;
INT32 errorNo; /**< Error Num | 错误序号 */
UINT32 signal; /**< Task signal | 任务信号类型,(SIGNAL_NONE,SIGNAL_KILL,SIGNAL_SUSPEND,SIGNAL_AFFI) */
sig_cb sig; ///< 信号控制块,用于异步通信,类似于 linux singal模块
#ifdef LOSCFG_KERNEL_SMP
UINT16 currCpu; /**< CPU core number of this task is running on */
UINT16 lastCpu; /**< CPU core number of this task is running on last time */
UINT16 cpuAffiMask; /**< CPU affinity mask, support up to 16 cores */
#ifdef LOSCFG_KERNEL_SMP_TASK_SYNC
UINT32 syncSignal; /**< Synchronization for signal handling */
UINT16 currCpu; /**< CPU core number of this task is running on | 正在运行此任务的CPU内核号 */
UINT16 lastCpu; /**< CPU core number of this task is running on last time | 上次运行此任务的CPU内核号 */
UINT16 cpuAffiMask; /**< CPU affinity mask, support up to 16 cores | CPU亲和力掩码最多支持16核亲和力很重要多核情况下尽量一个任务在一个CPU核上运行提高效率 */
#ifdef LOSCFG_KERNEL_SMP_TASK_SYNC //多核情况下的任务同步开关,采用信号量实现
UINT32 syncSignal; /**< Synchronization for signal handling | 用于CPU之间同步信号量 */
#endif
#ifdef LOSCFG_KERNEL_SMP_LOCKDEP
LockDep lockDep;
#ifdef LOSCFG_KERNEL_SMP_LOCKDEP //SMP死锁检测开关
LockDep lockDep; ///< 死锁依赖检测
#endif
#endif
#ifdef LOSCFG_SCHED_DEBUG
SchedStat schedStat; /**< Schedule statistics */
#ifdef LOSCFG_SCHED_DEBUG //调试调度开关
SchedStat schedStat; /**< Schedule statistics | 调度统计 */
#endif
#ifdef LOSCFG_KERNEL_VM
UINTPTR archMmu;
UINTPTR userArea;
UINTPTR userMapBase;
UINT32 userMapSize; /**< user thread stack size ,real size : userMapSize + USER_STACK_MIN_SIZE */
FutexNode futex;
UINTPTR userArea; ///< 用户空间的堆区开始位置
UINTPTR userMapBase; ///< 用户空间的栈顶位置,内存来自用户空间,和topOfStack有本质的区别.
UINT32 userMapSize; /**< user thread stack size ,real size : userMapSize + USER_STACK_MIN_SIZE | 用户栈大小 */
FutexNode futex; ///< 指明任务在等待哪把快锁,一次只等一锁,锁和任务的关系是(1:N)关系
#endif
UINTPTR processCB; /**< Which belong process */
LOS_DL_LIST joinList; /**< join list */
LOS_DL_LIST lockList; /**< Hold the lock list */
UINTPTR waitID; /**< Wait for the PID or GID of the child process */
LOS_DL_LIST joinList; /**< join list | 联结链表,允许任务之间相互释放彼此 */
LOS_DL_LIST lockList; /**< Hold the lock list | 该链表上挂的都是已持有的锁 */
UINTPTR waitID; /**< Wait for the PID or GID of the child process | 等待子进程的PID或GID */
UINT16 waitFlag; /**< The type of child process that is waiting, belonging to a group or parent,
a specific child process, or any child process */
#ifdef LOSCFG_KERNEL_LITEIPC
IpcTaskInfo *ipcTaskInfo;
a specific child process, or any child process | ? (OS_TASK_WAIT_PROCESS | OS_TASK_WAIT_GID | OS_TASK_WAIT_LITEIPC ..)
,*/
#ifdef LOSCFG_KERNEL_LITEIPC //轻量级进程间通信开关
IpcTaskInfo *ipcTaskInfo; ///< 任务间通讯信息结构体
#endif
#ifdef LOSCFG_KERNEL_PERF
UINTPTR pc;
UINTPTR fp;
UINTPTR pc; ///< pc寄存器
UINTPTR fp; ///< fp寄存器
#endif
#ifdef LOSCFG_PID_CONTAINER
PidContainer *pidContainer;
PidContainer *pidContainer;//进程容器
#endif
#ifdef LOSCFG_IPC_CONTAINER
BOOL cloneIpc;
BOOL cloneIpc;//是否克隆过IPC flags & CLONE_NEWIPC
#endif
} LosTaskCB;
@ -507,7 +509,7 @@ STATIC INLINE LosTaskCB *OsCurrTaskGet(VOID)
{
return (LosTaskCB *)ArchCurrTaskGet();
}
/// 注意任务地址由硬件保存,见于 CP15 | TPIDRPRW
STATIC INLINE VOID OsCurrTaskSet(LosTaskCB *task)
{
ArchCurrTaskSet(task);
@ -521,13 +523,13 @@ STATIC INLINE VOID OsCurrUserTaskSet(UINTPTR thread)
STATIC INLINE VOID OsSchedIrqUsedTimeUpdate(VOID)
{
LosTaskCB *runTask = OsCurrTaskGet();
runTask->irqUsedTime = OsGetCurrSchedTimeCycle() - runTask->irqStartTime;
runTask->irqUsedTime = OsGetCurrSchedTimeCycle() - runTask->irqStartTime;//获取时间差
}
/// 获取中断开始时间
STATIC INLINE VOID OsSchedIrqStartTime(VOID)
{
LosTaskCB *runTask = OsCurrTaskGet();
runTask->irqStartTime = OsGetCurrSchedTimeCycle();
runTask->irqStartTime = OsGetCurrSchedTimeCycle(); //获取当前时间
}
#ifdef LOSCFG_KERNEL_SMP
@ -654,11 +656,11 @@ STATIC INLINE VOID SchedTaskUnfreeze(LosTaskCB *taskCB)
#define OS_SCHEDULER_SET(cpuid) do { \
g_taskScheduled |= (1U << (cpuid)); \
} while (0);
//清楚调度标识位,对应位设置为0
#define OS_SCHEDULER_CLR(cpuid) do { \
g_taskScheduled &= ~(1U << (cpuid)); \
} while (0);
//获取最高优先级任务
#ifdef LOSCFG_KERNEL_SCHED_PLIMIT
BOOL OsSchedLimitCheckTime(LosTaskCB *task);
#endif

@ -46,7 +46,7 @@ extern UINT32 OsSemDbgInit(VOID);
STATIC INLINE UINT32 OsSemDbgInitHook(VOID)
{
#ifdef LOSCFG_DEBUG_SEMAPHORE
return OsSemDbgInit();
return OsSemDbgInit();//信号量debug初始化
#else
return LOS_OK;
#endif

@ -45,11 +45,11 @@ extern "C" {
* Semaphore control structure.
*/
typedef struct {
UINT8 semStat; /**< Semaphore state */
UINT16 semCount; /**< Number of available semaphores */
UINT16 maxSemCount; /**< Max number of available semaphores */
UINT32 semID; /**< Semaphore control structure ID */
LOS_DL_LIST semList; /**< Queue of tasks that are waiting on a semaphore */
UINT8 semStat; /**< Semaphore state | 信号量的状态 */
UINT16 semCount; /**< Number of available semaphores | 有效信号量的数量 */
UINT16 maxSemCount; /**< Max number of available semaphores | 有效信号量的最大数量 */
UINT32 semID; /**< Semaphore control structure ID | 信号量索引号 */
LOS_DL_LIST semList; /**< Queue of tasks that are waiting on a semaphore | 挂接阻塞于该信号量的任务 */
} LosSemCB;
/**

@ -1,6 +1,6 @@
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2023 Huawei Device Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
@ -43,15 +43,76 @@
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
/**
* @file los_signal.h
* @brief
* @verbatim
Linux
#define LOS_BIT_SET(val, bit) ((val) = (val) | (1ULL << (UINT32)(bit)))
#define LOS_BIT_CLR(val, bit) ((val) = (val) & ~(1ULL << (UINT32)(bit)))
#define LOS_IS_BIT_SET(val, bit) (bool)((((val) >> (UINT32)(bit)) & 1ULL))
signal
kill
: ..\third_party\musl\arch\aarch64\bits\signal.h
#define SIGHUP 1 //终端挂起或者控制进程终止
#define SIGINT 2 //键盘中断如break键被按下
#define SIGQUIT 3 //键盘的退出键被按下
#define SIGILL 4 //非法指令
#define SIGTRAP 5 //跟踪陷阱trace trap启动进程跟踪代码的执行
#define SIGABRT 6 //由abort(3)发出的退出指令
#define SIGIOT SIGABRT //abort发出的信号
#define SIGBUS 7 //总线错误
#define SIGFPE 8 //浮点异常
#define SIGKILL 9 //常用的命令 kill 9 123 | 不能被忽略、处理和阻塞
#define SIGUSR1 10 //用户自定义信号1
#define SIGSEGV 11 //无效的内存引用, 段违例segmentation violation进程试图去访问其虚地址空间以外的位置
#define SIGUSR2 12 //用户自定义信号2
#define SIGPIPE 13 //向某个非读管道中写入数据
#define SIGALRM 14 //由alarm(2)发出的信号,默认行为为进程终止
#define SIGTERM 15 //终止信号, kill不带参数时默认发送这个信号
#define SIGSTKFLT 16 //栈溢出
#define SIGCHLD 17 //子进程结束信号
#define SIGCONT 18 //进程继续(曾被停止的进程)
#define SIGSTOP 19 //终止进程 | 不能被忽略、处理和阻塞
#define SIGTSTP 20 //控制终端tty上 按下停止键
#define SIGTTIN 21 //进程停止,后台进程企图从控制终端读
#define SIGTTOU 22 //进程停止,后台进程企图从控制终端写
#define SIGURG 23 //I/O有紧急数据到达当前进程
#define SIGXCPU 24 //进程的CPU时间片到期
#define SIGXFSZ 25 //文件大小的超出上限
#define SIGVTALRM 26 //虚拟时钟超时
#define SIGPROF 27 //profile时钟超时
#define SIGWINCH 28 //窗口大小改变
#define SIGIO 29 //I/O相关
#define SIGPOLL 29 //
#define SIGPWR 30 //电源故障,关机
#define SIGSYS 31 //系统调用中参数错,如系统调用号非法
#define SIGUNUSED SIGSYS //系统调用异常
#define _NSIG 65 //信号范围,不超过_NSIG
https://www.cnblogs.com/hoys/archive/2012/08/19/2646377.html
Musl http://musl.libc.org/
muslLinuxAPICPOSIX
广musl.
* @endverbatim
* @param pathname
* @return int
*/
#define LOS_BIT_SET(val, bit) ((val) = (val) | (1ULL << (UINT32)(bit))) ///< 按位设置
#define LOS_BIT_CLR(val, bit) ((val) = (val) & ~(1ULL << (UINT32)(bit))) ///< 按位清除
#define LOS_IS_BIT_SET(val, bit) (bool)((((val) >> (UINT32)(bit)) & 1ULL)) ///< 位是否设置为1
#define SIG_STOP_VISIT 1
#define OS_KERNEL_KILL_PERMISSION 0U
#define OS_USER_KILL_PERMISSION 3U
#define OS_KERNEL_KILL_PERMISSION 0U ///< 内核态 kill 权限
#define OS_USER_KILL_PERMISSION 3U ///< 用户态 kill 权限
#define OS_RETURN_IF(expr, errcode) \
if ((expr)) { \
@ -91,20 +152,37 @@ typedef void (*sa_sighandler_t)(int);
typedef void (*sa_siginfoaction_t)(int, siginfo_t *, void *);
#define SIGNO2SET(s) ((sigset_t)1ULL << (s))
#define NULL_SIGNAL_SET ((sigset_t)0ULL)
#define FULL_SIGNAL_SET ((sigset_t)~0ULL)
#define NULL_SIGNAL_SET ((sigset_t)0ULL) ///< 信号集全部清0
#define FULL_SIGNAL_SET ((sigset_t)~0ULL) ///< 信号集全部置1
///信号ID是否有效
static inline int GOOD_SIGNO(unsigned int sig)
{
return (sig < _NSIG) ? 1 : 0;
return (sig < _NSIG) ? 1 : 0;//
}
#define MAX_SIG_ARRAY_IN_MUSL 128
#define MAX_SIG_ARRAY_IN_MUSL 128 ///< 128个信号
typedef struct {
unsigned long sig[MAX_SIG_ARRAY_IN_MUSL / sizeof(unsigned long)];
} sigset_t_l;
/***************************************************
struct sigaction {
union {
void (*sa_handler)(int); //信号处理函数——普通版
void (*sa_sigaction)(int, siginfo_t *, void *);//信号处理函数——高级版
} __sa_handler;
sigset_t sa_mask;//指定信号处理程序执行过程中需要阻塞的信号;
int sa_flags; //标示位
// SA_RESTART使被信号打断的syscall重新发起。
// SA_NOCLDSTOP使父进程在它的子进程暂停或继续运行时不会收到 SIGCHLD 信号。
// SA_NOCLDWAIT使父进程在它的子进程退出时不会收到SIGCHLD信号这时子进程如果退出也不会成为僵 尸进程。
// SA_NODEFER使对信号的屏蔽无效即在信号处理函数执行期间仍能发出这个信号。
// SA_RESETHAND信号处理之后重新设置为默认的处理方式。
// SA_SIGINFO使用sa_sigaction成员而不是sa_handler作为信号处理函数。
void (*sa_restorer)(void);
};
****************************************************/
typedef struct sigaction sigaction_t;
struct sigactq {
@ -126,7 +204,7 @@ struct sigpendq {
};
typedef struct sigpendq sigpendq_t;
struct sq_queue_s {
struct sq_queue_s {//信号队列
sq_entry_t *head;
sq_entry_t *tail;
};
@ -136,23 +214,24 @@ typedef struct SigInfoListNode {
struct SigInfoListNode *next;
siginfo_t info;
} SigInfoListNode;
/**
* @brief ()
*/
typedef struct {
sigset_t sigFlag;
sigset_t sigPendFlag;
sigset_t sigprocmask; /* Signals that are blocked */
sq_queue_t sigactionq;
LOS_DL_LIST waitList;
sigset_t sigwaitmask; /* Waiting for pending signals */
siginfo_t sigunbinfo; /* Signal info when task unblocked */
SigInfoListNode *tmpInfoListHead; /* Signal info List */
unsigned int sigIntLock;
void *sigContext;
unsigned int count;
sigset_t sigFlag; ///< 不屏蔽的信号集
sigset_t sigPendFlag; ///< 信号阻塞标签集,记录那些信号来过,任务依然阻塞的集合.即:这些信号不能唤醒任务
sigset_t sigprocmask; ///< Signals that are blocked | 任务屏蔽了哪些信号
sq_queue_t sigactionq; ///< 信号捕捉队列
LOS_DL_LIST waitList; ///< 待链表,上面挂的是等待信号到来的任务, 请查找 OsTaskWait(&sigcb->waitList, timeout, TRUE) 理解
sigset_t sigwaitmask; /*! Waiting for pending signals | 任务在等待哪些信号的到来 */
siginfo_t sigunbinfo; /*! Signal info when task unblocked | 任务解锁时的信号信息 */
SigInfoListNode *tmpInfoListHead; /*! Signal info List */
unsigned int sigIntLock;///< 信号中断锁
void *sigContext; ///< 信号上下文
unsigned int count;///< 信号数量
} sig_cb;
typedef struct ProcessCB LosProcessCB;
#define SIGEV_THREAD_ID 4
int sys_sigqueue(pid_t, int, const union sigval);

@ -42,17 +42,24 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
/*! \struct SortLinkList
*
*/
typedef struct {
LOS_DL_LIST sortLinkNode;
UINT64 responseTime;
LOS_DL_LIST sortLinkNode; ///< 排序链表,注意上面挂的是一个个等待被执行的任务/软件定时器
UINT64 responseTime; ///< 响应时间,这里提取了最近需要触发的定时器/任务的时间,见于 OsAddNode2SortLink 的实现
#ifdef LOSCFG_KERNEL_SMP
UINT32 cpuid;
UINT32 cpuid; ///< 需要哪个CPU处理
#endif
} SortLinkList;
/*! \struct SortLinkAttribute
* @brief
*/
typedef struct {
LOS_DL_LIST sortLink;
UINT32 nodeNum;
LOS_DL_LIST sortLink; ///< 排序链表,上面挂的任务/软件定时器
UINT32 nodeNum; ///< 链表结点数量
SPIN_LOCK_S spinLock; /* swtmr sort link spin lock */
} SortLinkAttribute;

@ -41,14 +41,17 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
/*! \struct StackInfo
*
*/
typedef struct {
VOID *stackTop;
UINT32 stackSize;
CHAR *stackName;
VOID *stackTop; ///< 栈顶
UINT32 stackSize; ///< 栈大小
CHAR *stackName; ///< 栈名称
} StackInfo;
#define OS_INVALID_WATERLINE 0xFFFFFFFF
#define OS_STACK_MAGIC_CHECK(topstack) (*(UINTPTR *)(topstack) == OS_STACK_MAGIC_WORD) /* 1:magic valid 0:invalid */
#define OS_STACK_MAGIC_CHECK(topstack) (*(UINTPTR *)(topstack) == OS_STACK_MAGIC_WORD) /* 1:magic valid 0:unvalid */
extern VOID OsExcStackInfo(VOID);
extern VOID OsExcStackInfoReg(const StackInfo *stackInfo, UINT32 stackNum);
@ -81,4 +84,4 @@ extern UINT32 OsStackWaterLineGet(const UINTPTR *stackBottom, const UINTPTR *sta
#endif /* __cplusplus */
#endif /* __cplusplus */
#endif /* _LOS_STACK_INFO_PRI_H */
#endif /* _LOS_STACK_INFO_PRI_H */

@ -1,6 +1,6 @@
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2023 Huawei Device Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
@ -39,7 +39,7 @@
#ifdef LOSCFG_SECURITY_VID
#include "vid_api.h"
#else
#define MAX_INVALID_TIMER_VID OS_SWTMR_MAX_TIMERID
#define MAX_INVALID_TIMER_VID OS_SWTMR_MAX_TIMERID //最大支持的软件定时器数量 < 65535
#endif
#ifdef __cplusplus
@ -52,21 +52,21 @@ extern "C" {
* @ingroup los_swtmr_pri
* Software timer state
*/
enum SwtmrState {
OS_SWTMR_STATUS_UNUSED, /**< The software timer is not used. */
OS_SWTMR_STATUS_CREATED, /**< The software timer is created. */
OS_SWTMR_STATUS_TICKING /**< The software timer is timing. */
enum SwtmrState { //定时器状态
OS_SWTMR_STATUS_UNUSED, /**< The software timer is not used. | 定时器未使用,系统在定时器模块初始化时,会将系统中所有定时器资源初始化成该状态。 */
OS_SWTMR_STATUS_CREATED, /**< The software timer is created. | 定时器创建后未启动,或已停止.定时器创建后,不处于计数状态时,定时器将变成该状态。 */
OS_SWTMR_STATUS_TICKING /**< The software timer is timing. | 定时器处于计数状态,在定时器创建后调用LOS_SwtmrStart接口启动定时器将变成该状态是定时器运行时的状态。 */
};
/**
* @ingroup los_swtmr_pri
* Structure of the callback function that handles software timer timeout
*/
typedef struct {
SWTMR_PROC_FUNC handler; /**< Callback function that handles software timer timeout */
typedef struct {//处理软件定时器超时的回调函数的结构体
SWTMR_PROC_FUNC handler; /**< Callback function that handles software timer timeout | 处理软件定时器超时的回调函数*/
UINTPTR arg; /**< Parameter passed in when the callback function
that handles software timer timeout is called */
LOS_DL_LIST node;
that handles software timer timeout is called | */
LOS_DL_LIST node; ///< 挂入定时器超时队列,详见 SwtmrWake( ... )
#ifdef LOSCFG_SWTMR_DEBUG
UINT32 swtmrID;
#endif
@ -75,11 +75,12 @@ typedef struct {
/**
* @ingroup los_swtmr_pri
* Type of the pointer to the structure of the callback function that handles software timer timeout
*/
*/ //指向处理软件计时器超时的回调函数结构的指针的类型
typedef SwtmrHandlerItem *SwtmrHandlerItemPtr;
extern SWTMR_CTRL_S *g_swtmrCBArray;
extern SWTMR_CTRL_S *g_swtmrCBArray;//软件定时器数组,后续统一注解为定时器池
//通过参数ID找到对应定时器描述体
#define OS_SWT_FROM_SID(swtmrID) ((SWTMR_CTRL_S *)g_swtmrCBArray + ((swtmrID) % LOSCFG_BASE_CORE_SWTMR_LIMIT))
/**

@ -43,63 +43,62 @@ extern "C" {
/**
* @ingroup los_sys
* Number of milliseconds in one second.
* Number of milliseconds in one second.
*/
#define OS_SYS_MS_PER_SECOND 1000
#define OS_SYS_MS_PER_SECOND 1000 ///< 一秒多少毫秒
/**
* @ingroup los_sys
* Number of microseconds in one second.
*/
#define OS_SYS_US_PER_SECOND 1000000
#define OS_SYS_US_PER_SECOND 1000000 ///< 一秒多少微秒
/**
* @ingroup los_sys
* Number of nanoseconds in one second.
*/
#define OS_SYS_NS_PER_SECOND 1000000000
#define OS_SYS_NS_PER_SECOND 1000000000 ///< 一秒多少纳秒
/**
* @ingroup los_sys
* Number of microseconds in one milliseconds.
*/
#define OS_SYS_US_PER_MS 1000
#define OS_SYS_US_PER_MS 1000 ///< 一毫秒的微秒数
/**
* @ingroup los_sys
* Number of nanoseconds in one milliseconds.
*/
#define OS_SYS_NS_PER_MS 1000000
#define OS_SYS_NS_PER_MS 1000000 ///< 一毫秒的纳秒数
/**
* @ingroup los_sys
* Number of nanoseconds in one microsecond.
*/
#define OS_SYS_NS_PER_US 1000
#define OS_SYS_NS_PER_US 1000 ///< 一微秒的纳秒数
/**
* @ingroup los_sys
* Number of cycle in one tick.
*/
#define OS_CYCLE_PER_TICK (OS_SYS_CLOCK / LOSCFG_BASE_CORE_TICK_PER_SECOND)
#define OS_CYCLE_PER_TICK (OS_SYS_CLOCK / LOSCFG_BASE_CORE_TICK_PER_SECOND) ///< 一个节拍的周期数
/**
* @ingroup los_sys
* Number of nanoseconds in one cycle.
*/
#define OS_NS_PER_CYCLE (OS_SYS_NS_PER_SECOND / OS_SYS_CLOCK)
#define OS_NS_PER_CYCLE (OS_SYS_NS_PER_SECOND / OS_SYS_CLOCK) ///< 一周期的纳秒数
/**
* @ingroup los_sys
* Number of microseconds in one tick.
*/
#define OS_US_PER_TICK (OS_SYS_US_PER_SECOND / LOSCFG_BASE_CORE_TICK_PER_SECOND)
#define OS_US_PER_TICK (OS_SYS_US_PER_SECOND / LOSCFG_BASE_CORE_TICK_PER_SECOND) ///< 一个tick的微秒数
/**
* @ingroup los_sys
* Number of nanoseconds in one tick.
*/
#define OS_NS_PER_TICK (OS_SYS_NS_PER_SECOND / LOSCFG_BASE_CORE_TICK_PER_SECOND)
#define OS_NS_PER_TICK (OS_SYS_NS_PER_SECOND / LOSCFG_BASE_CORE_TICK_PER_SECOND) ///< 一个tick的纳秒数
#define OS_US_TO_CYCLE(time, freq) ((((time) / OS_SYS_US_PER_SECOND) * (freq)) + \
(((time) % OS_SYS_US_PER_SECOND) * (freq) / OS_SYS_US_PER_SECOND))
@ -115,19 +114,19 @@ extern "C" {
* @ingroup los_sys
* The maximum length of name.
*/
#define OS_SYS_APPVER_NAME_MAX 64
#define OS_SYS_APPVER_NAME_MAX 64 ///< 名字的最大长度
/**
* @ingroup los_sys
* The magic word.
*/
#define OS_SYS_MAGIC_WORD 0xAAAAAAAA
#define OS_SYS_MAGIC_WORD 0xAAAAAAAA ///< 魔法数字,还记得栈顶的魔法数字是多少吗? 0xCCCCCCCC
/**
* @ingroup los_sys
* The initialization value of stack space.
*/
#define OS_SYS_EMPTY_STACK 0xCACACACA
#define OS_SYS_EMPTY_STACK 0xCACACACA ///< 栈的填充内容魔法数字
/**
* @ingroup los_sys

@ -1,6 +1,6 @@
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2023 Huawei Device Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
@ -43,17 +43,17 @@ extern "C" {
/**
* @ingroup los_task
* Define task signal types.
* Define task siginal types.
*
* Task signal types.
* Task siginal types.
*/
#define SIGNAL_NONE 0U
#define SIGNAL_KILL (1U << 0)
#define SIGNAL_SUSPEND (1U << 1)
#define SIGNAL_AFFI (1U << 2)
#define SIGNAL_NONE 0U ///< 无信号
#define SIGNAL_KILL (1U << 0) ///< 干掉
#define SIGNAL_SUSPEND (1U << 1) ///< 挂起
#define SIGNAL_AFFI (1U << 2) ///< CPU 亲和性,一个任务被切换后被同一个CPU再次执行,则亲和力高
/* scheduler lock */
extern SPIN_LOCK_S g_taskSpin;
extern SPIN_LOCK_S g_taskSpin;//任务自旋锁
#define SCHEDULER_HELD() LOS_SpinHeld(&g_taskSpin)
#define SCHEDULER_LOCK(state) LOS_SpinLockSave(&g_taskSpin, &(state))
#define SCHEDULER_UNLOCK(state) LOS_SpinUnlockRestore(&g_taskSpin, state)
@ -66,7 +66,7 @@ extern SPIN_LOCK_S g_taskSpin;
* Null task ID
*
*/
#define OS_TASK_ERRORID 0xFFFFFFFF
#define OS_TASK_ERRORID 0xFFFFFFFF
/**
* @ingroup los_task
@ -74,7 +74,7 @@ extern SPIN_LOCK_S g_taskSpin;
*
* The task control block is unused.
*/
#define OS_TASK_STATUS_UNUSED 0x0400U
#define OS_TASK_STATUS_UNUSED 0x0400U ///< 任务状态:未使用
/**
* @ingroup los_task
@ -82,7 +82,7 @@ extern SPIN_LOCK_S g_taskSpin;
*
* The task is joinable.
*/
#define OS_TASK_FLAG_PTHREAD_JOIN 0x0800U
#define OS_TASK_FLAG_PTHREAD_JOIN 0x0800U ///< 主task和子task连在一块不分离
/**
* @ingroup los_task
@ -98,15 +98,15 @@ extern SPIN_LOCK_S g_taskSpin;
*
* The task is system-level task, like idle, swtmr and etc.
*/
#define OS_TASK_FLAG_SYSTEM_TASK 0x2000U
#define OS_TASK_FLAG_SYSTEM_TASK 0x2000U ///< 系统任务
/**
* @ingroup los_task
* Flag that indicates the task property.
*
* The task is no-delete system task, like resourceTask.
* The task is no-delete system task, like resourceTask.
*/
#define OS_TASK_FLAG_NO_DELETE 0x4000U
#define OS_TASK_FLAG_NO_DELETE 0x4000U ///< 该任务是不可删除的系统任务,如资源回收任务
/**
* @ingroup los_task
@ -114,7 +114,7 @@ extern SPIN_LOCK_S g_taskSpin;
*
* Kills the thread during process exit.
*/
#define OS_TASK_FLAG_EXIT_KILL 0x8000U
#define OS_TASK_FLAG_EXIT_KILL 0x8000U ///< 在进程退出期间一同被干掉的任务
/**
* @ingroup los_task
@ -122,25 +122,25 @@ extern SPIN_LOCK_S g_taskSpin;
*
* Specifies the process creation task.
*/
#define OS_TASK_FLAG_SPECIFIES_PROCESS 0x0U
#define OS_TASK_FLAG_SPECIFIES_PROCESS 0x0U ///< 创建指定任务 例如: cat weharmony.net 的实现
/**
* @ingroup los_task
* Boundary on which the stack size is aligned.
*
*/
#define OS_TASK_STACK_SIZE_ALIGN 16U
#define OS_TASK_STACK_SIZE_ALIGN 16U ///< 堆栈大小对齐
/**
* @ingroup los_task
* Boundary on which the stack address is aligned.
*
*/
#define OS_TASK_STACK_ADDR_ALIGN 8U
#define OS_TASK_STACK_ADDR_ALIGN 8U ///< 堆栈地址对齐
/**
* @ingroup los_task
* Number of usable task priorities.
* Number of usable task priorities. |
*/
#define OS_TSK_PRINUM (OS_TASK_PRIORITY_LOWEST - OS_TASK_PRIORITY_HIGHEST + 1)
@ -175,9 +175,9 @@ extern SPIN_LOCK_S g_taskSpin;
* @par Dependency:
* <ul><li>los_task_pri.h: the header file that contains the API declaration.</li></ul>
* @see
*/
*/ ///通过pendList取出TCB,用于挂入链表节点时使用 pendList的情况
#define OS_TCB_FROM_PENDLIST(ptr) LOS_DL_LIST_ENTRY(ptr, LosTaskCB, pendList)
/**
* @ingroup los_task
* @brief Obtain the pointer to a task control block.
@ -204,56 +204,60 @@ extern SPIN_LOCK_S g_taskSpin;
#define LOSCFG_STACK_POINT_ALIGN_SIZE (sizeof(UINTPTR) * 2)
#endif
#define OS_TASK_RESOURCE_STATIC_SIZE 0x1000
#define OS_TASK_RESOURCE_FREE_PRIORITY 5
#define OS_RESOURCE_EVENT_MASK 0xFF
#define OS_RESOURCE_EVENT_OOM 0x02
#define OS_RESOURCE_EVENT_FREE 0x04
#define OS_TASK_RESOURCE_STATIC_SIZE 0x1000 ///< 4K
#define OS_TASK_RESOURCE_FREE_PRIORITY 5 ///< 回收资源任务的优先级
#define OS_RESOURCE_EVENT_MASK 0xFF ///< 资源事件的掩码
#define OS_RESOURCE_EVENT_OOM 0x02 ///< 内存溢出事件
#define OS_RESOURCE_EVENT_FREE 0x04 ///< 资源释放事件
///< LosTask结构体是给外部使用的
typedef struct {
LosTaskCB *runTask;
LosTaskCB *newTask;
} LosTask;
///< 进程信号描述符
struct ProcessSignalInfo {
siginfo_t *sigInfo; /**< Signal to be dispatched */
LosTaskCB *defaultTcb; /**< Default TCB */
LosTaskCB *unblockedTcb; /**< The signal unblock on this TCB*/
LosTaskCB *awakenedTcb; /**< This TCB was awakened */
LosTaskCB *receivedTcb; /**< This TCB received the signal */
siginfo_t *sigInfo; /**< Signal to be dispatched | 要发送的信号*/
LosTaskCB *defaultTcb; /**< Default TCB | 默认task,默认接收信号的任务. */
LosTaskCB *unblockedTcb; /**< The signal unblock on this TCB | 信号在此TCB上解除阻塞 */
LosTaskCB *awakenedTcb; /**< This TCB was awakened | 即 任务在等待这个信号,此信号一来任务被唤醒.*/
LosTaskCB *receivedTcb; /**< This TCB received the signal | 如果没有屏蔽信号,任务将接收这个信号. */
};
typedef int (*ForEachTaskCB)(LosTaskCB *tcb, void *arg);
typedef int (*ForEachTaskCB)(LosTaskCB *tcb, void *arg);///< 回调任务函数,例如:进程被kill 9 时,通知所有任务善后处理
/**
* @ingroup los_task
* Maximum number of tasks.
*
*/
extern UINT32 g_taskMaxNum;
extern UINT32 g_taskMaxNum;///< 任务最大数量 默认128个
/**
* @ingroup los_task
* Starting address of a task.
*
*/
extern LosTaskCB *g_taskCBArray;
extern LosTaskCB *g_taskCBArray;///< 外部变量 任务池 默认128个
/**
* @ingroup los_task
* Time slice structure.
*/
typedef struct {
LosTaskCB *task; /**< Current running task */
UINT16 time; /**< Expiration time point */
UINT16 timeout; /**< Expiration duration */
typedef struct {//时间片结构体,任务轮询
LosTaskCB *task; /**< Current running task | 当前运行着的任务*/
UINT16 time; /**< Expiration time point | 到期时间点*/
UINT16 timeout; /**< Expiration duration | 有效期*/
} OsTaskRobin;
/// 通过任务ID获取任务实体task由任务池分配本质是个数组彼此都挨在一块
STATIC INLINE LosTaskCB *OsGetTaskCB(UINT32 taskID)
{
return OS_TCB_FROM_TID(taskID);
}
/// 任务是否在使用
STATIC INLINE BOOL OsTaskIsUnused(const LosTaskCB *taskCB)
{
return ((taskCB->taskStatus & OS_TASK_STATUS_UNUSED) != 0);
@ -261,45 +265,46 @@ STATIC INLINE BOOL OsTaskIsUnused(const LosTaskCB *taskCB)
STATIC INLINE BOOL OsTaskIsKilled(const LosTaskCB *taskCB)
{
return((taskCB->taskStatus & OS_TASK_FLAG_EXIT_KILL) != 0);
return ((taskCB->taskStatus & OS_TASK_FLAG_EXIT_KILL) != 0);
}
STATIC INLINE BOOL OsTaskIsNotDelete(const LosTaskCB *taskCB)
{
return ((taskCB->taskStatus & (OS_TASK_STATUS_UNUSED | OS_TASK_FLAG_SYSTEM_TASK | OS_TASK_FLAG_NO_DELETE)) != 0);
}
STATIC INLINE BOOL OsTaskIsUserMode(const LosTaskCB *taskCB)
{
return ((taskCB->taskStatus & OS_TASK_FLAG_USER_MODE) != 0);
}
#define OS_TID_CHECK_INVALID(taskID) ((UINT32)(taskID) >= g_taskMaxNum)
#define OS_TID_CHECK_INVALID(taskID) ((UINT32)(taskID) >= g_taskMaxNum)//是否有无效的任务 > 128
/* get task info */
#define OS_ALL_TASK_MASK 0xFFFFFFFF
#define OS_TASK_WAIT_ANYPROCESS (1 << 0U)
#define OS_TASK_WAIT_PROCESS (1 << 1U)
#define OS_TASK_WAIT_GID (1 << 2U)
#define OS_TASK_WAIT_SEM (OS_TASK_WAIT_GID + 1)
#define OS_TASK_WAIT_QUEUE (OS_TASK_WAIT_SEM + 1)
#define OS_TASK_WAIT_JOIN (OS_TASK_WAIT_QUEUE + 1)
#define OS_TASK_WAIT_SIGNAL (OS_TASK_WAIT_JOIN + 1)
#define OS_TASK_WAIT_LITEIPC (OS_TASK_WAIT_SIGNAL + 1)
#define OS_TASK_WAIT_MUTEX (OS_TASK_WAIT_LITEIPC + 1)
#define OS_TASK_WAIT_FUTEX (OS_TASK_WAIT_MUTEX + 1)
#define OS_TASK_WAIT_EVENT (OS_TASK_WAIT_FUTEX + 1)
#define OS_TASK_WAIT_COMPLETE (OS_TASK_WAIT_EVENT + 1)
/// 任务的等待事件/信号列表
#define OS_TASK_WAIT_ANYPROCESS (1 << 0U) ///< 等待任意进程出现
#define OS_TASK_WAIT_PROCESS (1 << 1U) ///< 等待指定进程出现
#define OS_TASK_WAIT_GID (1 << 2U) ///< 等待组ID
#define OS_TASK_WAIT_SEM (OS_TASK_WAIT_GID + 1) ///< 等待信号量发生
#define OS_TASK_WAIT_QUEUE (OS_TASK_WAIT_SEM + 1) ///< 等待队列到来
#define OS_TASK_WAIT_JOIN (OS_TASK_WAIT_QUEUE + 1) ///< 等待联结到来
#define OS_TASK_WAIT_SIGNAL (OS_TASK_WAIT_JOIN + 1) ///< 等待普通信号到来
#define OS_TASK_WAIT_LITEIPC (OS_TASK_WAIT_SIGNAL + 1) ///< 等待liteipc到来
#define OS_TASK_WAIT_MUTEX (OS_TASK_WAIT_LITEIPC + 1) ///< 等待MUTEX到来
#define OS_TASK_WAIT_FUTEX (OS_TASK_WAIT_MUTEX + 1) ///< 等待FUTEX到来
#define OS_TASK_WAIT_EVENT (OS_TASK_WAIT_FUTEX + 1) ///< 等待事件发生
#define OS_TASK_WAIT_COMPLETE (OS_TASK_WAIT_EVENT + 1) ///< 等待结束信号
/// 设置事件阻塞掩码,即设置任务的等待事件.
STATIC INLINE VOID OsTaskWaitSetPendMask(UINT16 mask, UINTPTR lockID, UINT32 timeout)
{
LosTaskCB *runTask = OsCurrTaskGet();
runTask->waitID = lockID;
runTask->waitFlag = mask;
runTask->waitID = lockID; //
runTask->waitFlag = mask; //当前任务在等待什么东东到来 例如: OS_TASK_WAIT_LITEIPC
(VOID)timeout;
}
/// 清除事件阻塞掩码,即任务不再等待任何事件.
STATIC INLINE VOID OsTaskWakeClearPendMask(LosTaskCB *resumeTask)
{
resumeTask->waitID = 0;

@ -50,13 +50,13 @@ typedef struct UidGidMap {
UidGidExtent extent[UID_GID_MAP_MAX_EXTENTS];
};
} UidGidMap;
//用户容器
typedef struct UserContainer {
Atomic rc;
INT32 level;
UINT32 owner;
UINT32 group;
struct UserContainer *parent;
struct UserContainer *parent;
UidGidMap uidMap;
UidGidMap gidMap;
UINT32 containerID;

@ -39,11 +39,15 @@
typedef struct ProcessCB LosProcessCB;
struct Container;
/****************************************
* https://unix.stackexchange.com/questions/183717/whats-a-uts-namespace
* uts: UNIX Time Sharing, UNIX
* setting hostname, domainname will not affect rest of the system (CLONE_NEWUTS flag)
****************************************/
typedef struct UtsContainer {
Atomic rc;
UINT32 containerID;
struct utsname utsName;
Atomic rc; //原子操作 LDREX 和 STREX 指令保证了原子操作的底层实现
UINT32 containerID; //容器ID
struct utsname utsName; //存放系统信息的缓冲区
} UtsContainer;
UINT32 OsInitRootUtsContainer(UtsContainer **utsContainer);

@ -47,17 +47,17 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
#define OS_KHEAP_BLOCK_SIZE (512 * 1024UL)
#define OS_KHEAP_BLOCK_SIZE (512 * 1024UL) ///< 内核空间 堆内存部分大小, 512K
//记录 MMU 映射关系
typedef struct ArchMmuInitMapping {
PADDR_T phys;
VADDR_T virt;
size_t size;
unsigned int flags;
const char *name;
PADDR_T phys;///< 物理地址
VADDR_T virt;///< 虚拟地址
size_t size;///< 大小
unsigned int flags;///< 标识 读/写/.. VM_MAP_REGION_FLAG_PERM_*
const char *name;///< 名称
} LosArchMmuInitMapping;
extern LosArchMmuInitMapping g_archMmuInitMapping[];
extern LosArchMmuInitMapping g_archMmuInitMapping[];//映射关系表
extern UINTPTR g_vmBootMemBase;
extern BOOL g_kHeapInited;

@ -1,3 +1,64 @@
/*!
* @file los_vm_common.h
* @brief
* @link
@verbatim
@note_pic
鸿- USER_ASPACE_BASE USER_ASPACE_TOP_MAX
鸿: https://blog.csdn.net/kuangyufei
https://my.oschina.net/u/3751245
| /\ |
| || |
|---------------------------|KERNEL_ASPACE_BASE + KERNEL_ASPACE_SIZE
| |
| |
| |
| |
|---------------------------| KERNEL_ASPACE_BASE
| |
| 16M |
|---------------------------| USER_ASPACE_TOP_MAX = USER_ASPACE_BASE + USER_ASPACE_SIZE
| |
| stack |
| |
| || |
| || |
| || |
| \/ |
| |
|---------------------------| USER_MAP_BASE + USER_MAP_SIZE
| (,,I/O) |
| |
| |
| .so |
| |
| L1/L2 |
|---------------------------| USER_MAP_BASE = (USER_ASPACE_TOP_MAX >> 1)
| |
| |
| /\ |
| || |
| || |
| || |
| |
| heap |
| |
|---------------------------| USER_HEAP_BASE = USER_ASPACE_TOP_MAX >> 2
| |
| .bss |
| .data |
| .text |
|---------------------------| USER_ASPACE_BASE = 0x01000000UL
| |
| 16M |
|---------------------------| 0x00000000
@endverbatim
* @version
* @author weharmonyos.com | 鸿 |
* @date 2021-11-30
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
@ -43,38 +104,51 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
/* user address space, defaults to below kernel space with a 16MB guard gap on either side */
#ifndef USER_ASPACE_BASE
#define USER_ASPACE_BASE ((vaddr_t)0x01000000UL)
#ifndef USER_ASPACE_BASE ///< 用户地址空间默认为低于内核空间两侧各有16MB的保护间隙
#define USER_ASPACE_BASE ((vaddr_t)0x01000000UL) ///< 用户空间基地址 从16M位置开始 user_ram : ORIGIN = 0x1000000, LENGTH = 0x100000
#endif
#ifndef USER_ASPACE_SIZE
#define USER_ASPACE_SIZE ((vaddr_t)KERNEL_ASPACE_BASE - USER_ASPACE_BASE - 0x01000000UL)
#define USER_ASPACE_SIZE ((vaddr_t)KERNEL_ASPACE_BASE - USER_ASPACE_BASE - 0x01000000UL)///< 用户空间 < 内核空间 2个16M
#endif
#define USER_ASPACE_TOP_MAX ((vaddr_t)(USER_ASPACE_BASE + USER_ASPACE_SIZE))
#define USER_HEAP_BASE ((vaddr_t)(USER_ASPACE_TOP_MAX >> 2))
#define USER_MAP_BASE ((vaddr_t)(USER_ASPACE_TOP_MAX >> 1))
#define USER_MAP_SIZE ((vaddr_t)(USER_ASPACE_SIZE >> 3))
#define USER_ASPACE_TOP_MAX ((vaddr_t)(USER_ASPACE_BASE + USER_ASPACE_SIZE))///< 用户空间顶部位置
#define USER_HEAP_BASE ((vaddr_t)(USER_ASPACE_TOP_MAX >> 2)) ///< 堆的开始地址
#define USER_MAP_BASE ((vaddr_t)(USER_ASPACE_TOP_MAX >> 1)) ///< 用户映射区开始地址
#define USER_MAP_SIZE ((vaddr_t)(USER_ASPACE_SIZE >> 3)) ///< 用户空间映射大小 = 1/8 用户空间
#ifndef PAGE_SIZE
#define PAGE_SIZE (0x1000U)
#define PAGE_SIZE (0x1000U) ///< 页大小4K
#endif
#define PAGE_MASK (~(PAGE_SIZE - 1))
#define PAGE_SHIFT (12)
#define PAGE_MASK (~(PAGE_SIZE - 1)) ///< 页掩码,用于页内偏移地址的计算
#define PAGE_SHIFT (12)///< 12位 - 4K 偏移
#define KB (1024UL)
#define MB (1024UL * 1024UL)
#define GB (1024UL * 1024UL * 1024UL)
#define ROUNDUP(a, b) (((a) + ((b) - 1)) & ~((b) - 1))
#define ROUNDDOWN(a, b) ((a) & ~((b) - 1))
#define ROUNDOFFSET(a, b) ((a) & ((b) - 1))
#define MIN2(a, b) (((a) < (b)) ? (a) : (b))
#define IS_ALIGNED(a, b) (!(((UINTPTR)(a)) & (((UINTPTR)(b)) - 1)))
#define IS_PAGE_ALIGNED(x) IS_ALIGNED(x, PAGE_SIZE)
#define IS_SECTION_ALIGNED(x) IS_ALIGNED(x, SECTION_SIZE)
/**
* @brief
* @verbatim
:
ROUNDUP(7,4) = 8 ,ROUNDUP(8,4) = 8 ,ROUNDUP(9,4) = 12
ROUNDDOWN(7,4) = 4 ,ROUNDDOWN(8,4) = 8 ,ROUNDDOWN(9,4) = 8
ROUNDOFFSET(7,4) = 3 ,ROUNDOFFSET(8,4) = 0 ,ROUNDOFFSET(9,4) = 1
* @endverbatim
*/
#define ROUNDUP(a, b) (((a) + ((b) - 1)) & ~((b) - 1)) ///< 向上圆整
#define ROUNDDOWN(a, b) ((a) & ~((b) - 1)) ///< 向下圆整
#define ROUNDOFFSET(a, b) ((a) & ((b) - 1)) ///< 圆整偏移
#define MIN2(a, b) (((a) < (b)) ? (a) : (b)) ///< 找到最小值
#define IS_ALIGNED(a, b) (!(((UINTPTR)(a)) & (((UINTPTR)(b)) - 1)))///< 是否按指定的参数对齐
#define IS_PAGE_ALIGNED(x) IS_ALIGNED(x, PAGE_SIZE) ///< 是否按页大小对齐 4K
#define IS_SECTION_ALIGNED(x) IS_ALIGNED(x, SECTION_SIZE)///< 是否按段大小对齐
//虚拟内存的异常提示
#define LOS_ERRNO_VM_NO_ERROR (0)
#define LOS_ERRNO_VM_GENERIC (-1)
#define LOS_ERRNO_VM_NOT_FOUND (-2)

@ -55,7 +55,7 @@ typedef struct {
#define VM_MAP_PF_FLAG_USER (1U << 1)
#define VM_MAP_PF_FLAG_INSTRUCTION (1U << 2)
#define VM_MAP_PF_FLAG_NOT_PRESENT (1U << 3)
//缺页中断处理函数
STATUS_T OsVmPageFaultHandler(VADDR_T vaddr, UINT32 flags, ExcContext *frame);
#ifdef __cplusplus
#if __cplusplus

@ -1,3 +1,23 @@
/*!
* @file los_vm_filemap.h
* @brief
* @link
@verbatim
RAM 便
访访
A.
B.
C.
D.
E.
@endverbatim
* @version
* @author weharmonyos.com | 鸿 |
* @date 2021-12-9
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
@ -51,133 +71,158 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
#if 0 //@note_#if0
//page_mapping描述的是一个文件在内存中被映射了多少页,<文件,文件页的关系>
/* file mapped in VMM pages */
struct page_mapping {//记录文件页和文件关系的结构体,叫文件页映射
LOS_DL_LIST page_list; /* all pages | 链表上挂的是属于该文件的所有FilePage这些页的内容都来源同一个文件*/
SPIN_LOCK_S list_lock; /* lock protecting it | 操作page_list的自旋锁*/
LosMux mux_lock; /* mutex lock | 操作page_mapping的互斥量*/
unsigned long nrpages; /* number of total pages |page_list的节点数量 */
unsigned long flags; ///< @note_why 全量代码中也没查到源码中对其操作
Atomic ref; /* reference counting | 引用次数(自增/自减),对应add_mapping/dec_mapping*/
struct Vnode *host; /* owner of this mapping | 属于哪个文件的映射*/
};
/* map: full_path(owner) <-> mapping */ //叫文件映射
struct file_map { //为在内核层面文件在内存的身份证,每个需映射到内存的文件必须创建一个file_map都挂到全局g_file_mapping链表上
LOS_DL_LIST head; ///< 链表节点,用于挂到g_file_mapping上
LosMux lock; /* lock to protect this mapping */
struct page_mapping mapping; ///< 每个文件都有唯一的page_mapping标识其在内存的身份
char *owner; /* owner: full path of file | 文件全路径来标识唯一性*/
};
#endif
/// 文件页结构体
typedef struct FilePage {
LOS_DL_LIST node;
LOS_DL_LIST lru;
LOS_DL_LIST i_mmap; /* list of mappings */
UINT32 n_maps; /* num of mapping */
struct VmPhysSeg *physSeg; /* physical memory that file page belongs to */
struct VmPage *vmPage;
struct page_mapping *mapping;
VM_OFFSET_T pgoff;
UINT32 flags;
UINT16 dirtyOff;
UINT16 dirtyEnd;
LOS_DL_LIST node; ///< 节点,节点挂到page_mapping.page_list上,链表以 pgoff 从小到大方式排序.
LOS_DL_LIST lru; ///< lru节点, 结合 LosVmPhysSeg: LOS_DL_LIST lruList[VM_NR_LRU_LISTS] 理解
LOS_DL_LIST i_mmap; /* list of mappings | 链表记录文件页被哪些进程映射 MapInfo.node挂上来*/
UINT32 n_maps; /* num of mapping | 记录被进程映射的次数*/
struct VmPhysSeg *physSeg; /* physical memory that file page belongs to | 物理段:物理页框 = 1:N */
struct VmPage *vmPage; ///< 物理页框
struct page_mapping *mapping; ///< 此结构由文件系统提供,用于描述装入点 见于 ..\third_party\NuttX\include\nuttx\fs\fs.h
VM_OFFSET_T pgoff; ///< 页标,文件被切成一页一页读到内存
UINT32 flags; ///< 标签
UINT16 dirtyOff; ///< 脏页的页内偏移地址
UINT16 dirtyEnd; ///< 脏页的结束位置
} LosFilePage;
/// 虚拟地址和文件页的映射信息,在一个进程使用文件页之前,需要提前做好文件页在此内存空间的映射关系,如此通过虚拟内存就可以对文件页读写操作.
typedef struct MapInfo {
LOS_DL_LIST node;
VADDR_T vaddr;
LosFilePage *page;
LosArchMmu *archMmu;
LOS_DL_LIST node; ///< 节点,挂到page->i_mmap链表上.链表上记录要操作文件页的进程对这个page的映射信息
VADDR_T vaddr; ///< 虚拟地址.每个进程访问同一个文件页的虚拟地址都是不一样的
LosFilePage *page; ///< 文件页中只记录物理地址,是不会变的.但它是需要被多个进程访问,和映射的.
LosArchMmu *archMmu; ///< mmu完成vaddr和page->vmPage->physAddr物理地址的映射
} LosMapInfo;
/// Flags由 bitmap 管理
enum OsPageFlags {
FILE_PAGE_FREE,
FILE_PAGE_LOCKED,
FILE_PAGE_REFERENCED,
FILE_PAGE_DIRTY,
FILE_PAGE_LRU,
FILE_PAGE_ACTIVE,
FILE_PAGE_SHARED,
FILE_PAGE_FREE, ///< 空闲页
FILE_PAGE_LOCKED, ///< 被锁页
FILE_PAGE_REFERENCED, ///< 被引用页
FILE_PAGE_DIRTY, ///< 脏页
FILE_PAGE_LRU, ///< LRU置换页
FILE_PAGE_ACTIVE, ///< 活动页
FILE_PAGE_SHARED, ///< 共享页
};
#define PGOFF_MAX 2000
#define MAX_SHRINK_PAGECACHE_TRY 2
#define VM_FILEMAP_MAX_SCAN (SYS_MEM_SIZE_DEFAULT >> PAGE_SHIFT)
#define VM_FILEMAP_MIN_SCAN 32
#define VM_FILEMAP_MAX_SCAN (SYS_MEM_SIZE_DEFAULT >> PAGE_SHIFT) ///< 扫描文件映射页最大数量
#define VM_FILEMAP_MIN_SCAN 32 ///< 扫描文件映射页最小数量
/// 给页面贴上被锁的标签
STATIC INLINE VOID OsSetPageLocked(LosVmPage *page)
{
LOS_BitmapSet(&page->flags, FILE_PAGE_LOCKED);
}
/// 给页面撕掉被锁的标签
STATIC INLINE VOID OsCleanPageLocked(LosVmPage *page)
{
LOS_BitmapClr(&page->flags, FILE_PAGE_LOCKED);
}
/// 给页面贴上数据被修改的标签
STATIC INLINE VOID OsSetPageDirty(LosVmPage *page)
{
LOS_BitmapSet(&page->flags, FILE_PAGE_DIRTY);
}
/// 给页面撕掉数据被修改的标签
STATIC INLINE VOID OsCleanPageDirty(LosVmPage *page)
{
LOS_BitmapClr(&page->flags, FILE_PAGE_DIRTY);
}
/// 给页面贴上活动的标签
STATIC INLINE VOID OsSetPageActive(LosVmPage *page)
{
LOS_BitmapSet(&page->flags, FILE_PAGE_ACTIVE);
}
/// 给页面撕掉活动的标签
STATIC INLINE VOID OsCleanPageActive(LosVmPage *page)
{
LOS_BitmapClr(&page->flags, FILE_PAGE_ACTIVE);
}
/// 给页面贴上置换页的标签
STATIC INLINE VOID OsSetPageLRU(LosVmPage *page)
{
LOS_BitmapSet(&page->flags, FILE_PAGE_LRU);
}
/// 给页面贴上被释放的标签
STATIC INLINE VOID OsSetPageFree(LosVmPage *page)
{
LOS_BitmapSet(&page->flags, FILE_PAGE_FREE);
}
/// 给页面撕掉被释放的标签
STATIC INLINE VOID OsCleanPageFree(LosVmPage *page)
{
LOS_BitmapClr(&page->flags, FILE_PAGE_FREE);
}
/// 给页面贴上被引用的标签
STATIC INLINE VOID OsSetPageReferenced(LosVmPage *page)
{
LOS_BitmapSet(&page->flags, FILE_PAGE_REFERENCED);
}
/// 给页面撕掉被引用的标签
STATIC INLINE VOID OsCleanPageReferenced(LosVmPage *page)
{
LOS_BitmapClr(&page->flags, FILE_PAGE_REFERENCED);
}
/// 页面是否活动
STATIC INLINE BOOL OsIsPageActive(LosVmPage *page)
{
return BIT_GET(page->flags, FILE_PAGE_ACTIVE);
}
/// 页面是否被锁
STATIC INLINE BOOL OsIsPageLocked(LosVmPage *page)
{
return BIT_GET(page->flags, FILE_PAGE_LOCKED);
}
/// 页面是否被引用,只被一个进程引用的页叫私有页,多个进程引用就是共享页,此为共享内存的本质所在
STATIC INLINE BOOL OsIsPageReferenced(LosVmPage *page)
{
return BIT_GET(page->flags, FILE_PAGE_REFERENCED);
}
/// 页面是否为脏页,所谓脏页就是页内数据是否被更新过,只有脏页才会有写时拷贝
STATIC INLINE BOOL OsIsPageDirty(LosVmPage *page)
{
return BIT_GET(page->flags, FILE_PAGE_DIRTY);
}
/// 文件页是否映射过了
STATIC INLINE BOOL OsIsPageMapped(LosFilePage *page)
{
return (page->n_maps != 0);
return (page->n_maps != 0);//由映射的次数来判断
}
/* The follow three functions is used to SHM module */
/*! The follow three functions is used to SHM module | 给页面贴上共享页标签*/
STATIC INLINE VOID OsSetPageShared(LosVmPage *page)
{
LOS_BitmapSet(&page->flags, FILE_PAGE_SHARED);
LOS_BitmapSet(&page->flags, FILE_PAGE_SHARED);//设为共享页面,共享页位 置0
}
/// 给页面撕掉共享页标签
STATIC INLINE VOID OsCleanPageShared(LosVmPage *page)
{
LOS_BitmapClr(&page->flags, FILE_PAGE_SHARED);
LOS_BitmapClr(&page->flags, FILE_PAGE_SHARED);//共享页位 置0
}
/// 是否为共享页
STATIC INLINE BOOL OsIsPageShared(LosVmPage *page)
{
return BIT_GET(page->flags, FILE_PAGE_SHARED);

@ -41,9 +41,19 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
enum DmaMemType {
DMA_CACHE,
DMA_NOCACHE
/**
* @brief
* @verbatim
DMADirect Memory Access访
DMA
DMACPU
* @endverbatim
*/
enum DmaMemType {
DMA_CACHE, ///< 有缓存的DMA
DMA_NOCACHE ///< 无缓存的DMA
};
/* thread safety */

@ -46,19 +46,43 @@
#include "los_vm_common.h"
struct Vnode;
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
#if 0 // @note_#if0
file ..\third_party\NuttX\include\nuttx\fs\fs.h
struct file //打开文件的基本表示形式
{
unsigned int f_magicnum; /* file magic number */
int f_oflags; /* Open mode flags */
FAR struct inode *f_inode; /* Driver interface */
loff_t f_pos; /* File position */
unsigned long f_refcount; /* reference count */
char *f_path; /* File fullpath */
void *f_priv; /* Per file driver private data */
const char *f_relpath; /* realpath */
struct page_mapping *f_mapping; /* mapping file to memory */
void *f_dir; /* DIR struct for iterate the directory if open a directory */
};
struct page_mapping {
LOS_DL_LIST page_list; /* all pages */
SPIN_LOCK_S list_lock; /* lock protecting it */
LosMux mux_lock; /* mutex lock */
unsigned long nrpages; /* number of total pages */
unsigned long flags;
Atomic ref; /* reference counting */
struct file *host; /* owner of this mapping */
};
#endif
/* If the kernel malloc size is less than 16k, use heap, otherwise use physical pages */
#define KMALLOC_LARGE_SIZE (PAGE_SIZE << 2)
typedef struct VmMapRange {
VADDR_T base; /**< vm region base addr */
UINT32 size; /**< vm region size */
typedef struct VmMapRange {//线性区范围结构体
VADDR_T base; /**< vm region base addr | 线性区基地址*/
UINT32 size; /**< vm region size | 线性区大小*/
} LosVmMapRange;
struct VmMapRegion;
@ -67,104 +91,115 @@ struct VmFileOps;
typedef struct VmFileOps LosVmFileOps;
struct VmSpace;
typedef struct VmSpace LosVmSpace;
/// 缺页结构信息体
typedef struct VmFault {
UINT32 flags; /* FAULT_FLAG_xxx flags */
unsigned long pgoff; /* Logical page offset based on region */
VADDR_T vaddr; /* Faulting virtual address */
VADDR_T *pageKVaddr; /* KVaddr of pagefault's vm page's paddr */
UINT32 flags; /*! FAULT_FLAG_xxx flags | 缺页标识*/
unsigned long pgoff; /*! Logical page offset based on region | 基于线性区的逻辑页偏移量*/
VADDR_T vaddr; /*! Faulting virtual address | 产生缺页的虚拟地址*/
VADDR_T *pageKVaddr; /*! KVaddr of pagefault's vm page's paddr | page cache中的虚拟地址*/
} LosVmPgFault;
/// 虚拟内存文件操作函数指针,上层开发可理解为 class 里的方法,注意是对线性区的操作 , 文件操作 见于g_commVmOps
struct VmFileOps {
void (*open)(struct VmMapRegion *region);
void (*close)(struct VmMapRegion *region);
int (*fault)(struct VmMapRegion *region, LosVmPgFault *pageFault);
void (*remove)(struct VmMapRegion *region, LosArchMmu *archMmu, VM_OFFSET_T offset);
void (*open)(struct VmMapRegion *region); ///< 打开
void (*close)(struct VmMapRegion *region); ///< 关闭
int (*fault)(struct VmMapRegion *region, LosVmPgFault *pageFault); ///< 缺页,OsVmmFileFault
void (*remove)(struct VmMapRegion *region, LosArchMmu *archMmu, VM_OFFSET_T offset); ///< 删除 OsVmmFileRemove
};
/*!
线,线,线
,访.
访访,.
. .
., open ,read, write .
,,使 ,
. ,: open,read,write,close,mmap...
. malloc .
*/
struct VmMapRegion {
LosRbNode rbNode; /**< region red-black tree node */
LosVmSpace *space;
LOS_DL_LIST node; /**< region dl list */
LosVmMapRange range; /**< region address range */
VM_OFFSET_T pgOff; /**< region page offset to file */
UINT32 regionFlags; /**< region flags: cow, user_wired */
UINT32 shmid; /**< shmid about shared region */
UINT8 forkFlags; /**< vm space fork flags: COPY, ZERO, */
UINT8 regionType; /**< vm region type: ANON, FILE, DEV */
union {
struct VmRegionFile {
int f_oflags;
struct Vnode *vnode;
const LosVmFileOps *vmFOps;
LosRbNode rbNode; /**< region red-black tree node | 红黑树节点,通过它将本线性区挂在VmSpace.regionRbTree*/
LosVmSpace *space; ///< 所属虚拟空间,虚拟空间由多个线性区组成
LOS_DL_LIST node; /**< region dl list | 链表节点,通过它将本线性区挂在VmSpace.regions上 ,但最新版本没有regions了,可以删除了 */
LosVmMapRange range; /**< region address range | 记录线性区的范围*/
VM_OFFSET_T pgOff; /**< region page offset to file | 以文件开始处的偏移量, 必须是分页大小的整数倍, 通常为0, 表示从文件头开始映射。*/
UINT32 regionFlags; /**< region flags: cow, user_wired | 线性区标签*/
UINT32 shmid; /**< shmid about shared region | shmid为共享线性区id,id背后就是共享线性区*/
UINT8 forkFlags; /**< vm space fork flags: COPY, ZERO, | 线性区标记方式*/
UINT8 regionType; /**< vm region type: ANON, FILE, DEV | 映射类型是匿名,文件,还是设备,所谓匿名可理解为内存映射*/
union {
struct VmRegionFile {// <磁盘文件 , 物理内存, 用户进程虚拟地址空间 >
int f_oflags; ///< 读写标签
struct Vnode *vnode;///< 文件索引节点
const LosVmFileOps *vmFOps;///< 文件处理各操作接口,open,read,write,close,mmap
} rf;
struct VmRegionAnon {
LOS_DL_LIST node; /**< region LosVmPage list */
//匿名映射是指那些没有关联到文件页,如进程堆、栈、数据段和任务已修改的共享库等与物理内存的映射
struct VmRegionAnon {//<swap区 , 物理内存, 用户进程虚拟地址空间 >
LOS_DL_LIST node; /**< region LosVmPage list | 线性区虚拟页链表*/
} ra;
struct VmRegionDev {
LOS_DL_LIST node; /**< region LosVmPage list */
const LosVmFileOps *vmFOps;
struct VmRegionDev {//设备映射,也是一种文件
LOS_DL_LIST node; /**< region LosVmPage list | 线性区虚拟页链表*/
const LosVmFileOps *vmFOps; ///< 操作设备像操作文件一样方便.
} rd;
} unTypeData;
};
/// 虚拟空间,每个进程都有一个属于自己的虚拟内存地址空间
typedef struct VmSpace {
LOS_DL_LIST node; /**< vm space dl list */
LosRbTree regionRbTree; /**< region red-black tree root */
LosMux regionMux; /**< region red-black tree mutex lock */
VADDR_T base; /**< vm space base addr */
UINT32 size; /**< vm space size */
VADDR_T heapBase; /**< vm space heap base address */
VADDR_T heapNow; /**< vm space heap base now */
LosVmMapRegion *heap; /**< heap region */
VADDR_T mapBase; /**< vm space mapping area base */
UINT32 mapSize; /**< vm space mapping area size */
LosArchMmu archMmu; /**< vm mapping physical memory */
LOS_DL_LIST node; /**< vm space dl list | 节点,通过它挂到全局虚拟空间 g_vmSpaceList 链表上*/
LosRbTree regionRbTree; /**< region red-black tree root | 采用红黑树方式管理本空间各个线性区*/
LosMux regionMux; /**< region list mutex lock | 虚拟空间操作红黑树互斥锁*/
VADDR_T base; /**< vm space base addr | 虚拟空间的基地址,线性区的分配范围,常用于判断地址是否在内核还是用户空间*/
UINT32 size; /**< vm space size | 虚拟空间大小*/
VADDR_T heapBase; /**< vm space heap base address | 堆区基地址,指向堆区起点*/
VADDR_T heapNow; /**< vm space heap base now | 堆顶地址指向堆区终点do_brk()直接修改堆的大小返回新的堆区结束地址, heapNow >= heapBase*/
LosVmMapRegion *heap; /**< heap region | 传说中的堆区用于满足进程的动态内存需求大家熟知的malloc,realloc,free其实就是在操作这个区*/
VADDR_T mapBase; /**< vm space mapping area base | 虚拟空间映射区基地址,L1L2表存放在这个区 */
UINT32 mapSize; /**< vm space mapping area size | 虚拟空间映射区大小,映射区是个很大的区。*/
LosArchMmu archMmu; /**< vm mapping physical memory | MMU记录<虚拟地址,物理地址>的映射情况 */
#ifdef LOSCFG_DRIVERS_TZDRIVER
VADDR_T codeStart; /**< user process code area start */
VADDR_T codeEnd; /**< user process code area end */
VADDR_T codeStart; /**< user process code area start | 代码区开始位置 */
VADDR_T codeEnd; /**< user process code area end | 代码区结束位置 */
#endif
} LosVmSpace;
#define VM_MAP_REGION_TYPE_NONE (0x0)
#define VM_MAP_REGION_TYPE_ANON (0x1)
#define VM_MAP_REGION_TYPE_FILE (0x2)
#define VM_MAP_REGION_TYPE_DEV (0x4)
#define VM_MAP_REGION_TYPE_MASK (0x7)
#define VM_MAP_REGION_TYPE_NONE (0x0) ///< 初始化使用
#define VM_MAP_REGION_TYPE_ANON (0x1) ///< 匿名映射线性区
#define VM_MAP_REGION_TYPE_FILE (0x2) ///< 文件映射线性区
#define VM_MAP_REGION_TYPE_DEV (0x4) ///< 设备映射线性区
#define VM_MAP_REGION_TYPE_MASK (0x7) ///< 映射线性区掩码
/* the high 8 bits(24~31) should reserved, shm will use it */
#define VM_MAP_REGION_FLAG_CACHED (0<<0)
#define VM_MAP_REGION_FLAG_UNCACHED (1<<0)
#define VM_MAP_REGION_FLAG_CACHED (0<<0) ///< 缓冲区
#define VM_MAP_REGION_FLAG_UNCACHED (1<<0) ///< 非缓冲区
#define VM_MAP_REGION_FLAG_UNCACHED_DEVICE (2<<0) /* only exists on some arches, otherwise UNCACHED */
#define VM_MAP_REGION_FLAG_STRONGLY_ORDERED (3<<0) /* only exists on some arches, otherwise UNCACHED */
#define VM_MAP_REGION_FLAG_CACHE_MASK (3<<0)
#define VM_MAP_REGION_FLAG_PERM_USER (1<<2)
#define VM_MAP_REGION_FLAG_PERM_READ (1<<3)
#define VM_MAP_REGION_FLAG_PERM_WRITE (1<<4)
#define VM_MAP_REGION_FLAG_PERM_EXECUTE (1<<5)
#define VM_MAP_REGION_FLAG_PROT_MASK (0xF<<2)
#define VM_MAP_REGION_FLAG_NS (1<<6) /* NON-SECURE */
#define VM_MAP_REGION_FLAG_SHARED (1<<7)
#define VM_MAP_REGION_FLAG_PRIVATE (1<<8)
#define VM_MAP_REGION_FLAG_FLAG_MASK (3<<7)
#define VM_MAP_REGION_FLAG_STACK (1<<9)
#define VM_MAP_REGION_FLAG_HEAP (1<<10)
#define VM_MAP_REGION_FLAG_DATA (1<<11)
#define VM_MAP_REGION_FLAG_TEXT (1<<12)
#define VM_MAP_REGION_FLAG_BSS (1<<13)
#define VM_MAP_REGION_FLAG_VDSO (1<<14)
#define VM_MAP_REGION_FLAG_MMAP (1<<15)
#define VM_MAP_REGION_FLAG_SHM (1<<16)
#define VM_MAP_REGION_FLAG_FIXED (1<<17)
#define VM_MAP_REGION_FLAG_FIXED_NOREPLACE (1<<18)
#define VM_MAP_REGION_FLAG_CACHE_MASK (3<<0) ///< 缓冲区掩码
#define VM_MAP_REGION_FLAG_PERM_USER (1<<2) ///< 用户空间永久区,PERM表示常驻区,可理解为非栈,非堆区
#define VM_MAP_REGION_FLAG_PERM_READ (1<<3) ///< 永久可读取区
#define VM_MAP_REGION_FLAG_PERM_WRITE (1<<4) ///< 永久可写入区
#define VM_MAP_REGION_FLAG_PERM_EXECUTE (1<<5) ///< 永久可被执行区
#define VM_MAP_REGION_FLAG_PROT_MASK (0xF<<2) ///< 访问权限掩码
#define VM_MAP_REGION_FLAG_NS (1<<6) /* NON-SECURE */
#define VM_MAP_REGION_FLAG_SHARED (1<<7) ///< MAP_SHARED把对该内存段的修改保存到磁盘文件中 详见 OsCvtProtFlagsToRegionFlags ,要和 VM_MAP_REGION_FLAG_SHM区别理解
#define VM_MAP_REGION_FLAG_PRIVATE (1<<8) ///< MAP_PRIVATE内存段私有对它的修改值仅对本进程有效,详见 OsCvtProtFlagsToRegionFlags。
#define VM_MAP_REGION_FLAG_FLAG_MASK (3<<7) ///< 掩码
#define VM_MAP_REGION_FLAG_STACK (1<<9) ///< 线性区的类型:栈区
#define VM_MAP_REGION_FLAG_HEAP (1<<10) ///< 线性区的类型:堆区
#define VM_MAP_REGION_FLAG_DATA (1<<11) ///< data数据区 编译在ELF中
#define VM_MAP_REGION_FLAG_TEXT (1<<12) ///< 代码区
#define VM_MAP_REGION_FLAG_BSS (1<<13) ///< bbs数据区 由运行时动态分配,bss段Block Started by Symbol segment通常是指用来存放程序中未初始化的全局变量的一块内存区域。
#define VM_MAP_REGION_FLAG_VDSO (1<<14) ///< VDSOVirtual Dynamic Shared Object虚拟动态共享库由内核提供的虚拟.so文件它不在磁盘上而在内核里内核将其映射到一个地址空间中被所有程序共享正文段大小为一个页面。
#define VM_MAP_REGION_FLAG_MMAP (1<<15) ///< 映射区,虚拟空间内有专门用来存储<虚拟地址-物理地址>映射的区域
#define VM_MAP_REGION_FLAG_SHM (1<<16) ///< 共享内存区, 被多个进程线性区映射
#define VM_MAP_REGION_FLAG_FIXED (1<<17) ///< 线性区被填满
#define VM_MAP_REGION_FLAG_FIXED_NOREPLACE (1<<18) ///< 线性区不被替换
#define VM_MAP_REGION_FLAG_INVALID (1<<19) /* indicates that flags are not specified */
/// 从外部权限标签转化为线性区权限标签
STATIC INLINE UINT32 OsCvtProtFlagsToRegionFlags(unsigned long prot, unsigned long flags)
{
UINT32 regionFlags = 0;
regionFlags |= VM_MAP_REGION_FLAG_PERM_USER;
regionFlags |= (prot & PROT_READ) ? VM_MAP_REGION_FLAG_PERM_READ : 0;
regionFlags |= VM_MAP_REGION_FLAG_PERM_USER; //必须是用户空间区
regionFlags |= (prot & PROT_READ) ? VM_MAP_REGION_FLAG_PERM_READ : 0; //映射区可被读
regionFlags |= (prot & PROT_WRITE) ? (VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE) : 0;
regionFlags |= (prot & PROT_EXEC) ? (VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_EXECUTE) : 0;
regionFlags |= (flags & MAP_SHARED) ? VM_MAP_REGION_FLAG_SHARED : 0;
@ -174,86 +209,87 @@ STATIC INLINE UINT32 OsCvtProtFlagsToRegionFlags(unsigned long prot, unsigned lo
return regionFlags;
}
/// 虚拟地址是否在内核空间
STATIC INLINE BOOL LOS_IsKernelAddress(VADDR_T vaddr)
{
return ((vaddr >= (VADDR_T)KERNEL_ASPACE_BASE) &&
(vaddr <= ((VADDR_T)KERNEL_ASPACE_BASE + ((VADDR_T)KERNEL_ASPACE_SIZE - 1))));
}
/// 给定地址范围是否都在内核空间中
STATIC INLINE BOOL LOS_IsKernelAddressRange(VADDR_T vaddr, size_t len)
{
return (vaddr + len > vaddr) && LOS_IsKernelAddress(vaddr) && (LOS_IsKernelAddress(vaddr + len - 1));
}
/// 获取线性区的结束地址
STATIC INLINE VADDR_T LOS_RegionEndAddr(LosVmMapRegion *region)
{
return (region->range.base + region->range.size - 1);
}
/// 获取线性区大小
STATIC INLINE size_t LOS_RegionSize(VADDR_T start, VADDR_T end)
{
return (end - start + 1);
}
/// 是否为文件映射区
STATIC INLINE BOOL LOS_IsRegionTypeFile(LosVmMapRegion* region)
{
return region->regionType == VM_MAP_REGION_TYPE_FILE;
}
/// permanent 用户进程永久/常驻区
STATIC INLINE BOOL LOS_IsRegionPermUserReadOnly(LosVmMapRegion* region)
{
return ((region->regionFlags & VM_MAP_REGION_FLAG_PROT_MASK) ==
(VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ));
}
/// 是否为私有线性区
STATIC INLINE BOOL LOS_IsRegionFlagPrivateOnly(LosVmMapRegion* region)
{
return ((region->regionFlags & VM_MAP_REGION_FLAG_FLAG_MASK) == VM_MAP_REGION_FLAG_PRIVATE);
}
/// 设置线性区为文件映射
STATIC INLINE VOID LOS_SetRegionTypeFile(LosVmMapRegion* region)
{
region->regionType = VM_MAP_REGION_TYPE_FILE;
}
/// 是否为设备映射线性区 /dev/...
STATIC INLINE BOOL LOS_IsRegionTypeDev(LosVmMapRegion* region)
{
return region->regionType == VM_MAP_REGION_TYPE_DEV;
}
/// 设为设备映射线性区
STATIC INLINE VOID LOS_SetRegionTypeDev(LosVmMapRegion* region)
{
region->regionType = VM_MAP_REGION_TYPE_DEV;
}
/// 是否为匿名swap映射线性区
STATIC INLINE BOOL LOS_IsRegionTypeAnon(LosVmMapRegion* region)
{
return region->regionType == VM_MAP_REGION_TYPE_ANON;
}
/// 设为匿名swap映射线性区
STATIC INLINE VOID LOS_SetRegionTypeAnon(LosVmMapRegion* region)
{
region->regionType = VM_MAP_REGION_TYPE_ANON;
}
/// 虚拟地址是否在用户空间
STATIC INLINE BOOL LOS_IsUserAddress(VADDR_T vaddr)
{
return ((vaddr >= USER_ASPACE_BASE) &&
(vaddr <= (USER_ASPACE_BASE + (USER_ASPACE_SIZE - 1))));
}
/// 虚拟地址[vaddr,vaddr + len]是否在用户空间
STATIC INLINE BOOL LOS_IsUserAddressRange(VADDR_T vaddr, size_t len)
{
return (vaddr + len > vaddr) && LOS_IsUserAddress(vaddr) && (LOS_IsUserAddress(vaddr + len - 1));
}
//是否是一个动态分配的地址(通过vmalloc申请的)
STATIC INLINE BOOL LOS_IsVmallocAddress(VADDR_T vaddr)
{
return ((vaddr >= VMALLOC_START) &&
(vaddr <= (VMALLOC_START + (VMALLOC_SIZE - 1))));
}
/// 是否为一个空线性区
STATIC INLINE BOOL OsIsVmRegionEmpty(LosVmSpace *vmSpace)
{
if (vmSpace->regionRbTree.ulNodes == 0) {
@ -294,7 +330,6 @@ STATUS_T LOS_VmSpaceClone(UINT32 cloneFlags, LosVmSpace *oldVmSpace, LosVmSpace
LosMux *OsGVmSpaceMuxGet(VOID);
STATUS_T OsUnMMap(LosVmSpace *space, VADDR_T addr, size_t size);
STATUS_T OsVmSpaceRegionFree(LosVmSpace *space);
/**
* thread safety
* it is used to malloc continuous virtual memory, no sure for continuous physical memory.

@ -44,21 +44,28 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
/*!
* @brief
* @attention vmPage
\n nPagesorder,5,order3,2^35
*/
typedef struct VmPage {
LOS_DL_LIST node; /**< vm object dl list */
PADDR_T physAddr; /**< vm page physical addr */
Atomic refCounts; /**< vm page ref count */
UINT32 flags; /**< vm page flags */
UINT8 order; /**< vm page in which order list */
UINT8 segID; /**< the segment id of vm page */
UINT16 nPages; /**< the vm page is used for kernel heap */
LOS_DL_LIST node; /**< vm object dl list | 物理内框节点,通过它挂/摘到全局g_vmPhysSeg[segID]->freeList[order]物理页框链表 或被使用的链表
, shmIDSource.node*/
PADDR_T physAddr; /**< vm page physical addr | 物理页框起始物理地址,只能用于计算,不会用于操作(读/写数据==)*/
Atomic refCounts; /**< vm page ref count | 被引用次数,共享内存会有多次引用*/
UINT32 flags; /**< vm page flags | 页标签,同时可以有多个标签(共享/引用/活动/被锁==*/
UINT8 order; /**< vm page in which order list | 被安置在伙伴算法的几号序列( 2^0,2^1,2^2,...,2^order)*/
UINT8 segID; /**< the segment id of vm page | 所属物理内存段编号ID*/
UINT16 nPages; /**< the vm page is used for kernel heap | 分配页数,标识从本页开始连续的几页将一块被分配*/
#ifdef LOSCFG_PAGE_TABLE_FINE_LOCK
SPIN_LOCK_S lock; /**< lock for page table entry */
#endif
} LosVmPage;
extern LosVmPage *g_vmPageArray;
extern size_t g_vmPageArraySize;
extern LosVmPage *g_vmPageArray; ///< 物理页框(page frame)池,在g_vmPageArray中:不可能存在两个物理地址一样的物理页框,
extern size_t g_vmPageArraySize; ///< 物理总页框(page frame)数
LosVmPage *LOS_VmPageGet(PADDR_T paddr);
VOID OsVmPageStartup(VOID);

@ -43,52 +43,65 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
#define VM_LIST_ORDER_MAX 9
#define VM_PHYS_SEG_MAX 32
/*!
* @brief
* @verbatim
LRULeast Recently Used使
使使
LRU使
* @endverbatim
*/
#define VM_LIST_ORDER_MAX 9 ///< 伙伴算法分组数量,从 2^0,2^1,...,2^8 (256*4K)=1M
#define VM_PHYS_SEG_MAX 32 ///< 最大支持32个段
#ifndef min
#define min(x, y) ((x) < (y) ? (x) : (y))
#define min(x, y) ((x) < (y) ? (x) : (y))
#endif
#define VM_PAGE_TO_PHYS(page) ((page)->physAddr)
#define VM_ORDER_TO_PAGES(order) (1 << (order))
#define VM_ORDER_TO_PHYS(order) (1 << (PAGE_SHIFT + (order)))
#define VM_PHYS_TO_ORDER(phys) (min(LOS_LowBitGet((phys) >> PAGE_SHIFT), VM_LIST_ORDER_MAX - 1))
#define VM_PAGE_TO_PHYS(page) ((page)->physAddr) ///< 获取物理页框的物理基地址
#define VM_ORDER_TO_PAGES(order) (1 << (order)) ///< 伙伴算法由order 定位到该块组的页面单位,例如:order=2时page[4]
#define VM_ORDER_TO_PHYS(order) (1 << (PAGE_SHIFT + (order))) ///< 通过order块组跳到物理地址
#define VM_PHYS_TO_ORDER(phys) (min(LOS_LowBitGet((phys) >> PAGE_SHIFT), VM_LIST_ORDER_MAX - 1)) ///< 通过物理地址定位到order
struct VmFreeList {
LOS_DL_LIST node;
UINT32 listCnt;
LOS_DL_LIST node; ///< 双循环链表用于挂空闲物理内框节点,通过 VmPage->node 挂上来
UINT32 listCnt; ///< 空闲物理页总数
};
enum OsLruList {
VM_LRU_INACTIVE_ANON = 0,
VM_LRU_ACTIVE_ANON,
VM_LRU_INACTIVE_FILE,
VM_LRU_ACTIVE_FILE,
VM_LRU_UNEVICTABLE,
/*!
* @brief LruLeast Recently Used使
*/
enum OsLruList {// 页属性
VM_LRU_INACTIVE_ANON = 0, ///< 非活动匿名页swap
VM_LRU_ACTIVE_ANON, ///< 活动匿名页swap
VM_LRU_INACTIVE_FILE, ///< 非活动文件页(磁盘)
VM_LRU_ACTIVE_FILE, ///< 活动文件页(磁盘)
VM_LRU_UNEVICTABLE, ///< 禁止换出的页
VM_NR_LRU_LISTS
};
/*!
* @brief
*/
typedef struct VmPhysSeg {
PADDR_T start; /* The start of physical memory area */
size_t size; /* The size of physical memory area */
LosVmPage *pageBase; /* The first page address of this area */
SPIN_LOCK_S freeListLock; /* The buddy list spinlock */
struct VmFreeList freeList[VM_LIST_ORDER_MAX]; /* The free pages in the buddy list */
SPIN_LOCK_S lruLock;
size_t lruSize[VM_NR_LRU_LISTS];
LOS_DL_LIST lruList[VM_NR_LRU_LISTS];
PADDR_T start; /* The start of physical memory area | 物理内存段的开始地址*/
size_t size; /* The size of physical memory area | 物理内存段的大小*/
LosVmPage *pageBase; /* The first page address of this area | 本段首个物理页框地址*/
SPIN_LOCK_S freeListLock; /* The buddy list spinlock | 伙伴算法自旋锁,用于操作freeList链表*/
struct VmFreeList freeList[VM_LIST_ORDER_MAX]; /* The free pages in the buddy list | 伙伴算法的分组,默认分成10组 2^0,2^1,...,2^VM_LIST_ORDER_MAX*/
SPIN_LOCK_S lruLock; ///< 用于置换的自旋锁,用于操作lruList
size_t lruSize[VM_NR_LRU_LISTS]; ///< 5个双循环链表大小如此方便得到size
LOS_DL_LIST lruList[VM_NR_LRU_LISTS]; ///< 页面置换算法,5个双循环链表头它们分别描述五中不同类型的链表
} LosVmPhysSeg;
/*!
* @brief ,使
*/
struct VmPhysArea {
PADDR_T start;
size_t size;
PADDR_T start; ///< 物理内存区基地址
size_t size; ///< 物理内存总大小
};
extern struct VmPhysSeg g_vmPhysSeg[VM_PHYS_SEG_MAX];
extern INT32 g_vmPhysSegNum;
extern struct VmPhysSeg g_vmPhysSeg[VM_PHYS_SEG_MAX]; ///< 物理内存采用段页式管理,先切段后伙伴算法页
extern INT32 g_vmPhysSegNum; ///< 段总数
UINT32 OsVmPagesToOrder(size_t nPages);
struct VmPhysSeg *OsVmPhysSegGet(LosVmPage *page);

@ -45,12 +45,12 @@
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
//是否非匿名映射 文件映射:映射和实际文件相关联,通常是把文件的内容映射到进程地址空间,这样应用程序就可以像操作进程地址空间一样读写文件。
STATIC INLINE BOOL LOS_IsNamedMapping(unsigned long flags)
{
return ((flags & MAP_ANONYMOUS) == 0);
}
///是否匿名映射 匿名映射没有映射对应的相关文件这种映射的内存区域的内容会被初始化为0
STATIC INLINE BOOL LOS_IsAnonymousMapping(unsigned long flags)
{
return ((flags & MAP_ANONYMOUS) == MAP_ANONYMOUS);

@ -1,3 +1,91 @@
/*!
* @file los_vm_zone.h
* @brief
* @link
@verbatim
0x00000000U 0xFFFFFFFFU , @note_pic
鸿: http://weharmonyos.com | https://my.oschina.net/weharmony
+----------------------------+ 0xFFFFFFFFU
| IO |
| PERIPH_PMM_SIZE |
+----------------------------+ PERIPH_UNCACHED_BASE
| IO |
| PERIPH_PMM_SIZE |
+----------------------------+ PERIPH_CACHED_BASE
| IO |
| PERIPH_PMM_SIZE |
+----------------------------+ PERIPH_DEVICE_BASE
| Vmalloc |
| |
| 128M |
| |
+----------------------------+ VMALLOC_START
| DDR_MEM_SIZE |
| Uncached |
+----------------------------+ UNCACHED_VMM_BASE = KERNEL_VMM_BASE + KERNEL_VMM_SIZE
| |
| mmu table |
| .bss |Block Started by Symbol : , g_firstPageTable,
| .data |
| .rodata |
| .text |
| vectors |
+----------------------------+ KERNEL_ASPACE_BASE = KERNEL_VMM_BASE
| 16M |
+----------------------------+ USER_ASPACE_TOP_MAX = USER_ASPACE_BASE + USER_ASPACE_SIZE
| |
| |
| USER_ASPACE_SIZE |
| (stack) |
| (map) |
| (heap) |
| .bss |
| .data .text |
+----------------------------+ USER_ASPACE_BASE
| 16M |
+----------------------------+ 0x00000000U
..\vendor\hi3516dv300\config\board\include\board.h
liteos_a, KERNEL_VADDR_BASE ,
liteos_aboard.h
#ifdef LOSCFG_KERNEL_MMU
#ifdef LOSCFG_TEE_ENABLE
#define KERNEL_VADDR_BASE 0x41000000
#else
#define KERNEL_VADDR_BASE 0x40000000
#endif
#else
#define KERNEL_VADDR_BASE DDR_MEM_ADDR
#endif
#define KERNEL_VADDR_SIZE DDR_MEM_SIZE
#define SYS_MEM_BASE DDR_MEM_ADDR
#define SYS_MEM_END (SYS_MEM_BASE + SYS_MEM_SIZE_DEFAULT)
#define EXC_INTERACT_MEM_SIZE 0x100000
: 0x40000000 ~ 0xFFFFFFFF
: 0x00000000 ~ 0x3FFFFFFF
cacheduncached
cached访CPUCPU
CPUCPU
unchached访CPU访
IOuncached访IOIOCPU
IOCPUIOCPU
IOIOCPU
@endverbatim
* @version
* @author weharmonyos.com | 鸿 |
* @date 2021-11-30
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
@ -40,44 +128,47 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
#ifdef LOSCFG_KERNEL_MMU
#ifdef LOSCFG_KERNEL_MMU //
#ifdef LOSCFG_TEE_ENABLE
#define KERNEL_VADDR_BASE 0x41000000
#define KERNEL_VADDR_BASE 0x41000000 //用于链接器层面的宏配置 | 基地址
#else
#define KERNEL_VADDR_BASE 0x40000000
#define KERNEL_VADDR_BASE 0x40000000
#endif
#else
#define KERNEL_VADDR_BASE DDR_MEM_ADDR
#else //没有MMU时,内核运行基址 = 内存的基地址,因为没有了MMU,所以也没有了虚拟内存和物理内存的说法,统一就是物理内存.
#define KERNEL_VADDR_BASE DDR_MEM_ADDR ///< 内核运行基址 等于内存( Double Data Rate SDRAM)基地址
#endif
#define KERNEL_VADDR_SIZE DDR_MEM_SIZE
#define KERNEL_VADDR_SIZE DDR_MEM_SIZE ///< 真实主存的大小
#define SYS_MEM_BASE DDR_MEM_ADDR ///< 物理内存基地址
#define SYS_MEM_END (SYS_MEM_BASE + SYS_MEM_SIZE_DEFAULT) ///< 物理内存结束地址
#define SYS_MEM_BASE DDR_MEM_ADDR
#define SYS_MEM_END (SYS_MEM_BASE + SYS_MEM_SIZE_DEFAULT)
#define _U32_C(X) X##U
#define U32_C(X) _U32_C(X)
#define KERNEL_VMM_BASE U32_C(KERNEL_VADDR_BASE)
#define KERNEL_VMM_SIZE U32_C(KERNEL_VADDR_SIZE)
#define KERNEL_VMM_BASE U32_C(KERNEL_VADDR_BASE) ///< 内核内存管理层面的宏配置 | 基地址
#define KERNEL_VMM_SIZE U32_C(KERNEL_VADDR_SIZE) ///< 内核大小
#define KERNEL_ASPACE_BASE KERNEL_VMM_BASE
#define KERNEL_ASPACE_SIZE KERNEL_VMM_SIZE
#define KERNEL_ASPACE_BASE KERNEL_VMM_BASE ///< 内核运行空间层面的宏配置 | 基地址
#define KERNEL_ASPACE_SIZE KERNEL_VMM_SIZE ///< 内核空间大小
/* Uncached vmm aspace */
#define UNCACHED_VMM_BASE (KERNEL_VMM_BASE + KERNEL_VMM_SIZE)
#define UNCACHED_VMM_SIZE DDR_MEM_SIZE
#define VMALLOC_START (UNCACHED_VMM_BASE + UNCACHED_VMM_SIZE)
#define VMALLOC_SIZE 0x08000000
#ifdef LOSCFG_KERNEL_MMU
#define PERIPH_DEVICE_BASE (VMALLOC_START + VMALLOC_SIZE)
#define UNCACHED_VMM_BASE (KERNEL_VMM_BASE + KERNEL_VMM_SIZE) ///< 未缓存虚拟空间基地址,适用于DMA,LCD framebuf,
#define UNCACHED_VMM_SIZE DDR_MEM_SIZE ///<未缓存虚拟空间大小
#define VMALLOC_START (UNCACHED_VMM_BASE + UNCACHED_VMM_SIZE) ///< 内核堆空间基地址
#define VMALLOC_SIZE 0x08000000 ///< 内核堆空间大小, 128M
//UART,LCD,摄像头,I2C,中断控制器统称为外部设备, 统一编址
#ifdef LOSCFG_KERNEL_MMU //使用MMU时,只是虚拟地址不一样,但映射的物理设备空间一致.
#define PERIPH_DEVICE_BASE (VMALLOC_START + VMALLOC_SIZE) ///< 不使用buffer,cache
#define PERIPH_DEVICE_SIZE U32_C(PERIPH_PMM_SIZE)
#define PERIPH_CACHED_BASE (PERIPH_DEVICE_BASE + PERIPH_DEVICE_SIZE)
#define PERIPH_CACHED_BASE (PERIPH_DEVICE_BASE + PERIPH_DEVICE_SIZE) ///< 使用cache但不用buffer
#define PERIPH_CACHED_SIZE U32_C(PERIPH_PMM_SIZE)
#define PERIPH_UNCACHED_BASE (PERIPH_CACHED_BASE + PERIPH_CACHED_SIZE)
#define PERIPH_UNCACHED_BASE (PERIPH_CACHED_BASE + PERIPH_CACHED_SIZE) ///< 不使用cache但使用buffer
#define PERIPH_UNCACHED_SIZE U32_C(PERIPH_PMM_SIZE)
#else
#else //不使用MMU时,外部设备空间地址一致.
#define PERIPH_DEVICE_BASE PERIPH_PMM_BASE
#define PERIPH_DEVICE_SIZE U32_C(PERIPH_PMM_SIZE)
#define PERIPH_CACHED_BASE PERIPH_PMM_BASE
@ -86,9 +177,10 @@ extern "C" {
#define PERIPH_UNCACHED_SIZE U32_C(PERIPH_PMM_SIZE)
#endif
#define IO_DEVICE_ADDR(paddr) ((paddr) - PERIPH_PMM_BASE + PERIPH_DEVICE_BASE)
#define IO_CACHED_ADDR(paddr) ((paddr) - PERIPH_PMM_BASE + PERIPH_CACHED_BASE)
#define IO_UNCACHED_ADDR(paddr) ((paddr) - PERIPH_PMM_BASE + PERIPH_UNCACHED_BASE)
#define IO_DEVICE_ADDR(paddr) ((paddr) - PERIPH_PMM_BASE + PERIPH_DEVICE_BASE) ///< 通过物理地址获取IO设备虚拟地址
#define IO_CACHED_ADDR(paddr) ((paddr) - PERIPH_PMM_BASE + PERIPH_CACHED_BASE) ///< 通过物理地址获取IO设备虚拟缓存地址
#define IO_UNCACHED_ADDR(paddr) ((paddr) - PERIPH_PMM_BASE + PERIPH_UNCACHED_BASE) ///< 通过物理地址获取IO设备虚拟未缓存地址
//DDR_MEM_ADDRDDR内存全称是DDR SDRAM(Double Data Rate SDRAM双倍速率SDRAM)
#define MEM_CACHED_ADDR(paddr) ((paddr) - DDR_MEM_ADDR + KERNEL_VMM_BASE)
#define MEM_UNCACHED_ADDR(paddr) ((paddr) - DDR_MEM_ADDR + UNCACHED_VMM_BASE)

@ -1,6 +1,57 @@
/*!
* @file los_event.c
* @brief
* @link
@verbatim
Event
322531
LOS_WAITMODE_ANDeventMask
LOS_WAITMODE_OReventMask
LOS_WAITMODE_CLR
使LOS_WAITMODE_AND | LOS_WAITMODE_CLR LOS_WAITMODE_OR | LOS_WAITMODE_CLR
LOS_EventReadeventMask
LOS_WAITMODE_CLR
LOS_EventWrite
LOS_EventClear
0
使
LOS_EventClear ~events
LOS_EventRead25使
@endverbatim
* @version
* @author weharmonyos.com | 鸿 |
* @date 2022-1-15
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2022 Huawei Device Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
@ -40,6 +91,7 @@
#include "los_exc.h"
#endif
/// 初始化一个事件控制块
LITE_OS_SEC_TEXT_INIT UINT32 LOS_EventInit(PEVENT_CB_S eventCB)
{
UINT32 intSave;
@ -48,14 +100,14 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_EventInit(PEVENT_CB_S eventCB)
return LOS_ERRNO_EVENT_PTR_NULL;
}
intSave = LOS_IntLock();
eventCB->uwEventID = 0;
LOS_ListInit(&eventCB->stEventList);
LOS_IntRestore(intSave);
intSave = LOS_IntLock();//锁中断
eventCB->uwEventID = 0;//事件类型初始化
LOS_ListInit(&eventCB->stEventList);//事件链表初始化
LOS_IntRestore(intSave);//恢复中断
OsHookCall(LOS_HOOK_TYPE_EVENT_INIT, eventCB);
return LOS_OK;
}
///事件参数检查
LITE_OS_SEC_TEXT STATIC UINT32 OsEventParamCheck(const VOID *ptr, UINT32 eventMask, UINT32 mode)
{
if (ptr == NULL) {
@ -77,52 +129,53 @@ LITE_OS_SEC_TEXT STATIC UINT32 OsEventParamCheck(const VOID *ptr, UINT32 eventMa
}
return LOS_OK;
}
///根据用户传入的事件值、事件掩码及校验模式,返回用户传入的事件是否符合预期
LITE_OS_SEC_TEXT UINT32 OsEventPoll(UINT32 *eventID, UINT32 eventMask, UINT32 mode)
{
UINT32 ret = 0;
LOS_ASSERT(OsIntLocked());
LOS_ASSERT(LOS_SpinHeld(&g_taskSpin));
LOS_ASSERT(OsIntLocked());//断言不允许中断了
LOS_ASSERT(LOS_SpinHeld(&g_taskSpin));//任务自旋锁
if (mode & LOS_WAITMODE_OR) {
if (mode & LOS_WAITMODE_OR) {//如果模式是读取掩码中任意事件
if ((*eventID & eventMask) != 0) {
ret = *eventID & eventMask;
}
} else {
if ((eventMask != 0) && (eventMask == (*eventID & eventMask))) {
} else {//等待全部事件发生
if ((eventMask != 0) && (eventMask == (*eventID & eventMask))) {//必须满足全部事件发生
ret = *eventID & eventMask;
}
}
if (ret && (mode & LOS_WAITMODE_CLR)) {
if (ret && (mode & LOS_WAITMODE_CLR)) {//读取完成后清除事件
*eventID = *eventID & ~ret;
}
return ret;
}
///检查读事件
LITE_OS_SEC_TEXT STATIC UINT32 OsEventReadCheck(const PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode)
{
UINT32 ret;
LosTaskCB *runTask = NULL;
ret = OsEventParamCheck(eventCB, eventMask, mode);
ret = OsEventParamCheck(eventCB, eventMask, mode);//事件参数检查
if (ret != LOS_OK) {
return ret;
}
if (OS_INT_ACTIVE) {
return LOS_ERRNO_EVENT_READ_IN_INTERRUPT;
if (OS_INT_ACTIVE) {//中断正在进行
return LOS_ERRNO_EVENT_READ_IN_INTERRUPT;//不能在中断发送时读事件
}
runTask = OsCurrTaskGet();
if (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) {
runTask = OsCurrTaskGet();//获取当前任务
if (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) {//任务属于系统任务
OsBackTrace();
return LOS_ERRNO_EVENT_READ_IN_SYSTEM_TASK;
return LOS_ERRNO_EVENT_READ_IN_SYSTEM_TASK;//不能在系统任务中读取事件
}
return LOS_OK;
}
/// 读取指定事件类型的实现函数超时时间为相对时间单位为Tick
LITE_OS_SEC_TEXT STATIC UINT32 OsEventReadImp(PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode,
UINT32 timeout, BOOL once)
{
@ -131,57 +184,57 @@ LITE_OS_SEC_TEXT STATIC UINT32 OsEventReadImp(PEVENT_CB_S eventCB, UINT32 eventM
OsHookCall(LOS_HOOK_TYPE_EVENT_READ, eventCB, eventMask, mode, timeout);
if (once == FALSE) {
ret = OsEventPoll(&eventCB->uwEventID, eventMask, mode);
ret = OsEventPoll(&eventCB->uwEventID, eventMask, mode);//检测事件是否符合预期
}
if (ret == 0) {
if (timeout == 0) {
if (ret == 0) {//不符合预期时
if (timeout == 0) {//不等待的情况
return ret;
}
if (!OsPreemptableInSched()) {
if (!OsPreemptableInSched()) {//不能抢占式调度
return LOS_ERRNO_EVENT_READ_IN_LOCK;
}
runTask->eventMask = eventMask;
runTask->eventMode = mode;
runTask->taskEvent = eventCB;
OsTaskWaitSetPendMask(OS_TASK_WAIT_EVENT, eventMask, timeout);
runTask->eventMask = eventMask; //等待事件
runTask->eventMode = mode; //事件模式
runTask->taskEvent = eventCB; //事件控制块
OsTaskWaitSetPendMask(OS_TASK_WAIT_EVENT, eventMask, timeout);//任务进入等待状态,等待事件的到来并设置时长和掩码
ret = runTask->ops->wait(runTask, &eventCB->stEventList, timeout);
if (ret == LOS_ERRNO_TSK_TIMEOUT) {
return LOS_ERRNO_EVENT_READ_TIMEOUT;
}
ret = OsEventPoll(&eventCB->uwEventID, eventMask, mode);
ret = OsEventPoll(&eventCB->uwEventID, eventMask, mode);//检测事件是否符合预期
}
return ret;
}
///读取指定事件类型超时时间为相对时间单位为Tick
LITE_OS_SEC_TEXT STATIC UINT32 OsEventRead(PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode, UINT32 timeout,
BOOL once)
{
UINT32 ret;
UINT32 intSave;
ret = OsEventReadCheck(eventCB, eventMask, mode);
ret = OsEventReadCheck(eventCB, eventMask, mode);//读取事件检查
if (ret != LOS_OK) {
return ret;
}
SCHEDULER_LOCK(intSave);
ret = OsEventReadImp(eventCB, eventMask, mode, timeout, once);
ret = OsEventReadImp(eventCB, eventMask, mode, timeout, once);//读事件实现函数
SCHEDULER_UNLOCK(intSave);
return ret;
}
///事件恢复操作
LITE_OS_SEC_TEXT STATIC UINT8 OsEventResume(LosTaskCB *resumedTask, const PEVENT_CB_S eventCB, UINT32 events)
{
UINT8 exitFlag = 0;
UINT8 exitFlag = 0;//是否唤醒
if (((resumedTask->eventMode & LOS_WAITMODE_OR) && ((resumedTask->eventMask & events) != 0)) ||
((resumedTask->eventMode & LOS_WAITMODE_AND) &&
((resumedTask->eventMask & eventCB->uwEventID) == resumedTask->eventMask))) {
exitFlag = 1;
((resumedTask->eventMask & eventCB->uwEventID) == resumedTask->eventMask))) {//逻辑与 和 逻辑或 的处理
exitFlag = 1;
resumedTask->taskEvent = NULL;
OsTaskWakeClearPendMask(resumedTask);
@ -190,33 +243,33 @@ LITE_OS_SEC_TEXT STATIC UINT8 OsEventResume(LosTaskCB *resumedTask, const PEVENT
return exitFlag;
}
///以不安全的方式写事件
LITE_OS_SEC_TEXT VOID OsEventWriteUnsafe(PEVENT_CB_S eventCB, UINT32 events, BOOL once, UINT8 *exitFlag)
{
LosTaskCB *resumedTask = NULL;
LosTaskCB *nextTask = NULL;
BOOL schedFlag = FALSE;
OsHookCall(LOS_HOOK_TYPE_EVENT_WRITE, eventCB, events);
eventCB->uwEventID |= events;
if (!LOS_ListEmpty(&eventCB->stEventList)) {
eventCB->uwEventID |= events;//对应位贴上标签
if (!LOS_ListEmpty(&eventCB->stEventList)) {//等待事件链表判断,处理等待事件的任务
for (resumedTask = LOS_DL_LIST_ENTRY((&eventCB->stEventList)->pstNext, LosTaskCB, pendList);
&resumedTask->pendList != &eventCB->stEventList;) {
nextTask = LOS_DL_LIST_ENTRY(resumedTask->pendList.pstNext, LosTaskCB, pendList);
if (OsEventResume(resumedTask, eventCB, events)) {
schedFlag = TRUE;
&resumedTask->pendList != &eventCB->stEventList;) {//循环获取任务链表
nextTask = LOS_DL_LIST_ENTRY(resumedTask->pendList.pstNext, LosTaskCB, pendList);//获取任务实体
if (OsEventResume(resumedTask, eventCB, events)) {//是否恢复任务
schedFlag = TRUE;//任务已加至就绪队列,申请发生一次调度
}
if (once == TRUE) {
break;
if (once == TRUE) {//是否只处理一次任务
break;//退出循环
}
resumedTask = nextTask;
resumedTask = nextTask;//检查链表中下一个任务
}
}
if ((exitFlag != NULL) && (schedFlag == TRUE)) {
if ((exitFlag != NULL) && (schedFlag == TRUE)) {//是否让外面调度
*exitFlag = 1;
}
}
///写入事件
LITE_OS_SEC_TEXT STATIC UINT32 OsEventWrite(PEVENT_CB_S eventCB, UINT32 events, BOOL once)
{
UINT32 intSave;
@ -230,54 +283,54 @@ LITE_OS_SEC_TEXT STATIC UINT32 OsEventWrite(PEVENT_CB_S eventCB, UINT32 events,
return LOS_ERRNO_EVENT_SETBIT_INVALID;
}
SCHEDULER_LOCK(intSave);
OsEventWriteUnsafe(eventCB, events, once, &exitFlag);
SCHEDULER_UNLOCK(intSave);
SCHEDULER_LOCK(intSave); //禁止调度
OsEventWriteUnsafe(eventCB, events, once, &exitFlag);//写入事件
SCHEDULER_UNLOCK(intSave); //允许调度
if (exitFlag == 1) {
LOS_MpSchedule(OS_MP_CPU_ALL);
LOS_Schedule();
if (exitFlag == 1) { //需要发生调度
LOS_MpSchedule(OS_MP_CPU_ALL);//通知所有CPU调度
LOS_Schedule();//执行调度
}
return LOS_OK;
}
///根据用户传入的事件值、事件掩码及校验模式,返回用户传入的事件是否符合预期
LITE_OS_SEC_TEXT UINT32 LOS_EventPoll(UINT32 *eventID, UINT32 eventMask, UINT32 mode)
{
UINT32 ret;
UINT32 intSave;
//事件参数检查
ret = OsEventParamCheck((VOID *)eventID, eventMask, mode);
if (ret != LOS_OK) {
return ret;
}
SCHEDULER_LOCK(intSave);
SCHEDULER_LOCK(intSave);//申请任务自旋锁
ret = OsEventPoll(eventID, eventMask, mode);
SCHEDULER_UNLOCK(intSave);
return ret;
}
///读取指定事件类型超时时间为相对时间单位为Tick
LITE_OS_SEC_TEXT UINT32 LOS_EventRead(PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode, UINT32 timeout)
{
return OsEventRead(eventCB, eventMask, mode, timeout, FALSE);
}
///写指定的事件类型
LITE_OS_SEC_TEXT UINT32 LOS_EventWrite(PEVENT_CB_S eventCB, UINT32 events)
{
return OsEventWrite(eventCB, events, FALSE);
}
///只读一次事件
LITE_OS_SEC_TEXT_MINOR UINT32 OsEventReadOnce(PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode,
UINT32 timeout)
{
return OsEventRead(eventCB, eventMask, mode, timeout, TRUE);
}
///只写一次事件
LITE_OS_SEC_TEXT_MINOR UINT32 OsEventWriteOnce(PEVENT_CB_S eventCB, UINT32 events)
{
return OsEventWrite(eventCB, events, TRUE);
}
///销毁指定的事件控制块
LITE_OS_SEC_TEXT_INIT UINT32 LOS_EventDestroy(PEVENT_CB_S eventCB)
{
UINT32 intSave;
@ -298,7 +351,7 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_EventDestroy(PEVENT_CB_S eventCB)
OsHookCall(LOS_HOOK_TYPE_EVENT_DESTROY, eventCB);
return LOS_OK;
}
///清除指定的事件类型
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_EventClear(PEVENT_CB_S eventCB, UINT32 eventMask)
{
UINT32 intSave;
@ -313,7 +366,7 @@ LITE_OS_SEC_TEXT_MINOR UINT32 LOS_EventClear(PEVENT_CB_S eventCB, UINT32 eventMa
return LOS_OK;
}
///有条件式读事件
#ifdef LOSCFG_COMPAT_POSIX
LITE_OS_SEC_TEXT UINT32 OsEventReadWithCond(const EventCond *cond, PEVENT_CB_S eventCB,
UINT32 eventMask, UINT32 mode, UINT32 timeout)

@ -1,6 +1,60 @@
/*!
* @file los_futex.c
* @brief
* @link mutex http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-basic-trans-user-mutex.html @endlink
* @link d17a6152740c https://www.jianshu.com/p/d17a6152740c @endlink
@verbatim
Futex CPU
Futex
使 futex
使
Futex(Fast userspace mutex)
mutexbarriercond
线
线Futex线
线线
线Futex线
futex (fast userspace mutex) Linux
POSIXfutex使futex
SystemV IPC(inter process communication) semaphore
semop(2)PVuser mode
kernel modeuser stackkernel stack
semaphore
semaphoresemaphore
semaphoresemop(2)semaphoresemop(2)
semaphore
futexuser space
(wait wake up)futexuser modekernel mode
futexuser spacefutexuser modekernel modeuser mode
sys_futexkernel mode
线Futex
Futex1GiB便
Futex
800~6364~79
/Futex
: futexfutex_listfutex nodefutex nodetask
nodekeykeynodequeue_listtask
@endverbatim
@image html https://gitee.com/weharmonyos/resources/raw/master/81/futex.png
* @attention Futex使POSIX
* @version
* @author weharmonyos.com | 鸿 |
* @date 2021-11-23
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2022 Huawei Device Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
@ -43,28 +97,30 @@
#ifdef LOSCFG_KERNEL_VM
#define OS_FUTEX_FROM_FUTEXLIST(ptr) LOS_DL_LIST_ENTRY(ptr, FutexNode, futexList)
#define OS_FUTEX_FROM_QUEUELIST(ptr) LOS_DL_LIST_ENTRY(ptr, FutexNode, queueList)
#define OS_FUTEX_KEY_BASE USER_ASPACE_BASE
#define OS_FUTEX_KEY_MAX (USER_ASPACE_BASE + USER_ASPACE_SIZE)
#define OS_FUTEX_FROM_FUTEXLIST(ptr) LOS_DL_LIST_ENTRY(ptr, FutexNode, futexList) // 通过快锁节点找到结构体
#define OS_FUTEX_FROM_QUEUELIST(ptr) LOS_DL_LIST_ENTRY(ptr, FutexNode, queueList) // 通过队列节点找到结构体
#define OS_FUTEX_KEY_BASE USER_ASPACE_BASE ///< 进程用户空间基址
#define OS_FUTEX_KEY_MAX (USER_ASPACE_BASE + USER_ASPACE_SIZE) ///< 进程用户空间尾址
/* private: 0~63 hash index_num
* shared: 64~79 hash index_num */
#define FUTEX_INDEX_PRIVATE_MAX 64
#define FUTEX_INDEX_SHARED_MAX 16
#define FUTEX_INDEX_MAX (FUTEX_INDEX_PRIVATE_MAX + FUTEX_INDEX_SHARED_MAX)
#define FUTEX_INDEX_PRIVATE_MAX 64 ///< 0~63号桶用于存放私有锁以虚拟地址进行哈希,同一进程不同线程共享futex变量表明变量在进程地址空间中的位置
///< 它告诉内核这个futex是进程专有的不可以与其他进程共享。它仅仅用作同一进程的线程间同步。
#define FUTEX_INDEX_SHARED_MAX 16 ///< 64~79号桶用于存放共享锁以物理地址进行哈希,不同进程间通过文件共享futex变量表明该变量在文件中的位置
#define FUTEX_INDEX_MAX (FUTEX_INDEX_PRIVATE_MAX + FUTEX_INDEX_SHARED_MAX) ///< 80个哈希桶
#define FUTEX_INDEX_SHARED_POS FUTEX_INDEX_PRIVATE_MAX
#define FUTEX_INDEX_SHARED_POS FUTEX_INDEX_PRIVATE_MAX ///< 共享锁开始位置
#define FUTEX_HASH_PRIVATE_MASK (FUTEX_INDEX_PRIVATE_MAX - 1)
#define FUTEX_HASH_SHARED_MASK (FUTEX_INDEX_SHARED_MAX - 1)
/// 单独哈希桶,上面挂了一个个 FutexNode
typedef struct {
LosMux listLock;
LOS_DL_LIST lockList;
LosMux listLock;///< 内核操作lockList的互斥锁
LOS_DL_LIST lockList;///< 用于挂载 FutexNode (Fast userspace mutex用户态快速互斥锁)
} FutexHash;
FutexHash g_futexHash[FUTEX_INDEX_MAX];
FutexHash g_futexHash[FUTEX_INDEX_MAX];///< 80个哈希桶
/// 对互斥锁封装
STATIC INT32 OsFutexLock(LosMux *lock)
{
UINT32 ret = LOS_MuxLock(lock, LOS_WAIT_FOREVER);
@ -84,15 +140,15 @@ STATIC INT32 OsFutexUnlock(LosMux *lock)
}
return LOS_OK;
}
///< 初始化Futex(Fast userspace mutex用户态快速互斥锁)模块
UINT32 OsFutexInit(VOID)
{
INT32 count;
UINT32 ret;
// 初始化 80个哈希桶
for (count = 0; count < FUTEX_INDEX_MAX; count++) {
LOS_ListInit(&g_futexHash[count].lockList);
ret = LOS_MuxInit(&(g_futexHash[count].listLock), NULL);
LOS_ListInit(&g_futexHash[count].lockList); // 初始化双向链表,上面挂 FutexNode
ret = LOS_MuxInit(&(g_futexHash[count].listLock), NULL);//初始化互斥锁
if (ret) {
return ret;
}
@ -101,7 +157,7 @@ UINT32 OsFutexInit(VOID)
return LOS_OK;
}
LOS_MODULE_INIT(OsFutexInit, LOS_INIT_LEVEL_KMOD_EXTENDED);
LOS_MODULE_INIT(OsFutexInit, LOS_INIT_LEVEL_KMOD_EXTENDED);///< 注册Futex模块
#ifdef LOS_FUTEX_DEBUG
STATIC VOID OsFutexShowTaskNodeAttr(const LOS_DL_LIST *futexList)
@ -152,63 +208,63 @@ VOID OsFutexHashShow(VOID)
}
}
#endif
/// 通过用户空间地址获取哈希key
STATIC INLINE UINTPTR OsFutexFlagsToKey(const UINT32 *userVaddr, const UINT32 flags)
{
UINTPTR futexKey;
if (flags & FUTEX_PRIVATE) {
futexKey = (UINTPTR)userVaddr;
futexKey = (UINTPTR)userVaddr;//私有锁(以虚拟地址进行哈希)
} else {
futexKey = (UINTPTR)LOS_PaddrQuery((UINT32 *)userVaddr);
futexKey = (UINTPTR)LOS_PaddrQuery((UINT32 *)userVaddr);//共享锁(以物理地址进行哈希)
}
return futexKey;
}
/// 通过哈希key获取索引
STATIC INLINE UINT32 OsFutexKeyToIndex(const UINTPTR futexKey, const UINT32 flags)
{
UINT32 index = LOS_HashFNV32aBuf(&futexKey, sizeof(UINTPTR), FNV1_32A_INIT);
UINT32 index = LOS_HashFNV32aBuf(&futexKey, sizeof(UINTPTR), FNV1_32A_INIT);//获取哈希桶索引
if (flags & FUTEX_PRIVATE) {
index &= FUTEX_HASH_PRIVATE_MASK;
index &= FUTEX_HASH_PRIVATE_MASK;//将index锁定在 0 ~ 63号
} else {
index &= FUTEX_HASH_SHARED_MASK;
index += FUTEX_INDEX_SHARED_POS;
index += FUTEX_INDEX_SHARED_POS;//共享锁索引,将index锁定在 64 ~ 79号
}
return index;
}
/// 设置快锁哈希key
STATIC INLINE VOID OsFutexSetKey(UINTPTR futexKey, UINT32 flags, FutexNode *node)
{
node->key = futexKey;
node->index = OsFutexKeyToIndex(futexKey, flags);
node->pid = (flags & FUTEX_PRIVATE) ? LOS_GetCurrProcessID() : OS_INVALID;
node->key = futexKey;//哈希key
node->index = OsFutexKeyToIndex(futexKey, flags);//哈希桶索引
node->pid = (flags & FUTEX_PRIVATE) ? LOS_GetCurrProcessID() : OS_INVALID;//获取进程ID,共享快锁时 快锁节点没有进程ID
}
//析构参数节点
STATIC INLINE VOID OsFutexDeinitFutexNode(FutexNode *node)
{
node->index = OS_INVALID_VALUE;
node->pid = 0;
LOS_ListDelete(&node->queueList);
}
/// 新旧两个节点交换 futexList 位置
STATIC INLINE VOID OsFutexReplaceQueueListHeadNode(FutexNode *oldHeadNode, FutexNode *newHeadNode)
{
LOS_DL_LIST *futexList = oldHeadNode->futexList.pstPrev;
LOS_ListDelete(&oldHeadNode->futexList);
LOS_ListHeadInsert(futexList, &newHeadNode->futexList);
if ((newHeadNode->queueList.pstNext == NULL) || (newHeadNode->queueList.pstPrev == NULL)) {
LOS_ListInit(&newHeadNode->queueList);
LOS_ListDelete(&oldHeadNode->futexList);//将旧节点从futexList链表上摘除
LOS_ListHeadInsert(futexList, &newHeadNode->futexList);//将新节点从头部插入futexList链表
if ((newHeadNode->queueList.pstNext == NULL) || (newHeadNode->queueList.pstPrev == NULL)) {//新节点前后没有等待这把锁的任务
LOS_ListInit(&newHeadNode->queueList);//初始化等锁任务链表
}
}
/// 将参数节点从futexList上摘除
STATIC INLINE VOID OsFutexDeleteKeyFromFutexList(FutexNode *node)
{
LOS_ListDelete(&node->futexList);
}
/// 从哈希桶中删除快锁节点
STATIC VOID OsFutexDeleteKeyNodeFromHash(FutexNode *node, BOOL isDeleteHead, FutexNode **headNode, BOOL *queueFlags)
{
FutexNode *nextNode = NULL;
@ -217,8 +273,8 @@ STATIC VOID OsFutexDeleteKeyNodeFromHash(FutexNode *node, BOOL isDeleteHead, Fut
return;
}
if (LOS_ListEmpty(&node->queueList)) {
OsFutexDeleteKeyFromFutexList(node);
if (LOS_ListEmpty(&node->queueList)) {//如果没有任务在等锁
OsFutexDeleteKeyFromFutexList(node);//从快锁链表上摘除
if (queueFlags != NULL) {
*queueFlags = TRUE;
}
@ -226,10 +282,10 @@ STATIC VOID OsFutexDeleteKeyNodeFromHash(FutexNode *node, BOOL isDeleteHead, Fut
}
/* FutexList is not NULL, but the header node of queueList */
if (node->futexList.pstNext != NULL) {
if (isDeleteHead == TRUE) {
nextNode = OS_FUTEX_FROM_QUEUELIST(LOS_DL_LIST_FIRST(&node->queueList));
OsFutexReplaceQueueListHeadNode(node, nextNode);
if (node->futexList.pstNext != NULL) {//是头节点
if (isDeleteHead == TRUE) {//是否要删除头节点
nextNode = OS_FUTEX_FROM_QUEUELIST(LOS_DL_LIST_FIRST(&node->queueList));//取出第一个快锁节点
OsFutexReplaceQueueListHeadNode(node, nextNode);//两个节点交换位置
if (headNode != NULL) {
*headNode = nextNode;
}
@ -242,22 +298,22 @@ EXIT:
OsFutexDeinitFutexNode(node);
return;
}
/// 从哈希桶上删除快锁
VOID OsFutexNodeDeleteFromFutexHash(FutexNode *node, BOOL isDeleteHead, FutexNode **headNode, BOOL *queueFlags)
{
FutexHash *hashNode = NULL;
//通过key找到桶号
UINT32 index = OsFutexKeyToIndex(node->key, (node->pid == OS_INVALID) ? 0 : FUTEX_PRIVATE);
if (index >= FUTEX_INDEX_MAX) {
return;
}
hashNode = &g_futexHash[index];
hashNode = &g_futexHash[index];//找到hash桶
if (OsMuxLockUnsafe(&hashNode->listLock, LOS_WAIT_FOREVER)) {
return;
}
if (node->index != index) {
if (node->index != index) {//快锁节点桶号需和哈希桶号一致
goto EXIT;
}
@ -270,7 +326,7 @@ EXIT:
return;
}
/// 这块代码谁写的? 这种命名 ...
STATIC FutexNode *OsFutexDeleteAlreadyWakeTaskAndGetNext(const FutexNode *node, FutexNode **headNode, BOOL isDeleteHead)
{
FutexNode *tempNode = (FutexNode *)node;
@ -292,7 +348,7 @@ STATIC FutexNode *OsFutexDeleteAlreadyWakeTaskAndGetNext(const FutexNode *node,
return tempNode;
}
/// 插入一把新Futex锁到哈希桶中,只有是新的key时才会插入,因为其实存在多个FutexNode是一个key
STATIC VOID OsFutexInsertNewFutexKeyToHash(FutexNode *node)
{
FutexNode *headNode = NULL;
@ -322,16 +378,17 @@ STATIC VOID OsFutexInsertNewFutexKeyToHash(FutexNode *node)
futexList != &(hashNode->lockList);
futexList = futexList->pstNext) {
headNode = OS_FUTEX_FROM_FUTEXLIST(futexList);
if (node->key <= headNode->key) {
if (node->key <= headNode->key) {
LOS_ListTailInsert(&(headNode->futexList), &(node->futexList));
break;
}
}
EXIT:
return;
}
///< 从后往前插入快锁 Form写错了 @note_thinking
STATIC INT32 OsFutexInsertFindFormBackToFront(LOS_DL_LIST *queueList, const LosTaskCB *runTask, FutexNode *node)
{
LOS_DL_LIST *listHead = queueList;
@ -407,55 +464,55 @@ STATIC INT32 OsFutexRecycleAndFindHeadNode(FutexNode *headNode, FutexNode *node,
return LOS_OK;
}
///< 将快锁挂到任务的阻塞链表上
STATIC INT32 OsFutexInsertTasktoPendList(FutexNode **firstNode, FutexNode *node, const LosTaskCB *run)
{
LosTaskCB *taskHead = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&((*firstNode)->pendList)));
LosTaskCB *taskHead = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&((*firstNode)->pendList)));//获取阻塞链表首个任务
LOS_DL_LIST *queueList = &((*firstNode)->queueList);
INT32 ret1 = OsSchedParamCompare(run, taskHead);
if (ret1 < 0) {
/* The one with the highest priority is inserted at the top of the queue */
LOS_ListTailInsert(queueList, &(node->queueList));
OsFutexReplaceQueueListHeadNode(*firstNode, node);
LOS_ListTailInsert(queueList, &(node->queueList));//查到queueList的尾部
OsFutexReplaceQueueListHeadNode(*firstNode, node);//同时交换futexList链表上的位置
*firstNode = node;
return LOS_OK;
}
//如果等锁链表上没有任务或者当前任务大于链表首个任务
if (LOS_ListEmpty(queueList) && (ret1 >= 0)) {
/* Insert the next position in the queue with equal priority */
LOS_ListHeadInsert(queueList, &(node->queueList));
LOS_ListHeadInsert(queueList, &(node->queueList));//从头部插入当前任务,当前任务是要被挂起的
return LOS_OK;
}
FutexNode *tailNode = OS_FUTEX_FROM_QUEUELIST(LOS_DL_LIST_LAST(queueList));
LosTaskCB *taskTail = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(tailNode->pendList)));
FutexNode *tailNode = OS_FUTEX_FROM_QUEUELIST(LOS_DL_LIST_LAST(queueList));//获取尾部节点
LosTaskCB *taskTail = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(tailNode->pendList)));//获取阻塞任务的最后一个
INT32 ret2 = OsSchedParamCompare(taskTail, run);
if ((ret2 <= 0) || (ret1 > ret2)) {
return OsFutexInsertFindFormBackToFront(queueList, run, node);
return OsFutexInsertFindFormBackToFront(queueList, run, node);//从后往前插入
}
return OsFutexInsertFindFromFrontToBack(queueList, run, node);
return OsFutexInsertFindFromFrontToBack(queueList, run, node);//否则从前往后插入
}
/// 由指定快锁找到对应哈希桶
STATIC FutexNode *OsFindFutexNode(const FutexNode *node)
{
FutexHash *hashNode = &g_futexHash[node->index];
FutexHash *hashNode = &g_futexHash[node->index];//先找到所在哈希桶
LOS_DL_LIST *futexList = &(hashNode->lockList);
FutexNode *headNode = NULL;
for (futexList = futexList->pstNext;
futexList != &(hashNode->lockList);
futexList != &(hashNode->lockList);//判断循环结束条件,相等时说明跑完一轮了
futexList = futexList->pstNext) {
headNode = OS_FUTEX_FROM_FUTEXLIST(futexList);
if ((headNode->key == node->key) && (headNode->pid == node->pid)) {
return headNode;
}
headNode = OS_FUTEX_FROM_FUTEXLIST(futexList);//拿到快锁节点实体
if ((headNode->key == node->key) && (headNode->pid == node->pid)) {//已经存在这个节点,注意这里的比较
return headNode;//是key和pid 一起比较,因为只有这样才能确定唯一性
}//详细讲解请查看 鸿蒙内核源码分析(内核态锁篇) | 如何实现快锁Futex(下)
}
return NULL;
}
///< 查找快锁并插入哈希桶中
STATIC INT32 OsFindAndInsertToHash(FutexNode *node)
{
FutexNode *headNode = NULL;
@ -464,7 +521,7 @@ STATIC INT32 OsFindAndInsertToHash(FutexNode *node)
INT32 ret;
headNode = OsFindFutexNode(node);
if (headNode == NULL) {
if (headNode == NULL) {//没有找到,说明这是一把新锁
OsFutexInsertNewFutexKeyToHash(node);
LOS_ListInit(&(node->queueList));
return LOS_OK;
@ -483,14 +540,14 @@ STATIC INT32 OsFindAndInsertToHash(FutexNode *node)
return ret;
}
/// 共享内存检查
STATIC INT32 OsFutexKeyShmPermCheck(const UINT32 *userVaddr, const UINT32 flags)
{
PADDR_T paddr;
/* Check whether the futexKey is a shared lock */
if (!(flags & FUTEX_PRIVATE)) {
paddr = (UINTPTR)LOS_PaddrQuery((UINT32 *)userVaddr);
if (!(flags & FUTEX_PRIVATE)) {//非私有快锁
paddr = (UINTPTR)LOS_PaddrQuery((UINT32 *)userVaddr);//能否查询到物理地址
if (paddr == 0) return LOS_NOK;
}
@ -549,13 +606,13 @@ STATIC INT32 OsFutexDeleteTimeoutTaskNode(FutexHash *hashNode, FutexNode *node)
}
return LOS_ETIMEDOUT;
}
/// 将快锁节点插入任务
STATIC INT32 OsFutexInsertTaskToHash(LosTaskCB **taskCB, FutexNode **node, const UINTPTR futexKey, const UINT32 flags)
{
INT32 ret;
*taskCB = OsCurrTaskGet();
*node = &((*taskCB)->futex);
OsFutexSetKey(futexKey, flags, *node);
*taskCB = OsCurrTaskGet(); //获取当前任务
*node = &((*taskCB)->futex); //获取当前任务的快锁节点
OsFutexSetKey(futexKey, flags, *node);//设置参数 key index pid
ret = OsFindAndInsertToHash(*node);
if (ret) {
@ -565,33 +622,33 @@ STATIC INT32 OsFutexInsertTaskToHash(LosTaskCB **taskCB, FutexNode **node, const
LOS_ListInit(&((*node)->pendList));
return LOS_OK;
}
/// 将当前任务挂入等待链表中
STATIC INT32 OsFutexWaitTask(const UINT32 *userVaddr, const UINT32 flags, const UINT32 val, const UINT32 timeout)
{
INT32 futexRet;
UINT32 intSave, lockVal;
LosTaskCB *taskCB = NULL;
FutexNode *node = NULL;
UINTPTR futexKey = OsFutexFlagsToKey(userVaddr, flags);
UINT32 index = OsFutexKeyToIndex(futexKey, flags);
UINTPTR futexKey = OsFutexFlagsToKey(userVaddr, flags);//通过地址和flags 找到 key
UINT32 index = OsFutexKeyToIndex(futexKey, flags);//通过key找到哈希桶
FutexHash *hashNode = &g_futexHash[index];
if (OsFutexLock(&hashNode->listLock)) {
if (OsFutexLock(&hashNode->listLock)) {//操作快锁节点链表前先上互斥锁
return LOS_EINVAL;
}
if (LOS_ArchCopyFromUser(&lockVal, userVaddr, sizeof(UINT32))) {
//userVaddr必须是用户空间虚拟地址
if (LOS_ArchCopyFromUser(&lockVal, userVaddr, sizeof(UINT32))) {//将值拷贝到内核空间
PRINT_ERR("Futex wait param check failed! copy from user failed!\n");
futexRet = LOS_EINVAL;
goto EXIT_ERR;
}
if (lockVal != val) {
if (lockVal != val) {//对参数内部逻辑检查
futexRet = LOS_EBADF;
goto EXIT_ERR;
}
if (OsFutexInsertTaskToHash(&taskCB, &node, futexKey, flags)) {
//注意第二个参数 FutexNode *node = NULL
if (OsFutexInsertTaskToHash(&taskCB, &node, futexKey, flags)) {// node = taskCB->futex
futexRet = LOS_NOK;
goto EXIT_ERR;
}
@ -602,7 +659,7 @@ STATIC INT32 OsFutexWaitTask(const UINT32 *userVaddr, const UINT32 flags, const
taskCB->ops->wait(taskCB, &(node->pendList), timeout);
LOS_SpinUnlock(&g_taskSpin);
futexRet = OsFutexUnlock(&hashNode->listLock);
futexRet = OsFutexUnlock(&hashNode->listLock);//
if (futexRet) {
OsSchedUnlock();
LOS_IntRestore(intSave);
@ -632,21 +689,21 @@ EXIT_ERR:
EXIT_UNLOCK_ERR:
return futexRet;
}
/// 设置线程等待 | 向Futex表中插入代表被阻塞的线程的node
INT32 OsFutexWait(const UINT32 *userVaddr, UINT32 flags, UINT32 val, UINT32 absTime)
{
INT32 ret;
UINT32 timeout = LOS_WAIT_FOREVER;
ret = OsFutexWaitParamCheck(userVaddr, flags, absTime);
ret = OsFutexWaitParamCheck(userVaddr, flags, absTime);//参数检查
if (ret) {
return ret;
}
if (absTime != LOS_WAIT_FOREVER) {
timeout = OsNS2Tick((UINT64)absTime * OS_SYS_NS_PER_US);
if (absTime != LOS_WAIT_FOREVER) {//转换时间 , 内核的时间单位是 tick
timeout = OsNS2Tick((UINT64)absTime * OS_SYS_NS_PER_US); //转成 tick
}
return OsFutexWaitTask(userVaddr, flags, val, timeout);
return OsFutexWaitTask(userVaddr, flags, val, timeout);//将任务挂起 timeOut 时长
}
STATIC INT32 OsFutexWakeParamCheck(const UINT32 *userVaddr, UINT32 flags)
@ -657,12 +714,12 @@ STATIC INT32 OsFutexWakeParamCheck(const UINT32 *userVaddr, UINT32 flags)
PRINT_ERR("Futex wake param check failed! error flags: 0x%x\n", flags);
return LOS_EINVAL;
}
//地址必须在用户空间
if ((vaddr % sizeof(INT32)) || (vaddr < OS_FUTEX_KEY_BASE) || (vaddr >= OS_FUTEX_KEY_MAX)) {
PRINT_ERR("Futex wake param check failed! error userVaddr: 0x%x\n", userVaddr);
return LOS_EINVAL;
}
//必须得是个共享内存地址
if (flags && (OsFutexKeyShmPermCheck(userVaddr, flags) != LOS_OK)) {
PRINT_ERR("Futex wake param check failed! error shared memory perm userVaddr: 0x%x\n", userVaddr);
return LOS_EINVAL;
@ -672,7 +729,8 @@ STATIC INT32 OsFutexWakeParamCheck(const UINT32 *userVaddr, UINT32 flags)
}
/* Check to see if the task to be awakened has timed out
* if time out, to weak next pend task.
* if time out, to weak next pend task.
* | ,
*/
STATIC VOID OsFutexCheckAndWakePendTask(FutexNode *headNode, const INT32 wakeNumber,
FutexHash *hashNode, FutexNode **nextNode, BOOL *wakeAny)
@ -707,7 +765,19 @@ STATIC VOID OsFutexCheckAndWakePendTask(FutexNode *headNode, const INT32 wakeNum
}
return;
}
/*!
* @brief OsFutexWakeTask
*
* @param flags
* @param futexKey
* @param newHeadNode
* @param wakeAny
* @param wakeNumber
* @return
*
* @see
*/
STATIC INT32 OsFutexWakeTask(UINTPTR futexKey, UINT32 flags, INT32 wakeNumber, FutexNode **newHeadNode, BOOL *wakeAny)
{
UINT32 intSave;
@ -715,13 +785,13 @@ STATIC INT32 OsFutexWakeTask(UINTPTR futexKey, UINT32 flags, INT32 wakeNumber, F
FutexNode *headNode = NULL;
UINT32 index = OsFutexKeyToIndex(futexKey, flags);
FutexHash *hashNode = &g_futexHash[index];
FutexNode tempNode = {
FutexNode tempNode = { //先组成一个临时快锁节点,目的是为了找到哈希桶中是否有这个节点
.key = futexKey,
.index = index,
.pid = (flags & FUTEX_PRIVATE) ? LOS_GetCurrProcessID() : OS_INVALID,
};
node = OsFindFutexNode(&tempNode);
node = OsFindFutexNode(&tempNode);//找快锁节点
if (node == NULL) {
return LOS_EBADF;
}
@ -729,7 +799,7 @@ STATIC INT32 OsFutexWakeTask(UINTPTR futexKey, UINT32 flags, INT32 wakeNumber, F
headNode = node;
SCHEDULER_LOCK(intSave);
OsFutexCheckAndWakePendTask(headNode, wakeNumber, hashNode, newHeadNode, wakeAny);
OsFutexCheckAndWakePendTask(headNode, wakeNumber, hashNode, newHeadNode, wakeAny);//再找到等这把锁的唤醒指向数量的任务
if ((*newHeadNode) != NULL) {
OsFutexReplaceQueueListHeadNode(headNode, *newHeadNode);
OsFutexDeinitFutexNode(headNode);
@ -741,7 +811,7 @@ STATIC INT32 OsFutexWakeTask(UINTPTR futexKey, UINT32 flags, INT32 wakeNumber, F
return LOS_OK;
}
/// 唤醒一个被指定锁阻塞的线程
INT32 OsFutexWake(const UINT32 *userVaddr, UINT32 flags, INT32 wakeNumber)
{
INT32 ret, futexRet;
@ -750,11 +820,11 @@ INT32 OsFutexWake(const UINT32 *userVaddr, UINT32 flags, INT32 wakeNumber)
FutexHash *hashNode = NULL;
FutexNode *headNode = NULL;
BOOL wakeAny = FALSE;
//1.检查参数
if (OsFutexWakeParamCheck(userVaddr, flags)) {
return LOS_EINVAL;
}
//2.找到指定用户空间地址对应的桶
futexKey = OsFutexFlagsToKey(userVaddr, flags);
index = OsFutexKeyToIndex(futexKey, flags);
@ -762,7 +832,7 @@ INT32 OsFutexWake(const UINT32 *userVaddr, UINT32 flags, INT32 wakeNumber)
if (OsFutexLock(&hashNode->listLock)) {
return LOS_EINVAL;
}
//3.换起等待该锁的进程
ret = OsFutexWakeTask(futexKey, flags, wakeNumber, &headNode, &wakeAny);
if (ret) {
goto EXIT_ERR;
@ -776,7 +846,7 @@ INT32 OsFutexWake(const UINT32 *userVaddr, UINT32 flags, INT32 wakeNumber)
if (futexRet) {
goto EXIT_UNLOCK_ERR;
}
//4.根据指定参数决定是否发起调度
if (wakeAny == TRUE) {
LOS_MpSchedule(OS_MP_CPU_ALL);
LOS_Schedule();
@ -885,7 +955,7 @@ STATIC VOID OsFutexRequeueSplitTwoLists(FutexHash *oldHashNode, FutexNode *oldHe
tailNode->queueList.pstNext = &newHeadNode->queueList;
return;
}
/// 删除旧key并获取头节点
STATIC FutexNode *OsFutexRequeueRemoveOldKeyAndGetHead(UINTPTR oldFutexKey, UINT32 flags, INT32 wakeNumber,
UINTPTR newFutexKey, INT32 requeueCount, BOOL *wakeAny)
{
@ -921,7 +991,7 @@ STATIC FutexNode *OsFutexRequeueRemoveOldKeyAndGetHead(UINTPTR oldFutexKey, UINT
return oldHeadNode;
}
/// 检查锁在Futex表中的状态
STATIC INT32 OsFutexRequeueParamCheck(const UINT32 *oldUserVaddr, UINT32 flags, const UINT32 *newUserVaddr)
{
VADDR_T oldVaddr = (VADDR_T)(UINTPTR)oldUserVaddr;
@ -930,12 +1000,12 @@ STATIC INT32 OsFutexRequeueParamCheck(const UINT32 *oldUserVaddr, UINT32 flags,
if (oldVaddr == newVaddr) {
return LOS_EINVAL;
}
//检查标记
if ((flags & (~FUTEX_PRIVATE)) != FUTEX_REQUEUE) {
PRINT_ERR("Futex requeue param check failed! error flags: 0x%x\n", flags);
return LOS_EINVAL;
}
//检查地址范围,必须在用户空间
if ((oldVaddr % sizeof(INT32)) || (oldVaddr < OS_FUTEX_KEY_BASE) || (oldVaddr >= OS_FUTEX_KEY_MAX)) {
PRINT_ERR("Futex requeue param check failed! error old userVaddr: 0x%x\n", oldUserVaddr);
return LOS_EINVAL;
@ -948,7 +1018,7 @@ STATIC INT32 OsFutexRequeueParamCheck(const UINT32 *oldUserVaddr, UINT32 flags,
return LOS_OK;
}
/// 调整指定锁在Futex表中的位置
INT32 OsFutexRequeue(const UINT32 *userVaddr, UINT32 flags, INT32 wakeNumber, INT32 count, const UINT32 *newUserVaddr)
{
INT32 ret;
@ -965,12 +1035,12 @@ INT32 OsFutexRequeue(const UINT32 *userVaddr, UINT32 flags, INT32 wakeNumber, IN
return LOS_EINVAL;
}
oldFutexKey = OsFutexFlagsToKey(userVaddr, flags);
oldFutexKey = OsFutexFlagsToKey(userVaddr, flags);//先拿key
newFutexKey = OsFutexFlagsToKey(newUserVaddr, flags);
oldIndex = OsFutexKeyToIndex(oldFutexKey, flags);
oldIndex = OsFutexKeyToIndex(oldFutexKey, flags);//再拿所在哈希桶位置,共有80个哈希桶
newIndex = OsFutexKeyToIndex(newFutexKey, flags);
oldHashNode = &g_futexHash[oldIndex];
oldHashNode = &g_futexHash[oldIndex];//拿到对应哈希桶实体
if (OsFutexLock(&oldHashNode->listLock)) {
return LOS_EINVAL;
}

@ -1,6 +1,59 @@
/*!
* @file los_mux.c
* @brief
* @link kernel-mini-basic-ipc-mutex-guide http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-mini-basic-ipc-mutex-guide.html @endlink
@verbatim
访
访
使
访访
访访
访
使
访访
make menuconfig
LOS_MuxCreate
LOS_MuxPend
LOS_MuxPost
LOS_MuxDelete
@endverbatim
* @image html https://gitee.com/weharmonyos/resources/raw/master/27/mux.png
* @attention
\n 使
\n LiteOS-M
\n LOS_TaskPriSet
* @version
* @author weharmonyos.com | 鸿 |
* @date 2021-11-18
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2022 Huawei Device Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
@ -40,19 +93,19 @@
#ifdef LOSCFG_BASE_IPC_MUX
#define MUTEXATTR_TYPE_MASK 0x0FU
///互斥属性初始化
LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrInit(LosMuxAttr *attr)
{
if (attr == NULL) {
return LOS_EINVAL;
}
attr->protocol = LOS_MUX_PRIO_INHERIT;
attr->prioceiling = OS_TASK_PRIORITY_LOWEST;
attr->type = LOS_MUX_DEFAULT;
attr->protocol = LOS_MUX_PRIO_INHERIT; //协议默认用继承方式, A(4)task等B(19)释放锁时,B的调度优先级直接升到(4)
attr->prioceiling = OS_TASK_PRIORITY_LOWEST;//最低优先级
attr->type = LOS_MUX_DEFAULT; //默认 LOS_MUX_RECURSIVE
return LOS_OK;
}
/// ????? 销毁互斥属 ,这里啥也没干呀
LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrDestroy(LosMuxAttr *attr)
{
if (attr == NULL) {
@ -61,7 +114,7 @@ LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrDestroy(LosMuxAttr *attr)
return LOS_OK;
}
///获取互斥锁的类型属性,由outType接走,不送!
LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrGetType(const LosMuxAttr *attr, INT32 *outType)
{
INT32 type;
@ -79,7 +132,7 @@ LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrGetType(const LosMuxAttr *attr, INT32 *outTyp
return LOS_OK;
}
///设置互斥锁的类型属性
LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrSetType(LosMuxAttr *attr, INT32 type)
{
if ((attr == NULL) || (type < LOS_MUX_NORMAL) || (type > LOS_MUX_ERRORCHECK)) {
@ -89,7 +142,7 @@ LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrSetType(LosMuxAttr *attr, INT32 type)
attr->type = (UINT8)((attr->type & ~MUTEXATTR_TYPE_MASK) | (UINT32)type);
return LOS_OK;
}
///获取互斥锁的类型属性
LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrGetProtocol(const LosMuxAttr *attr, INT32 *protocol)
{
if ((attr != NULL) && (protocol != NULL)) {
@ -100,7 +153,7 @@ LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrGetProtocol(const LosMuxAttr *attr, INT32 *pr
return LOS_OK;
}
///设置互斥锁属性的协议
LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrSetProtocol(LosMuxAttr *attr, INT32 protocol)
{
if (attr == NULL) {
@ -117,7 +170,7 @@ LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrSetProtocol(LosMuxAttr *attr, INT32 protocol)
return LOS_EINVAL;
}
}
///获取互斥锁属性优先级
LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrGetPrioceiling(const LosMuxAttr *attr, INT32 *prioceiling)
{
if (attr == NULL) {
@ -130,7 +183,7 @@ LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrGetPrioceiling(const LosMuxAttr *attr, INT32
return LOS_OK;
}
///设置互斥锁属性的优先级的上限
LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrSetPrioceiling(LosMuxAttr *attr, INT32 prioceiling)
{
if ((attr == NULL) ||
@ -143,7 +196,7 @@ LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrSetPrioceiling(LosMuxAttr *attr, INT32 prioce
return LOS_OK;
}
///设置互斥锁的优先级的上限,老优先级由oldPrioceiling带走
LITE_OS_SEC_TEXT UINT32 LOS_MuxSetPrioceiling(LosMux *mutex, INT32 prioceiling, INT32 *oldPrioceiling)
{
INT32 ret;
@ -172,7 +225,7 @@ LITE_OS_SEC_TEXT UINT32 LOS_MuxSetPrioceiling(LosMux *mutex, INT32 prioceiling,
return ret;
}
///获取互斥锁的优先级的上限
LITE_OS_SEC_TEXT UINT32 LOS_MuxGetPrioceiling(const LosMux *mutex, INT32 *prioceiling)
{
if ((mutex != NULL) && (prioceiling != NULL) && (mutex->magic == OS_MUX_MAGIC)) {
@ -182,7 +235,7 @@ LITE_OS_SEC_TEXT UINT32 LOS_MuxGetPrioceiling(const LosMux *mutex, INT32 *prioce
return LOS_EINVAL;
}
///互斥锁是否有效
LITE_OS_SEC_TEXT BOOL LOS_MuxIsValid(const LosMux *mutex)
{
if ((mutex != NULL) && (mutex->magic == OS_MUX_MAGIC)) {
@ -191,7 +244,7 @@ LITE_OS_SEC_TEXT BOOL LOS_MuxIsValid(const LosMux *mutex)
return FALSE;
}
///检查互斥锁属性是否OK,否则 no ok :|)
STATIC UINT32 OsCheckMutexAttr(const LosMuxAttr *attr)
{
if (((INT8)(attr->type) < LOS_MUX_NORMAL) || (attr->type > LOS_MUX_ERRORCHECK)) {
@ -205,7 +258,7 @@ STATIC UINT32 OsCheckMutexAttr(const LosMuxAttr *attr)
}
return LOS_OK;
}
/// 初始化互斥锁
LITE_OS_SEC_TEXT UINT32 LOS_MuxInit(LosMux *mutex, const LosMuxAttr *attr)
{
UINT32 intSave;
@ -215,24 +268,24 @@ LITE_OS_SEC_TEXT UINT32 LOS_MuxInit(LosMux *mutex, const LosMuxAttr *attr)
}
if (attr == NULL) {
(VOID)LOS_MuxAttrInit(&mutex->attr);
(VOID)LOS_MuxAttrInit(&mutex->attr);//属性初始化
} else {
(VOID)memcpy_s(&mutex->attr, sizeof(LosMuxAttr), attr, sizeof(LosMuxAttr));
(VOID)memcpy_s(&mutex->attr, sizeof(LosMuxAttr), attr, sizeof(LosMuxAttr));//把attr 拷贝到 mutex->attr
}
if (OsCheckMutexAttr(&mutex->attr) != LOS_OK) {
if (OsCheckMutexAttr(&mutex->attr) != LOS_OK) {//检查属性
return LOS_EINVAL;
}
SCHEDULER_LOCK(intSave);
mutex->muxCount = 0;
mutex->owner = NULL;
LOS_ListInit(&mutex->muxList);
mutex->magic = OS_MUX_MAGIC;
SCHEDULER_UNLOCK(intSave);
SCHEDULER_LOCK(intSave); //拿到调度自旋锁
mutex->muxCount = 0; //锁定互斥量的次数
mutex->owner = NULL; //谁持有该锁
LOS_ListInit(&mutex->muxList); //互斥量双循环链表
mutex->magic = OS_MUX_MAGIC; //固定标识,互斥锁的魔法数字
SCHEDULER_UNLOCK(intSave); //释放调度自旋锁
return LOS_OK;
}
///销毁互斥锁
LITE_OS_SEC_TEXT UINT32 LOS_MuxDestroy(LosMux *mutex)
{
UINT32 intSave;
@ -241,22 +294,22 @@ LITE_OS_SEC_TEXT UINT32 LOS_MuxDestroy(LosMux *mutex)
return LOS_EINVAL;
}
SCHEDULER_LOCK(intSave);
SCHEDULER_LOCK(intSave); //保存调度自旋锁
if (mutex->magic != OS_MUX_MAGIC) {
SCHEDULER_UNLOCK(intSave);
SCHEDULER_UNLOCK(intSave);//释放调度自旋锁
return LOS_EBADF;
}
if (mutex->muxCount != 0) {
SCHEDULER_UNLOCK(intSave);
SCHEDULER_UNLOCK(intSave);//释放调度自旋锁
return LOS_EBUSY;
}
(VOID)memset_s(mutex, sizeof(LosMux), 0, sizeof(LosMux));
SCHEDULER_UNLOCK(intSave);
(VOID)memset_s(mutex, sizeof(LosMux), 0, sizeof(LosMux));//很简单,全部清0处理.
SCHEDULER_UNLOCK(intSave); //释放调度自旋锁
return LOS_OK;
}
///设置互斥锁位图
STATIC VOID OsMuxBitmapSet(const LosMux *mutex, const LosTaskCB *runTask)
{
if (mutex->attr.protocol != LOS_MUX_PRIO_INHERIT) {
@ -271,7 +324,7 @@ STATIC VOID OsMuxBitmapSet(const LosMux *mutex, const LosTaskCB *runTask)
owner->ops->priorityInheritance(owner, &param);
}
}
///恢复互斥锁位图
VOID OsMuxBitmapRestore(const LosMux *mutex, const LOS_DL_LIST *list, const LosTaskCB *runTask)
{
if (mutex->attr.protocol != LOS_MUX_PRIO_INHERIT) {
@ -284,20 +337,21 @@ VOID OsMuxBitmapRestore(const LosMux *mutex, const LOS_DL_LIST *list, const LosT
owner->ops->priorityRestore(owner, list, &param);
}
/// 最坏情况就是拿锁失败,让出CPU,变成阻塞任务,等别的任务释放锁后排到自己了接着执行.
STATIC UINT32 OsMuxPendOp(LosTaskCB *runTask, LosMux *mutex, UINT32 timeout)
{
UINT32 ret;
if ((mutex->muxList.pstPrev == NULL) || (mutex->muxList.pstNext == NULL)) {
if ((mutex->muxList.pstPrev == NULL) || (mutex->muxList.pstNext == NULL)) {//列表为空时的处理
/* This is for mutex macro initialization. */
mutex->muxCount = 0;
mutex->owner = NULL;
LOS_ListInit(&mutex->muxList);
mutex->muxCount = 0;//锁计数器清0
mutex->owner = NULL;//锁没有归属任务
LOS_ListInit(&mutex->muxList);//初始化锁的任务链表,后续申请这把锁任务都会挂上去
}
if (mutex->muxCount == 0) {
mutex->muxCount++;
mutex->owner = (VOID *)runTask;
if (mutex->muxCount == 0) {//无task用锁时,肯定能拿到锁了.在里面返回
mutex->muxCount++; //互斥锁计数器加1
mutex->owner = (VOID *)runTask; //当前任务拿到锁
LOS_ListTailInsert(&runTask->lockList, &mutex->holdList);
if (mutex->attr.protocol == LOS_MUX_PRIO_PROTECT) {
SchedParam param = { 0 };
@ -307,23 +361,23 @@ STATIC UINT32 OsMuxPendOp(LosTaskCB *runTask, LosMux *mutex, UINT32 timeout)
}
return LOS_OK;
}
if (((LosTaskCB *)mutex->owner == runTask) && (mutex->attr.type == LOS_MUX_RECURSIVE)) {
mutex->muxCount++;
return LOS_OK;
//递归锁muxCount>0 如果是递归锁就要处理两种情况 1.runtask持有锁 2.锁被别的任务拿走了
if (((LosTaskCB *)mutex->owner == runTask) && (mutex->attr.type == LOS_MUX_RECURSIVE)) {//第一种情况 runtask是锁持有方
mutex->muxCount++; //递归锁计数器加1,递归锁的目的是防止死锁,鸿蒙默认用的就是递归锁(LOS_MUX_DEFAULT = LOS_MUX_RECURSIVE)
return LOS_OK; //成功退出
}
if (!timeout) {
return LOS_EINVAL;
//到了这里说明锁在别的任务那里,当前任务只能被阻塞了.
if (!timeout) {//参数timeout表示等待多久再来拿锁
return LOS_EINVAL;//timeout = 0表示不等了,没拿到锁就返回不纠结,返回错误.见于LOS_MuxTrylock
}
if (!OsPreemptableInSched()) {
return LOS_EDEADLK;
//自己要被阻塞,只能申请调度,让出CPU core 让别的任务上
if (!OsPreemptableInSched()) {//不能申请调度 (不能调度的原因是因为没有持有调度任务自旋锁)
return LOS_EDEADLK;//返回错误,自旋锁被别的CPU core 持有
}
OsMuxBitmapSet(mutex, runTask);
OsMuxBitmapSet(mutex, runTask);//设置锁位图,尽可能的提高锁持有任务的优先级
runTask->taskMux = (VOID *)mutex;
runTask->taskMux = (VOID *)mutex; //记下当前任务在等待这把锁
LOS_DL_LIST *node = OsSchedLockPendFindPos(runTask, &mutex->muxList);
if (node == NULL) {
ret = LOS_NOK;
@ -332,10 +386,10 @@ STATIC UINT32 OsMuxPendOp(LosTaskCB *runTask, LosMux *mutex, UINT32 timeout)
OsTaskWaitSetPendMask(OS_TASK_WAIT_MUTEX, (UINTPTR)mutex, timeout);
ret = runTask->ops->wait(runTask, node, timeout);
if (ret == LOS_ERRNO_TSK_TIMEOUT) {
if (ret == LOS_ERRNO_TSK_TIMEOUT) {//这行代码虽和OsTaskWait挨在一起,但要过很久才会执行到,因为在OsTaskWait中CPU切换了任务上下文
OsMuxBitmapRestore(mutex, NULL, runTask);
runTask->taskMux = NULL;
ret = LOS_ETIMEDOUT;
runTask->taskMux = NULL;// 所以重新回到这里时可能已经超时了
ret = LOS_ETIMEDOUT;//返回超时
}
return ret;
@ -343,7 +397,7 @@ STATIC UINT32 OsMuxPendOp(LosTaskCB *runTask, LosMux *mutex, UINT32 timeout)
UINT32 OsMuxLockUnsafe(LosMux *mutex, UINT32 timeout)
{
LosTaskCB *runTask = OsCurrTaskGet();
LosTaskCB *runTask = OsCurrTaskGet();//获取当前任务
if (mutex->magic != OS_MUX_MAGIC) {
return LOS_EBADF;
@ -352,23 +406,23 @@ UINT32 OsMuxLockUnsafe(LosMux *mutex, UINT32 timeout)
if (OsCheckMutexAttr(&mutex->attr) != LOS_OK) {
return LOS_EINVAL;
}
//LOS_MUX_ERRORCHECK 时 muxCount是要等于0 ,当前任务持有锁就不能再lock了. 鸿蒙默认用的是递归锁LOS_MUX_RECURSIVE
if ((mutex->attr.type == LOS_MUX_ERRORCHECK) && (mutex->owner == (VOID *)runTask)) {
return LOS_EDEADLK;
}
return OsMuxPendOp(runTask, mutex, timeout);
}
/// 尝试加锁,
UINT32 OsMuxTrylockUnsafe(LosMux *mutex, UINT32 timeout)
{
LosTaskCB *runTask = OsCurrTaskGet();
LosTaskCB *runTask = OsCurrTaskGet();//获取当前任务
if (mutex->magic != OS_MUX_MAGIC) {
if (mutex->magic != OS_MUX_MAGIC) {//检查MAGIC有没有被改变
return LOS_EBADF;
}
if (OsCheckMutexAttr(&mutex->attr) != LOS_OK) {
if (OsCheckMutexAttr(&mutex->attr) != LOS_OK) {//检查互斥锁属性
return LOS_EINVAL;
}
@ -377,9 +431,9 @@ UINT32 OsMuxTrylockUnsafe(LosMux *mutex, UINT32 timeout)
return LOS_EBUSY;
}
return OsMuxPendOp(runTask, mutex, timeout);
return OsMuxPendOp(runTask, mutex, timeout);//当前任务去拿锁,拿不到就等timeout
}
/// 拿互斥锁,
LITE_OS_SEC_TEXT UINT32 LOS_MuxLock(LosMux *mutex, UINT32 timeout)
{
LosTaskCB *runTask = NULL;
@ -394,19 +448,19 @@ LITE_OS_SEC_TEXT UINT32 LOS_MuxLock(LosMux *mutex, UINT32 timeout)
return LOS_EINTR;
}
runTask = (LosTaskCB *)OsCurrTaskGet();
runTask = (LosTaskCB *)OsCurrTaskGet();//获取当前任务
/* DO NOT Call blocking API in system tasks */
if (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) {
if (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) {//不要在内核任务里用mux锁
PRINTK("Warning: DO NOT call %s in system tasks.\n", __FUNCTION__);
OsBackTrace();
OsBackTrace();//打印task信息
}
SCHEDULER_LOCK(intSave);
ret = OsMuxLockUnsafe(mutex, timeout);
SCHEDULER_LOCK(intSave);//调度自旋锁
ret = OsMuxLockUnsafe(mutex, timeout);//如果任务没拿到锁,将进入阻塞队列一直等待,直到timeout或者持锁任务释放锁时唤醒它
SCHEDULER_UNLOCK(intSave);
return ret;
}
///尝试要锁,没拿到也不等,直接返回,不纠结
LITE_OS_SEC_TEXT UINT32 LOS_MuxTrylock(LosMux *mutex)
{
LosTaskCB *runTask = NULL;
@ -421,39 +475,50 @@ LITE_OS_SEC_TEXT UINT32 LOS_MuxTrylock(LosMux *mutex)
return LOS_EINTR;
}
runTask = (LosTaskCB *)OsCurrTaskGet();
runTask = (LosTaskCB *)OsCurrTaskGet();//获取当前执行的任务
/* DO NOT Call blocking API in system tasks */
if (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) {
if (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) {//系统任务不能
PRINTK("Warning: DO NOT call %s in system tasks.\n", __FUNCTION__);
OsBackTrace();
}
SCHEDULER_LOCK(intSave);
ret = OsMuxTrylockUnsafe(mutex, 0);
ret = OsMuxTrylockUnsafe(mutex, 0);//timeout = 0,不等待,没拿到锁就算了
SCHEDULER_UNLOCK(intSave);
return ret;
}
/*!
* @brief OsMuxPostOp
* ,,
* OsMuxPostOpOsMuxUnlockUnsafe,,, ,OsMuxPostOp
* @param mutex
* @param needSched
* @param taskCB
* @return
*
* @see
*/
STATIC UINT32 OsMuxPostOp(LosTaskCB *taskCB, LosMux *mutex, BOOL *needSched)
{
if (LOS_ListEmpty(&mutex->muxList)) {
LOS_ListDelete(&mutex->holdList);
if (LOS_ListEmpty(&mutex->muxList)) {//如果互斥锁列表为空
LOS_ListDelete(&mutex->holdList);//把持有互斥锁的节点摘掉
mutex->owner = NULL;
return LOS_OK;
}
LosTaskCB *resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(mutex->muxList)));
LosTaskCB *resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(mutex->muxList)));//拿到等待互斥锁链表的第一个任务实体,接下来要唤醒任务
OsMuxBitmapRestore(mutex, &mutex->muxList, resumedTask);
mutex->muxCount = 1;
mutex->owner = (VOID *)resumedTask;
LOS_ListDelete(&mutex->holdList);
LOS_ListTailInsert(&resumedTask->lockList, &mutex->holdList);
mutex->muxCount = 1;//互斥锁数量为1
mutex->owner = (VOID *)resumedTask;//互斥锁的持有人换了
LOS_ListDelete(&mutex->holdList);//自然要从等锁链表中把自己摘出去
LOS_ListTailInsert(&resumedTask->lockList, &mutex->holdList);//把锁挂到恢复任务的锁链表上,lockList是任务持有的所有锁记录
OsTaskWakeClearPendMask(resumedTask);
resumedTask->ops->wake(resumedTask);
resumedTask->taskMux = NULL;
if (needSched != NULL) {
*needSched = TRUE;
if (needSched != NULL) {//如果不为空
*needSched = TRUE;//就走起再次调度流程
}
return LOS_OK;
@ -476,21 +541,21 @@ UINT32 OsMuxUnlockUnsafe(LosTaskCB *taskCB, LosMux *mutex, BOOL *needSched)
if (mutex->muxCount == 0) {
return LOS_EPERM;
}
if ((--mutex->muxCount != 0) && (mutex->attr.type == LOS_MUX_RECURSIVE)) {
//注意 --mutex->muxCount 先执行了-- 操作.
if ((--mutex->muxCount != 0) && (mutex->attr.type == LOS_MUX_RECURSIVE)) {//属性类型为LOS_MUX_RECURSIVE时,muxCount是可以不为0的
return LOS_OK;
}
if (mutex->attr.protocol == LOS_MUX_PRIO_PROTECT) {
if (mutex->attr.protocol == LOS_MUX_PRIO_PROTECT) {//属性协议为保护时
SchedParam param = { 0 };
taskCB->ops->schedParamGet(taskCB, &param);
taskCB->ops->priorityRestore(taskCB, NULL, &param);
}
/* Whether a task block the mutex lock. */
return OsMuxPostOp(taskCB, mutex, needSched);
/* Whether a task block the mutex lock. *///任务是否阻塞互斥锁
return OsMuxPostOp(taskCB, mutex, needSched);//一个任务去唤醒另一个在等锁的任务
}
///释放锁
LITE_OS_SEC_TEXT UINT32 LOS_MuxUnlock(LosMux *mutex)
{
LosTaskCB *runTask = NULL;
@ -506,9 +571,9 @@ LITE_OS_SEC_TEXT UINT32 LOS_MuxUnlock(LosMux *mutex)
return LOS_EINTR;
}
runTask = (LosTaskCB *)OsCurrTaskGet();
runTask = (LosTaskCB *)OsCurrTaskGet();//获取当前任务
/* DO NOT Call blocking API in system tasks */
if (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) {
if (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) {//不能在系统任务里调用,因为很容易让系统任务发生死锁
PRINTK("Warning: DO NOT call %s in system tasks.\n", __FUNCTION__);
OsBackTrace();
}
@ -516,12 +581,12 @@ LITE_OS_SEC_TEXT UINT32 LOS_MuxUnlock(LosMux *mutex)
SCHEDULER_LOCK(intSave);
ret = OsMuxUnlockUnsafe(runTask, mutex, &needSched);
SCHEDULER_UNLOCK(intSave);
if (needSched == TRUE) {
LOS_MpSchedule(OS_MP_CPU_ALL);
LOS_Schedule();
if (needSched == TRUE) {//需要调度的情况
LOS_MpSchedule(OS_MP_CPU_ALL);//向所有CPU发送调度指令
LOS_Schedule();//发起调度
}
return ret;
}
#endif /* LOSCFG_BASE_IPC_MUX */
#endif /* (LOSCFG_BASE_IPC_MUX == YES) */

File diff suppressed because it is too large Load Diff

@ -1,6 +1,32 @@
/*!
* @file los_rwlock.c
* @brief
* @link rwlock https://weharmony.github.io/openharmony/zh-cn/device-dev/kernel/kernel-small-basic-trans-rwlock.html @endlink
@verbatim
使
访访
访
-
访
A
A
@endverbatim
@image html
* @attention
* @version
* @author weharmonyos.com | 鸿 |
* @date 2022-02-18
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2022 Huawei Device Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
@ -37,9 +63,10 @@
#include "los_exc.h"
#include "los_sched_pri.h"
#ifdef LOSCFG_BASE_IPC_RWLOCK
#define RWLOCK_COUNT_MASK 0x00FFFFFFU
/// 判断读写锁有效性
BOOL LOS_RwlockIsValid(const LosRwlock *rwlock)
{
if ((rwlock != NULL) && ((rwlock->magic & RWLOCK_COUNT_MASK) == OS_RWLOCK_MAGIC)) {
@ -48,7 +75,7 @@ BOOL LOS_RwlockIsValid(const LosRwlock *rwlock)
return FALSE;
}
/// 创建读写锁,初始化锁信息
UINT32 LOS_RwlockInit(LosRwlock *rwlock)
{
UINT32 intSave;
@ -71,7 +98,7 @@ UINT32 LOS_RwlockInit(LosRwlock *rwlock)
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
}
/// 删除指定的读写锁
UINT32 LOS_RwlockDestroy(LosRwlock *rwlock)
{
UINT32 intSave;
@ -95,18 +122,18 @@ UINT32 LOS_RwlockDestroy(LosRwlock *rwlock)
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
}
/// 读写锁检查
STATIC UINT32 OsRwlockCheck(const LosRwlock *rwlock)
{
if (rwlock == NULL) {
return LOS_EINVAL;
}
if (OS_INT_ACTIVE) {
if (OS_INT_ACTIVE) { // 读写锁不能在中断服务程序中使用。请想想为什么 ?
return LOS_EINTR;
}
/* DO NOT Call blocking API in system tasks */
/* DO NOT Call blocking API in system tasks | 系统任务不能使用读写锁 */
LosTaskCB *runTask = (LosTaskCB *)OsCurrTaskGet();
if (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) {
return LOS_EPERM;
@ -114,19 +141,23 @@ STATIC UINT32 OsRwlockCheck(const LosRwlock *rwlock)
return LOS_OK;
}
/// 指定任务优先级优先级是否低于 写锁任务最高优先级
STATIC BOOL OsRwlockPriCompare(LosTaskCB *runTask, LOS_DL_LIST *rwList)
{
if (!LOS_ListEmpty(rwList)) {
LosTaskCB *highestTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(rwList));
if (OsSchedParamCompare(runTask, highestTask) < 0) {
LosTaskCB *highestTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(rwList));//首个写锁任务优先级是最高的
if (OsSchedParamCompare(runTask, highestTask) < 0) {//如果当前任务优先级低于等待写锁任务
return TRUE;
}
return FALSE;
}
return TRUE;
}
/* 申请读模式下的锁,分三种情况:
1.
2.
3.
*/
STATIC UINT32 OsRwlockRdPendOp(LosTaskCB *runTask, LosRwlock *rwlock, UINT32 timeout)
{
UINT32 ret;
@ -135,12 +166,12 @@ STATIC UINT32 OsRwlockRdPendOp(LosTaskCB *runTask, LosRwlock *rwlock, UINT32 tim
* When the rwlock mode is read mode or free mode and the priority of the current read task
* is higher than the first pended write task. current read task can obtain this rwlock.
*/
if (rwlock->rwCount >= 0) {
if (OsRwlockPriCompare(runTask, &(rwlock->writeList))) {
if (rwlock->rwCount == INT8_MAX) {
if (rwlock->rwCount >= 0) {//第一和第二种情况
if (OsRwlockPriCompare(runTask, &(rwlock->writeList))) {//读优先级低于写优先级,意思就是必须先写再读
if (rwlock->rwCount == INT8_MAX) {//读锁任务达到上限
return LOS_EINVAL;
}
rwlock->rwCount++;
rwlock->rwCount++;//拿读锁成功
return LOS_OK;
}
}
@ -149,45 +180,51 @@ STATIC UINT32 OsRwlockRdPendOp(LosTaskCB *runTask, LosRwlock *rwlock, UINT32 tim
return LOS_EINVAL;
}
if (!OsPreemptableInSched()) {
if (!OsPreemptableInSched()) {//不可抢占时
return LOS_EDEADLK;
}
/* The current task is not allowed to obtain the write lock when it obtains the read lock. */
if ((LosTaskCB *)(rwlock->writeOwner) == runTask) {
/* The current task is not allowed to obtain the write lock when it obtains the read lock.
| */
if ((LosTaskCB *)(rwlock->writeOwner) == runTask) { //拥有写锁任务是否为当前任务
return LOS_EINVAL;
}
/*
* When the rwlock mode is write mode or the priority of the current read task
* is lower than the first pended write task, current read task will be pended.
| rwlock
*/
LOS_DL_LIST *node = OsSchedLockPendFindPos(runTask, &(rwlock->readList));
ret = runTask->ops->wait(runTask, node, timeout);
LOS_DL_LIST *node = OsSchedLockPendFindPos(runTask, &(rwlock->readList));//找到要挂入的位置
//例如现有链表内任务优先级为 0 3 8 9 23 当前为 10 时, 返回的是 9 这个节点
ret = runTask->ops->wait(runTask, node, timeout);//从尾部插入读锁链表 由此变成了 0 3 8 9 10 23
if (ret == LOS_ERRNO_TSK_TIMEOUT) {
return LOS_ETIMEDOUT;
}
return ret;
}
/// 申请写模式下的锁
STATIC UINT32 OsRwlockWrPendOp(LosTaskCB *runTask, LosRwlock *rwlock, UINT32 timeout)
{
UINT32 ret;
/* When the rwlock is free mode, current write task can obtain this rwlock. */
/* When the rwlock is free mode, current write task can obtain this rwlock.
| */
if (rwlock->rwCount == 0) {
rwlock->rwCount = -1;
rwlock->writeOwner = (VOID *)runTask;
rwlock->writeOwner = (VOID *)runTask;//直接给当前进程锁
return LOS_OK;
}
/* Current write task can use one rwlock once again if the rwlock owner is it. */
/* Current write task can use one rwlock once again if the rwlock owner is it.
| rwlock 使*/
if ((rwlock->rwCount < 0) && ((LosTaskCB *)(rwlock->writeOwner) == runTask)) {
if (rwlock->rwCount == INT8_MIN) {
return LOS_EINVAL;
}
rwlock->rwCount--;
rwlock->rwCount--;//注意再次拥有算是两把写锁了.
return LOS_OK;
}
@ -201,9 +238,9 @@ STATIC UINT32 OsRwlockWrPendOp(LosTaskCB *runTask, LosRwlock *rwlock, UINT32 tim
/*
* When the rwlock is read mode or other write task obtains this rwlock, current
* write task will be pended.
* write task will be pended. | rwlock rwlock
*/
LOS_DL_LIST *node = OsSchedLockPendFindPos(runTask, &(rwlock->writeList));
LOS_DL_LIST *node = OsSchedLockPendFindPos(runTask, &(rwlock->writeList));//找到要挂入的位置
ret = runTask->ops->wait(runTask, node, timeout);
if (ret == LOS_ERRNO_TSK_TIMEOUT) {
ret = LOS_ETIMEDOUT;
@ -265,20 +302,22 @@ UINT32 OsRwlockTryWrUnsafe(LosRwlock *rwlock, UINT32 timeout)
return LOS_EBADF;
}
/* When the rwlock is read mode, current write task will be pended. */
/* When the rwlock is read mode, current write task will be pended.
| rwlock */
if (rwlock->rwCount > 0) {
return LOS_EBUSY;
}
/* When other write task obtains this rwlock, current write task will be pended. */
/* When other write task obtains this rwlock, current write task will be pended.
| rwlock*/
LosTaskCB *runTask = OsCurrTaskGet();
if ((rwlock->rwCount < 0) && ((LosTaskCB *)(rwlock->writeOwner) != runTask)) {
return LOS_EBUSY;
}
return OsRwlockWrPendOp(runTask, rwlock, timeout);
return OsRwlockWrPendOp(runTask, rwlock, timeout);//
}
/// 申请指定的读模式下的锁
UINT32 LOS_RwlockRdLock(LosRwlock *rwlock, UINT32 timeout)
{
UINT32 intSave;
@ -293,7 +332,7 @@ UINT32 LOS_RwlockRdLock(LosRwlock *rwlock, UINT32 timeout)
SCHEDULER_UNLOCK(intSave);
return ret;
}
/// 尝试申请指定的读模式下的锁
UINT32 LOS_RwlockTryRdLock(LosRwlock *rwlock)
{
UINT32 intSave;
@ -304,11 +343,11 @@ UINT32 LOS_RwlockTryRdLock(LosRwlock *rwlock)
}
SCHEDULER_LOCK(intSave);
ret = OsRwlockTryRdUnsafe(rwlock, 0);
ret = OsRwlockTryRdUnsafe(rwlock, 0);//所谓尝试就是没锁爷就返回,不等待,不纠结.当前任务也不会被挂起
SCHEDULER_UNLOCK(intSave);
return ret;
}
/// 申请指定的写模式下的锁
UINT32 LOS_RwlockWrLock(LosRwlock *rwlock, UINT32 timeout)
{
UINT32 intSave;
@ -323,7 +362,7 @@ UINT32 LOS_RwlockWrLock(LosRwlock *rwlock, UINT32 timeout)
SCHEDULER_UNLOCK(intSave);
return ret;
}
/// 尝试申请指定的写模式下的锁
UINT32 LOS_RwlockTryWrLock(LosRwlock *rwlock)
{
UINT32 intSave;
@ -334,32 +373,32 @@ UINT32 LOS_RwlockTryWrLock(LosRwlock *rwlock)
}
SCHEDULER_LOCK(intSave);
ret = OsRwlockTryWrUnsafe(rwlock, 0);
ret = OsRwlockTryWrUnsafe(rwlock, 0);//所谓尝试就是没锁爷就返回,不等待,不纠结.当前任务也不会被挂起
SCHEDULER_UNLOCK(intSave);
return ret;
}
/// 获取读写锁模式
STATIC UINT32 OsRwlockGetMode(LOS_DL_LIST *readList, LOS_DL_LIST *writeList)
{
BOOL isReadEmpty = LOS_ListEmpty(readList);
BOOL isWriteEmpty = LOS_ListEmpty(writeList);
if (isReadEmpty && isWriteEmpty) {
return RWLOCK_NONE_MODE;
if (isReadEmpty && isWriteEmpty) { //读写链表都没有内容
return RWLOCK_NONE_MODE; //自由模式
}
if (!isReadEmpty && isWriteEmpty) {
if (!isReadEmpty && isWriteEmpty) { //读链表有数据,写链表没有数据
return RWLOCK_READ_MODE;
}
if (isReadEmpty && !isWriteEmpty) {
if (isReadEmpty && !isWriteEmpty) { //写链表有数据,读链表没有数据
return RWLOCK_WRITE_MODE;
}
LosTaskCB *pendedReadTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(readList));
LosTaskCB *pendedWriteTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(writeList));
if (OsSchedParamCompare(pendedWriteTask, pendedReadTask) <= 0) {
return RWLOCK_WRITEFIRST_MODE;
return RWLOCK_WRITEFIRST_MODE; //写的优先级高时,为写优先模式
}
return RWLOCK_READFIRST_MODE;
return RWLOCK_READFIRST_MODE; //读的优先级高时,为读优先模式
}
/// 释放锁
STATIC UINT32 OsRwlockPostOp(LosRwlock *rwlock, BOOL *needSched)
{
UINT32 rwlockMode;
@ -367,15 +406,15 @@ STATIC UINT32 OsRwlockPostOp(LosRwlock *rwlock, BOOL *needSched)
rwlock->rwCount = 0;
rwlock->writeOwner = NULL;
rwlockMode = OsRwlockGetMode(&(rwlock->readList), &(rwlock->writeList));
if (rwlockMode == RWLOCK_NONE_MODE) {
rwlockMode = OsRwlockGetMode(&(rwlock->readList), &(rwlock->writeList));//先获取模式
if (rwlockMode == RWLOCK_NONE_MODE) {//自由模式则正常返回
return LOS_OK;
}
/* In this case, rwlock will wake the first pended write task. */
if ((rwlockMode == RWLOCK_WRITE_MODE) || (rwlockMode == RWLOCK_WRITEFIRST_MODE)) {
resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(rwlock->writeList)));
rwlock->rwCount = -1;
rwlock->writeOwner = (VOID *)resumedTask;
/* In this case, rwlock will wake the first pended write task. | 在这种情况下rwlock 将唤醒第一个挂起的写任务。 */
if ((rwlockMode == RWLOCK_WRITE_MODE) || (rwlockMode == RWLOCK_WRITEFIRST_MODE)) {//如果当前是写模式 (有任务在等写锁涅)
resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(rwlock->writeList)));//获取任务实体
rwlock->rwCount = -1;//直接干成-1,注意这里并不是 --
rwlock->writeOwner = (VOID *)resumedTask;//有锁了则唤醒等锁的任务(写模式)
resumedTask->ops->wake(resumedTask);
if (needSched != NULL) {
*needSched = TRUE;
@ -383,29 +422,30 @@ STATIC UINT32 OsRwlockPostOp(LosRwlock *rwlock, BOOL *needSched)
return LOS_OK;
}
rwlock->rwCount = 1;
rwlock->rwCount = 1; //直接干成1,因为是释放操作
resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(rwlock->readList)));
resumedTask->ops->wake(resumedTask);
while (!LOS_ListEmpty(&(rwlock->readList))) {
while (!LOS_ListEmpty(&(rwlock->readList))) {//遍历读链表,目的是要唤醒其他读模式的任务(优先级得要高于pendedWriteTaskPri才行)
resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(rwlock->readList)));
if (rwlockMode == RWLOCK_READFIRST_MODE) {
LosTaskCB *pendedWriteTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(rwlock->writeList)));
if (OsSchedParamCompare(resumedTask, pendedWriteTask) >= 0) {
break;
}
break;//跳出循环
}
}
if (rwlock->rwCount == INT8_MAX) {
return EINVAL;
}
rwlock->rwCount++;
resumedTask->ops->wake(resumedTask);
rwlock->rwCount++;//读锁任务数量增加
resumedTask->ops->wake(resumedTask);//不断唤醒读锁任务,由此实现了允许多个读操作并发,因为在多核情况下resumedTask很大可能
//与当前任务并不在同一个核上运行, 此处非常有意思,点赞! @note_good
}
if (needSched != NULL) {
*needSched = TRUE;
}
return LOS_OK;
}
/// 释放锁,唤醒任务
UINT32 OsRwlockUnlockUnsafe(LosRwlock *rwlock, BOOL *needSched)
{
if ((rwlock->magic & RWLOCK_COUNT_MASK) != OS_RWLOCK_MAGIC) {
@ -417,27 +457,28 @@ UINT32 OsRwlockUnlockUnsafe(LosRwlock *rwlock, BOOL *needSched)
}
LosTaskCB *runTask = OsCurrTaskGet();
if ((rwlock->rwCount < 0) && ((LosTaskCB *)(rwlock->writeOwner) != runTask)) {
if ((rwlock->rwCount < 0) && ((LosTaskCB *)(rwlock->writeOwner) != runTask)) {//写模式时,当前任务未持有锁
return LOS_EPERM;
}
/*
* When the rwCount of the rwlock more than 1 or less than -1, the rwlock mode will
* not changed after current unlock operation, so pended tasks can not be waken.
| rwlock rwCount 1 -1 rwlock
*/
if (rwlock->rwCount > 1) {
if (rwlock->rwCount > 1) {//读模式
rwlock->rwCount--;
return LOS_OK;
}
if (rwlock->rwCount < -1) {
if (rwlock->rwCount < -1) {//写模式
rwlock->rwCount++;
return LOS_OK;
}
return OsRwlockPostOp(rwlock, needSched);
}
/// 释放指定读写锁
UINT32 LOS_RwlockUnLock(LosRwlock *rwlock)
{
UINT32 intSave;
@ -451,9 +492,9 @@ UINT32 LOS_RwlockUnLock(LosRwlock *rwlock)
SCHEDULER_LOCK(intSave);
ret = OsRwlockUnlockUnsafe(rwlock, &needSched);
SCHEDULER_UNLOCK(intSave);
LOS_MpSchedule(OS_MP_CPU_ALL);
if (needSched == TRUE) {
LOS_Schedule();
LOS_MpSchedule(OS_MP_CPU_ALL);//设置调度CPU的方式,所有CPU参与调度
if (needSched == TRUE) {//是否需要调度
LOS_Schedule();//产生调度,切换任务执行
}
return ret;
}

@ -1,6 +1,52 @@
/*!
* @file los_sem.c
* @brief
* @link kernel-mini-basic-ipc-sem-basic http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-mini-basic-ipc-sem-basic.html @endlink
@verbatim
Semaphore访
使
0
使
0使
使使0
访1使
0121ReadyRunning
NNLOSCFG_BASE_IPC_SEM_LIMIT使
使使
使
01
1
使使使
访访访
LOS_SemCreateLOS_BinarySemCreate
LOS_SemPend
LOS_SemPost
LOS_SemDelete
@endverbatim
* @image html https://gitee.com/weharmonyos/resources/raw/master/29/sem_run.png
* @attention 使
* @version
* @author weharmonyos.com | 鸿 |
* @date 2021-11-18
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2022 Huawei Device Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
@ -40,17 +86,18 @@
#include "los_percpu_pri.h"
#include "los_hook.h"
#ifdef LOSCFG_BASE_IPC_SEM
#if (LOSCFG_BASE_IPC_SEM_LIMIT <= 0)
#error "sem maxnum cannot be zero"
#endif /* LOSCFG_BASE_IPC_SEM_LIMIT <= 0 */
LITE_OS_SEC_DATA_INIT STATIC LOS_DL_LIST g_unusedSemList;
LITE_OS_SEC_BSS LosSemCB *g_allSem = NULL;
LITE_OS_SEC_DATA_INIT STATIC LOS_DL_LIST g_unusedSemList; ///< 可用的信号量列表,干嘛不用freeList? 可以看出这里是另一个人写的代码
LITE_OS_SEC_BSS LosSemCB *g_allSem = NULL; ///< 信号池,一次分配 LOSCFG_BASE_IPC_SEM_LIMIT 个信号量
/*
* Description : Initialize the semaphore doubly linked list
* Description : Initialize the semaphore doubly linked list |
* Return : LOS_OK on success, or error code on failure
*/
LITE_OS_SEC_TEXT_INIT UINT32 OsSemInit(VOID)
@ -58,18 +105,18 @@ LITE_OS_SEC_TEXT_INIT UINT32 OsSemInit(VOID)
LosSemCB *semNode = NULL;
UINT32 index;
LOS_ListInit(&g_unusedSemList);
LOS_ListInit(&g_unusedSemList);//初始化链表,链表上挂未使用的信号量,用于分配信号量,鸿蒙信号量的个数是有限的,默认1024个
/* system resident memory, don't free */
g_allSem = (LosSemCB *)LOS_MemAlloc(m_aucSysMem0, (LOSCFG_BASE_IPC_SEM_LIMIT * sizeof(LosSemCB)));
g_allSem = (LosSemCB *)LOS_MemAlloc(m_aucSysMem0, (LOSCFG_BASE_IPC_SEM_LIMIT * sizeof(LosSemCB)));//分配信号池
if (g_allSem == NULL) {
return LOS_ERRNO_SEM_NO_MEMORY;
}
for (index = 0; index < LOSCFG_BASE_IPC_SEM_LIMIT; index++) {
semNode = ((LosSemCB *)g_allSem) + index;
semNode->semID = SET_SEM_ID(0, index);
semNode->semStat = OS_SEM_UNUSED;
LOS_ListTailInsert(&g_unusedSemList, &semNode->semList);
semNode = ((LosSemCB *)g_allSem) + index;//拿信号控制块, 可以直接g_allSem[index]来嘛
semNode->semID = SET_SEM_ID(0, index);//保存ID
semNode->semStat = OS_SEM_UNUSED;//标记未使用
LOS_ListTailInsert(&g_unusedSemList, &semNode->semList);//通过semList把 信号块挂到空闲链表上
}
if (OsSemDbgInitHook() != LOS_OK) {
@ -97,45 +144,46 @@ LITE_OS_SEC_TEXT_INIT UINT32 OsSemCreate(UINT16 count, UINT16 maxCount, UINT32 *
return LOS_ERRNO_SEM_PTR_NULL;
}
if (count > maxCount) {
if (count > maxCount) {//信号量不能大于最大值,两参数都是外面给的
OS_GOTO_ERR_HANDLER(LOS_ERRNO_SEM_OVERFLOW);
}
SCHEDULER_LOCK(intSave);
SCHEDULER_LOCK(intSave);//进入临界区,拿自旋锁
if (LOS_ListEmpty(&g_unusedSemList)) {
if (LOS_ListEmpty(&g_unusedSemList)) {//没有可分配的空闲信号提供
SCHEDULER_UNLOCK(intSave);
OsSemInfoGetFullDataHook();
OS_GOTO_ERR_HANDLER(LOS_ERRNO_SEM_ALL_BUSY);
}
unusedSem = LOS_DL_LIST_FIRST(&g_unusedSemList);
LOS_ListDelete(unusedSem);
unusedSem = LOS_DL_LIST_FIRST(&g_unusedSemList);//从未使用信号量池中取首个
LOS_ListDelete(unusedSem);//从空闲链表上摘除
SCHEDULER_UNLOCK(intSave);
semCreated = GET_SEM_LIST(unusedSem);
semCreated->semCount = count;
semCreated->semStat = OS_SEM_USED;
semCreated->maxSemCount = maxCount;
LOS_ListInit(&semCreated->semList);
*semHandle = semCreated->semID;
semCreated = GET_SEM_LIST(unusedSem);//通过semList挂到链表上的,这里也要通过它把LosSemCB头查到. 进程,线程等结构体也都是这么干的.
semCreated->semCount = count;//设置数量
semCreated->semStat = OS_SEM_USED;//设置可用状态
semCreated->maxSemCount = maxCount;//设置最大信号数量
LOS_ListInit(&semCreated->semList);//初始化链表,后续阻塞任务通过task->pendList挂到semList链表上,就知道哪些任务在等它了.
*semHandle = semCreated->semID;//参数带走 semID
OsHookCall(LOS_HOOK_TYPE_SEM_CREATE, semCreated);
OsSemDbgUpdateHook(semCreated->semID, OsCurrTaskGet()->taskEntry, count);
return LOS_OK;
ERR_HANDLER:
OS_RETURN_ERROR_P2(errLine, errNo);
}
///对外接口 创建信号量
LITE_OS_SEC_TEXT_INIT UINT32 LOS_SemCreate(UINT16 count, UINT32 *semHandle)
{
return OsSemCreate(count, OS_SEM_COUNT_MAX, semHandle);
}
///对外接口 创建二值信号量其计数值最大为1可以当互斥锁用
LITE_OS_SEC_TEXT_INIT UINT32 LOS_BinarySemCreate(UINT16 count, UINT32 *semHandle)
{
return OsSemCreate(count, OS_SEM_BINARY_COUNT_MAX, semHandle);
}
///对外接口 删除指定的信号量,参数就是 semID
LITE_OS_SEC_TEXT_INIT UINT32 LOS_SemDelete(UINT32 semHandle)
{
UINT32 intSave;
@ -147,23 +195,23 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_SemDelete(UINT32 semHandle)
OS_GOTO_ERR_HANDLER(LOS_ERRNO_SEM_INVALID);
}
semDeleted = GET_SEM(semHandle);
semDeleted = GET_SEM(semHandle);//通过ID拿到信号量实体
SCHEDULER_LOCK(intSave);
if ((semDeleted->semStat == OS_SEM_UNUSED) || (semDeleted->semID != semHandle)) {
if ((semDeleted->semStat == OS_SEM_UNUSED) || (semDeleted->semID != semHandle)) {//参数判断
SCHEDULER_UNLOCK(intSave);
OS_GOTO_ERR_HANDLER(LOS_ERRNO_SEM_INVALID);
}
if (!LOS_ListEmpty(&semDeleted->semList)) {
if (!LOS_ListEmpty(&semDeleted->semList)) {//当前还有任务挂在这个信号上面,当然不能删除
SCHEDULER_UNLOCK(intSave);
OS_GOTO_ERR_HANDLER(LOS_ERRNO_SEM_PENDED);
OS_GOTO_ERR_HANDLER(LOS_ERRNO_SEM_PENDED);//这个宏很有意思,里面goto到ERR_HANDLER
}
LOS_ListTailInsert(&g_unusedSemList, &semDeleted->semList);
semDeleted->semStat = OS_SEM_UNUSED;
semDeleted->semID = SET_SEM_ID(GET_SEM_COUNT(semDeleted->semID) + 1, GET_SEM_INDEX(semDeleted->semID));
LOS_ListTailInsert(&g_unusedSemList, &semDeleted->semList);//通过semList从尾部插入空闲链表
semDeleted->semStat = OS_SEM_UNUSED;//状态变成了未使用
semDeleted->semID = SET_SEM_ID(GET_SEM_COUNT(semDeleted->semID) + 1, GET_SEM_INDEX(semDeleted->semID));//设置ID
OsHookCall(LOS_HOOK_TYPE_SEM_DELETE, semDeleted);
OsSemDbgUpdateHook(semDeleted->semID, NULL, 0);
@ -174,11 +222,11 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_SemDelete(UINT32 semHandle)
ERR_HANDLER:
OS_RETURN_ERROR_P2(errLine, errNo);
}
///对外接口 申请指定的信号量,并设置超时时间
LITE_OS_SEC_TEXT UINT32 LOS_SemPend(UINT32 semHandle, UINT32 timeout)
{
UINT32 intSave;
LosSemCB *semPended = GET_SEM(semHandle);
LosSemCB *semPended = GET_SEM(semHandle);//通过ID拿到信号体
UINT32 retErr = LOS_OK;
LosTaskCB *runTask = NULL;
@ -192,7 +240,7 @@ LITE_OS_SEC_TEXT UINT32 LOS_SemPend(UINT32 semHandle, UINT32 timeout)
return LOS_ERRNO_SEM_PEND_INTERR;
}
runTask = OsCurrTaskGet();
runTask = OsCurrTaskGet();//获取当前任务
if (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) {
OsBackTrace();
return LOS_ERRNO_SEM_PEND_IN_SYSTEM_TASK;
@ -204,19 +252,20 @@ LITE_OS_SEC_TEXT UINT32 LOS_SemPend(UINT32 semHandle, UINT32 timeout)
retErr = LOS_ERRNO_SEM_INVALID;
goto OUT;
}
/* Update the operate time, no matter the actual Pend success or not */
OsSemDbgTimeUpdateHook(semHandle);
if (semPended->semCount > 0) {
semPended->semCount--;
if (semPended->semCount > 0) {//还有资源可用,返回肯定得成功,semCount=0时代表没资源了,task会必须去睡眠了
semPended->semCount--;//资源少了一个
OsHookCall(LOS_HOOK_TYPE_SEM_PEND, semPended, runTask, timeout);
goto OUT;
goto OUT;//注意这里 retErr = LOS_OK ,所以返回是OK的
} else if (!timeout) {
retErr = LOS_ERRNO_SEM_UNAVAILABLE;
goto OUT;
}
if (!OsPreemptableInSched()) {
if (!OsPreemptableInSched()) {//不能申请调度 (不能调度的原因是因为没有持有调度任务自旋锁)
PRINT_ERR("!!!LOS_ERRNO_SEM_PEND_IN_LOCK!!!\n");
OsBackTrace();
retErr = LOS_ERRNO_SEM_PEND_IN_LOCK;
@ -226,7 +275,7 @@ LITE_OS_SEC_TEXT UINT32 LOS_SemPend(UINT32 semHandle, UINT32 timeout)
OsHookCall(LOS_HOOK_TYPE_SEM_PEND, semPended, runTask, timeout);
OsTaskWaitSetPendMask(OS_TASK_WAIT_SEM, semPended->semID, timeout);
retErr = runTask->ops->wait(runTask, &semPended->semList, timeout);
if (retErr == LOS_ERRNO_TSK_TIMEOUT) {
if (retErr == LOS_ERRNO_TSK_TIMEOUT) {//注意:这里是涉及到task切换的,把自己挂起,唤醒其他task
retErr = LOS_ERRNO_SEM_TIMEOUT;
}
@ -234,7 +283,7 @@ OUT:
SCHEDULER_UNLOCK(intSave);
return retErr;
}
///以不安全的方式释放指定的信号量,所谓不安全指的是不用自旋锁
LITE_OS_SEC_TEXT UINT32 OsSemPostUnsafe(UINT32 semHandle, BOOL *needSched)
{
LosTaskCB *resumedTask = NULL;
@ -246,23 +295,23 @@ LITE_OS_SEC_TEXT UINT32 OsSemPostUnsafe(UINT32 semHandle, BOOL *needSched)
/* Update the operate time, no matter the actual Post success or not */
OsSemDbgTimeUpdateHook(semHandle);
if (semPosted->semCount == OS_SEM_COUNT_MAX) {
if (semPosted->semCount == OS_SEM_COUNT_MAX) {//当前信号资源不能大于最大资源量
return LOS_ERRNO_SEM_OVERFLOW;
}
if (!LOS_ListEmpty(&semPosted->semList)) {
resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(semPosted->semList)));
if (!LOS_ListEmpty(&semPosted->semList)) {//当前有任务挂在semList上,要去唤醒任务
resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(semPosted->semList)));//semList上面挂的都是task->pendlist节点,取第一个task下来唤醒
OsTaskWakeClearPendMask(resumedTask);
resumedTask->ops->wake(resumedTask);
if (needSched != NULL) {
*needSched = TRUE;
if (needSched != NULL) {//参数不为空,就返回需要调度的标签
*needSched = TRUE;//TRUE代表需要调度
}
} else {
semPosted->semCount++;
} else {//当前没有任务挂在semList上,
semPosted->semCount++;//信号资源多一个
}
OsHookCall(LOS_HOOK_TYPE_SEM_POST, semPosted, resumedTask);
return LOS_OK;
}
///对外接口 释放指定的信号量
LITE_OS_SEC_TEXT UINT32 LOS_SemPost(UINT32 semHandle)
{
UINT32 intSave;
@ -272,16 +321,15 @@ LITE_OS_SEC_TEXT UINT32 LOS_SemPost(UINT32 semHandle)
if (GET_SEM_INDEX(semHandle) >= LOSCFG_BASE_IPC_SEM_LIMIT) {
return LOS_ERRNO_SEM_INVALID;
}
SCHEDULER_LOCK(intSave);
ret = OsSemPostUnsafe(semHandle, &needSched);
SCHEDULER_UNLOCK(intSave);
if (needSched) {
LOS_MpSchedule(OS_MP_CPU_ALL);
LOS_Schedule();
if (needSched) {//需要调度的情况
LOS_MpSchedule(OS_MP_CPU_ALL);//向所有CPU发送调度指令
LOS_Schedule();////发起调度
}
return ret;
}
#endif /* LOSCFG_BASE_IPC_SEM */
#endif /* (LOSCFG_BASE_IPC_SEM == YES) */

@ -78,11 +78,11 @@ STATIC VOID OsSemPendedTaskNamePrint(LosSemCB *semNode)
#ifdef LOSCFG_DEBUG_SEMAPHORE
typedef struct {
UINT16 origSemCount; /* Number of original available semaphores */
UINT64 lastAccessTime; /* The last operation time */
TSK_ENTRY_FUNC creator; /* The task entry who created this sem */
UINT16 origSemCount; /* Number of orignal available semaphores *///原始可用信号量数
UINT64 lastAccessTime; /* The last operation time */ //最后操作时间
TSK_ENTRY_FUNC creator; /* The task entry who created this sem */ //由哪个task的入口函数创建了这个任务
} SemDebugCB;
STATIC SemDebugCB *g_semDebugArray = NULL;
STATIC SemDebugCB *g_semDebugArray = NULL;//默认1024个SemDebugCB debug信号量池
STATIC BOOL SemCompareValue(const IpcSortParam *sortParam, UINT32 left, UINT32 right)
{
@ -102,23 +102,23 @@ UINT32 OsSemDbgInit(VOID)
(VOID)memset_s(g_semDebugArray, size, 0, size);
return LOS_OK;
}
///更新最后访问时间
VOID OsSemDbgTimeUpdate(UINT32 semID)
{
SemDebugCB *semDebug = &g_semDebugArray[GET_SEM_INDEX(semID)];
semDebug->lastAccessTime = LOS_TickCountGet();
semDebug->lastAccessTime = LOS_TickCountGet();//获取tick总数
return;
}
///更新信号量
VOID OsSemDbgUpdate(UINT32 semID, TSK_ENTRY_FUNC creator, UINT16 count)
{
SemDebugCB *semDebug = &g_semDebugArray[GET_SEM_INDEX(semID)];
semDebug->creator = creator;
semDebug->lastAccessTime = LOS_TickCountGet();
semDebug->origSemCount = count;
semDebug->creator = creator; //改为由参数入口函数创建了这个任务
semDebug->lastAccessTime = LOS_TickCountGet();//获取tick总数
semDebug->origSemCount = count;//原始信号量改变
return;
}
///按信号量访问时间排序
STATIC VOID OsSemSort(UINT32 *semIndexArray, UINT32 usedCount)
{
UINT32 i, intSave;
@ -296,6 +296,6 @@ LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdSemInfoGet(UINT32 argc, const CHAR **arg
return ret;
}
SHELLCMD_ENTRY(sem_shellcmd, CMD_TYPE_EX, "sem", 1, (CmdCallBackFunc)OsShellCmdSemInfoGet);
SHELLCMD_ENTRY(sem_shellcmd, CMD_TYPE_EX, "sem", 1, (CmdCallBackFunc)OsShellCmdSemInfoGet);//采用shell命令静态注册方式
#endif

@ -1,6 +1,6 @@
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2023 Huawei Device Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
@ -53,15 +53,22 @@ int raise(int sig)
#define GETUNMASKSET(procmask, pendFlag) ((~(procmask)) & (sigset_t)(pendFlag))
#define UINT64_BIT_SIZE 64
/**
* @brief signo10-1
* @param set
* @param signo
* @return int
*/
int OsSigIsMember(const sigset_t *set, int signo)
{
int ret = LOS_NOK;
/* In musl, sig No bits 00000100 present sig No 3, but 1<< 3 = 00001000, so signo needs minus 1 */
/* In musl, sig No bits 00000100 present sig No 3, but 1<< 3 = 00001000, so signo needs minus 1 */
//在musl中sig No bits 00000100表示sig No 3但是在SIGNO2SET中 1<<3 = 00001000,因此signo需要减1
signo -= 1;
/* Verify the signal */
if (GOOD_SIGNO(signo)) {
if (GOOD_SIGNO(signo)) {//有效信号判断
/* Check if the signal is in the set */
ret = ((*set & SIGNO2SET((unsigned int)signo)) != 0);
ret = ((*set & SIGNO2SET((unsigned int)signo)) != 0);//检查信号是否还在集合中
}
return ret;
@ -120,7 +127,6 @@ VOID OsClearSigInfoTmpList(sig_cb *sigcb)
(VOID)LOS_MemFree(m_aucSysMem0, tmpInfoNode);
}
}
STATIC INLINE VOID OsSigWaitTaskWake(LosTaskCB *taskCB, INT32 signo)
{
sig_cb *sigcb = &taskCB->sig;
@ -132,14 +138,14 @@ STATIC INLINE VOID OsSigWaitTaskWake(LosTaskCB *taskCB, INT32 signo)
OsSigEmptySet(&sigcb->sigwaitmask);
}
}
///< 唤醒被挂起的处于等待指定信号的任务
STATIC UINT32 OsPendingTaskWake(LosTaskCB *taskCB, INT32 signo)
{
if (!OsTaskIsPending(taskCB) || !OsProcessIsUserMode(OS_PCB_FROM_TCB(taskCB))) {
return 0;
}
if ((signo != SIGKILL) && (taskCB->waitFlag != OS_TASK_WAIT_SIGNAL)) {
if ((signo != SIGKILL) && (taskCB->waitFlag != OS_TASK_WAIT_SIGNAL)) { // @note_thinking 这个判断会不会有问题 ?
return 0;
}
@ -153,16 +159,16 @@ STATIC UINT32 OsPendingTaskWake(LosTaskCB *taskCB, INT32 signo)
OsTaskWakeClearPendMask(taskCB);
taskCB->ops->wake(taskCB);
break;
case OS_TASK_WAIT_SIGNAL:
case OS_TASK_WAIT_SIGNAL://等待普通信号
OsSigWaitTaskWake(taskCB, signo);
break;
case OS_TASK_WAIT_LITEIPC:
OsTaskWakeClearPendMask(taskCB);
case OS_TASK_WAIT_LITEIPC://等待liteipc信号
OsTaskWakeClearPendMask(taskCB);//重置任务的等待信息
taskCB->ops->wake(taskCB);
break;
case OS_TASK_WAIT_FUTEX:
OsFutexNodeDeleteFromFutexHash(&taskCB->futex, TRUE, NULL, NULL);
OsTaskWakeClearPendMask(taskCB);
case OS_TASK_WAIT_FUTEX://等待快锁信号
OsFutexNodeDeleteFromFutexHash(&taskCB->futex, TRUE, NULL, NULL);//从哈希桶中删除快锁
OsTaskWakeClearPendMask(taskCB);//重置任务的等待信息
taskCB->ops->wake(taskCB);
break;
default:
@ -171,7 +177,7 @@ STATIC UINT32 OsPendingTaskWake(LosTaskCB *taskCB, INT32 signo)
return 0;
}
///给任务(线程)发送一个信号
int OsTcbDispatch(LosTaskCB *stcb, siginfo_t *info)
{
bool masked = FALSE;
@ -179,19 +185,19 @@ int OsTcbDispatch(LosTaskCB *stcb, siginfo_t *info)
OS_RETURN_IF_NULL(sigcb);
/* If signo is 0, not send signal, just check process or pthread exist */
if (info->si_signo == 0) {
if (info->si_signo == 0) {//如果信号为0,则不发送信号,只是作为检查进程和线程是否还存在.
return 0;
}
masked = (bool)OsSigIsMember(&sigcb->sigprocmask, info->si_signo);
if (masked) {
/* If signal is in wait list and mask list, need unblock it */
masked = (bool)OsSigIsMember(&sigcb->sigprocmask, info->si_signo);//@note_thinking 这里还有 masked= -1的情况要处理!!!
if (masked) {//如果信号被屏蔽了,要看等待信号集,sigwaitmask
/* If signal is in wait list and mask list, need unblock it */ //如果信号在等待列表和掩码列表中,需要解除阻止
if (LOS_ListEmpty(&sigcb->waitList) ||
(!LOS_ListEmpty(&sigcb->waitList) && !OsSigIsMember(&sigcb->sigwaitmask, info->si_signo))) {
OsSigAddSet(&sigcb->sigPendFlag, info->si_signo);
(!LOS_ListEmpty(&sigcb->waitList) && !OsSigIsMember(&sigcb->sigwaitmask, info->si_signo))) {
OsSigAddSet(&sigcb->sigPendFlag, info->si_signo);//将信号加入挂起/待办集
}
} else {
} else {//信号没有被屏蔽的处理
/* unmasked signal actions */
OsSigAddSet(&sigcb->sigFlag, info->si_signo);
OsSigAddSet(&sigcb->sigFlag, info->si_signo);//不屏蔽的信号集
}
if (OsAddSigInfoToTmpList(sigcb, info) == LOS_NOK) {
@ -206,14 +212,23 @@ void OsSigMaskSwitch(LosTaskCB * const rtcb, sigset_t set)
sigset_t unmaskset;
rtcb->sig.sigprocmask = set;
unmaskset = GETUNMASKSET(rtcb->sig.sigprocmask, rtcb->sig.sigPendFlag);
unmaskset = GETUNMASKSET(rtcb->sig.sigprocmask, rtcb->sig.sigPendFlag);//过滤出没有被屏蔽的信号集
if (unmaskset != NULL_SIGNAL_SET) {
/* pendlist do */
rtcb->sig.sigFlag |= unmaskset;
rtcb->sig.sigPendFlag ^= unmaskset;
rtcb->sig.sigFlag |= unmaskset; //加入不屏蔽信号集
rtcb->sig.sigPendFlag ^= unmaskset;//从挂起/待办集中去掉unmaskset
}
}
/**
* @brief
* @verbatim
SIG_BLOCKset
SIG_UNBLOCKset
SIG_SETMASKset
* @endverbatim
*/
int OsSigprocMask(int how, const sigset_t_l *setl, sigset_t_l *oldsetl)
{
LosTaskCB *spcb = NULL;
@ -223,11 +238,11 @@ int OsSigprocMask(int how, const sigset_t_l *setl, sigset_t_l *oldsetl)
SCHEDULER_LOCK(intSave);
spcb = OsCurrTaskGet();
/* If requested, copy the old mask to user. */
/* If requested, copy the old mask to user. | 如果需要,请将旧掩码复制给用户*/
if (oldsetl != NULL) {
*(sigset_t *)oldsetl = spcb->sig.sigprocmask;
}
/* If requested, modify the current signal mask. */
/* If requested, modify the current signal mask. | 如有要求,修改当前信号屏蔽*/
if (setl != NULL) {
set = *(sigset_t *)setl;
/* Okay, determine what we are supposed to do */
@ -236,46 +251,46 @@ int OsSigprocMask(int how, const sigset_t_l *setl, sigset_t_l *oldsetl)
* set pointed to by set as the new sigprocmask.
*/
case SIG_BLOCK:
spcb->sig.sigprocmask |= set;
spcb->sig.sigprocmask |= set;//增加信号屏蔽位
break;
/* Set the intersection of the current set and the
* signal set pointed to by set as the new sigprocmask.
*/
case SIG_UNBLOCK:
spcb->sig.sigprocmask &= ~(set);
spcb->sig.sigprocmask &= ~(set);//解除信号屏蔽位
break;
/* Set the signal set pointed to by set as the new sigprocmask. */
case SIG_SETMASK:
spcb->sig.sigprocmask = set;
spcb->sig.sigprocmask = set;//设置一个新的屏蔽掩码
break;
default:
ret = -EINVAL;
break;
}
/* If pending mask not in sigmask, need set sigflag. */
OsSigMaskSwitch(spcb, spcb->sig.sigprocmask);
OsSigMaskSwitch(spcb, spcb->sig.sigprocmask);//更新与屏蔽信号相关的变量
}
SCHEDULER_UNLOCK(intSave);
return ret;
}
///让进程的每一个task执行参数函数
int OsSigProcessForeachChild(LosProcessCB *spcb, ForEachTaskCB handler, void *arg)
{
int ret;
/* Visit the main thread last (if present) */
LosTaskCB *taskCB = NULL;
LOS_DL_LIST_FOR_EACH_ENTRY(taskCB, &(spcb->threadSiblingList), LosTaskCB, threadList) {
ret = handler(taskCB, arg);
OS_RETURN_IF(ret != 0, ret);
LosTaskCB *taskCB = NULL;//遍历进程的 threadList 链表,里面存放的都是task节点
LOS_DL_LIST_FOR_EACH_ENTRY(taskCB, &(spcb->threadSiblingList), LosTaskCB, threadList) {//遍历进程的任务列表
ret = handler(taskCB, arg);//回调参数函数
OS_RETURN_IF(ret != 0, ret);//这个宏的意思就是只有ret = 0时,啥也不处理.其余就返回 ret
}
return LOS_OK;
}
///信号处理函数,这里就是上面的 handler = SigProcessSignalHandler,见于 OsSigProcessSend
static int SigProcessSignalHandler(LosTaskCB *tcb, void *arg)
{
struct ProcessSignalInfo *info = (struct ProcessSignalInfo *)arg;
struct ProcessSignalInfo *info = (struct ProcessSignalInfo *)arg;//先把参数解出来
int ret;
int isMember;
@ -283,128 +298,130 @@ static int SigProcessSignalHandler(LosTaskCB *tcb, void *arg)
return 0;
}
/* If the default tcb is not set, then set this one as default. */
if (!info->defaultTcb) {
/* If the default tcb is not setted, then set this one as default. */
if (!info->defaultTcb) {//如果没有默认发送方的任务,即默认参数任务.
info->defaultTcb = tcb;
}
isMember = OsSigIsMember(&tcb->sig.sigwaitmask, info->sigInfo->si_signo);
if (isMember && (!info->awakenedTcb)) {
isMember = OsSigIsMember(&tcb->sig.sigwaitmask, info->sigInfo->si_signo);//任务是否在等待这个信号
if (isMember && (!info->awakenedTcb)) {//是在等待,并尚未向该任务时发送信号时
/* This means the task is waiting for this signal. Stop looking for it and use this tcb.
* The requirement is: if more than one task in this task group is waiting for the signal,
* then only one indeterminate task in the group will receive the signal.
*/
ret = OsTcbDispatch(tcb, info->sigInfo);
OS_RETURN_IF(ret < 0, ret);
ret = OsTcbDispatch(tcb, info->sigInfo);//发送信号,注意这是给其他任务发送信号,tcb不是当前任务
OS_RETURN_IF(ret < 0, ret);//这种写法很有意思
/* set this tcb as awakenedTcb */
info->awakenedTcb = tcb;
OS_RETURN_IF(info->receivedTcb != NULL, SIG_STOP_VISIT); /* Stop search */
}
/* Is this signal unblocked on this thread? */
isMember = OsSigIsMember(&tcb->sig.sigprocmask, info->sigInfo->si_signo);
if ((!isMember) && (!info->receivedTcb) && (tcb != info->awakenedTcb)) {
/* if unblockedTcb of this signal is not set, then set it. */
isMember = OsSigIsMember(&tcb->sig.sigprocmask, info->sigInfo->si_signo);//任务是否屏蔽了这个信号
if ((!isMember) && (!info->receivedTcb) && (tcb != info->awakenedTcb)) {//没有屏蔽,有唤醒任务没有接收任务.
/* if unblockedTcb of this signal is not setted, then set it. */
if (!info->unblockedTcb) {
info->unblockedTcb = tcb;
}
ret = OsTcbDispatch(tcb, info->sigInfo);
ret = OsTcbDispatch(tcb, info->sigInfo);//向任务发送信号
OS_RETURN_IF(ret < 0, ret);
/* set this tcb as receivedTcb */
info->receivedTcb = tcb;
info->receivedTcb = tcb;//设置这个任务为接收任务
OS_RETURN_IF(info->awakenedTcb != NULL, SIG_STOP_VISIT); /* Stop search */
}
return 0; /* Keep searching */
}
///进程收到 SIGKILL 信号后,通知任务tcb处理.
static int SigProcessKillSigHandler(LosTaskCB *tcb, void *arg)
{
struct ProcessSignalInfo *info = (struct ProcessSignalInfo *)arg;
struct ProcessSignalInfo *info = (struct ProcessSignalInfo *)arg;//转参
return OsPendingTaskWake(tcb, info->sigInfo->si_signo);
}
//处理信号发送
static void SigProcessLoadTcb(struct ProcessSignalInfo *info, siginfo_t *sigInfo)
{
LosTaskCB *tcb = NULL;
if (info->awakenedTcb == NULL && info->receivedTcb == NULL) {
if (info->unblockedTcb) {
tcb = info->unblockedTcb;
} else if (info->defaultTcb) {
if (info->awakenedTcb == NULL && info->receivedTcb == NULL) {//信号即没有指定接收task 也没有指定被唤醒task
if (info->unblockedTcb) {//如果进程信号信息体中有阻塞task
tcb = info->unblockedTcb;//
} else if (info->defaultTcb) {//如果有默认的发送方task
tcb = info->defaultTcb;
} else {
return;
}
/* Deliver the signal to the selected task */
(void)OsTcbDispatch(tcb, sigInfo);
(void)OsTcbDispatch(tcb, sigInfo);//向所选任务发送信号
}
}
///给参数进程发送参数信号
int OsSigProcessSend(LosProcessCB *spcb, siginfo_t *sigInfo)
{
int ret;
struct ProcessSignalInfo info = {
.sigInfo = sigInfo,
.defaultTcb = NULL,
.sigInfo = sigInfo, //信号内容
.defaultTcb = NULL, //以下四个值将在OsSigProcessForeachChild中根据条件完善
.unblockedTcb = NULL,
.awakenedTcb = NULL,
.receivedTcb = NULL
};
if (info.sigInfo == NULL) {
//总之是要从进程中找个至少一个任务来接受这个信号,优先级
//awakenedTcb > receivedTcb > unblockedTcb > defaultTcb
if (info.sigInfo == NULL){
return -EFAULT;
}
/* visit all taskcb and dispatch signal */
if (info.sigInfo->si_signo == SIGKILL) {
OsSigAddSet(&spcb->sigShare, info.sigInfo->si_signo);
/* visit all taskcb and dispatch signal */ //访问所有任务和分发信号
if (info.sigInfo->si_signo == SIGKILL) {//需要干掉进程时 SIGKILL = 9 #linux kill 9 14
OsSigAddSet(&spcb->sigShare, info.sigInfo->si_signo);//信号集中增加信号
(void)OsSigProcessForeachChild(spcb, SigProcessKillSigHandler, &info);
return 0;
} else {
ret = OsSigProcessForeachChild(spcb, SigProcessSignalHandler, &info);
ret = OsSigProcessForeachChild(spcb, SigProcessSignalHandler, &info);//进程通知所有task处理信号
}
if (ret < 0) {
return ret;
}
SigProcessLoadTcb(&info, sigInfo);
SigProcessLoadTcb(&info, sigInfo);//确保能给一个任务发送信号
return 0;
}
///信号集全部清0
int OsSigEmptySet(sigset_t *set)
{
*set = NULL_SIGNAL_SET;
return 0;
}
/* Privilege process can't send to kernel and privilege process */
/* Privilege process can't send to kernel and privilege process */ //内核进程组和用户特权进程组无法发送
static int OsSignalPermissionToCheck(const LosProcessCB *spcb)
{
UINTPTR gid = (UINTPTR)OS_GET_PGROUP_LEADER(spcb->pgroup);
if (gid == OS_KERNEL_PROCESS_GROUP) {
if (gid == OS_KERNEL_PROCESS_GROUP) {//内核进程组
return -EPERM;
} else if (gid == OS_USER_PRIVILEGE_PROCESS_GROUP) {
} else if (gid == OS_USER_PRIVILEGE_PROCESS_GROUP) {//用户特权进程组
return -EPERM;
}
return 0;
}
///信号分发,发送信号权限/进程组过滤.
STATIC int SendSigPermissionCheck(LosProcessCB *spcb, int permission)
{
if (spcb == NULL) {
return -ESRCH;
}
if (OsProcessIsUnused(spcb)) {
if (OsProcessIsUnused(spcb)) {//进程是否还在使用,不一定是当前进程但必须是个有效进程
return -ESRCH;
}
#ifdef LOSCFG_SECURITY_CAPABILITY
LosProcessCB *current = OsCurrProcessGet();
/* Kernel process always has kill permission and user process should check permission */
if (OsProcessIsUserMode(current) && !(current->processStatus & OS_PROCESS_FLAG_EXIT)) {
#ifdef LOSCFG_SECURITY_CAPABILITY //启用能力安全模式
LosProcessCB *current = OsCurrProcessGet();//获取当前进程,检查当前进程是否有发送信号的权限.
/* Kernel process always has kill permission and user process should check permission *///内核进程总是有kill权限用户进程需要检查权限
if (OsProcessIsUserMode(current) && !(current->processStatus & OS_PROCESS_FLAG_EXIT)) {//用户进程检查能力范围
if ((current != spcb) && (!IsCapPermit(CAP_KILL)) && (current->user->userID != spcb->user->userID)) {
return -EPERM;
}
@ -437,7 +454,7 @@ int OsSendSigToProcess(LosProcessCB *spcb, int sig, int permission)
info.si_code = SI_USER;
info.si_value.sival_ptr = NULL;
return OsSigProcessSend(spcb, &info);
return OsSigProcessSend(spcb, &info);//给参数进程发送信号
}
int OsDispatch(pid_t pid, siginfo_t *info, int permission)
@ -459,7 +476,14 @@ int OsDispatch(pid_t pid, siginfo_t *info, int permission)
return OsSigProcessSend(spcb, info);
}
/**
* @brief
* @verbatim
shell kill 14 7kill -14 7
14SIGALRM7
* @endverbatim
*/
int OsKill(pid_t pid, int sig, int permission)
{
siginfo_t info;
@ -470,14 +494,14 @@ int OsKill(pid_t pid, int sig, int permission)
return -EINVAL;
}
/* Create the siginfo structure */
info.si_signo = sig;
info.si_code = SI_USER;
/* Create the siginfo structure */ //创建信号结构体
info.si_signo = sig; //信号编号
info.si_code = SI_USER; //来自用户进程信号
info.si_value.sival_ptr = NULL;
if (pid > 0) {
/* Send the signal to the specify process */
ret = OsDispatch(pid, &info, permission);
ret = OsDispatch(pid, &info, permission);//发送信号
} else if (pid == -1) {
/* Send SIG to all processes */
ret = OsSendSignalToAllProcess(&info, permission);
@ -489,18 +513,17 @@ int OsKill(pid_t pid, int sig, int permission)
}
return ret;
}
///给发送信号过程加锁
int OsKillLock(pid_t pid, int sig)
{
int ret;
unsigned int intSave;
SCHEDULER_LOCK(intSave);
ret = OsKill(pid, sig, OS_USER_KILL_PERMISSION);
ret = OsKill(pid, sig, OS_USER_KILL_PERMISSION);//用户权限向进程发送信号
SCHEDULER_UNLOCK(intSave);
return ret;
}
INT32 OsTaskKillUnsafe(UINT32 taskID, INT32 signo)
{
siginfo_t info;
@ -519,7 +542,7 @@ INT32 OsTaskKillUnsafe(UINT32 taskID, INT32 signo)
* dispatch rules. */
return OsTcbDispatch(taskCB, &info);
}
///发送信号
int OsPthreadKill(UINT32 tid, int signo)
{
int ret;
@ -537,7 +560,7 @@ int OsPthreadKill(UINT32 tid, int signo)
SCHEDULER_UNLOCK(intSave);
return ret;
}
///向信号集中加入signo信号
int OsSigAddSet(sigset_t *set, int signo)
{
/* Verify the signal */
@ -545,13 +568,13 @@ int OsSigAddSet(sigset_t *set, int signo)
return -EINVAL;
} else {
/* In musl, sig No bits 00000100 present sig No 3, but 1<< 3 = 00001000, so signo needs minus 1 */
signo -= 1;
signo -= 1;// 信号范围是 [1 ~ 64 ],而保存变量位的范围是[0 ~ 63]
/* Add the signal to the set */
*set |= SIGNO2SET((unsigned int)signo);
*set |= SIGNO2SET((unsigned int)signo);//填充信号集
return LOS_OK;
}
}
///获取阻塞当前任务的信号集
int OsSigPending(sigset_t *set)
{
LosTaskCB *tcb = NULL;
@ -563,7 +586,7 @@ int OsSigPending(sigset_t *set)
SCHEDULER_LOCK(intSave);
tcb = OsCurrTaskGet();
*set = tcb->sig.sigPendFlag;
*set = tcb->sig.sigPendFlag;//被阻塞的信号集
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
}
@ -578,7 +601,7 @@ STATIC int FindFirstSetedBit(UINT64 n)
for (count = 0; (count < UINT64_BIT_SIZE) && (n ^ 1ULL); n >>= 1, count++) {}
return (count < UINT64_BIT_SIZE) ? count : (-1);
}
///等待信号时间
int OsSigTimedWaitNoLock(sigset_t *set, siginfo_t *info, unsigned int timeout)
{
LosTaskCB *task = NULL;
@ -589,19 +612,19 @@ int OsSigTimedWaitNoLock(sigset_t *set, siginfo_t *info, unsigned int timeout)
sigcb = &task->sig;
if (sigcb->waitList.pstNext == NULL) {
LOS_ListInit(&sigcb->waitList);
LOS_ListInit(&sigcb->waitList);//初始化信号等待链表
}
/* If pendingflag & set > 0, should clear pending flag */
/* If pendingflag & set > 0, shound clear pending flag */
sigset_t clear = sigcb->sigPendFlag & *set;
if (clear) {
sigcb->sigPendFlag ^= clear;
ret = FindFirstSetedBit((UINT64)clear) + 1;
OsMoveTmpInfoToUnbInfo(sigcb, ret);
} else {
OsSigAddSet(set, SIGKILL);
OsSigAddSet(set, SIGSTOP);
OsSigAddSet(set, SIGKILL);//kill 9 14 必须要处理
OsSigAddSet(set, SIGSTOP);//终止进程的信号也必须处理
sigcb->sigwaitmask |= *set;
sigcb->sigwaitmask |= *set;//按位加到等待集上,也就是说sigwaitmask的信号来了都是要处理的.
OsTaskWaitSetPendMask(OS_TASK_WAIT_SIGNAL, sigcb->sigwaitmask, timeout);
ret = task->ops->wait(task, &sigcb->waitList, timeout);
if (ret == LOS_ERRNO_TSK_TIMEOUT) {
@ -614,7 +637,7 @@ int OsSigTimedWaitNoLock(sigset_t *set, siginfo_t *info, unsigned int timeout)
}
return ret;
}
///让当前任务等待的信号
int OsSigTimedWait(sigset_t *set, siginfo_t *info, unsigned int timeout)
{
int ret;
@ -622,12 +645,12 @@ int OsSigTimedWait(sigset_t *set, siginfo_t *info, unsigned int timeout)
SCHEDULER_LOCK(intSave);
ret = OsSigTimedWaitNoLock(set, info, timeout);
ret = OsSigTimedWaitNoLock(set, info, timeout);//以不加锁的方式等待
SCHEDULER_UNLOCK(intSave);
return ret;
}
///通过信号挂起当前任务
int OsPause(void)
{
LosTaskCB *spcb = NULL;
@ -637,7 +660,7 @@ int OsPause(void)
oldSigprocmask = spcb->sig.sigprocmask;
return OsSigSuspend(&oldSigprocmask);
}
///用参数set代替进程的原有掩码并暂停进程执行直到收到信号再恢复原有掩码并继续执行进程。
int OsSigSuspend(const sigset_t *set)
{
unsigned int intSave;
@ -677,6 +700,17 @@ int OsSigSuspend(const sigset_t *set)
return -EINTR;
}
/**
* @brief
* @verbatim
,
sig:SIGKILLSIGSTOP
act:signal
oldact:
NULL
0 -1
* @endverbatim
*/
int OsSigAction(int sig, const sigaction_t *act, sigaction_t *oact)
{
UINTPTR addr;
@ -685,14 +719,17 @@ int OsSigAction(int sig, const sigaction_t *act, sigaction_t *oact)
if (!GOOD_SIGNO(sig) || sig < 1 || act == NULL) {
return -EINVAL;
}
if (LOS_ArchCopyFromUser(&action, act, sizeof(sigaction_t)) != LOS_OK) {
return -EFAULT;
}
if (sig == SIGSYS) {
addr = OsGetSigHandler();
if (addr == 0) {
OsSetSigHandler((unsigned long)(UINTPTR)action.sa_handler);
//将数据从用户空间拷贝到内核空间
if (LOS_ArchCopyFromUser(&action, act, sizeof(sigaction_t)) != LOS_OK) {
return -EFAULT;
}
if (sig == SIGSYS) {//鸿蒙此处通过错误的系统调用 来安装信号处理函数,有点巧妙.
addr = OsGetSigHandler();//是否已存在信号处理函数
if (addr == 0) {//进程没有设置信号处理函数时
OsSetSigHandler((unsigned long)(UINTPTR)action.sa_handler);//设置进程信号处理函数
//void (*sa_handler)(int); //信号处理函数——普通版
//void (*sa_sigaction)(int, siginfo_t *, void *);//信号处理函数——高级版
return LOS_OK;
}
return -EINVAL;
@ -717,11 +754,17 @@ VOID OsSigIntUnlock(VOID)
(VOID)LOS_AtomicSub((Atomic *)&sigcb->sigIntLock, 1);
}
/**
* @brief
* @verbatim
,,
PC
* @endverbatim
*/
VOID *OsSaveSignalContext(VOID *sp, VOID *newSp)
{
UINTPTR sigHandler;
UINT32 intSave;
LosTaskCB *task = OsCurrTaskGet();
LosProcessCB *process = OsCurrProcessGet();
sig_cb *sigcb = &task->sig;
@ -754,7 +797,7 @@ VOID *OsSaveSignalContext(VOID *sp, VOID *newSp)
OsProcessExitCodeSignalSet(process, signo);
sigcb->sigContext = sp;
OsInitSignalContext(sp, newSp, sigHandler, signo, sigVal);
OsInitSignalContext(sp, newSp, sigHandler, signo, sigVal);//初始化信号上下文
/* sig No bits 00000100 present sig No 3, but 1<< 3 = 00001000, so signo needs minus 1 */
sigcb->sigFlag ^= 1ULL << (signo - 1);
@ -767,6 +810,16 @@ VOID *OsSaveSignalContext(VOID *sp, VOID *newSp)
return sp;
}
/**
* @brief
* @verbatim
,__NR_sigreturn,.
?
,使,CPU,
,,CPU
* @endverbatim
*/
VOID *OsRestorSignalContext(VOID *sp)
{
UINT32 intSave;
@ -785,8 +838,8 @@ VOID *OsRestorSignalContext(VOID *sp)
VOID *saveContext = sigcb->sigContext;
sigcb->sigContext = NULL;
sigcb->count--;
process->sigShare = 0;
OsProcessExitCodeSignalClear(process);
process->sigShare = 0; //回到用户态,信号共享清0
OsProcessExitCodeSignalClear(process);//清空进程退出码
SCHEDULER_UNLOCK(intSave);
return saveContext;
}

@ -32,9 +32,9 @@
#include "los_memstat_pri.h"
#include "los_task_pri.h"
/// 记录每个任务对内存的使用情况
/// 记录每个任务对内存的使用情况
LITE_OS_SEC_BSS_MINOR STATIC TskMemUsedInfo g_tskMemUsedInfo[LOSCFG_BASE_CORE_TSK_LIMIT];
/// 计算指定任务对内存使用增加量
/// 计算指定任务对内存使用增加量
LITE_OS_SEC_TEXT_MINOR VOID OsTaskMemUsedInc(UINT32 usedSize, UINT32 taskID)
{
if (taskID >= LOSCFG_BASE_CORE_TSK_LIMIT) {
@ -43,9 +43,9 @@ LITE_OS_SEC_TEXT_MINOR VOID OsTaskMemUsedInc(UINT32 usedSize, UINT32 taskID)
if (OS_INT_ACTIVE) {
return;
}
g_tskMemUsedInfo[taskID].memUsed += usedSize; ///< 叠加
g_tskMemUsedInfo[taskID].memUsed += usedSize; ///< 叠加
}
/// 计算指定任务对内存使用减少量
/// 计算指定任务对内存使用减少量
LITE_OS_SEC_TEXT_MINOR VOID OsTaskMemUsedDec(UINT32 usedSize, UINT32 taskID)
{
if (taskID >= LOSCFG_BASE_CORE_TSK_LIMIT) {
@ -56,12 +56,12 @@ LITE_OS_SEC_TEXT_MINOR VOID OsTaskMemUsedDec(UINT32 usedSize, UINT32 taskID)
}
if (g_tskMemUsedInfo[taskID].memUsed < usedSize) {
PRINT_WARN("mem used of current task '%s':0x%x, decrease size:0x%x\n",
OsCurrTaskGet()->taskName, g_tskMemUsedInfo[taskID].memUsed, usedSize);
OsCurrTaskGet()->taskName, g_tskMemUsedInfo[taskID].memUsed, usedSize);
return;
}
g_tskMemUsedInfo[taskID].memUsed -= usedSize; ///< 递减
g_tskMemUsedInfo[taskID].memUsed -= usedSize; ///< 递减
}
/// 获取指定任务对内存的使用情况
/// 获取指定任务对内存的使用情况
LITE_OS_SEC_TEXT_MINOR UINT32 OsTaskMemUsage(UINT32 taskID)
{
if (taskID >= LOSCFG_BASE_CORE_TSK_LIMIT) {
@ -70,7 +70,7 @@ LITE_OS_SEC_TEXT_MINOR UINT32 OsTaskMemUsage(UINT32 taskID)
return g_tskMemUsedInfo[taskID].memUsed;
}
/// 清空任务内存使用记录
/// 清空任务内存使用记录
LITE_OS_SEC_TEXT_MINOR VOID OsTaskMemClear(UINT32 taskID)
{
if (taskID >= LOSCFG_BASE_CORE_TSK_LIMIT) {
@ -78,11 +78,11 @@ LITE_OS_SEC_TEXT_MINOR VOID OsTaskMemClear(UINT32 taskID)
}
if (g_tskMemUsedInfo[taskID].memUsed != 0) {
PRINT_WARN("mem used of task '%s' is:0x%x, not zero when task being deleted\n",
OS_TCB_FROM_TID(taskID)->taskName, g_tskMemUsedInfo[taskID].memUsed);
OS_TCB_FROM_TID(taskID)->taskName, g_tskMemUsedInfo[taskID].memUsed);
}
g_tskMemUsedInfo[taskID].memUsed = 0;
}
// Slab是一种内存分配器通过将内存划分不同大小的空间分配给对象使用来进行缓存管理应用于内核对象的缓存。
// Slab是一种内存分配器通过将内存划分不同大小的空间分配给对象使用来进行缓存管理应用于内核对象的缓存。
#ifdef LOS_MEM_SLAB //
LITE_OS_SEC_BSS_MINOR STATIC TskSlabUsedInfo g_tskSlabUsedInfo[LOSCFG_BASE_CORE_TSK_LIMIT];

@ -1,3 +1,34 @@
/*!
* @file los_membox.c
* @brief
* @link
@verbatim
使
使使
使使
make menuconfig
LOS_MemboxInit
NN
LOS_MemboxAlloc
LOS_MemboxClr
LOS_MemboxFree
,使使
@endverbatim
* @version
* @author weharmonyos.com | 鸿 |
* @date 2022-04-02
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
@ -33,26 +64,25 @@
#include "los_hwi.h"
#include "los_spinlock.h"
#ifdef LOSCFG_AARCH64
#define OS_MEMBOX_MAGIC 0xa55a5aa5a55a5aa5
#define OS_MEMBOX_MAGIC 0xa55a5aa5a55a5aa5 //魔法数字,@note_good 点赞,设计的很精巧,node内容从下一个节点地址变成魔法数字
#else
#define OS_MEMBOX_MAGIC 0xa55a5aa5
#define OS_MEMBOX_MAGIC 0xa55a5aa5
#endif
#define OS_MEMBOX_SET_MAGIC(addr) \
((LOS_MEMBOX_NODE *)(addr))->pstNext = (LOS_MEMBOX_NODE *)OS_MEMBOX_MAGIC
((LOS_MEMBOX_NODE *)(addr))->pstNext = (LOS_MEMBOX_NODE *)OS_MEMBOX_MAGIC //设置魔法数字
#define OS_MEMBOX_CHECK_MAGIC(addr) \
((((LOS_MEMBOX_NODE *)(addr))->pstNext == (LOS_MEMBOX_NODE *)OS_MEMBOX_MAGIC) ? LOS_OK : LOS_NOK)
#define OS_MEMBOX_USER_ADDR(addr) \
((VOID *)((UINT8 *)(addr) + OS_MEMBOX_NODE_HEAD_SIZE))
((VOID *)((UINT8 *)(addr) + OS_MEMBOX_NODE_HEAD_SIZE)) //@note_good 使用之前要去掉节点信息,太赞了! 很艺术化!!
#define OS_MEMBOX_NODE_ADDR(addr) \
((LOS_MEMBOX_NODE *)(VOID *)((UINT8 *)(addr) - OS_MEMBOX_NODE_HEAD_SIZE))
((LOS_MEMBOX_NODE *)(VOID *)((UINT8 *)(addr) - OS_MEMBOX_NODE_HEAD_SIZE)) //节块 = (节头 + 节体) addr = 节体
/* spinlock for mem module, only available on SMP mode */
LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_memboxSpin);
#define MEMBOX_LOCK(state) LOS_SpinLockSave(&g_memboxSpin, &(state))
#define MEMBOX_UNLOCK(state) LOS_SpinUnlockRestore(&g_memboxSpin, (state))
#define MEMBOX_LOCK(state) LOS_SpinLockSave(&g_memboxSpin, &(state)) ///< 获取静态内存池自旋锁
#define MEMBOX_UNLOCK(state) LOS_SpinUnlockRestore(&g_memboxSpin, (state))///< 释放静态内存池自旋锁
/// 检查静态内存块
STATIC INLINE UINT32 OsCheckBoxMem(const LOS_MEMBOX_INFO *boxInfo, const VOID *node)
{
UINT32 offset;
@ -70,12 +100,12 @@ STATIC INLINE UINT32 OsCheckBoxMem(const LOS_MEMBOX_INFO *boxInfo, const VOID *n
return LOS_NOK;
}
return OS_MEMBOX_CHECK_MAGIC(node);
return OS_MEMBOX_CHECK_MAGIC(node);//检查魔法数字是否被修改过了
}
/// 初始化一个静态内存池,根据入参设定其起始地址、总大小及每个内存块大小
LITE_OS_SEC_TEXT_INIT UINT32 LOS_MemboxInit(VOID *pool, UINT32 poolSize, UINT32 blkSize)
{
LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool;
LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool;//在内存起始处安置池头
LOS_MEMBOX_NODE *node = NULL;
UINT32 index;
UINT32 intSave;
@ -93,30 +123,30 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_MemboxInit(VOID *pool, UINT32 poolSize, UINT32
}
MEMBOX_LOCK(intSave);
boxInfo->uwBlkSize = LOS_MEMBOX_ALIGNED(blkSize + OS_MEMBOX_NODE_HEAD_SIZE);
boxInfo->uwBlkNum = (poolSize - sizeof(LOS_MEMBOX_INFO)) / boxInfo->uwBlkSize;
boxInfo->uwBlkCnt = 0;
if (boxInfo->uwBlkNum == 0) {
boxInfo->uwBlkSize = LOS_MEMBOX_ALIGNED(blkSize + OS_MEMBOX_NODE_HEAD_SIZE); //节块总大小(节头+节体)
boxInfo->uwBlkNum = (poolSize - sizeof(LOS_MEMBOX_INFO)) / boxInfo->uwBlkSize;//总节块数量
boxInfo->uwBlkCnt = 0; //已分配的数量
if (boxInfo->uwBlkNum == 0) {//只有0块的情况
MEMBOX_UNLOCK(intSave);
return LOS_NOK;
}
node = (LOS_MEMBOX_NODE *)(boxInfo + 1);
node = (LOS_MEMBOX_NODE *)(boxInfo + 1);//去除池头,找到第一个节块位置
boxInfo->stFreeList.pstNext = node;
boxInfo->stFreeList.pstNext = node;//池头空闲链表指向第一个节块
for (index = 0; index < boxInfo->uwBlkNum - 1; ++index) {
node->pstNext = OS_MEMBOX_NEXT(node, boxInfo->uwBlkSize);
node = node->pstNext;
for (index = 0; index < boxInfo->uwBlkNum - 1; ++index) {//切割节块,挂入空闲链表
node->pstNext = OS_MEMBOX_NEXT(node, boxInfo->uwBlkSize);//按块大小切割好,统一由pstNext指向
node = node->pstNext;//node存储了下一个节点的地址信息
}
node->pstNext = NULL;
node->pstNext = NULL;//最后一个为null
MEMBOX_UNLOCK(intSave);
return LOS_OK;
}
/// 从指定的静态内存池中申请一块静态内存块,整个内核源码只有 OsSwtmrScan中用到了静态内存.
LITE_OS_SEC_TEXT VOID *LOS_MemboxAlloc(VOID *pool)
{
LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool;
@ -129,18 +159,18 @@ LITE_OS_SEC_TEXT VOID *LOS_MemboxAlloc(VOID *pool)
}
MEMBOX_LOCK(intSave);
node = &(boxInfo->stFreeList);
if (node->pstNext != NULL) {
nodeTmp = node->pstNext;
node->pstNext = nodeTmp->pstNext;
OS_MEMBOX_SET_MAGIC(nodeTmp);
boxInfo->uwBlkCnt++;
node = &(boxInfo->stFreeList);//拿到空闲单链表
if (node->pstNext != NULL) {//不需要遍历链表,因为这是空闲链表
nodeTmp = node->pstNext;//先记录要使用的节点
node->pstNext = nodeTmp->pstNext;//不再空闲了,把节点摘出去了.
OS_MEMBOX_SET_MAGIC(nodeTmp);//为已使用的节块设置魔法数字
boxInfo->uwBlkCnt++;//已使用块数增加
}
MEMBOX_UNLOCK(intSave);
return (nodeTmp == NULL) ? NULL : OS_MEMBOX_USER_ADDR(nodeTmp);
return (nodeTmp == NULL) ? NULL : OS_MEMBOX_USER_ADDR(nodeTmp);//返回可用的虚拟地址
}
/// 释放指定的一块静态内存块
LITE_OS_SEC_TEXT UINT32 LOS_MemboxFree(VOID *pool, VOID *box)
{
LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool;
@ -153,21 +183,21 @@ LITE_OS_SEC_TEXT UINT32 LOS_MemboxFree(VOID *pool, VOID *box)
MEMBOX_LOCK(intSave);
do {
LOS_MEMBOX_NODE *node = OS_MEMBOX_NODE_ADDR(box);
LOS_MEMBOX_NODE *node = OS_MEMBOX_NODE_ADDR(box);//通过节体获取节块首地址
if (OsCheckBoxMem(boxInfo, node) != LOS_OK) {
break;
}
node->pstNext = boxInfo->stFreeList.pstNext;
boxInfo->stFreeList.pstNext = node;
boxInfo->uwBlkCnt--;
node->pstNext = boxInfo->stFreeList.pstNext;//节块指向空闲链表表头
boxInfo->stFreeList.pstNext = node;//空闲链表表头反指向它,意味节块排到第一,下次申请将首个分配它
boxInfo->uwBlkCnt--;//已经使用的内存块减一
ret = LOS_OK;
} while (0);
} while (0);//将被编译时优化
MEMBOX_UNLOCK(intSave);
return ret;
}
/// 清零指定静态内存块的内容
LITE_OS_SEC_TEXT_MINOR VOID LOS_MemboxClr(VOID *pool, VOID *box)
{
LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool;
@ -175,11 +205,12 @@ LITE_OS_SEC_TEXT_MINOR VOID LOS_MemboxClr(VOID *pool, VOID *box)
if ((pool == NULL) || (box == NULL)) {
return;
}
//将魔法数字一并清除了.
(VOID)memset_s(box, (boxInfo->uwBlkSize - OS_MEMBOX_NODE_HEAD_SIZE), 0,
(boxInfo->uwBlkSize - OS_MEMBOX_NODE_HEAD_SIZE));
}
/// 打印指定静态内存池所有节点信息打印等级是LOS_INFO_LEVEL包括内存池起始地址、
/// 内存块大小、总内存块数量、每个空闲内存块的起始地址、所有内存块的起始地址
LITE_OS_SEC_TEXT_MINOR VOID LOS_ShowBox(VOID *pool)
{
UINT32 index;
@ -206,7 +237,7 @@ LITE_OS_SEC_TEXT_MINOR VOID LOS_ShowBox(VOID *pool)
}
MEMBOX_UNLOCK(intSave);
}
/// 获取指定静态内存池的信息,包括内存池中总内存块数量、已经分配出去的内存块数量、每个内存块的大小
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemboxStatisticsGet(const VOID *boxMem, UINT32 *maxBlk,
UINT32 *blkCnt, UINT32 *blkSize)
{

File diff suppressed because it is too large Load Diff

@ -52,7 +52,23 @@ LITE_OS_SEC_TEXT_MINOR VOID OsPrintKillUsage(VOID)
{
PRINTK("\nkill: usage: kill [sigspec] [pid]\n");
}
/*********************************************
kill [signo | -signo] [pid]
signo ID [1,30]
pid ID [1,MAX_INT]
signo[0,64][1,30]
使
pid256[1-256]
*********************************************/
LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdKill(INT32 argc, const CHAR **argv)
{
#define ARG_NUM 2

@ -38,27 +38,53 @@
#include "shell.h"
#endif
const StackInfo *g_stackInfo = NULL;
UINT32 g_stackNum;
/**
* @file los_stackinfo.c
* @brief
* @verbatim
@note_pic OsExcStackInfo CPU,,CPU
__undef_stack(SMP)
+-------------------+ <--- cpu1 top
| |
| CPU core1 |
| |
+--------------------<--- cpu2 top
| |
| cpu core 2 |
| |
+--------------------<--- cpu3 top
| |
| cpu core 3 |
| |
+--------------------<--- cpu4 top
| |
| cpu core 4 |
| |
+-------------------+
* @endverbatim
*/
const StackInfo *g_stackInfo = NULL; ///< CPU所有工作模式的栈信息
UINT32 g_stackNum; ///< CPU所有工作模式的栈数量
///获取栈的吃水线
UINT32 OsStackWaterLineGet(const UINTPTR *stackBottom, const UINTPTR *stackTop, UINT32 *peakUsed)
{
UINT32 size;
const UINTPTR *tmp = NULL;
if (*stackTop == OS_STACK_MAGIC_WORD) {
if (*stackTop == OS_STACK_MAGIC_WORD) {//栈顶值是否等于 magic 0xCCCCCCCC
tmp = stackTop + 1;
while ((tmp < stackBottom) && (*tmp == OS_STACK_INIT)) {
while ((tmp < stackBottom) && (*tmp == OS_STACK_INIT)) {//记录从栈顶到栈低有多少个连续的 0xCACACACA
tmp++;
}
size = (UINT32)((UINTPTR)stackBottom - (UINTPTR)tmp);
*peakUsed = (size == 0) ? size : (size + sizeof(CHAR *));
size = (UINT32)((UINTPTR)stackBottom - (UINTPTR)tmp);//剩余多少非0xCACACACA的栈空间
*peakUsed = (size == 0) ? size : (size + sizeof(CHAR *));//得出高峰用值,还剩多少可用
return LOS_OK;
} else {
*peakUsed = OS_INVALID_WATERLINE;
*peakUsed = OS_INVALID_WATERLINE;//栈溢出了
return LOS_NOK;
}
}
///异常情况下的栈检查,主要就是检查栈顶值有没有被改写
VOID OsExcStackCheck(VOID)
{
UINT32 index;
@ -71,7 +97,7 @@ VOID OsExcStackCheck(VOID)
for (index = 0; index < g_stackNum; index++) {
for (cpuid = 0; cpuid < LOSCFG_KERNEL_CORE_NUM; cpuid++) {
stackTop = (UINTPTR *)((UINTPTR)g_stackInfo[index].stackTop + cpuid * g_stackInfo[index].stackSize);
if (*stackTop != OS_STACK_MAGIC_WORD) {
if (*stackTop != OS_STACK_MAGIC_WORD) {// 只要栈顶内容不是 0xCCCCCCCCC 就是溢出了.
PRINT_ERR("cpu:%u %s overflow , magic word changed to 0x%x\n",
LOSCFG_KERNEL_CORE_NUM - 1 - cpuid, g_stackInfo[index].stackName, *stackTop);
}
@ -79,6 +105,7 @@ VOID OsExcStackCheck(VOID)
}
}
///打印栈的信息 把每个CPU的栈信息打印出来
VOID OsExcStackInfo(VOID)
{
UINT32 index;
@ -93,36 +120,37 @@ VOID OsExcStackInfo(VOID)
PrintExcInfo("\n stack name cpu id stack addr total size used size\n"
" ---------- ------ --------- -------- --------\n");
for (index = 0; index < g_stackNum; index++) {
for (cpuid = 0; cpuid < LOSCFG_KERNEL_CORE_NUM; cpuid++) {
for (cpuid = 0; cpuid < LOSCFG_KERNEL_CORE_NUM; cpuid++) {//可以看出 各个CPU的栈是紧挨的的
stackTop = (UINTPTR *)((UINTPTR)g_stackInfo[index].stackTop + cpuid * g_stackInfo[index].stackSize);
stack = (UINTPTR *)((UINTPTR)stackTop + g_stackInfo[index].stackSize);
(VOID)OsStackWaterLineGet(stack, stackTop, &size);
(VOID)OsStackWaterLineGet(stack, stackTop, &size);//获取吃水线, 鸿蒙用WaterLine 这个词用的很妙
PrintExcInfo("%11s %-5d %-10p 0x%-8x 0x%-4x\n", g_stackInfo[index].stackName,
LOSCFG_KERNEL_CORE_NUM - 1 - cpuid, stackTop, g_stackInfo[index].stackSize, size);
}
}
OsExcStackCheck();
OsExcStackCheck();//发生异常时栈检查
}
///注册栈信息
VOID OsExcStackInfoReg(const StackInfo *stackInfo, UINT32 stackNum)
{
g_stackInfo = stackInfo;
g_stackInfo = stackInfo; //全局变量指向g_excStack
g_stackNum = stackNum;
}
///task栈的初始化,设置固定的值. 0xcccccccc 和 0xcacacaca
VOID OsStackInit(VOID *stacktop, UINT32 stacksize)
{
/* initialize the task stack, write magic num to stack top */
errno_t ret = memset_s(stacktop, stacksize, (INT32)OS_STACK_INIT, stacksize);
errno_t ret = memset_s(stacktop, stacksize, (INT32)OS_STACK_INIT, stacksize);//清一色填 0xCACACACA
if (ret == EOK) {
*((UINTPTR *)stacktop) = OS_STACK_MAGIC_WORD;
*((UINTPTR *)stacktop) = OS_STACK_MAGIC_WORD;//0xCCCCCCCCC 中文就是"烫烫烫烫" 这几个字懂点计算机的人都不会陌生了.
}
}
#ifdef LOSCFG_SHELL_CMD_DEBUG
SHELLCMD_ENTRY(stack_shellcmd, CMD_TYPE_EX, "stack", 1, (CmdCallBackFunc)OsExcStackInfo);
SHELLCMD_ENTRY(stack_shellcmd, CMD_TYPE_EX, "stack", 1, (CmdCallBackFunc)OsExcStackInfo);//采用shell命令静态注册方式
#endif

@ -193,7 +193,7 @@ LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdUname(INT32 argc, const CHAR *argv[])
if (argc == 1) {
if (strcmp(argv[0], "-a") == 0) {
PRINTK("%s %d.%d.%d.%d %s %s\n", KERNEL_NAME, KERNEL_MAJOR, KERNEL_MINOR, KERNEL_PATCH, KERNEL_ITRE, \
PRINTK("%s %d.%d.%d.%d %s %s\n", KERNEL_NAME, KERNEL_MAJOR, KERNEL_MINOR, KERNEL_PATCH, KERNEL_ITRE,\
__DATE__, __TIME__);
return 0;
} else if (strcmp(argv[0], "-s") == 0) {

@ -58,20 +58,21 @@ STATIC VOID OsPrintSwtmrMsg(const SWTMR_CTRL_S *swtmr)
(VOID)LOS_SwtmrTimeGet(swtmr->usTimerID, &ticks);
PRINTK("%7u%10s%8s%12u%7u%#12x%#12x\n",
swtmr->usTimerID % LOSCFG_BASE_CORE_SWTMR_LIMIT,
g_shellSwtmrStatus[swtmr->ucState],
g_shellSwtmrMode[swtmr->ucMode],
swtmr->uwInterval,
swtmr->usTimerID % LOSCFG_BASE_CORE_SWTMR_LIMIT, //软件定时器ID。
g_shellSwtmrStatus[swtmr->ucState], //软件定时器状态,状态可能为:"UnUsed", "Created", "Ticking"。
g_shellSwtmrMode[swtmr->ucMode], //软件定时器模式。模式可能为:"Once", "Period", "NSD单次定时器定时结束后不会自动删除"
swtmr->uwInterval, //软件定时器使用的Tick数。
ticks,
swtmr->uwArg,
swtmr->pfnHandler);
swtmr->uwArg, //传入的参数。
swtmr->pfnHandler); //回调函数的地址。
}
STATIC INLINE VOID OsPrintSwtmrMsgHead(VOID)
{
PRINTK("\r\nSwTmrID State Mode Interval Count Arg handlerAddr\n");
}
///shell命令之swtmr 命令用于查询系统软件定时器相关信息。
//参数缺省时,默认显示所有软件定时器的相关信息。
STATIC UINT32 SwtmrBaseInfoGet(UINT32 timerID)
{
SWTMR_CTRL_S *swtmr = g_swtmrCBArray;
@ -173,7 +174,6 @@ SWTMR_HELP:
PRINTK(" swtmr ID --- Specifies information about a software timer.\n");
return LOS_OK;
}
SHELLCMD_ENTRY(swtmr_shellcmd, CMD_TYPE_EX, "swtmr", 1, (CmdCallBackFunc)OsShellCmdSwtmrInfoGet);
SHELLCMD_ENTRY(swtmr_shellcmd, CMD_TYPE_EX, "swtmr", 1, (CmdCallBackFunc)OsShellCmdSwtmrInfoGet);//采用shell命令静态注册方式
#endif /* LOSCFG_SHELL */

@ -118,7 +118,7 @@ UINT32 OsShellCmdSwtmrCntGet(VOID)
LOS_IntRestore(intSave);
return swtmrCnt;
}
///查看系统资源使用情况
LITE_OS_SEC_TEXT_MINOR VOID OsShellCmdSystemInfoGet(VOID)
{
UINT8 isTaskEnable = TRUE;
@ -137,27 +137,27 @@ LITE_OS_SEC_TEXT_MINOR VOID OsShellCmdSystemInfoGet(VOID)
#else
UINT8 isSwtmrEnable = FALSE;
#endif
//模块名称 当前使用量 最大可用量 模块是否开启
PRINTK("\n Module Used Total Enabled\n");
PRINTK("--------------------------------------------\n");
PRINTK(" Task %-10u%-10d%s\n",
OsShellCmdTaskCntGet(),
LOSCFG_BASE_CORE_TSK_LIMIT,
SYSINFO_ENABLED(isTaskEnable));
OsShellCmdTaskCntGet(), //有效任务数
LOSCFG_BASE_CORE_TSK_LIMIT, //任务最大数 128
SYSINFO_ENABLED(isTaskEnable));//任务是否失效 YES or NO
PRINTK(" Sem %-10u%-10d%s\n",
OsShellCmdSemCntGet(),
LOSCFG_BASE_IPC_SEM_LIMIT,
SYSINFO_ENABLED(isSemEnable));
OsShellCmdSemCntGet(), //信号量的数量
LOSCFG_BASE_IPC_SEM_LIMIT, //信号量最大数 1024
SYSINFO_ENABLED(isSemEnable));//信号量是否失效 YES or NO
PRINTK(" Queue %-10u%-10d%s\n",
OsShellCmdQueueCntGet(),
LOSCFG_BASE_IPC_QUEUE_LIMIT,
SYSINFO_ENABLED(isQueueEnable));
OsShellCmdQueueCntGet(), //队列的数量
LOSCFG_BASE_IPC_QUEUE_LIMIT, //队列的最大数 1024
SYSINFO_ENABLED(isQueueEnable));//队列是否失效 YES or NO
PRINTK(" SwTmr %-10u%-10d%s\n",
OsShellCmdSwtmrCntGet(),
LOSCFG_BASE_CORE_SWTMR_LIMIT,
SYSINFO_ENABLED(isSwtmrEnable));
OsShellCmdSwtmrCntGet(), //定时器的数量
LOSCFG_BASE_CORE_SWTMR_LIMIT, //定时器的总数 1024
SYSINFO_ENABLED(isSwtmrEnable)); //定时器是否失效 YES or NO
}
///systeminfo命令用于显示当前操作系统内资源使用情况包括任务、信号量、互斥量、队列、定时器等。
INT32 OsShellCmdSystemInfo(INT32 argc, const CHAR **argv)
{
if (argc == 0) {

@ -54,7 +54,7 @@
#define VMM_CMD "vmm"
#define OOM_CMD "oom"
#define VMM_PMM_CMD "v2p"
//dump内核空间
LITE_OS_SEC_TEXT_MINOR VOID OsDumpKernelAspace(VOID)
{
LosVmSpace *kAspace = LOS_GetKVmSpace();
@ -104,26 +104,26 @@ LITE_OS_SEC_TEXT_MINOR VOID OsDoDumpVm(pid_t pid)
PRINTK("\tThe process [%d] not active\n", pid);
}
}
///查看进程的虚拟内存使用情况。vmm [-a / -h / --help] vmm [pid]
LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdDumpVm(INT32 argc, const CHAR *argv[])
{
if (argc == 0) {
if (argc == 0) { //没有参数 使用 # vmm 查看所有进程使用虚拟内存的情况
OsDumpAllAspace();
} else if (argc == 1) {
pid_t pid = OsPid(argv[0]);
if (strcmp(argv[0], "-a") == 0) {
if (strcmp(argv[0], "-a") == 0) { //# vmm -a 查看所有进程使用虚拟内存的情况
OsDumpAllAspace();
} else if (strcmp(argv[0], "-k") == 0) {
} else if (strcmp(argv[0], "-k") == 0) {//# vmm -k 查看内核进程使用虚拟内存的情况
OsDumpKernelAspace();
} else if (pid >= 0) {
} else if (pid >= 0) { //# vmm 3 查看3号进程使用虚拟内存的情况
OsDoDumpVm(pid);
} else if (strcmp(argv[0], "-h") == 0 || strcmp(argv[0], "--help") == 0) {
} else if (strcmp(argv[0], "-h") == 0 || strcmp(argv[0], "--help") == 0) { //# vmm -h 或者 vmm --help
OsPrintUsage();
} else {
PRINTK("%s: invalid option: %s\n", VMM_CMD, argv[0]);
PRINTK("%s: invalid option: %s\n", VMM_CMD, argv[0]); //格式错误,输出规范格式
OsPrintUsage();
}
} else {
} else { //多于一个参数 例如 # vmm 3 9
OsPrintUsage();
}
@ -135,7 +135,7 @@ LITE_OS_SEC_TEXT_MINOR VOID V2PPrintUsage(VOID)
PRINTK("pid vaddr(0x1000000~0x3e000000), print physical address of virtual address\n"
"-h | --help, print v2p command usage\n");
}
///v2p 虚拟内存对应的物理内存
LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdV2P(INT32 argc, const CHAR *argv[])
{
UINT32 vaddr;
@ -180,7 +180,7 @@ LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdV2P(INT32 argc, const CHAR *argv[])
return LOS_OK;
}
///查看系统内存物理页及pagecache物理页使用情况 , Debug版本才具备的命令 # pmm
LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdDumpPmm(VOID)
{
OsVmPhysDump();
@ -192,12 +192,13 @@ LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdDumpPmm(VOID)
LITE_OS_SEC_TEXT_MINOR VOID OomPrintUsage(VOID)
{
PRINTK("\t-i [interval], set oom check interval (ms)\n"
"\t-m [mem byte], set oom low memory threshold (Byte)\n"
"\t-r [mem byte], set page cache reclaim memory threshold (Byte)\n"
"\t-h | --help, print vmm command usage\n");
PRINTK("\t-i [interval], set oom check interval (ms)\n" //设置oom线程任务检查的时间间隔。
"\t-m [mem byte], set oom low memory threshold (Byte)\n" //设置低内存阈值。
"\t-r [mem byte], set page cache reclaim memory threshold (Byte)\n" //设置pagecache内存回收阈值。
"\t-h | --help, print vmm command usage\n"); //使用帮助。
}
///查看和设置低内存阈值以及pagecache内存回收阈值。参数缺省时显示oom功能当前配置信息。
//当系统内存不足时,会打印出内存不足的提示信息。
LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdOom(INT32 argc, const CHAR *argv[])
{
UINT32 lowMemThreshold;
@ -219,7 +220,7 @@ LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdOom(INT32 argc, const CHAR *argv[])
PRINTK("[oom] low mem threshold %s(byte) invalid.\n", argv[1]);
return OS_ERROR;
} else {
OomSetLowMemThreashold(lowMemThreshold);
OomSetLowMemThreashold(lowMemThreshold);//设置低内存阈值
}
} else if (strcmp(argv[0], "-i") == 0) {
checkInterval = strtoul((CHAR *)argv[1], &endPtr, 0);
@ -227,7 +228,7 @@ LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdOom(INT32 argc, const CHAR *argv[])
PRINTK("[oom] check interval %s(us) invalid.\n", argv[1]);
return OS_ERROR;
} else {
OomSetCheckInterval(checkInterval);
OomSetCheckInterval(checkInterval);//设置oom线程任务检查的时间间隔
}
} else if (strcmp(argv[0], "-r") == 0) {
reclaimMemThreshold = strtoul((CHAR *)argv[1], &endPtr, 0);
@ -235,7 +236,7 @@ LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdOom(INT32 argc, const CHAR *argv[])
PRINTK("[oom] reclaim mem threshold %s(byte) invalid.\n", argv[1]);
return OS_ERROR;
} else {
OomSetReclaimMemThreashold(reclaimMemThreshold);
OomSetReclaimMemThreashold(reclaimMemThreshold);//设置pagecache内存回收阈值
}
} else {
PRINTK("%s: invalid option: %s %s\n", OOM_CMD, argv[0], argv[1]);
@ -250,13 +251,13 @@ LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdOom(INT32 argc, const CHAR *argv[])
}
#ifdef LOSCFG_SHELL_CMD_DEBUG
SHELLCMD_ENTRY(oom_shellcmd, CMD_TYPE_SHOW, OOM_CMD, 2, (CmdCallBackFunc)OsShellCmdOom);
SHELLCMD_ENTRY(vm_shellcmd, CMD_TYPE_SHOW, VMM_CMD, 1, (CmdCallBackFunc)OsShellCmdDumpVm);
SHELLCMD_ENTRY(v2p_shellcmd, CMD_TYPE_SHOW, VMM_PMM_CMD, 1, (CmdCallBackFunc)OsShellCmdV2P);
SHELLCMD_ENTRY(oom_shellcmd, CMD_TYPE_SHOW, OOM_CMD, 2, (CmdCallBackFunc)OsShellCmdOom);//采用shell命令静态注册方式
SHELLCMD_ENTRY(vm_shellcmd, CMD_TYPE_SHOW, VMM_CMD, 1, (CmdCallBackFunc)OsShellCmdDumpVm);//采用shell命令静态注册方式 vmm
SHELLCMD_ENTRY(v2p_shellcmd, CMD_TYPE_SHOW, VMM_PMM_CMD, 1, (CmdCallBackFunc)OsShellCmdV2P);//采用shell命令静态注册方式 v2p
#endif
#ifdef LOSCFG_SHELL
SHELLCMD_ENTRY(pmm_shellcmd, CMD_TYPE_SHOW, "pmm", 0, (CmdCallBackFunc)OsShellCmdDumpPmm);
SHELLCMD_ENTRY(pmm_shellcmd, CMD_TYPE_SHOW, "pmm", 0, (CmdCallBackFunc)OsShellCmdDumpPmm);//采用shell命令静态注册方式
#endif
#endif

@ -1,3 +1,32 @@
/*!
* @file los_mp.c
* @brief
* @link
* @verbatim
CPU3(SMP+AMP+BMP) 鸿 SMP
Asymmetric multiprocessingAMPCPU
instantiation
Symmetric multiprocessingSMP
CPU
Bound multiprocessingBMP
CPU
线
PIC(Programmable Interrupt ControllerPIC
线线(Inter-Processor Interrupts,IPI
SGI:(Software Generated Interrupt)arm
SGI16,ID0~ID15
* @endverbatim
* @version
* @author weharmonyos.com | 鸿 |
* @date 2021-11-18
*
* @history
*
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
@ -36,43 +65,43 @@
#include "los_swtmr.h"
#include "los_task_pri.h"
#ifdef LOSCFG_KERNEL_SMP
#ifdef LOSCFG_KERNEL_SMP
//给参数CPU发送调度信号
#ifdef LOSCFG_KERNEL_SMP_CALL
LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_mpCallSpin);
#define MP_CALL_LOCK(state) LOS_SpinLockSave(&g_mpCallSpin, &(state))
#define MP_CALL_UNLOCK(state) LOS_SpinUnlockRestore(&g_mpCallSpin, (state))
#endif
VOID LOS_MpSchedule(UINT32 target)
VOID LOS_MpSchedule(UINT32 target)//target每位对应CPU core
{
UINT32 cpuid = ArchCurrCpuid();
target &= ~(1U << cpuid);
HalIrqSendIpi(target, LOS_MP_IPI_SCHEDULE);
target &= ~(1U << cpuid);//获取除了自身之外的其他CPU
HalIrqSendIpi(target, LOS_MP_IPI_SCHEDULE);//向目标CPU发送调度信号,核间中断(Inter-Processor Interrupts),IPI
}
///硬中断唤醒处理函数
VOID OsMpWakeHandler(VOID)
{
/* generic wakeup ipi, do nothing */
}
///硬中断调度处理函数
VOID OsMpScheduleHandler(VOID)
{
{//将调度标志设置为与唤醒功能不同,这样就可以在硬中断结束时触发调度程序。
/*
* set schedule flag to differ from wake function,
* so that the scheduler can be triggered at the end of irq.
*/
OsSchedRunqueuePendingSet();
}
///硬中断暂停处理函数
VOID OsMpHaltHandler(VOID)
{
(VOID)LOS_IntLock();
OsPercpuGet()->excFlag = CPU_HALT;
OsPercpuGet()->excFlag = CPU_HALT;//让当前Cpu停止工作
while (1) {}
while (1) {}//陷入空循环,也就是空闲状态
}
///MP定时器处理函数, 递归检查所有可用任务
VOID OsMpCollectTasks(VOID)
{
LosTaskCB *taskCB = NULL;
@ -80,19 +109,19 @@ VOID OsMpCollectTasks(VOID)
UINT32 ret;
/* recursive checking all the available task */
for (; taskID <= g_taskMaxNum; taskID++) {
for (; taskID <= g_taskMaxNum; taskID++) { //递归检查所有可用任务
taskCB = &g_taskCBArray[taskID];
if (OsTaskIsUnused(taskCB) || OsTaskIsRunning(taskCB)) {
continue;
}
/*
/* 虽然任务状态不是原子的,但此检查可能成功,但无法完成删除,此删除将在下次运行之前处理
* though task status is not atomic, this check may success but not accomplish
* the deletion; this deletion will be handled until the next run.
*/
if (taskCB->signal & SIGNAL_KILL) {
ret = LOS_TaskDelete(taskID);
if (taskCB->signal & SIGNAL_KILL) {//任务收到被干掉信号
ret = LOS_TaskDelete(taskID);//干掉任务,回归任务池
if (ret != LOS_OK) {
PRINT_WARN("GC collect task failed err:0x%x\n", ret);
}
@ -101,6 +130,17 @@ VOID OsMpCollectTasks(VOID)
}
#ifdef LOSCFG_KERNEL_SMP_CALL
/*!
* @brief OsMpFuncCall
* CPUfuncLink, ? ?
* \n CPU ab,b, ?
* @param args
* @param func
* @param target
* @return
*
* @see
*/
VOID OsMpFuncCall(UINT32 target, SMP_FUNC_CALL func, VOID *args)
{
UINT32 index;
@ -110,13 +150,13 @@ VOID OsMpFuncCall(UINT32 target, SMP_FUNC_CALL func, VOID *args)
return;
}
if (!(target & OS_MP_CPU_ALL)) {
if (!(target & OS_MP_CPU_ALL)) {//检查目标CPU是否正确
return;
}
for (index = 0; index < LOSCFG_KERNEL_CORE_NUM; index++) {
for (index = 0; index < LOSCFG_KERNEL_CORE_NUM; index++) {//遍历所有核
if (CPUID_TO_AFFI_MASK(index) & target) {
MpCallFunc *mpCallFunc = (MpCallFunc *)LOS_MemAlloc(m_aucSysMem0, sizeof(MpCallFunc));
MpCallFunc *mpCallFunc = (MpCallFunc *)LOS_MemAlloc(m_aucSysMem0, sizeof(MpCallFunc));//从内核空间 分配回调结构体
if (mpCallFunc == NULL) {
PRINT_ERR("smp func call malloc failed\n");
return;
@ -125,59 +165,66 @@ VOID OsMpFuncCall(UINT32 target, SMP_FUNC_CALL func, VOID *args)
mpCallFunc->args = args;
MP_CALL_LOCK(intSave);
LOS_ListAdd(&g_percpu[index].funcLink, &(mpCallFunc->node));
LOS_ListAdd(&g_percpu[index].funcLink, &(mpCallFunc->node));//将回调结构体挂入链表尾部
MP_CALL_UNLOCK(intSave);
}
}
HalIrqSendIpi(target, LOS_MP_IPI_FUNC_CALL);
HalIrqSendIpi(target, LOS_MP_IPI_FUNC_CALL);//向目标CPU发起核间中断
}
/*!
* @brief OsMpFuncCallHandler
* CPU
* @return
*
* @see
*/
VOID OsMpFuncCallHandler(VOID)
{
UINT32 intSave;
UINT32 cpuid = ArchCurrCpuid();
UINT32 cpuid = ArchCurrCpuid();//获取当前CPU
LOS_DL_LIST *list = NULL;
MpCallFunc *mpCallFunc = NULL;
MP_CALL_LOCK(intSave);
while (!LOS_ListEmpty(&g_percpu[cpuid].funcLink)) {
list = LOS_DL_LIST_FIRST(&g_percpu[cpuid].funcLink);
LOS_ListDelete(list);
while (!LOS_ListEmpty(&g_percpu[cpuid].funcLink)) {//遍历回调函数链表,知道为空
list = LOS_DL_LIST_FIRST(&g_percpu[cpuid].funcLink);//获取链表第一个数据
LOS_ListDelete(list);//将自己从链表上摘除
MP_CALL_UNLOCK(intSave);
mpCallFunc = LOS_DL_LIST_ENTRY(list, MpCallFunc, node);
mpCallFunc->func(mpCallFunc->args);
(VOID)LOS_MemFree(m_aucSysMem0, mpCallFunc);
mpCallFunc = LOS_DL_LIST_ENTRY(list, MpCallFunc, node);//获取回调函数
mpCallFunc->func(mpCallFunc->args);//获取参数并回调该函数
(VOID)LOS_MemFree(m_aucSysMem0, mpCallFunc);//释放回调函数内存
MP_CALL_LOCK(intSave);
}
MP_CALL_UNLOCK(intSave);
}
/// CPU层级的回调模块初始化
VOID OsMpFuncCallInit(VOID)
{
UINT32 index;
/* init funclink for each core */
/* init funclink for each core | 为每个CPU核整一个回调函数链表*/
for (index = 0; index < LOSCFG_KERNEL_CORE_NUM; index++) {
LOS_ListInit(&g_percpu[index].funcLink);
LOS_ListInit(&g_percpu[index].funcLink);//链表初始化
}
}
#endif /* LOSCFG_KERNEL_SMP_CALL */
//MP(multiprocessing) 多核处理器初始化
UINT32 OsMpInit(VOID)
{
UINT16 swtmrId;
(VOID)LOS_SwtmrCreate(OS_MP_GC_PERIOD, LOS_SWTMR_MODE_PERIOD,
(SWTMR_PROC_FUNC)OsMpCollectTasks, &swtmrId, 0);
(VOID)LOS_SwtmrStart(swtmrId);
(VOID)LOS_SwtmrCreate(OS_MP_GC_PERIOD, LOS_SWTMR_MODE_PERIOD, //创建一个周期性,持续时间为 100个tick的定时器
(SWTMR_PROC_FUNC)OsMpCollectTasks, &swtmrId, 0);//OsMpCollectTasks为超时回调函数
(VOID)LOS_SwtmrStart(swtmrId);//开始定时任务
#ifdef LOSCFG_KERNEL_SMP_CALL
OsMpFuncCallInit();
#endif
return LOS_OK;
}
LOS_MODULE_INIT(OsMpInit, LOS_INIT_LEVEL_KMOD_TASK);
LOS_MODULE_INIT(OsMpInit, LOS_INIT_LEVEL_KMOD_TASK);//多处理器模块初始化
#endif

@ -33,7 +33,7 @@
#include "los_printf.h"
#ifdef LOSCFG_KERNEL_SMP
Percpu g_percpu[LOSCFG_KERNEL_CORE_NUM];
Percpu g_percpu[LOSCFG_KERNEL_CORE_NUM]; ///< CPU池,池大小由CPU核数决定
VOID OsAllCpuStatusOutput(VOID)
{

@ -31,9 +31,33 @@
#include "los_err.h"
/**
* @file los_err.c
* @brief
* @verbatim
便
LITE_OS_SEC_BSS STATIC LOS_ERRORHANDLE_FUNC g_errHandleHook = NULL;
* @endverbatim
*/
LITE_OS_SEC_BSS STATIC LOS_ERRORHANDLE_FUNC g_errHandleHook = NULL;///< 错误接管钩子函数
/**
* @brief
* @param fileName ,"os_unspecific_file"
* @param lineNo 0xa1b2c3f8
* @param errorNo
* @param paraLen para0
* @param para NULL
* @return LITE_OS_SEC_TEXT_INIT
*/
LITE_OS_SEC_TEXT_INIT UINT32 LOS_ErrHandle(CHAR *fileName, UINT32 lineNo, UINT32 errorNo,
UINT32 paraLen, VOID *para)
{
@ -43,7 +67,7 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_ErrHandle(CHAR *fileName, UINT32 lineNo, UINT32
return LOS_OK;
}
///设置钩子函数,处理错误
LITE_OS_SEC_TEXT_INIT VOID LOS_SetErrHandleHook(LOS_ERRORHANDLE_FUNC fun)
{
g_errHandleHook = fun;

@ -44,7 +44,7 @@ STATIC VOID IdleTimeSliceUpdate(SchedRunqueue *rq, LosTaskCB *taskCB, UINT64 cur
STATIC INT32 IdleParamCompare(const SchedPolicy *sp1, const SchedPolicy *sp2);
STATIC VOID IdlePriorityInheritance(LosTaskCB *owner, const SchedParam *param);
STATIC VOID IdlePriorityRestore(LosTaskCB *owner, const LOS_DL_LIST *list, const SchedParam *param);
//空闲调度
const STATIC SchedOps g_idleOps = {
.dequeue = IdleDequeue,
.enqueue = IdleEnqueue,

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022-2023 Huawei Device Co., Ltd. All rights reserved.
* Copyright (c) 2022-2022 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
@ -43,6 +43,8 @@
#define OS_SCHED_READY_MAX 30
#define OS_TIME_SLICE_MIN (INT32)((50 * OS_SYS_NS_PER_US) / OS_NS_PER_CYCLE) /* 50us */
//基于优先数调度算法 Highest-Priority-First (HPF)
STATIC HPFRunqueue g_schedHPF;
STATIC VOID HPFDequeue(SchedRunqueue *rq, LosTaskCB *taskCB);
@ -63,7 +65,7 @@ STATIC VOID HPFTimeSliceUpdate(SchedRunqueue *rq, LosTaskCB *taskCB, UINT64 curr
STATIC INT32 HPFParamCompare(const SchedPolicy *sp1, const SchedPolicy *sp2);
STATIC VOID HPFPriorityInheritance(LosTaskCB *owner, const SchedParam *param);
STATIC VOID HPFPriorityRestore(LosTaskCB *owner, const LOS_DL_LIST *list, const SchedParam *param);
//优先级调度算法操作
const STATIC SchedOps g_priorityOps = {
.dequeue = HPFDequeue,
.enqueue = HPFEnqueue,
@ -243,7 +245,7 @@ STATIC INLINE VOID PriQueInsert(HPFRunqueue *rq, LosTaskCB *taskCB)
taskCB->taskStatus &= ~OS_TASK_STATUS_BLOCKED;
taskCB->taskStatus |= OS_TASK_STATUS_READY;
}
//入就绪队列
STATIC VOID HPFEnqueue(SchedRunqueue *rq, LosTaskCB *taskCB)
{
#ifdef LOSCFG_SCHED_HPF_DEBUG
@ -253,14 +255,14 @@ STATIC VOID HPFEnqueue(SchedRunqueue *rq, LosTaskCB *taskCB)
#endif
PriQueInsert(rq->hpfRunqueue, taskCB);
}
//出就绪队列
STATIC VOID HPFDequeue(SchedRunqueue *rq, LosTaskCB *taskCB)
{
SchedHPF *sched = (SchedHPF *)&taskCB->sp;
if (taskCB->taskStatus & OS_TASK_STATUS_READY) {
if (taskCB->taskStatus & OS_TASK_STATUS_READY) {//是否有就绪状态
PriQueDelete(rq->hpfRunqueue, sched->basePrio, &taskCB->pendList, sched->priority);
taskCB->taskStatus &= ~OS_TASK_STATUS_READY;
taskCB->taskStatus &= ~OS_TASK_STATUS_READY;//更新成非就绪状态
}
}
@ -475,7 +477,7 @@ STATIC VOID HPFPriorityInheritance(LosTaskCB *owner, const SchedParam *param)
LOS_BitmapSet(&sp->priBitmap, sp->priority);
sp->priority = param->priority;
}
/// 恢复任务优先级
STATIC VOID HPFPriorityRestore(LosTaskCB *owner, const LOS_DL_LIST *list, const SchedParam *param)
{
UINT16 priority;
@ -498,8 +500,8 @@ STATIC VOID HPFPriorityRestore(LosTaskCB *owner, const LOS_DL_LIST *list, const
}
if ((list != NULL) && !LOS_ListEmpty((LOS_DL_LIST *)list)) {
priority = LOS_HighBitGet(sp->priBitmap);
LOS_DL_LIST_FOR_EACH_ENTRY(pendedTask, list, LosTaskCB, pendList) {
priority = LOS_HighBitGet(sp->priBitmap);//获取在历史调度中最高优先级
LOS_DL_LIST_FOR_EACH_ENTRY(pendedTask, list, LosTaskCB, pendList) {//遍历链表
SchedHPF *pendSp = (SchedHPF *)&pendedTask->sp;
if ((pendedTask->ops == owner->ops) && (priority != pendSp->priority)) {
LOS_BitmapClr(&sp->priBitmap, pendSp->priority);
@ -537,7 +539,7 @@ VOID HPFProcessDefaultSchedParamGet(SchedParam *param)
{
param->basePrio = OS_USER_PROCESS_PRIORITY_HIGHEST;
}
//HPF 调度策略初始化
VOID HPFSchedPolicyInit(SchedRunqueue *rq)
{
if (ArchCurrCpuid() > 0) {

@ -1,6 +1,6 @@
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2022 Huawei Device Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
@ -30,7 +30,7 @@
*/
#include "los_sortlink_pri.h"
/// 排序链表初始化
VOID OsSortLinkInit(SortLinkAttribute *sortLinkHeader)
{
LOS_ListInit(&sortLinkHeader->sortLink);
@ -38,38 +38,47 @@ VOID OsSortLinkInit(SortLinkAttribute *sortLinkHeader)
sortLinkHeader->nodeNum = 0;
}
/*!
* @brief OsAddNode2SortLink ,
*
* @param sortLinkHeader
* @param sortList
* @return
*
* @see
*/
STATIC INLINE VOID AddNode2SortLink(SortLinkAttribute *sortLinkHeader, SortLinkList *sortList)
{
LOS_DL_LIST *head = (LOS_DL_LIST *)&sortLinkHeader->sortLink;
LOS_DL_LIST *head = (LOS_DL_LIST *)&sortLinkHeader->sortLink; //获取双向链表
if (LOS_ListEmpty(head)) {
LOS_ListHeadInsert(head, &sortList->sortLinkNode);
sortLinkHeader->nodeNum++;
if (LOS_ListEmpty(head)) { //空链表,直接插入
LOS_ListHeadInsert(head, &sortList->sortLinkNode);//插入结点
sortLinkHeader->nodeNum++;//CPU的工作量增加了
return;
}
//链表不为空时,插入分三种情况, responseTime 大于,等于,小于的处理
SortLinkList *listSorted = LOS_DL_LIST_ENTRY(head->pstNext, SortLinkList, sortLinkNode);
if (listSorted->responseTime > sortList->responseTime) {
LOS_ListAdd(head, &sortList->sortLinkNode);
sortLinkHeader->nodeNum++;
return;
} else if (listSorted->responseTime == sortList->responseTime) {
LOS_ListAdd(head->pstNext, &sortList->sortLinkNode);
if (listSorted->responseTime > sortList->responseTime) {//如果要插入的节点 responseTime 最小
LOS_ListAdd(head, &sortList->sortLinkNode);//能跑进来说明是最小的,直接插入到第一的位置
sortLinkHeader->nodeNum++;//CPU的工作量增加了
return;//直接返回了
} else if (listSorted->responseTime == sortList->responseTime) {//相等的情况
LOS_ListAdd(head->pstNext, &sortList->sortLinkNode);//插到第二的位置
sortLinkHeader->nodeNum++;
return;
}
LOS_DL_LIST *prevNode = head->pstPrev;
do {
listSorted = LOS_DL_LIST_ENTRY(prevNode, SortLinkList, sortLinkNode);
if (listSorted->responseTime <= sortList->responseTime) {
//处理大于链表中第一个responseTime的情况,需要遍历链表
LOS_DL_LIST *prevNode = head->pstPrev;//注意这里用的前一个结点,也就是说前一个结点中的responseTime 是最大的
do { // @note_good 这里写的有点妙,也是双向链表的魅力所在
listSorted = LOS_DL_LIST_ENTRY(prevNode, SortLinkList, sortLinkNode);//一个个遍历,先比大的再比小的
if (listSorted->responseTime <= sortList->responseTime) {//如果时间比你小,就插到后面
LOS_ListAdd(prevNode, &sortList->sortLinkNode);
sortLinkHeader->nodeNum++;
break;
}
prevNode = prevNode->pstPrev;
} while (1);
prevNode = prevNode->pstPrev;//再拿上一个更小的responseTime进行比较
} while (1);//死循环
}
VOID OsAdd2SortLink(SortLinkAttribute *head, SortLinkList *node, UINT64 responseTime, UINT16 idleCpu)

@ -38,10 +38,15 @@
#include "los_vm_page.h"
#include "los_arch_mmu.h"
/**
* @brief , los_vm_zone.h 鸿
*/
UINTPTR g_vmBootMemBase = (UINTPTR)&__bss_end; ///< 内核空间可用于分配的区域,紧挨着.bss区
BOOL g_kHeapInited = FALSE; ///< 内核堆区初始化变量
UINTPTR g_vmBootMemBase = (UINTPTR)&__bss_end;
BOOL g_kHeapInited = FALSE;
///< 开机引导分配器分配内存,只有开机时采用的分配方式
VOID *OsVmBootMemAlloc(size_t len)
{
UINTPTR ptr;
@ -51,33 +56,33 @@ VOID *OsVmBootMemAlloc(size_t len)
return NULL;
}
ptr = LOS_Align(g_vmBootMemBase, sizeof(UINTPTR));
g_vmBootMemBase = ptr + LOS_Align(len, sizeof(UINTPTR));
ptr = LOS_Align(g_vmBootMemBase, sizeof(UINTPTR));//对齐
g_vmBootMemBase = ptr + LOS_Align(len, sizeof(UINTPTR));//通过改变 g_vmBootMemBase来获取内存
//这样也行,g_vmBootMemBase 真是野蛮粗暴
return (VOID *)ptr;
}
///整个系统内存初始化
UINT32 OsSysMemInit(VOID)
{
STATUS_T ret;
#ifdef LOSCFG_KERNEL_VM
OsKSpaceInit();
OsKSpaceInit();//内核空间初始化
#endif
ret = OsKHeapInit(OS_KHEAP_BLOCK_SIZE);
ret = OsKHeapInit(OS_KHEAP_BLOCK_SIZE);// 内核堆空间初始化 512K
if (ret != LOS_OK) {
VM_ERR("OsKHeapInit fail\n");
return LOS_NOK;
}
#ifdef LOSCFG_KERNEL_VM
OsVmPageStartup();
g_kHeapInited = TRUE;
OsInitMappingStartUp();
OsVmPageStartup();// 物理内存初始化
g_kHeapInited = TRUE; //内核堆区初始化完成
OsInitMappingStartUp();//映射初始化
#else
g_kHeapInited = TRUE;
g_kHeapInited = TRUE;//内核堆区完成初始化
#endif
return LOS_OK;
}

@ -53,7 +53,7 @@
#define FLAG_SIZE 4
#define FLAG_START 2
//获取线性区的名称或文件路径
const CHAR *OsGetRegionNameOrFilePath(LosVmMapRegion *region)
{
struct Vnode *vnode = NULL;
@ -64,24 +64,24 @@ const CHAR *OsGetRegionNameOrFilePath(LosVmMapRegion *region)
vnode = region->unTypeData.rf.vnode;
return vnode->filePath;
#endif
} else if (region->regionFlags & VM_MAP_REGION_FLAG_HEAP) {
} else if (region->regionFlags & VM_MAP_REGION_FLAG_HEAP) {//堆区
return "HEAP";
} else if (region->regionFlags & VM_MAP_REGION_FLAG_STACK) {
} else if (region->regionFlags & VM_MAP_REGION_FLAG_STACK) {//栈区
return "STACK";
} else if (region->regionFlags & VM_MAP_REGION_FLAG_TEXT) {
} else if (region->regionFlags & VM_MAP_REGION_FLAG_TEXT) {//文本区
return "Text";
} else if (region->regionFlags & VM_MAP_REGION_FLAG_VDSO) {
} else if (region->regionFlags & VM_MAP_REGION_FLAG_VDSO) {//虚拟动态链接对象区Virtual Dynamically Shared Object、VDSO
return "VDSO";
} else if (region->regionFlags & VM_MAP_REGION_FLAG_MMAP) {
} else if (region->regionFlags & VM_MAP_REGION_FLAG_MMAP) {//映射区
return "MMAP";
} else if (region->regionFlags & VM_MAP_REGION_FLAG_SHM) {
} else if (region->regionFlags & VM_MAP_REGION_FLAG_SHM) {//共享区
return "SHM";
} else {
return "";
}
return "";
}
///
INT32 OsRegionOverlapCheckUnlock(LosVmSpace *space, LosVmMapRegion *region)
{
LosVmMapRegion *regionTemp = NULL;
@ -107,7 +107,7 @@ INT32 OsRegionOverlapCheckUnlock(LosVmSpace *space, LosVmMapRegion *region)
return 0;
}
///shell task 进程虚拟内存的使用情况
UINT32 OsShellCmdProcessVmUsage(LosVmSpace *space)
{
LosVmMapRegion *region = NULL;
@ -119,7 +119,7 @@ UINT32 OsShellCmdProcessVmUsage(LosVmSpace *space)
return 0;
}
if (space == LOS_GetKVmSpace()) {
if (space == LOS_GetKVmSpace()) {//内核空间
OsShellCmdProcessPmUsage(space, NULL, &used);
return used;
}
@ -127,15 +127,14 @@ UINT32 OsShellCmdProcessVmUsage(LosVmSpace *space)
if (ret != 0) {
return 0;
}
RB_SCAN_SAFE(&space->regionRbTree, pstRbNode, pstRbNodeNext)
region = (LosVmMapRegion *)pstRbNode;
used += region->range.size;
RB_SCAN_SAFE_END(&space->regionRbTree, pstRbNode, pstRbNodeNext)
RB_SCAN_SAFE(&space->regionRbTree, pstRbNode, pstRbNodeNext)//开始扫描红黑树
region = (LosVmMapRegion *)pstRbNode;//拿到线性区,注意LosVmMapRegion结构体的第一个变量就是pstRbNode,所以可直接(LosVmMapRegion *)转
used += region->range.size;//size叠加,算出总使用
RB_SCAN_SAFE_END(&space->regionRbTree, pstRbNode, pstRbNodeNext)//结束扫描红黑树
(VOID)LOS_MuxRelease(&space->regionMux);
return used;
}
///内核空间物理内存使用情况统计
UINT32 OsKProcessPmUsage(LosVmSpace *kSpace, UINT32 *actualPm)
{
UINT32 memUsed;
@ -159,26 +158,26 @@ UINT32 OsKProcessPmUsage(LosVmSpace *kSpace, UINT32 *actualPm)
/* Kernel resident memory, include default heap memory */
memUsed = SYS_MEM_SIZE_DEFAULT - (totalCount << PAGE_SHIFT);
spaceList = LOS_GetVmSpaceList();
spaceList = LOS_GetVmSpaceList();//获取虚拟空间链表,上面挂了所有虚拟空间
LosMux *vmSpaceListMux = OsGVmSpaceMuxGet();
(VOID)LOS_MuxAcquire(vmSpaceListMux);
LOS_DL_LIST_FOR_EACH_ENTRY(space, spaceList, LosVmSpace, node) {
if (space == LOS_GetKVmSpace()) {
LOS_DL_LIST_FOR_EACH_ENTRY(space, spaceList, LosVmSpace, node) {//遍历链表
if (space == LOS_GetKVmSpace()) {//内核空间不统计
continue;
}
UProcessUsed += OsUProcessPmUsage(space, NULL, NULL);
}
(VOID)LOS_MuxRelease(vmSpaceListMux);
/* Kernel dynamic memory, include extended heap memory */
/* Kernel dynamic memory, include extended heap memory */ //内核动态内存,包括扩展堆内存
memUsed += ((usedCount << PAGE_SHIFT) - UProcessUsed);
/* Remaining heap memory */
/* Remaining heap memory */ //剩余堆内存
memUsed -= freeMem;
*actualPm = memUsed;
return memUsed;
}
///shell task 物理内存的使用情况
UINT32 OsShellCmdProcessPmUsage(LosVmSpace *space, UINT32 *sharePm, UINT32 *actualPm)
{
if (space == NULL) {
@ -194,7 +193,7 @@ UINT32 OsShellCmdProcessPmUsage(LosVmSpace *space, UINT32 *sharePm, UINT32 *actu
}
return OsUProcessPmUsage(space, sharePm, actualPm);
}
///虚拟空间物理内存的使用情况,参数同时带走共享物理内存 sharePm和actualPm 单位是字节
UINT32 OsUProcessPmUsage(LosVmSpace *space, UINT32 *sharePm, UINT32 *actualPm)
{
LosVmMapRegion *region = NULL;
@ -230,10 +229,10 @@ UINT32 OsUProcessPmUsage(LosVmSpace *space, UINT32 *sharePm, UINT32 *actualPm)
continue;
}
shareRef = LOS_AtomicRead(&page->refCounts);
shareRef = LOS_AtomicRead(&page->refCounts);//ref 大于1 说明page被其他空间也引用了这就是共享内存核心定义
if (shareRef > 1) {
if (sharePm != NULL) {
*sharePm += PAGE_SIZE;
*sharePm += PAGE_SIZE;//一页 4K 字节
}
pmSize += PAGE_SIZE / shareRef;
} else {
@ -250,7 +249,7 @@ UINT32 OsUProcessPmUsage(LosVmSpace *space, UINT32 *sharePm, UINT32 *actualPm)
return pmSize;
}
///通过虚拟空间获取进程实体
LosProcessCB *OsGetPIDByAspace(const LosVmSpace *space)
{
UINT32 pid;
@ -258,13 +257,13 @@ LosProcessCB *OsGetPIDByAspace(const LosVmSpace *space)
LosProcessCB *processCB = NULL;
SCHEDULER_LOCK(intSave);
for (pid = 0; pid < g_processMaxNum; ++pid) {
for (pid = 0; pid < g_processMaxNum; ++pid) {//循环进程池,进程池本质是个数组
processCB = g_processCBArray + pid;
if (OsProcessIsUnused(processCB)) {
continue;
if (OsProcessIsUnused(processCB)) {//进程还没被分配使用
continue;//继续找呗
}
if (processCB->vmSpace == space) {
if (processCB->vmSpace == space) {//找到了
SCHEDULER_UNLOCK(intSave);
return processCB;
}
@ -272,7 +271,7 @@ LosProcessCB *OsGetPIDByAspace(const LosVmSpace *space)
SCHEDULER_UNLOCK(intSave);
return NULL;
}
///统计虚拟空间中某个线性区的页数
UINT32 OsCountRegionPages(LosVmSpace *space, LosVmMapRegion *region, UINT32 *pssPages)
{
UINT32 regionPages = 0;
@ -301,12 +300,12 @@ UINT32 OsCountRegionPages(LosVmSpace *space, LosVmMapRegion *region, UINT32 *pss
}
if (pssPages != NULL) {
*pssPages = (UINT32)(pss + 0.5); /* 0.5, for page alignment */
*pssPages = (UINT32)(pss + 0.5);
}
return regionPages;
}
///统计虚拟空间的总页数
UINT32 OsCountAspacePages(LosVmSpace *space)
{
UINT32 spacePages = 0;
@ -390,27 +389,30 @@ VOID OsDumpRegion2(LosVmSpace *space, LosVmMapRegion *region)
region->range.size, flagsStr, regionPages, pssPages);
(VOID)LOS_MemFree(m_aucSysMem0, flagsStr);
}
///dump 指定虚拟空间的信息
VOID OsDumpAspace(LosVmSpace *space)
{
LosVmMapRegion *region = NULL;
LosRbNode *pstRbNode = NULL;
LosRbNode *pstRbNodeNext = NULL;
UINT32 spacePages;
LosProcessCB *pcb = OsGetPIDByAspace(space);
LosProcessCB *pcb = OsGetPIDByAspace(space);//通过虚拟空间找到进程实体
if (pcb == NULL) {
return;
}
spacePages = OsCountAspacePages(space);
//进程ID | 进程虚拟内存控制块地址信息 | 虚拟内存起始地址 | 虚拟内存大小 | 已使用的物理页数量
spacePages = OsCountAspacePages(space);//获取空间的页数
PRINTK("\r\n PID aspace name base size pages \n");
PRINTK(" ---- ------ ---- ---- ----- ----\n");
PRINTK(" %-4d %#010x %-10.10s %#010x %#010x %d\n", pcb->processID, space, pcb->processName,
space->base, space->size, spacePages);
PRINTK("\r\n\t region name base size mmu_flags pages pg/ref\n");
//虚拟区间控制块地址信息 | 虚拟区间类型 | 虚拟区间起始地址 | 虚拟区间大小 | 虚拟区间mmu映射属性 | 已使用的物理页数量(包括共享内存部分 | 已使用的物理页数量
PRINTK("\r\n\t region name base size mmu_flags pages pg/ref\n");
PRINTK("\t ------ ---- ---- ---- --------- ----- -----\n");
RB_SCAN_SAFE(&space->regionRbTree, pstRbNode, pstRbNodeNext)
RB_SCAN_SAFE(&space->regionRbTree, pstRbNode, pstRbNodeNext)//按region 轮询统计
region = (LosVmMapRegion *)pstRbNode;
if (region != NULL) {
OsDumpRegion2(space, region);
@ -421,14 +423,14 @@ VOID OsDumpAspace(LosVmSpace *space)
RB_SCAN_SAFE_END(&space->regionRbTree, pstRbNode, pstRbNodeNext)
return;
}
///查看所有进程使用虚拟内存的情况
VOID OsDumpAllAspace(VOID)
{
LosVmSpace *space = NULL;
LOS_DL_LIST *aspaceList = LOS_GetVmSpaceList();
LOS_DL_LIST_FOR_EACH_ENTRY(space, aspaceList, LosVmSpace, node) {
LOS_DL_LIST *aspaceList = LOS_GetVmSpaceList();//获取所有空间链表
LOS_DL_LIST_FOR_EACH_ENTRY(space, aspaceList, LosVmSpace, node) {//循环取出进程虚拟空间
(VOID)LOS_MuxAcquire(&space->regionMux);
OsDumpAspace(space);
OsDumpAspace(space);//dump 空间
(VOID)LOS_MuxRelease(&space->regionMux);
}
return;
@ -447,11 +449,11 @@ STATUS_T OsRegionOverlapCheck(LosVmSpace *space, LosVmMapRegion *region)
(VOID)LOS_MuxRelease(&space->regionMux);
return ret;
}
///dump 页表项
VOID OsDumpPte(VADDR_T vaddr)
{
UINT32 l1Index = vaddr >> MMU_DESCRIPTOR_L1_SMALL_SHIFT;
LosVmSpace *space = LOS_SpaceGet(vaddr);
LosVmSpace *space = LOS_SpaceGet(vaddr);//通过虚拟地址获取空间,内核分三个空间 内核进程空间,内核堆空间,用户进程空间
UINT32 ttEntry;
LosVmPage *page = NULL;
PTE_T *l2Table = NULL;
@ -461,27 +463,27 @@ VOID OsDumpPte(VADDR_T vaddr)
return;
}
ttEntry = space->archMmu.virtTtb[l1Index];
ttEntry = space->archMmu.virtTtb[l1Index];//找到 L1 页面项
if (ttEntry) {
l2Table = LOS_PaddrToKVaddr(MMU_DESCRIPTOR_L1_PAGE_TABLE_ADDR(ttEntry));
l2Index = (vaddr % MMU_DESCRIPTOR_L1_SMALL_SIZE) >> PAGE_SHIFT;
l2Table = LOS_PaddrToKVaddr(MMU_DESCRIPTOR_L1_PAGE_TABLE_ADDR(ttEntry));//找到L1页面项对应的 L2表
l2Index = (vaddr % MMU_DESCRIPTOR_L1_SMALL_SIZE) >> PAGE_SHIFT;//找到L2页面项
if (l2Table == NULL) {
goto ERR;
}
page = LOS_VmPageGet(l2Table[l2Index] & ~(PAGE_SIZE - 1));
page = LOS_VmPageGet(l2Table[l2Index] & ~(PAGE_SIZE - 1));//获取物理页框
if (page == NULL) {
goto ERR;
}
PRINTK("vaddr %p, l1Index %d, ttEntry %p, l2Table %p, l2Index %d, pfn %p count %d\n",
vaddr, l1Index, ttEntry, l2Table, l2Index, l2Table[l2Index], LOS_AtomicRead(&page->refCounts));
} else {
vaddr, l1Index, ttEntry, l2Table, l2Index, l2Table[l2Index], LOS_AtomicRead(&page->refCounts));//打印L1 L2 页表项
} else {//不在L1表
PRINTK("vaddr %p, l1Index %d, ttEntry %p\n", vaddr, l1Index, ttEntry);
}
return;
ERR:
PRINTK("%s, error vaddr: %#x, l2Table: %#x, l2Index: %#x\n", __FUNCTION__, vaddr, l2Table, l2Index);
}
///获取段剩余页框数
UINT32 OsVmPhySegPagesGet(LosVmPhysSeg *seg)
{
UINT32 intSave;
@ -489,14 +491,25 @@ UINT32 OsVmPhySegPagesGet(LosVmPhysSeg *seg)
UINT32 segFreePages = 0;
LOS_SpinLockSave(&seg->freeListLock, &intSave);
for (flindex = 0; flindex < VM_LIST_ORDER_MAX; flindex++) {
segFreePages += ((1 << flindex) * seg->freeList[flindex].listCnt);
for (flindex = 0; flindex < VM_LIST_ORDER_MAX; flindex++) {//遍历块组
segFreePages += ((1 << flindex) * seg->freeList[flindex].listCnt);//1 << flindex等于页数, * 节点数 得到组块的总页数.
}
LOS_SpinUnlockRestore(&seg->freeListLock, intSave);
return segFreePages;
return segFreePages;//返回剩余未分配的总物理页框
}
///dump 物理内存
/***********************************************************
* phys_seg:
* base:
* size:
* free_pages:
* active anon: pagecache
* inactive anon: pagecache
* active file: pagecache
* inactive file: pagecache
* pmm pages totalused使free
************************************************************/
VOID OsVmPhysDump(VOID)
{
LosVmPhysSeg *seg = NULL;
@ -508,7 +521,7 @@ VOID OsVmPhysDump(VOID)
UINT32 flindex;
UINT32 listCount[VM_LIST_ORDER_MAX] = {0};
for (segIndex = 0; segIndex < g_vmPhysSegNum; segIndex++) {
for (segIndex = 0; segIndex < g_vmPhysSegNum; segIndex++) {//循环取段
seg = &g_vmPhysSeg[segIndex];
if (seg->size > 0) {
segFreePages = OsVmPhySegPagesGet(seg);
@ -538,7 +551,7 @@ VOID OsVmPhysDump(VOID)
PRINTK("\n\rpmm pages: total = %u, used = %u, free = %u\n",
totalPages, (totalPages - totalFreePages), totalFreePages);
}
///获取物理内存的使用信息,两个参数接走数据
VOID OsVmPhysUsedInfoGet(UINT32 *usedCount, UINT32 *totalCount)
{
UINT32 index;
@ -551,12 +564,12 @@ VOID OsVmPhysUsedInfoGet(UINT32 *usedCount, UINT32 *totalCount)
*usedCount = 0;
*totalCount = 0;
for (index = 0; index < g_vmPhysSegNum; index++) {
for (index = 0; index < g_vmPhysSegNum; index++) {//循环取段
physSeg = &g_vmPhysSeg[index];
if (physSeg->size > 0) {
*totalCount += physSeg->size >> PAGE_SHIFT;
segFreePages = OsVmPhySegPagesGet(physSeg);
*usedCount += (*totalCount - segFreePages);
*totalCount += physSeg->size >> PAGE_SHIFT;//叠加段的总页数
segFreePages = OsVmPhySegPagesGet(physSeg);//获取段的剩余页数
*usedCount += (*totalCount - segFreePages);//叠加段的使用页数
}
}
}

@ -49,12 +49,11 @@
#include "vnode.h"
#endif
#ifdef LOSCFG_KERNEL_VM
extern char __exc_table_start[];
extern char __exc_table_end[];
//线性区正确性检查
STATIC STATUS_T OsVmRegionPermissionCheck(LosVmMapRegion *region, UINT32 flags)
{
if ((region->regionFlags & VM_MAP_REGION_FLAG_PERM_READ) != VM_MAP_REGION_FLAG_PERM_READ) {
@ -62,14 +61,14 @@ STATIC STATUS_T OsVmRegionPermissionCheck(LosVmMapRegion *region, UINT32 flags)
return LOS_NOK;
}
if ((flags & VM_MAP_PF_FLAG_WRITE) == VM_MAP_PF_FLAG_WRITE) {
if ((flags & VM_MAP_PF_FLAG_WRITE) == VM_MAP_PF_FLAG_WRITE) {//写入许可
if ((region->regionFlags & VM_MAP_REGION_FLAG_PERM_WRITE) != VM_MAP_REGION_FLAG_PERM_WRITE) {
VM_ERR("write permission check failed operation flags %x, region flags %x", flags, region->regionFlags);
return LOS_NOK;
}
}
if ((flags & VM_MAP_PF_FLAG_INSTRUCTION) == VM_MAP_PF_FLAG_INSTRUCTION) {
if ((flags & VM_MAP_PF_FLAG_INSTRUCTION) == VM_MAP_PF_FLAG_INSTRUCTION) {//指令
if ((region->regionFlags & VM_MAP_REGION_FLAG_PERM_EXECUTE) != VM_MAP_REGION_FLAG_PERM_EXECUTE) {
VM_ERR("exec permission check failed operation flags %x, region flags %x", flags, region->regionFlags);
return LOS_NOK;
@ -96,8 +95,9 @@ STATIC VOID OsFaultTryFixup(ExcContext *frame, VADDR_T excVaddr, STATUS_T *statu
}
}
#ifdef LOSCFG_FS_VFS
STATIC STATUS_T OsDoReadFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault)
#ifdef LOSCFG_FS_VFS
//读页时发生缺页的处理
STATIC STATUS_T OsDoReadFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault)//读缺页
{
status_t ret;
PADDR_T paddr;
@ -105,26 +105,26 @@ STATIC STATUS_T OsDoReadFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault)
VADDR_T vaddr = (VADDR_T)vmPgFault->vaddr;
LosVmSpace *space = region->space;
ret = LOS_ArchMmuQuery(&space->archMmu, vaddr, NULL, NULL);
if (ret == LOS_OK) {
return LOS_OK;
ret = LOS_ArchMmuQuery(&space->archMmu, vaddr, NULL, NULL);//查询是否缺页
if (ret == LOS_OK) {//注意这里时LOS_OK却返回,都OK了说明查到了物理地址,有页了。
return LOS_OK;//查到了就说明不缺页的,缺页就是因为虚拟地址没有映射到物理地址嘛
}
if (region->unTypeData.rf.vmFOps == NULL || region->unTypeData.rf.vmFOps->fault == NULL) {
if (region->unTypeData.rf.vmFOps == NULL || region->unTypeData.rf.vmFOps->fault == NULL) {//线性区必须有实现了缺页接口
VM_ERR("region args invalid, file path: %s", region->unTypeData.rf.vnode->filePath);
return LOS_ERRNO_VM_INVALID_ARGS;
}
(VOID)LOS_MuxAcquire(&region->unTypeData.rf.vnode->mapping.mux_lock);
ret = region->unTypeData.rf.vmFOps->fault(region, vmPgFault);
ret = region->unTypeData.rf.vmFOps->fault(region, vmPgFault);// 函数指针执行的是g_commVmOps.OsVmmFileFault
if (ret == LOS_OK) {
paddr = LOS_PaddrQuery(vmPgFault->pageKVaddr);
page = LOS_VmPageGet(paddr);
paddr = LOS_PaddrQuery(vmPgFault->pageKVaddr);//查询物理地址
page = LOS_VmPageGet(paddr);//获取page
if (page != NULL) { /* just incase of page null */
LOS_AtomicInc(&page->refCounts);
LOS_AtomicInc(&page->refCounts);//ref 自增
OsCleanPageLocked(page);
}
ret = LOS_ArchMmuMap(&space->archMmu, vaddr, paddr, 1,
region->regionFlags & (~VM_MAP_REGION_FLAG_PERM_WRITE));
region->regionFlags & (~VM_MAP_REGION_FLAG_PERM_WRITE));//重新映射为非可写
if (ret < 0) {
VM_ERR("LOS_ArchMmuMap failed");
OsDelMapInfo(region, vmPgFault, false);
@ -140,7 +140,7 @@ STATIC STATUS_T OsDoReadFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault)
return LOS_ERRNO_VM_NO_MEMORY;
}
/* unmap a page when cow happened only */
/* numap a page when cow happend only *///仅当写时拷贝发生时取消页面映射
STATIC LosVmPage *OsCowUnmapOrg(LosArchMmu *archMmu, LosVmMapRegion *region, LosVmPgFault *vmf)
{
UINT32 intSave;
@ -168,7 +168,7 @@ STATIC LosVmPage *OsCowUnmapOrg(LosArchMmu *archMmu, LosVmMapRegion *region, Los
return oldPage;
}
#endif
//在私有线性区写入文件时发生缺页的处理
status_t OsDoCowFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault)
{
STATUS_T ret;
@ -186,23 +186,23 @@ status_t OsDoCowFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault)
}
space = region->space;
ret = LOS_ArchMmuQuery(&space->archMmu, (VADDR_T)vmPgFault->vaddr, &oldPaddr, NULL);
ret = LOS_ArchMmuQuery(&space->archMmu, (VADDR_T)vmPgFault->vaddr, &oldPaddr, NULL);//查询出老物理地址
if (ret == LOS_OK) {
oldPage = OsCowUnmapOrg(&space->archMmu, region, vmPgFault);
oldPage = OsCowUnmapOrg(&space->archMmu, region, vmPgFault);//取消页面映射
}
newPage = LOS_PhysPageAlloc();
newPage = LOS_PhysPageAlloc();//分配一个新页面
if (newPage == NULL) {
VM_ERR("LOS_PhysPageAlloc failed");
ret = LOS_ERRNO_VM_NO_MEMORY;
goto ERR_OUT;
}
newPaddr = VM_PAGE_TO_PHYS(newPage);
kvaddr = OsVmPageToVaddr(newPage);
newPaddr = VM_PAGE_TO_PHYS(newPage);//拿到新的物理地址
kvaddr = OsVmPageToVaddr(newPage);//拿到新的虚拟地址
(VOID)LOS_MuxAcquire(&region->unTypeData.rf.vnode->mapping.mux_lock);
ret = region->unTypeData.rf.vmFOps->fault(region, vmPgFault);
ret = region->unTypeData.rf.vmFOps->fault(region, vmPgFault);// 函数指针 g_commVmOps.OsVmmFileFault
if (ret != LOS_OK) {
VM_ERR("call region->vm_ops->fault fail");
(VOID)LOS_MuxRelease(&region->unTypeData.rf.vnode->mapping.mux_lock);
@ -214,20 +214,20 @@ status_t OsDoCowFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault)
* we can take it as a normal file cow map. 2.this page has done file cow map,
* we can take it as a anonymous cow map.
*/
if ((oldPaddr == 0) || (LOS_PaddrToKVaddr(oldPaddr) == vmPgFault->pageKVaddr)) {
(VOID)memcpy_s(kvaddr, PAGE_SIZE, vmPgFault->pageKVaddr, PAGE_SIZE);
LOS_AtomicInc(&newPage->refCounts);
OsCleanPageLocked(LOS_VmPageGet(LOS_PaddrQuery(vmPgFault->pageKVaddr)));
if ((oldPaddr == 0) || (LOS_PaddrToKVaddr(oldPaddr) == vmPgFault->pageKVaddr)) {//没有映射或者 已在pagecache有映射
(VOID)memcpy_s(kvaddr, PAGE_SIZE, vmPgFault->pageKVaddr, PAGE_SIZE);//直接copy到新页
LOS_AtomicInc(&newPage->refCounts);//引用ref++
OsCleanPageLocked(LOS_VmPageGet(LOS_PaddrQuery(vmPgFault->pageKVaddr)));//解锁
} else {
OsPhysSharePageCopy(oldPaddr, &newPaddr, newPage);
OsPhysSharePageCopy(oldPaddr, &newPaddr, newPage);//调用之前 oldPaddr肯定不等于newPaddr
/* use old page free the new one */
if (newPaddr == oldPaddr) {
LOS_PhysPageFree(newPage);
if (newPaddr == oldPaddr) {//注意这里newPaddr可能已经被改变了,参数传入的是 &newPaddr
LOS_PhysPageFree(newPage);//释放新页,别浪费的内存,内核使用内存是一分钱当十块用.
newPage = NULL;
}
}
ret = LOS_ArchMmuMap(&space->archMmu, (VADDR_T)vmPgFault->vaddr, newPaddr, 1, region->regionFlags);
ret = LOS_ArchMmuMap(&space->archMmu, (VADDR_T)vmPgFault->vaddr, newPaddr, 1, region->regionFlags);//把新物理地址映射给缺页的虚拟地址,这样就不会缺页啦
if (ret < 0) {
VM_ERR("LOS_ArchMmuMap failed");
ret = LOS_ERRNO_VM_NO_MEMORY;
@ -252,7 +252,7 @@ ERR_OUT:
return ret;
}
///在共享线性区写文件操作发生缺页的情况处理,因为线性区是共享的
status_t OsDoSharedFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault)
{
STATUS_T ret;
@ -268,10 +268,10 @@ status_t OsDoSharedFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault)
return LOS_ERRNO_VM_INVALID_ARGS;
}
ret = LOS_ArchMmuQuery(&space->archMmu, vmPgFault->vaddr, &paddr, NULL);
ret = LOS_ArchMmuQuery(&space->archMmu, vmPgFault->vaddr, &paddr, NULL);//查询物理地址
if (ret == LOS_OK) {
LOS_ArchMmuUnmap(&space->archMmu, vmPgFault->vaddr, 1);
ret = LOS_ArchMmuMap(&space->archMmu, vaddr, paddr, 1, region->regionFlags);
LOS_ArchMmuUnmap(&space->archMmu, vmPgFault->vaddr, 1);//先取消映射
ret = LOS_ArchMmuMap(&space->archMmu, vaddr, paddr, 1, region->regionFlags);//再重新映射,为啥这么干,是因为regionFlags变了,
if (ret < 0) {
VM_ERR("LOS_ArchMmuMap failed. ret=%d", ret);
return LOS_ERRNO_VM_NO_MEMORY;
@ -279,16 +279,16 @@ status_t OsDoSharedFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault)
LOS_SpinLockSave(&region->unTypeData.rf.vnode->mapping.list_lock, &intSave);
fpage = OsFindGetEntry(&region->unTypeData.rf.vnode->mapping, vmPgFault->pgoff);
if (fpage) {
OsMarkPageDirty(fpage, region, 0, 0);
if (fpage) {//在页高速缓存(page cache)中找到了
OsMarkPageDirty(fpage, region, 0, 0);//标记为脏页
}
LOS_SpinUnlockRestore(&region->unTypeData.rf.vnode->mapping.list_lock, intSave);
return LOS_OK;
}
//以下是没有映射到物理地址的处理
(VOID)LOS_MuxAcquire(&region->unTypeData.rf.vnode->mapping.mux_lock);
ret = region->unTypeData.rf.vmFOps->fault(region, vmPgFault);
ret = region->unTypeData.rf.vmFOps->fault(region, vmPgFault);//函数指针执行的是g_commVmOps.OsVmmFileFault
if (ret == LOS_OK) {
paddr = LOS_PaddrQuery(vmPgFault->pageKVaddr);
page = LOS_VmPageGet(paddr);
@ -319,26 +319,39 @@ status_t OsDoSharedFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault)
* For COW fault, pagecache is copied to private anonyous pages and the changes on this page
* won't write through to the underlying file. For SHARED fault, pagecache is mapping with
* region->arch_mmu_flags and the changes on this page will write through to the underlying file
*/
*/ //操作文件时产生缺页中断
STATIC STATUS_T OsDoFileFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault, UINT32 flags)
{
STATUS_T ret;
if (flags & VM_MAP_PF_FLAG_WRITE) {
if (region->regionFlags & VM_MAP_REGION_FLAG_SHARED) {
ret = OsDoSharedFault(region, vmPgFault);
} else {
ret = OsDoCowFault(region, vmPgFault);
if (flags & VM_MAP_PF_FLAG_WRITE) {//写页的时候产生缺页
if (region->regionFlags & VM_MAP_REGION_FLAG_SHARED) {//共享线性区
ret = OsDoSharedFault(region, vmPgFault);//写操作时的共享缺页,最复杂,此页上的更改将写入磁盘文件
} else {//非共享线性区
ret = OsDoCowFault(region, vmPgFault);//(写时拷贝技术)写操作时的私有缺页,pagecache被复制到私有的任意一个页面上并在此页面上进行更改,不会直接写入磁盘文件
}
} else {
ret = OsDoReadFault(region, vmPgFault);
} else {//读页的时候产生缺页
ret = OsDoReadFault(region, vmPgFault);//页面读取操作很简单只需共享页面缓存节省内存并进行读权限映射region->arch_mmu_flags&~arch_mmu_FLAG_PERM_WRITE
}
return ret;
}
/***************************************************************
:
:
***************************************************************/
/**
* @brief
* @param vaddr
* @param flags
* @param frame
* @return STATUS_T
*/
STATUS_T OsVmPageFaultHandler(VADDR_T vaddr, UINT32 flags, ExcContext *frame)
{
LosVmSpace *space = LOS_SpaceGet(vaddr);
LosVmSpace *space = LOS_SpaceGet(vaddr);//获取虚拟地址所属空间
LosVmMapRegion *region = NULL;
STATUS_T status;
PADDR_T oldPaddr;
@ -354,9 +367,9 @@ STATUS_T OsVmPageFaultHandler(VADDR_T vaddr, UINT32 flags, ExcContext *frame)
return status;
}
if (((flags & VM_MAP_PF_FLAG_USER) != 0) && (!LOS_IsUserAddress(vaddr))) {
if (((flags & VM_MAP_PF_FLAG_USER) != 0) && (!LOS_IsUserAddress(vaddr))) {//地址保护,用户空间不允许跨界访问
VM_ERR("user space not allowed to access invalid address: %#x", vaddr);
return LOS_ERRNO_VM_ACCESS_DENIED;
return LOS_ERRNO_VM_ACCESS_DENIED;//拒绝访问
}
#ifdef LOSCFG_KERNEL_PLIMITS
@ -366,7 +379,7 @@ STATUS_T OsVmPageFaultHandler(VADDR_T vaddr, UINT32 flags, ExcContext *frame)
#endif
(VOID)LOS_MuxAcquire(&space->regionMux);
region = LOS_RegionFind(space, vaddr);
region = LOS_RegionFind(space, vaddr);//通过虚拟地址找到所在线性区
if (region == NULL) {
VM_ERR("region not exists, vaddr: %#x", vaddr);
status = LOS_ERRNO_VM_NOT_FOUND;
@ -375,11 +388,11 @@ STATUS_T OsVmPageFaultHandler(VADDR_T vaddr, UINT32 flags, ExcContext *frame)
status = OsVmRegionPermissionCheck(region, flags);
if (status != LOS_OK) {
status = LOS_ERRNO_VM_ACCESS_DENIED;
status = LOS_ERRNO_VM_ACCESS_DENIED;//拒绝访问
goto CHECK_FAILED;
}
if (OomCheckProcess()) {
if (OomCheckProcess()) {//低内存检查
/*
* under low memory, when user process request memory allocation
* it will fail, and result is LOS_NOK and current user process
@ -389,18 +402,18 @@ STATUS_T OsVmPageFaultHandler(VADDR_T vaddr, UINT32 flags, ExcContext *frame)
goto CHECK_FAILED;
}
vaddr = ROUNDDOWN(vaddr, PAGE_SIZE);
#ifdef LOSCFG_FS_VFS
if (LOS_IsRegionFileValid(region)) {
vaddr = ROUNDDOWN(vaddr, PAGE_SIZE);//为啥要向下圆整,因为这一页要重新使用,需找到页面基地址
#ifdef LOSCFG_FS_VFS
if (LOS_IsRegionFileValid(region)) {//是否为文件线性区
if (region->unTypeData.rf.vnode == NULL) {
goto CHECK_FAILED;
}
vmPgFault.vaddr = vaddr;
vmPgFault.pgoff = ((vaddr - region->range.base) >> PAGE_SHIFT) + region->pgOff;
vmPgFault.vaddr = vaddr;//虚拟地址
vmPgFault.pgoff = ((vaddr - region->range.base) >> PAGE_SHIFT) + region->pgOff;//计算出文件读取位置
vmPgFault.flags = flags;
vmPgFault.pageKVaddr = NULL;
vmPgFault.pageKVaddr = NULL;//缺失页初始化没有物理地址
status = OsDoFileFault(region, &vmPgFault, flags);
status = OsDoFileFault(region, &vmPgFault, flags);//缺页处理
if (status) {
VM_ERR("vm fault error, status=%d", status);
goto CHECK_FAILED;
@ -408,27 +421,27 @@ STATUS_T OsVmPageFaultHandler(VADDR_T vaddr, UINT32 flags, ExcContext *frame)
goto DONE;
}
#endif
newPage = LOS_PhysPageAlloc();
//请求调页:推迟到不能再推迟为止
newPage = LOS_PhysPageAlloc();//分配一个新的物理页
if (newPage == NULL) {
status = LOS_ERRNO_VM_NO_MEMORY;
goto CHECK_FAILED;
}
newPaddr = VM_PAGE_TO_PHYS(newPage);
(VOID)memset_s(OsVmPageToVaddr(newPage), PAGE_SIZE, 0, PAGE_SIZE);
status = LOS_ArchMmuQuery(&space->archMmu, vaddr, &oldPaddr, NULL);
if (status >= 0) {
LOS_ArchMmuUnmap(&space->archMmu, vaddr, 1);
OsPhysSharePageCopy(oldPaddr, &newPaddr, newPage);
newPaddr = VM_PAGE_TO_PHYS(newPage);//获取物理地址
(VOID)memset_s(OsVmPageToVaddr(newPage), PAGE_SIZE, 0, PAGE_SIZE);//获取虚拟地址 清0
status = LOS_ArchMmuQuery(&space->archMmu, vaddr, &oldPaddr, NULL);//通过虚拟地址查询老物理地址
if (status >= 0) {//已经映射过了,@note_thinking 不是缺页吗,怎么会有页的情况?
LOS_ArchMmuUnmap(&space->archMmu, vaddr, 1);//解除映射关系
OsPhysSharePageCopy(oldPaddr, &newPaddr, newPage);//将oldPaddr的数据拷贝到newPage
/* use old page free the new one */
if (newPaddr == oldPaddr) {
LOS_PhysPageFree(newPage);
if (newPaddr == oldPaddr) {//新老物理地址一致
LOS_PhysPageFree(newPage);//继续使用旧页释放新页
newPage = NULL;
}
/* map all of the pages */
status = LOS_ArchMmuMap(&space->archMmu, vaddr, newPaddr, 1, region->regionFlags);
status = LOS_ArchMmuMap(&space->archMmu, vaddr, newPaddr, 1, region->regionFlags);//重新映射新物理地址
if (status < 0) {
VM_ERR("failed to map replacement page, status:%d", status);
status = LOS_ERRNO_VM_MAP_FAILED;
@ -437,10 +450,10 @@ STATUS_T OsVmPageFaultHandler(VADDR_T vaddr, UINT32 flags, ExcContext *frame)
status = LOS_OK;
goto DONE;
} else {
} else {//
/* map all of the pages */
LOS_AtomicInc(&newPage->refCounts);
status = LOS_ArchMmuMap(&space->archMmu, vaddr, newPaddr, 1, region->regionFlags);
LOS_AtomicInc(&newPage->refCounts);//引用数自增
status = LOS_ArchMmuMap(&space->archMmu, vaddr, newPaddr, 1, region->regionFlags);//映射新物理地址,如此下次就不会缺页了
if (status < 0) {
VM_ERR("failed to map page, status:%d", status);
status = LOS_ERRNO_VM_MAP_FAILED;

@ -66,98 +66,114 @@ VOID ResetPageCacheHitInfo(int *try, int *hit)
#define TRACE_TRY_CACHE()
#define TRACE_HIT_CACHE()
#endif
#ifdef LOSCFG_KERNEL_VM
/**
* @brief
@verbatim
(page cache)
LosFilePage,seek,,
pgoff,cache.
@endverbatim
* @param page
* @param mapping
* @param pgoff
* @return STATIC
*/
STATIC VOID OsPageCacheAdd(LosFilePage *page, struct page_mapping *mapping, VM_OFFSET_T pgoff)
{
LosFilePage *fpage = NULL;
LOS_DL_LIST_FOR_EACH_ENTRY(fpage, &mapping->page_list, LosFilePage, node) {
if (fpage->pgoff > pgoff) {
LOS_ListTailInsert(&fpage->node, &page->node);
LOS_DL_LIST_FOR_EACH_ENTRY(fpage, &mapping->page_list, LosFilePage, node) {//遍历page_list链表
if (fpage->pgoff > pgoff) {//插入的条件,这样插入保证了按pgoff 从小到大排序
LOS_ListTailInsert(&fpage->node, &page->node);//等于挂到fpage节点的前面了
goto done_add;
}
}
LOS_ListTailInsert(&mapping->page_list, &page->node);
LOS_ListTailInsert(&mapping->page_list, &page->node);//将页挂到文件映射的链表上,相当于挂到了最后
done_add:
mapping->nrpages++;
mapping->nrpages++; //文件在缓存中多了一个 文件页
}
///将页面加到活动文件页LRU链表上
VOID OsAddToPageacheLru(LosFilePage *page, struct page_mapping *mapping, VM_OFFSET_T pgoff)
{
OsPageCacheAdd(page, mapping, pgoff);
OsLruCacheAdd(page, VM_LRU_ACTIVE_FILE);
}
///从页高速缓存上删除页
VOID OsPageCacheDel(LosFilePage *fpage)
{
/* delete from file cache list */
LOS_ListDelete(&fpage->node);
fpage->mapping->nrpages--;
LOS_ListDelete(&fpage->node);//将自己从链表上摘除
fpage->mapping->nrpages--;//文件映射的页总数减少
/* unmap and remove map info */
if (OsIsPageMapped(fpage)) {
if (OsIsPageMapped(fpage)) {//是否映射过
OsUnmapAllLocked(fpage);
}
LOS_PhysPageFree(fpage->vmPage);
LOS_PhysPageFree(fpage->vmPage);//释放物理内存
LOS_MemFree(m_aucSysMem0, fpage);
LOS_MemFree(m_aucSysMem0, fpage);//释放文件页结构体内存
}
/**************************************************************************************************
, 访LosFilePage,使
LosFilePage.
1. 2.
**************************************************************************************************/
VOID OsAddMapInfo(LosFilePage *page, LosArchMmu *archMmu, VADDR_T vaddr)
{
LosMapInfo *info = NULL;
info = (LosMapInfo *)LOS_MemAlloc(m_aucSysMem0, sizeof(LosMapInfo));
info = (LosMapInfo *)LOS_MemAlloc(m_aucSysMem0, sizeof(LosMapInfo));//分配一个映射信息
if (info == NULL) {
VM_ERR("OsAddMapInfo alloc memory failed!");
return;
}
info->page = page;
info->archMmu = archMmu;
info->vaddr = vaddr;
info->page = page; //文件页
info->archMmu = archMmu;//进程MMU,完成虚实地址转换
info->vaddr = vaddr; //虚拟地址
LOS_ListAdd(&page->i_mmap, &info->node);
page->n_maps++;
LOS_ListAdd(&page->i_mmap, &info->node);//将 LosMapInfo 节点挂入链表
page->n_maps++;//映射总数++
}
///通过虚拟地址获取文件页映射信息,archMmu每个进程都有属于自己的mmu
LosMapInfo *OsGetMapInfo(const LosFilePage *page, const LosArchMmu *archMmu, VADDR_T vaddr)
{
LosMapInfo *info = NULL;
const LOS_DL_LIST *immap = &page->i_mmap;
const LOS_DL_LIST *immap = &page->i_mmap;//一个文件页被多个进程映射
LOS_DL_LIST_FOR_EACH_ENTRY(info, immap, LosMapInfo, node) {
if ((info->archMmu == archMmu) && (info->vaddr == vaddr) && (info->page == page)) {
LOS_DL_LIST_FOR_EACH_ENTRY(info, immap, LosMapInfo, node) {//遍历每个节点
if ((info->archMmu == archMmu) && (info->vaddr == vaddr) && (info->page == page)) {//全等时返回
return info;
}
}
return NULL;
}
///删除页高速缓存和LRU,对应 OsAddToPageacheLru
VOID OsDeletePageCacheLru(LosFilePage *page)
{
/* delete from lru list */
OsLruCacheDel(page);
/* delete from cache list and free pmm if needed */
OsPageCacheDel(page);
/* delete form lru list */
OsLruCacheDel(page); //将页面从lru列表中删除
/* delete from cache lits and free pmm if need */
OsPageCacheDel(page); //从page缓存中删除
}
//解除文件页和进程的映射关系
STATIC VOID OsPageCacheUnmap(LosFilePage *fpage, LosArchMmu *archMmu, VADDR_T vaddr)
{
UINT32 intSave;
LosMapInfo *info = NULL;
LOS_SpinLockSave(&fpage->physSeg->lruLock, &intSave);
info = OsGetMapInfo(fpage, archMmu, vaddr);
info = OsGetMapInfo(fpage, archMmu, vaddr);//获取文件页在进程的映射信息
if (info == NULL) {
VM_ERR("OsPageCacheUnmap get map info failed!");
} else {
OsUnmapPageLocked(fpage, info);
OsUnmapPageLocked(fpage, info);//解除进程和文件页映射关系
}
if (!(OsIsPageMapped(fpage) && ((fpage->flags & VM_MAP_REGION_FLAG_PERM_EXECUTE) ||
OsIsPageDirty(fpage->vmPage)))) {
@ -166,7 +182,7 @@ STATIC VOID OsPageCacheUnmap(LosFilePage *fpage, LosArchMmu *archMmu, VADDR_T va
LOS_SpinUnlockRestore(&fpage->physSeg->lruLock, intSave);
}
///删除文件
VOID OsVmmFileRemove(LosVmMapRegion *region, LosArchMmu *archMmu, VM_OFFSET_T pgoff)
{
UINT32 intSave;
@ -179,31 +195,31 @@ VOID OsVmmFileRemove(LosVmMapRegion *region, LosArchMmu *archMmu, VM_OFFSET_T pg
LosVmPage *mapPage = NULL;
if (!LOS_IsRegionFileValid(region) || (region->unTypeData.rf.vnode == NULL)) {
return;
return;//判断是否为文件映射是否已map
}
vnode = region->unTypeData.rf.vnode;
mapping = &vnode->mapping;
vaddr = region->range.base + ((UINT32)(pgoff - region->pgOff) << PAGE_SHIFT);
vaddr = region->range.base + ((UINT32)(pgoff - region->pgOff) << PAGE_SHIFT);//得到虚拟地址
status_t status = LOS_ArchMmuQuery(archMmu, vaddr, &paddr, NULL);
status_t status = LOS_ArchMmuQuery(archMmu, vaddr, &paddr, NULL);//获取物理地址
if (status != LOS_OK) {
return;
}
mapPage = LOS_VmPageGet(paddr);
mapPage = LOS_VmPageGet(paddr);//获取物理页框
/* is page is in cache list */
LOS_SpinLockSave(&mapping->list_lock, &intSave);
fpage = OsFindGetEntry(mapping, pgoff);
fpage = OsFindGetEntry(mapping, pgoff);//获取fpage
/* no cache or have cache but not map(cow), free it direct */
if ((fpage == NULL) || (fpage->vmPage != mapPage)) {
LOS_PhysPageFree(mapPage);
LOS_ArchMmuUnmap(archMmu, vaddr, 1);
if ((fpage == NULL) || (fpage->vmPage != mapPage)) {//没有缓存或有缓存但没有映射cow直接释放它
LOS_PhysPageFree(mapPage);//释放物理页框
LOS_ArchMmuUnmap(archMmu, vaddr, 1);//取消虚拟地址的映射
/* this is a page cache map! */
} else {
OsPageCacheUnmap(fpage, archMmu, vaddr);
if (OsIsPageDirty(fpage->vmPage)) {
tmpPage = OsDumpDirtyPage(fpage);
OsPageCacheUnmap(fpage, archMmu, vaddr);////取消缓存中的映射
if (OsIsPageDirty(fpage->vmPage)) {//脏页处理
tmpPage = OsDumpDirtyPage(fpage);//dump 脏页
}
}
LOS_SpinUnlockRestore(&mapping->list_lock, intSave);
@ -213,15 +229,15 @@ VOID OsVmmFileRemove(LosVmMapRegion *region, LosArchMmu *archMmu, VM_OFFSET_T pg
}
return;
}
///标记page为脏页 进程修改了高速缓存里的数据时,该页就被内核标记为脏页
VOID OsMarkPageDirty(LosFilePage *fpage, const LosVmMapRegion *region, INT32 off, INT32 len)
{
if (region != NULL) {
OsSetPageDirty(fpage->vmPage);
fpage->dirtyOff = off;
fpage->dirtyEnd = len;
OsSetPageDirty(fpage->vmPage);//设置为脏页
fpage->dirtyOff = off;//脏页偏移位置
fpage->dirtyEnd = len;//脏页结束位置
} else {
OsSetPageDirty(fpage->vmPage);
OsSetPageDirty(fpage->vmPage);//设置为脏页
if ((off + len) > fpage->dirtyEnd) {
fpage->dirtyEnd = off + len;
}
@ -258,22 +274,22 @@ STATIC UINT32 GetDirtySize(LosFilePage *fpage, struct Vnode *vnode)
return PAGE_SIZE;
}
///冲洗脏页,回写磁盘
STATIC INT32 OsFlushDirtyPage(LosFilePage *fpage)
{
UINT32 ret;
size_t len;
char *buff = NULL;
struct Vnode *vnode = fpage->mapping->host;
struct Vnode *vnode = fpage->mapping->host;/* owner of this mapping */ //此映射属于哪个文件,注意<file,page_mapping>是1:1的关系.
if (vnode == NULL) {
VM_ERR("page cache vnode error");
return LOS_NOK;
}
len = fpage->dirtyEnd - fpage->dirtyOff;
len = fpage->dirtyEnd - fpage->dirtyOff;//计算出脏数据长度
len = (len == 0) ? GetDirtySize(fpage, vnode) : len;
if (len == 0) {
OsCleanPageDirty(fpage->vmPage);
if (len == 0) {//没有脏数据
OsCleanPageDirty(fpage->vmPage);//页面取消脏标签
return LOS_OK;
}
@ -290,7 +306,7 @@ STATIC INT32 OsFlushDirtyPage(LosFilePage *fpage)
return ret;
}
///备份脏页,老脏页撕掉脏页标签
LosFilePage *OsDumpDirtyPage(LosFilePage *oldFPage)
{
LosFilePage *newFPage = NULL;
@ -302,11 +318,11 @@ LosFilePage *OsDumpDirtyPage(LosFilePage *oldFPage)
}
OsCleanPageDirty(oldFPage->vmPage);
(VOID)memcpy_s(newFPage, sizeof(LosFilePage), oldFPage, sizeof(LosFilePage));
(VOID)memcpy_s(newFPage, sizeof(LosFilePage), oldFPage, sizeof(LosFilePage));//直接内存拷贝
return newFPage;
}
///冲洗脏页数据,将脏页数据回写磁盘
VOID OsDoFlushDirtyPage(LosFilePage *fpage)
{
if (fpage == NULL) {
@ -328,7 +344,7 @@ STATIC VOID OsReleaseFpage(struct page_mapping *mapping, LosFilePage *fpage)
LOS_SpinUnlockRestore(lruLock, lruSave);
LOS_SpinUnlockRestore(&mapping->list_lock, intSave);
}
///删除映射信息
VOID OsDelMapInfo(LosVmMapRegion *region, LosVmPgFault *vmf, BOOL cleanDirty)
{
UINT32 intSave;
@ -349,9 +365,9 @@ VOID OsDelMapInfo(LosVmMapRegion *region, LosVmPgFault *vmf, BOOL cleanDirty)
}
if (cleanDirty) {
OsCleanPageDirty(fpage->vmPage);
OsCleanPageDirty(fpage->vmPage);//恢复干净页
}
info = OsGetMapInfo(fpage, &region->space->archMmu, (vaddr_t)vmf->vaddr);
info = OsGetMapInfo(fpage, &region->space->archMmu, (vaddr_t)vmf->vaddr);//通过虚拟地址获取映射信息
if (info != NULL) {
fpage->n_maps--;
LOS_ListDelete(&info->node);
@ -362,7 +378,10 @@ VOID OsDelMapInfo(LosVmMapRegion *region, LosVmPgFault *vmf, BOOL cleanDirty)
}
LOS_SpinUnlockRestore(&mapping->list_lock, intSave);
}
/*!
,
OsDoReadFault(...),OsDoCowFault(...),OsDoSharedFault(...)
*/
INT32 OsVmmFileFault(LosVmMapRegion *region, LosVmPgFault *vmf)
{
INT32 ret;
@ -374,7 +393,7 @@ INT32 OsVmmFileFault(LosVmMapRegion *region, LosVmPgFault *vmf)
struct page_mapping *mapping = NULL;
LosFilePage *fpage = NULL;
if (!LOS_IsRegionFileValid(region) || (region->unTypeData.rf.vnode == NULL) || (vmf == NULL)) {
if (!LOS_IsRegionFileValid(region) || (region->unTypeData.rf.vnode == NULL) || (vmf == NULL)) {//文件是否映射到了内存
VM_ERR("Input param is NULL");
return LOS_NOK;
}
@ -383,26 +402,26 @@ INT32 OsVmmFileFault(LosVmMapRegion *region, LosVmPgFault *vmf)
/* get or create a new cache node */
LOS_SpinLockSave(&mapping->list_lock, &intSave);
fpage = OsFindGetEntry(mapping, vmf->pgoff);
fpage = OsFindGetEntry(mapping, vmf->pgoff);//获取文件页
TRACE_TRY_CACHE();
if (fpage != NULL) {
if (fpage != NULL) {//找到了,说明该页已经在页高速缓存中
TRACE_HIT_CACHE();
OsPageRefIncLocked(fpage);
} else {
fpage = OsPageCacheAlloc(mapping, vmf->pgoff);
} else {//真的缺页了,页高速缓存中没找到
fpage = OsPageCacheAlloc(mapping, vmf->pgoff);//分配一个文件页将数据初始化好包括vmpage(物理页框)
if (fpage == NULL) {
LOS_SpinUnlockRestore(&mapping->list_lock, intSave);
VM_ERR("Failed to alloc a page frame");
return LOS_NOK;
}
newCache = true;
newCache = true;//分配了新文件页
}
OsSetPageLocked(fpage->vmPage);
OsSetPageLocked(fpage->vmPage);//对vmpage上锁
LOS_SpinUnlockRestore(&mapping->list_lock, intSave);
kvaddr = OsVmPageToVaddr(fpage->vmPage);
kvaddr = OsVmPageToVaddr(fpage->vmPage);//获取该页框在内核空间的虚拟地址,因为 page cache本身就是在内核空间,
/* read file to new page cache */
if (newCache) {
if (newCache) {//新cache
ret = vnode->vop->ReadPage(vnode, kvaddr, fpage->pgoff << PAGE_SHIFT);
if (ret == 0) {
VM_ERR("Failed to read from file!");
@ -410,32 +429,32 @@ INT32 OsVmmFileFault(LosVmMapRegion *region, LosVmPgFault *vmf)
return LOS_NOK;
}
LOS_SpinLockSave(&mapping->list_lock, &intSave);
OsAddToPageacheLru(fpage, mapping, vmf->pgoff);
OsAddToPageacheLru(fpage, mapping, vmf->pgoff);//将fpage挂入pageCache 和 LruCache
LOS_SpinUnlockRestore(&mapping->list_lock, intSave);
}
LOS_SpinLockSave(&mapping->list_lock, &intSave);
/* cow fault case no need to save mapinfo */
if (!((vmf->flags & VM_MAP_PF_FLAG_WRITE) && !(region->regionFlags & VM_MAP_REGION_FLAG_SHARED))) {
OsAddMapInfo(fpage, &region->space->archMmu, (vaddr_t)vmf->vaddr);
OsAddMapInfo(fpage, &region->space->archMmu, (vaddr_t)vmf->vaddr);//添加<虚拟地址,文件页>的映射关系,如此进程以后就能通过虚拟地址操作文件页了.
fpage->flags = region->regionFlags;
}
/* share page fault, mark the page dirty */
if ((vmf->flags & VM_MAP_PF_FLAG_WRITE) && (region->regionFlags & VM_MAP_REGION_FLAG_SHARED)) {
OsMarkPageDirty(fpage, region, 0, 0);
if ((vmf->flags & VM_MAP_PF_FLAG_WRITE) && (region->regionFlags & VM_MAP_REGION_FLAG_SHARED)) {//有过写操作或者为共享线性区
OsMarkPageDirty(fpage, region, 0, 0);//标记为脏页,要回写磁盘,内核会在适当的时候回写磁盘
}
vmf->pageKVaddr = kvaddr;
vmf->pageKVaddr = kvaddr;//缺陷页记录文件页的虚拟地址
LOS_SpinUnlockRestore(&mapping->list_lock, intSave);
return LOS_OK;
}
///文件缓存冲洗,把所有fpage冲洗一边把脏页洗到dirtyList中,配合OsFileCacheRemove理解
VOID OsFileCacheFlush(struct page_mapping *mapping)
{
UINT32 intSave;
UINT32 lruLock;
LOS_DL_LIST_HEAD(dirtyList);
LOS_DL_LIST_HEAD(dirtyList);//LOS_DL_LIST list = { &(list), &(list) };
LosFilePage *ftemp = NULL;
LosFilePage *fpage = NULL;
@ -443,70 +462,77 @@ VOID OsFileCacheFlush(struct page_mapping *mapping)
return;
}
LOS_SpinLockSave(&mapping->list_lock, &intSave);
LOS_DL_LIST_FOR_EACH_ENTRY(fpage, &mapping->page_list, LosFilePage, node) {
LOS_DL_LIST_FOR_EACH_ENTRY(fpage, &mapping->page_list, LosFilePage, node) {//循环从page_list中取node给fpage
LOS_SpinLockSave(&fpage->physSeg->lruLock, &lruLock);
if (OsIsPageDirty(fpage->vmPage)) {
ftemp = OsDumpDirtyPage(fpage);
if (OsIsPageDirty(fpage->vmPage)) {//是否为脏页
ftemp = OsDumpDirtyPage(fpage);//这里挺妙的copy出一份新页老页变成了非脏页继续用
if (ftemp != NULL) {
LOS_ListTailInsert(&dirtyList, &ftemp->node);
LOS_ListTailInsert(&dirtyList, &ftemp->node);//将新页插入脏页List,等待回写磁盘
}
}
LOS_SpinUnlockRestore(&fpage->physSeg->lruLock, lruLock);
}
LOS_SpinUnlockRestore(&mapping->list_lock, intSave);
LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(fpage, ftemp, &dirtyList, LosFilePage, node) {
OsDoFlushDirtyPage(fpage);
LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(fpage, ftemp, &dirtyList, LosFilePage, node) {//仔细看这个宏,关键在 &(item)->member != (list);
OsDoFlushDirtyPage(fpage);//立马洗掉所以dirtyList可以不是全局变量
}
}
/******************************************************************************
,page cache
mapping
******************************************************************************/
VOID OsFileCacheRemove(struct page_mapping *mapping)
{
UINT32 intSave;
UINT32 lruSave;
SPIN_LOCK_S *lruLock = NULL;
LOS_DL_LIST_HEAD(dirtyList);
LOS_DL_LIST_HEAD(dirtyList);//定义一个叫dirtyList的双循环链表并初始化,用于挂脏页
LosFilePage *ftemp = NULL;
LosFilePage *fpage = NULL;
LosFilePage *fnext = NULL;
LOS_SpinLockSave(&mapping->list_lock, &intSave);
LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(fpage, fnext, &mapping->page_list, LosFilePage, node) {
LOS_SpinLockSave(&mapping->list_lock, &intSave);//多进程操作,必须上锁.
LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(fpage, fnext, &mapping->page_list, LosFilePage, node) {//遍历文件在内存中产生的所有文件页(例如1,4,8页)不一定连续,取决于用户的读取顺序
lruLock = &fpage->physSeg->lruLock;
LOS_SpinLockSave(lruLock, &lruSave);
if (OsIsPageDirty(fpage->vmPage)) {
ftemp = OsDumpDirtyPage(fpage);
if (ftemp != NULL) {
LOS_ListTailInsert(&dirtyList, &ftemp->node);
LOS_SpinLockSave(lruLock, &lruSave);//@note_why 自旋锁有必要从这里开始上锁吗?
if (OsIsPageDirty(fpage->vmPage)) {//数据是脏页吗,脏页就是被修改过数据的页
ftemp = OsDumpDirtyPage(fpage);//做这个拷贝动作是为了fpage的统一下线,因为数据回写磁盘的速度是很慢的,如果直接在这里处理脏数据
if (ftemp != NULL) {//会导致函数持有mapping->list_lock自旋锁的时间太长了,影响其他CPU的处理效率
LOS_ListTailInsert(&dirtyList, &ftemp->node);//将临时脏页挂到记录脏页链表上
}
}
OsDeletePageCacheLru(fpage);
OsDeletePageCacheLru(fpage);//删除高速缓存和从置换链表中下线
LOS_SpinUnlockRestore(lruLock, lruSave);
}
LOS_SpinUnlockRestore(&mapping->list_lock, intSave);
LOS_SpinUnlockRestore(&mapping->list_lock, intSave);//恢复自旋锁,不能让别的CPU等太久
LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(fpage, fnext, &dirtyList, LosFilePage, node) {
OsDoFlushDirtyPage(fpage);
LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(fpage, fnext, &dirtyList, LosFilePage, node) {//到这里,再来慢慢的统一处理脏页数据
OsDoFlushDirtyPage(fpage);//遍历脏页链表,一页一页处理
}
}
LosVmFileOps g_commVmOps = {
///虚拟内存文件操作实现类
LosVmFileOps g_commVmOps = {//
.open = NULL,
.close = NULL,
.fault = OsVmmFileFault,
.remove = OsVmmFileRemove,
.fault = OsVmmFileFault, //缺页中断处理
.remove = OsVmmFileRemove,//删除页
};
//文件映射
INT32 OsVfsFileMmap(struct file *filep, LosVmMapRegion *region)
{
region->unTypeData.rf.vmFOps = &g_commVmOps;
region->unTypeData.rf.vmFOps = &g_commVmOps;//文件操作
region->unTypeData.rf.vnode = filep->f_vnode;
region->unTypeData.rf.f_oflags = filep->f_oflags;
return ENOERR;
}
/*!
,,
filep广,鸿,//////
*/
STATUS_T OsNamedMMap(struct file *filep, LosVmMapRegion *region)
{
struct Vnode *vnode = NULL;
@ -519,10 +545,10 @@ STATUS_T OsNamedMMap(struct file *filep, LosVmMapRegion *region)
vnode->useCount++;
VnodeDrop();
if (filep->ops != NULL && filep->ops->mmap != NULL) {
if (vnode->type == VNODE_TYPE_CHR || vnode->type == VNODE_TYPE_BLK) {
LOS_SetRegionTypeDev(region);
if (vnode->type == VNODE_TYPE_CHR || vnode->type == VNODE_TYPE_BLK) {//块设备或者字符设备 /dev/..
LOS_SetRegionTypeDev(region);//设置为设备类型
} else {
LOS_SetRegionTypeFile(region);
LOS_SetRegionTypeFile(region);//设置为文件类型
}
int ret = filep->ops->mmap(filep, region);
if (ret != LOS_OK) {
@ -538,17 +564,21 @@ STATUS_T OsNamedMMap(struct file *filep, LosVmMapRegion *region)
return LOS_OK;
}
/**************************************************************************************************
:mapping->page_list 1,3,4,6 ,5
**************************************************************************************************/
LosFilePage *OsFindGetEntry(struct page_mapping *mapping, VM_OFFSET_T pgoff)
{
LosFilePage *fpage = NULL;
LOS_DL_LIST_FOR_EACH_ENTRY(fpage, &mapping->page_list, LosFilePage, node) {
if (fpage->pgoff == pgoff) {
LOS_DL_LIST_FOR_EACH_ENTRY(fpage, &mapping->page_list, LosFilePage, node) {//遍历文件页
if (fpage->pgoff == pgoff) {//找到指定的页,
return fpage;
}
if (fpage->pgoff > pgoff) {
break;
if (fpage->pgoff > pgoff) {//大于之前还没有找到,说明不在链表中,往后的也不用找了,
break;//因为 mapping->page_list节点上的数据都是按 fpage->pgoff 从小到大的顺序排列的.
}
}
@ -556,6 +586,11 @@ LosFilePage *OsFindGetEntry(struct page_mapping *mapping, VM_OFFSET_T pgoff)
}
/* need mutex & change memory to dma zone. */
/*!
LosFilePage
Direct Memory Access访
"DMA控制器"CPU
*/
LosFilePage *OsPageCacheAlloc(struct page_mapping *mapping, VM_OFFSET_T pgoff)
{
VOID *kvaddr = NULL;
@ -563,39 +598,39 @@ LosFilePage *OsPageCacheAlloc(struct page_mapping *mapping, VM_OFFSET_T pgoff)
LosVmPage *vmPage = NULL;
LosFilePage *fpage = NULL;
vmPage = LOS_PhysPageAlloc();
vmPage = LOS_PhysPageAlloc(); //先分配一个物理页
if (vmPage == NULL) {
VM_ERR("alloc vm page failed");
return NULL;
}
physSeg = OsVmPhysSegGet(vmPage);
kvaddr = OsVmPageToVaddr(vmPage);
physSeg = OsVmPhysSegGet(vmPage);//通过页获取所在seg
kvaddr = OsVmPageToVaddr(vmPage);//获取内核空间的虚拟地址,具体点进去看函数说明,这里一定要理解透彻!
if ((physSeg == NULL) || (kvaddr == NULL)) {
LOS_PhysPageFree(vmPage);
LOS_PhysPageFree(vmPage); //异常情况要释放vmPage
VM_ERR("alloc vm page failed!");
return NULL;
}
fpage = (LosFilePage *)LOS_MemAlloc(m_aucSysMem0, sizeof(LosFilePage));
fpage = (LosFilePage *)LOS_MemAlloc(m_aucSysMem0, sizeof(LosFilePage));//从内存池中分配一个filePage
if (fpage == NULL) {
LOS_PhysPageFree(vmPage);
LOS_PhysPageFree(vmPage); //异常情况要释放vmPage
VM_ERR("Failed to allocate for page!");
return NULL;
}
(VOID)memset_s((VOID *)fpage, sizeof(LosFilePage), 0, sizeof(LosFilePage));
(VOID)memset_s((VOID *)fpage, sizeof(LosFilePage), 0, sizeof(LosFilePage));//调标准库函数 置0
LOS_ListInit(&fpage->i_mmap);
LOS_ListInit(&fpage->node);
LOS_ListInit(&fpage->lru);
fpage->n_maps = 0;
fpage->dirtyOff = PAGE_SIZE;
fpage->dirtyEnd = 0;
fpage->physSeg = physSeg;
fpage->vmPage = vmPage;
fpage->mapping = mapping;
fpage->pgoff = pgoff;
(VOID)memset_s(kvaddr, PAGE_SIZE, 0, PAGE_SIZE);
LOS_ListInit(&fpage->i_mmap); //初始化映射,链表上挂 MapInfo
LOS_ListInit(&fpage->node); //节点初始化
LOS_ListInit(&fpage->lru); //LRU初始化
fpage->n_maps = 0; //映射次数
fpage->dirtyOff = PAGE_SIZE; //默认页尾部,相当于没有脏数据
fpage->dirtyEnd = 0; //脏页结束位置
fpage->physSeg = physSeg; //页框所属段.其中包含了 LRU LIST ==
fpage->vmPage = vmPage; //物理页框
fpage->mapping = mapping; //记录所有文件页映射
fpage->pgoff = pgoff; //将文件切成一页页,页标
(VOID)memset_s(kvaddr, PAGE_SIZE, 0, PAGE_SIZE);//页内数据清0
return fpage;
}

@ -1,3 +1,49 @@
/*!
* @file los_vm_iomap.c
* @brief DMA
* @link
@verbatim
访
访Direct Memory AccessDMA访
CPU
DMA使DMA
DMA
使
DMA使
DMA
使DMA
ISA DMA8DMA7
DMA1616DMA
DMA
"分散-收集"Scatter-gatherDMADMADMA
DRQDMADACKDMADMA
DMA线
DMADMA访
访
DMADMA
访访
Cache-coherent system
Non-coherent systemDMA
DMA
DMA
@endverbatim
* @version
* @author weharmonyos.com | 鸿 |
* @date 2022-04-02
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
@ -36,7 +82,7 @@
#include "los_vm_map.h"
#include "los_memory.h"
/// 分配DMA空间
VOID *LOS_DmaMemAlloc(DMA_ADDR_T *dmaAddr, size_t size, size_t align, enum DmaMemType type)
{
VOID *kVaddr = NULL;
@ -51,9 +97,9 @@ VOID *LOS_DmaMemAlloc(DMA_ADDR_T *dmaAddr, size_t size, size_t align, enum DmaMe
}
#ifdef LOSCFG_KERNEL_VM
kVaddr = LOS_KernelMallocAlign(size, align);
kVaddr = LOS_KernelMallocAlign(size, align);//不走内存池方式, 直接申请物理页
#else
kVaddr = LOS_MemAllocAlign(OS_SYS_MEM_ADDR, size, align);
kVaddr = LOS_MemAllocAlign(OS_SYS_MEM_ADDR, size, align);//从内存池中申请
#endif
if (kVaddr == NULL) {
VM_ERR("failed, size = %u, align = %u", size, align);
@ -61,16 +107,16 @@ VOID *LOS_DmaMemAlloc(DMA_ADDR_T *dmaAddr, size_t size, size_t align, enum DmaMe
}
if (dmaAddr != NULL) {
*dmaAddr = (DMA_ADDR_T)LOS_PaddrQuery(kVaddr);
*dmaAddr = (DMA_ADDR_T)LOS_PaddrQuery(kVaddr);//查询物理地址, DMA直接将数据灌到物理地址
}
if (type == DMA_NOCACHE) {
if (type == DMA_NOCACHE) {//无缓存模式 , 计算新的虚拟地址
kVaddr = (VOID *)VMM_TO_UNCACHED_ADDR((UINTPTR)kVaddr);
}
return kVaddr;
}
/// 释放 DMA指针
VOID LOS_DmaMemFree(VOID *vaddr)
{
UINTPTR addr;
@ -79,13 +125,13 @@ VOID LOS_DmaMemFree(VOID *vaddr)
return;
}
addr = (UINTPTR)vaddr;
// 未缓存区
if ((addr >= UNCACHED_VMM_BASE) && (addr < UNCACHED_VMM_BASE + UNCACHED_VMM_SIZE)) {
addr = UNCACHED_TO_VMM_ADDR(addr);
addr = UNCACHED_TO_VMM_ADDR(addr); //转换成未缓存区地址
#ifdef LOSCFG_KERNEL_VM
LOS_KernelFree((VOID *)addr);
LOS_KernelFree((VOID *)addr);//
#else
LOS_MemFree(OS_SYS_MEM_ADDR, (VOID *)addr);
LOS_MemFree(OS_SYS_MEM_ADDR, (VOID *)addr);//内存池方式释放
#endif
} else if ((addr >= KERNEL_VMM_BASE) && (addr < KERNEL_VMM_BASE + KERNEL_VMM_SIZE)) {
#ifdef LOSCFG_KERNEL_VM
@ -98,7 +144,7 @@ VOID LOS_DmaMemFree(VOID *vaddr)
}
return;
}
/// 将DMA虚拟地址转成物理地址
DMA_ADDR_T LOS_DmaVaddrToPaddr(VOID *vaddr)
{
return (DMA_ADDR_T)LOS_PaddrQuery(vaddr);

File diff suppressed because it is too large Load Diff

@ -40,34 +40,37 @@
#ifdef LOSCFG_KERNEL_VM
LosVmPage *g_vmPageArray = NULL;
size_t g_vmPageArraySize;
LosVmPage *g_vmPageArray = NULL;//物理页框数组
size_t g_vmPageArraySize;//物理页框大小
//页框初始化
STATIC VOID OsVmPageInit(LosVmPage *page, paddr_t pa, UINT8 segID)
{
LOS_ListInit(&page->node);
page->flags = FILE_PAGE_FREE;
LOS_AtomicSet(&page->refCounts, 0);
page->physAddr = pa;
page->segID = segID;
page->order = VM_LIST_ORDER_MAX;
LOS_ListInit(&page->node); //页节点初始化
page->flags = FILE_PAGE_FREE; //页标签,初始为空闲页
LOS_AtomicSet(&page->refCounts, 0); //引用次数0
page->physAddr = pa; //物理地址
page->segID = segID; //物理地址使用段管理段ID
page->order = VM_LIST_ORDER_MAX; //初始化值,不属于任何块组
page->nPages = 0;
#ifdef LOSCFG_PAGE_TABLE_FINE_LOCK
LOS_SpinInit(&page->lock);
#endif
}
///伙伴算法初始化
STATIC INLINE VOID OsVmPageOrderListInit(LosVmPage *page, size_t nPages)
{
OsVmPhysPagesFreeContiguous(page, nPages);
{//@note_why 此时所有页面 page->order = VM_LIST_ORDER_MAX,能挂入伙伴算法的链表吗?
OsVmPhysPagesFreeContiguous(page, nPages);//释放连续的物理页框
}
#define VMPAGEINIT(page, pa, segID) do { \
OsVmPageInit(page, pa, segID); \
(page)++; \
(pa) += PAGE_SIZE; \
} while (0)
/*!
,
1.g_vmPageArrayLosVmPage,4K.
*/
VOID OsVmPageStartup(VOID)
{
struct VmPhysSeg *seg = NULL;
@ -76,7 +79,7 @@ VOID OsVmPageStartup(VOID)
UINT32 nPage;
INT32 segID;
OsVmPhysAreaSizeAdjust(ROUNDUP((g_vmBootMemBase - KERNEL_ASPACE_BASE), PAGE_SIZE));
OsVmPhysAreaSizeAdjust(ROUNDUP((g_vmBootMemBase - KERNEL_ASPACE_BASE), PAGE_SIZE));//校正 g_physArea size
/*
* Pages getting from OsVmPhysPageNumGet() interface here contain the memory
@ -85,20 +88,20 @@ VOID OsVmPageStartup(VOID)
*/
UINT32 pageNum = OsVmPhysPageNumGet();
nPage = pageNum * PAGE_SIZE / (sizeof(LosVmPage) + PAGE_SIZE);
g_vmPageArraySize = nPage * sizeof(LosVmPage);
g_vmPageArray = (LosVmPage *)OsVmBootMemAlloc(g_vmPageArraySize);
g_vmPageArraySize = nPage * sizeof(LosVmPage);//页表总大小
g_vmPageArray = (LosVmPage *)OsVmBootMemAlloc(g_vmPageArraySize);//实模式下申请内存,此时还没有初始化MMU
OsVmPhysAreaSizeAdjust(ROUNDUP(g_vmPageArraySize, PAGE_SIZE));
OsVmPhysAreaSizeAdjust(ROUNDUP(g_vmPageArraySize, PAGE_SIZE));//
OsVmPhysSegAdd();
OsVmPhysInit();
OsVmPhysSegAdd();// 完成对段的初始化
OsVmPhysInit();// 加入空闲链表和设置置换算法,LRU(最近最久未使用)算法
#ifdef LOSCFG_KERNEL_PLIMITS
OsMemLimitSetLimit(pageNum * PAGE_SIZE);
#endif
for (segID = 0; segID < g_vmPhysSegNum; segID++) {
for (segID = 0; segID < g_vmPhysSegNum; segID++) {//遍历物理段,将段切成一页一页
seg = &g_vmPhysSeg[segID];
nPage = seg->size >> PAGE_SHIFT;
nPage = seg->size >> PAGE_SHIFT;//本段总页数
UINT32 count = nPage >> 3; /* 3: 2 ^ 3, nPage / 8, cycle count */
UINT32 left = nPage & 0x7; /* 0x7: nPage % 8, left page */
@ -116,17 +119,17 @@ VOID OsVmPageStartup(VOID)
for (; left > 0; left--) {
VMPAGEINIT(page, pa, segID);
}
OsVmPageOrderListInit(seg->pageBase, nPage);
OsVmPageOrderListInit(seg->pageBase, nPage);//伙伴算法初始化,将所有页加入空闲链表供分配
}
}
///通过物理地址获取页框
LosVmPage *LOS_VmPageGet(PADDR_T paddr)
{
INT32 segID;
LosVmPage *page = NULL;
for (segID = 0; segID < g_vmPhysSegNum; segID++) {
page = OsVmPhysToPage(paddr, segID);
for (segID = 0; segID < g_vmPhysSegNum; segID++) {//物理内存采用段页管理
page = OsVmPhysToPage(paddr, segID);//通过物理地址和段ID找出物理页框
if (page != NULL) {
break;
}

@ -1,3 +1,38 @@
/*!
* @file los_vm_phys.c
* @brief -
* @link physical http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-basic-memory-physical.html @endlink
@verbatim
CPU线
LiteOS-A
4KiB便
LiteOS-A使
-----------------------------------------------------
kernel.bin | heap | page frames
() | () | ()
-----------------------------------------------------
92020
1828256
20KiB4K,592820KiB12KiB
3320121
1010
12KiB3322111
201
1
@endverbatim
* @image html https://gitee.com/weharmonyos/resources/raw/master/17/malloc_phy.png
* @image html https://gitee.com/weharmonyos/resources/raw/master/17/free_phy.png
* @version
* @author weharmonyos.com | 鸿 |
* @date 2021-11-25
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
@ -41,36 +76,36 @@
#define ONE_PAGE 1
/* Physical memory area array */
STATIC struct VmPhysArea g_physArea[] = {
/* Physical memory area array | 物理内存区数组 */
STATIC struct VmPhysArea g_physArea[] = {///< 这里只有一个区域,即只生成一个段
{
.start = SYS_MEM_BASE,
.size = SYS_MEM_SIZE_DEFAULT,
.start = SYS_MEM_BASE, //整个物理内存基地址,#define SYS_MEM_BASE DDR_MEM_ADDR , 0x80000000
.size = SYS_MEM_SIZE_DEFAULT,//整个物理内存总大小 0x07f00000
},
};
struct VmPhysSeg g_vmPhysSeg[VM_PHYS_SEG_MAX];
INT32 g_vmPhysSegNum = 0;
struct VmPhysSeg g_vmPhysSeg[VM_PHYS_SEG_MAX]; ///< 最大32段
INT32 g_vmPhysSegNum = 0; ///< 段数
/// 获取段数组,全局变量,变量放在 .bbs 区
LosVmPhysSeg *OsGVmPhysSegGet(void)
{
return g_vmPhysSeg;
}
/// 初始化Lru置换链表
STATIC VOID OsVmPhysLruInit(struct VmPhysSeg *seg)
{
INT32 i;
UINT32 intSave;
LOS_SpinInit(&seg->lruLock);
LOS_SpinInit(&seg->lruLock);//初始化自旋锁,自旋锁用于CPU多核同步
LOS_SpinLockSave(&seg->lruLock, &intSave);
for (i = 0; i < VM_NR_LRU_LISTS; i++) {
seg->lruSize[i] = 0;
LOS_ListInit(&seg->lruList[i]);
for (i = 0; i < VM_NR_LRU_LISTS; i++) { //五个双循环链表
seg->lruSize[i] = 0; //记录链表节点数
LOS_ListInit(&seg->lruList[i]); //初始化LRU链表
}
LOS_SpinUnlockRestore(&seg->lruLock, intSave);
}
/// 创建物理段,由区划分转成段管理
STATIC INT32 OsVmPhysSegCreate(paddr_t start, size_t size)
{
struct VmPhysSeg *seg = NULL;
@ -79,8 +114,8 @@ STATIC INT32 OsVmPhysSegCreate(paddr_t start, size_t size)
return -1;
}
seg = &g_vmPhysSeg[g_vmPhysSegNum++];
for (; (seg > g_vmPhysSeg) && ((seg - 1)->start > (start + size)); seg--) {
seg = &g_vmPhysSeg[g_vmPhysSegNum++];//拿到一段数据
for (; (seg > g_vmPhysSeg) && ((seg - 1)->start > (start + size)); seg--) {//定位到合适的段
*seg = *(seg - 1);
}
seg->start = start;
@ -88,21 +123,21 @@ STATIC INT32 OsVmPhysSegCreate(paddr_t start, size_t size)
return 0;
}
/// 添加物理段
VOID OsVmPhysSegAdd(VOID)
{
INT32 i, ret;
LOS_ASSERT(g_vmPhysSegNum < VM_PHYS_SEG_MAX);
for (i = 0; i < (sizeof(g_physArea) / sizeof(g_physArea[0])); i++) {
ret = OsVmPhysSegCreate(g_physArea[i].start, g_physArea[i].size);
for (i = 0; i < (sizeof(g_physArea) / sizeof(g_physArea[0])); i++) {//遍历g_physArea数组
ret = OsVmPhysSegCreate(g_physArea[i].start, g_physArea[i].size);//由区划分转成段管理
if (ret != 0) {
VM_ERR("create phys seg failed");
}
}
}
/// 段区域大小调整
VOID OsVmPhysAreaSizeAdjust(size_t size)
{
/*
@ -113,35 +148,36 @@ VOID OsVmPhysAreaSizeAdjust(size_t size)
g_physArea[0].size -= size;
}
/// 获得物理内存的总页数
UINT32 OsVmPhysPageNumGet(VOID)
{
UINT32 nPages = 0;
INT32 i;
for (i = 0; i < (sizeof(g_physArea) / sizeof(g_physArea[0])); i++) {
nPages += g_physArea[i].size >> PAGE_SHIFT;
nPages += g_physArea[i].size >> PAGE_SHIFT;//右移12位相当于除以4K, 计算出总页数
}
return nPages;
return nPages;//返回所有物理内存总页数
}
/// 初始化空闲链表,分配物理页框使用伙伴算法
STATIC INLINE VOID OsVmPhysFreeListInit(struct VmPhysSeg *seg)
{
int i;
UINT32 intSave;
struct VmFreeList *list = NULL;
LOS_SpinInit(&seg->freeListLock);
LOS_SpinInit(&seg->freeListLock);//初始化用于分配的自旋锁
LOS_SpinLockSave(&seg->freeListLock, &intSave);
for (i = 0; i < VM_LIST_ORDER_MAX; i++) {
list = &seg->freeList[i];
LOS_ListInit(&list->node);
list->listCnt = 0;
for (i = 0; i < VM_LIST_ORDER_MAX; i++) {//遍历伙伴算法空闲块组链表
list = &seg->freeList[i]; //一个个来
LOS_ListInit(&list->node); //LosVmPage.node将挂到list->node上
list->listCnt = 0; //链表上的数量默认0
}
LOS_SpinUnlockRestore(&seg->freeListLock, intSave);
}
/// 物理段初始化
VOID OsVmPhysInit(VOID)
{
struct VmPhysSeg *seg = NULL;
@ -150,13 +186,13 @@ VOID OsVmPhysInit(VOID)
for (i = 0; i < g_vmPhysSegNum; i++) {
seg = &g_vmPhysSeg[i];
seg->pageBase = &g_vmPageArray[nPages];
nPages += seg->size >> PAGE_SHIFT;
OsVmPhysFreeListInit(seg);
OsVmPhysLruInit(seg);
seg->pageBase = &g_vmPageArray[nPages];//记录本段首页物理页框地址
nPages += seg->size >> PAGE_SHIFT;//偏移12位,按4K一页,算出本段总页数
OsVmPhysFreeListInit(seg); //初始化空闲链表,分配页框使用伙伴算法
OsVmPhysLruInit(seg); //初始化LRU置换链表
}
}
/// 将页框挂入空闲链表,分配物理页框从空闲链表里拿
STATIC VOID OsVmPhysFreeListAddUnsafe(LosVmPage *page, UINT8 order)
{
struct VmPhysSeg *seg = NULL;
@ -173,36 +209,44 @@ STATIC VOID OsVmPhysFreeListAddUnsafe(LosVmPage *page, UINT8 order)
LOS_ListTailInsert(&list->node, &page->node);
list->listCnt++;
}
///将物理页框从空闲链表上摘除,见于物理页框被分配的情况
STATIC VOID OsVmPhysFreeListDelUnsafe(LosVmPage *page)
{
struct VmPhysSeg *seg = NULL;
struct VmFreeList *list = NULL;
if ((page->segID >= VM_PHYS_SEG_MAX) || (page->order >= VM_LIST_ORDER_MAX)) {
if ((page->segID >= VM_PHYS_SEG_MAX) || (page->order >= VM_LIST_ORDER_MAX)) {//等于VM_LIST_ORDER_MAX也不行,说明伙伴算法最大支持 2^8的分配
LOS_Panic("The page segment id(%u) or order(%u) is invalid\n", page->segID, page->order);
}
seg = &g_vmPhysSeg[page->segID];
list = &seg->freeList[page->order];
list->listCnt--;
LOS_ListDelete(&page->node);
page->order = VM_LIST_ORDER_MAX;
seg = &g_vmPhysSeg[page->segID]; //找到物理页框对应的段
list = &seg->freeList[page->order]; //根据伙伴算法组序号找到空闲链表
list->listCnt--; //链表节点总数减一
LOS_ListDelete(&page->node); //将自己从链表上摘除
page->order = VM_LIST_ORDER_MAX; //告诉系统物理页框已不在空闲链表上, 用于OsVmPhysPagesSpiltUnsafe的断言
}
/**
* @brief ,,.
* @param page
* @param oldOrder 2^2
* @param newOrder 2^8
* @return STATIC
*/
STATIC VOID OsVmPhysPagesSpiltUnsafe(LosVmPage *page, UINT8 oldOrder, UINT8 newOrder)
{
UINT32 order;
LosVmPage *buddyPage = NULL;
for (order = newOrder; order > oldOrder;) {
order--;
buddyPage = &page[VM_ORDER_TO_PAGES(order)];
LOS_ASSERT(buddyPage->order == VM_LIST_ORDER_MAX);
OsVmPhysFreeListAddUnsafe(buddyPage, order);
for (order = newOrder; order > oldOrder;) {//把肉剁碎的过程,把多余的肉块切成2^7,2^6...标准块,
order--;//越切越小,逐一挂到对应的空闲链表上
buddyPage = &page[VM_ORDER_TO_PAGES(order)];//@note_good 先把多余的肉割出来,这句代码很赞!因为LosVmPage本身是在一个大数组上,page[nPages]可直接定位
LOS_ASSERT(buddyPage->order == VM_LIST_ORDER_MAX);//没挂到伙伴算法对应组块空闲链表上的物理页框的order必须是VM_LIST_ORDER_MAX
OsVmPhysFreeListAddUnsafe(buddyPage, order);//将劈开的节点挂到对应序号的链表上,buddyPage->order = order
}
}
///通过物理地址获取所属参数段的物理页框
LosVmPage *OsVmPhysToPage(paddr_t pa, UINT8 segID)
{
struct VmPhysSeg *seg = NULL;
@ -216,8 +260,8 @@ LosVmPage *OsVmPhysToPage(paddr_t pa, UINT8 segID)
return NULL;
}
offset = pa - seg->start;
return (seg->pageBase + (offset >> PAGE_SHIFT));
offset = pa - seg->start;//得到物理地址的偏移量
return (seg->pageBase + (offset >> PAGE_SHIFT));//得到对应的物理页框
}
LosVmPage *OsVmPaddrToPage(paddr_t paddr)
@ -233,31 +277,37 @@ LosVmPage *OsVmPaddrToPage(paddr_t paddr)
}
return NULL;
}
VOID *OsVmPageToVaddr(LosVmPage *page)
/*!
* @brief page OsArchMmuInit
\n #define SYS_MEM_BASE DDR_MEM_ADDR /* physical memory base 物理地址的起始地址 * /
\n
\n :,
* @param page
* @return VOID*
*/
VOID *OsVmPageToVaddr(LosVmPage *page)//
{
VADDR_T vaddr;
vaddr = KERNEL_ASPACE_BASE + page->physAddr - SYS_MEM_BASE;
return (VOID *)(UINTPTR)vaddr;
vaddr = KERNEL_ASPACE_BASE + page->physAddr - SYS_MEM_BASE;//表示申请的物理地址在物理空间的偏移量等于映射的虚拟地址在内核空间的偏移量
return (VOID *)(UINTPTR)vaddr;//不需要存储映射关系,这简直就是神来之笔,拍案叫绝。@note_good 详见 鸿蒙内核源码分析(页表管理篇)
}
///通过虚拟地址找映射的物理页框
LosVmPage *OsVmVaddrToPage(VOID *ptr)
{
struct VmPhysSeg *seg = NULL;
PADDR_T pa = LOS_PaddrQuery(ptr);
PADDR_T pa = LOS_PaddrQuery(ptr);//通过空间的虚拟地址查询物理地址
UINT32 segID;
for (segID = 0; segID < g_vmPhysSegNum; segID++) {
for (segID = 0; segID < g_vmPhysSegNum; segID++) {//遍历所有段
seg = &g_vmPhysSeg[segID];
if ((pa >= seg->start) && (pa < (seg->start + seg->size))) {
return seg->pageBase + ((pa - seg->start) >> PAGE_SHIFT);
if ((pa >= seg->start) && (pa < (seg->start + seg->size))) {//找到物理地址所在的段
return seg->pageBase + ((pa - seg->start) >> PAGE_SHIFT);//段基地址+页偏移索引 得到虚拟地址经映射所在物理页框
}
}
return NULL;
}
/// 回收一定范围内的页框
STATIC INLINE VOID OsVmRecycleExtraPages(LosVmPage *page, size_t startPage, size_t endPage)
{
if (startPage >= endPage) {
@ -266,7 +316,7 @@ STATIC INLINE VOID OsVmRecycleExtraPages(LosVmPage *page, size_t startPage, size
OsVmPhysPagesFreeContiguous(page, endPage - startPage);
}
/// 大块的物理内存分配
STATIC LosVmPage *OsVmPhysLargeAlloc(struct VmPhysSeg *seg, size_t nPages)
{
struct VmFreeList *list = NULL;
@ -276,11 +326,11 @@ STATIC LosVmPage *OsVmPhysLargeAlloc(struct VmPhysSeg *seg, size_t nPages)
PADDR_T paEnd;
size_t size = nPages << PAGE_SHIFT;
list = &seg->freeList[VM_LIST_ORDER_MAX - 1];
LOS_DL_LIST_FOR_EACH_ENTRY(page, &list->node, LosVmPage, node) {
list = &seg->freeList[VM_LIST_ORDER_MAX - 1];//先找伙伴算法中内存块最大的开撸
LOS_DL_LIST_FOR_EACH_ENTRY(page, &list->node, LosVmPage, node) {//遍历链表
paStart = page->physAddr;
paEnd = paStart + size;
if (paEnd > (seg->start + seg->size)) {
if (paEnd > (seg->start + seg->size)) {//匹配物理地址范围
continue;
}
@ -302,7 +352,7 @@ STATIC LosVmPage *OsVmPhysLargeAlloc(struct VmPhysSeg *seg, size_t nPages)
return NULL;
}
/// 申请物理页并挂在对应的链表上
STATIC LosVmPage *OsVmPhysPagesAlloc(struct VmPhysSeg *seg, size_t nPages)
{
struct VmFreeList *list = NULL;
@ -312,13 +362,13 @@ STATIC LosVmPage *OsVmPhysPagesAlloc(struct VmPhysSeg *seg, size_t nPages)
UINT32 newOrder;
order = OsVmPagesToOrder(nPages);
if (order < VM_LIST_ORDER_MAX) {
for (newOrder = order; newOrder < VM_LIST_ORDER_MAX; newOrder++) {
if (order < VM_LIST_ORDER_MAX) {//按正常的伙伴算法分配
for (newOrder = order; newOrder < VM_LIST_ORDER_MAX; newOrder++) {//从小往大了撸
list = &seg->freeList[newOrder];
if (LOS_ListEmpty(&list->node)) {
continue;
if (LOS_ListEmpty(&list->node)) {//这条链路上没有可分配的物理页框
continue;//继续往大的找
}
page = LOS_DL_LIST_ENTRY(LOS_DL_LIST_FIRST(&list->node), LosVmPage, node);
page = LOS_DL_LIST_ENTRY(LOS_DL_LIST_FIRST(&list->node), LosVmPage, node);//找到了直接返回第一个节点
goto DONE;
}
} else {
@ -339,7 +389,7 @@ DONE:
return page;
}
/// 释放物理页框,所谓释放物理页就是把页挂到空闲链表中
VOID OsVmPhysPagesFree(LosVmPage *page, UINT8 order)
{
paddr_t pa;
@ -349,51 +399,59 @@ VOID OsVmPhysPagesFree(LosVmPage *page, UINT8 order)
return;
}
if (order < VM_LIST_ORDER_MAX - 1) {
pa = VM_PAGE_TO_PHYS(page);
do {
pa ^= VM_ORDER_TO_PHYS(order);
buddyPage = OsVmPhysToPage(pa, page->segID);
if ((buddyPage == NULL) || (buddyPage->order != order)) {
if (order < VM_LIST_ORDER_MAX - 1) {//order[0,7]
pa = VM_PAGE_TO_PHYS(page);//获取物理地址
do {//按位异或
pa ^= VM_ORDER_TO_PHYS(order);//@note_good 注意这里是高位和低位的 ^= ,也就是说跳到order块组物理地址处,此处处理甚妙!
buddyPage = OsVmPhysToPage(pa, page->segID);//通过物理地址拿到页框
if ((buddyPage == NULL) || (buddyPage->order != order)) {//页框所在组块必须要对应
break;
}
OsVmPhysFreeListDelUnsafe(buddyPage);
OsVmPhysFreeListDelUnsafe(buddyPage);//注意buddypage是连续的物理页框 例如order=2时,2^2=4页就是一个块组 |_|_|_|_|
order++;
pa &= ~(VM_ORDER_TO_PHYS(order) - 1);
page = OsVmPhysToPage(pa, page->segID);
} while (order < VM_LIST_ORDER_MAX - 1);
}
OsVmPhysFreeListAddUnsafe(page, order);
OsVmPhysFreeListAddUnsafe(page, order);//伙伴算法 空闲节点增加
}
///连续的释放物理页框, 如果8页连在一块是一起释放的
VOID OsVmPhysPagesFreeContiguous(LosVmPage *page, size_t nPages)
{
paddr_t pa;
UINT32 order;
size_t n;
while (TRUE) {
pa = VM_PAGE_TO_PHYS(page);
order = VM_PHYS_TO_ORDER(pa);
n = VM_ORDER_TO_PAGES(order);
if (n > nPages) {
while (TRUE) {//死循环
pa = VM_PAGE_TO_PHYS(page);//获取页面物理地址
order = VM_PHYS_TO_ORDER(pa);//通过物理地址找到伙伴算法的级别
n = VM_ORDER_TO_PAGES(order);//通过级别找到物理页块 (1<<order),意思是如果order=3就可以释放8个页块
if (n > nPages) {//nPages只剩下小于2^order时退出循环
break;
}
OsVmPhysPagesFree(page, order);
nPages -= n;
page += n;
OsVmPhysPagesFree(page, order);//释放伙伴算法对应块组
nPages -= n;//总页数减少
page += n;//释放的页数增多
}
//举例剩下 7个页框时依次用 2^2 2^1 2^0 方式释放
while (nPages > 0) {
order = LOS_HighBitGet(nPages);
n = VM_ORDER_TO_PAGES(order);
OsVmPhysPagesFree(page, order);
order = LOS_HighBitGet(nPages);//从高到低块组释放
n = VM_ORDER_TO_PAGES(order);//2^order次方
OsVmPhysPagesFree(page, order);//释放块组
nPages -= n;
page += n;
page += n;//相当于page[n]
}
}
/*!
* @brief OsVmPhysPagesGet LosVmPage,
* LosVmPage->nPages
* @param nPages
* @return
*
* @see
*/
STATIC LosVmPage *OsVmPhysPagesGet(size_t nPages)
{
UINT32 intSave;
@ -404,11 +462,11 @@ STATIC LosVmPage *OsVmPhysPagesGet(size_t nPages)
for (segID = 0; segID < g_vmPhysSegNum; segID++) {
seg = &g_vmPhysSeg[segID];
LOS_SpinLockSave(&seg->freeListLock, &intSave);
page = OsVmPhysPagesAlloc(seg, nPages);
if (page != NULL) {
/* the first page of continuous physical addresses holds refCounts */
LOS_AtomicSet(&page->refCounts, 0);
page->nPages = nPages;
page = OsVmPhysPagesAlloc(seg, nPages);//分配指定页数的物理页,nPages需小于伙伴算法一次能分配的最大页数
if (page != NULL) {//分配成功
/* */
LOS_AtomicSet(&page->refCounts, 0);//设置引用次数为0
page->nPages = nPages;//页数
LOS_SpinUnlockRestore(&seg->freeListLock, intSave);
return page;
}
@ -416,7 +474,7 @@ STATIC LosVmPage *OsVmPhysPagesGet(size_t nPages)
}
return NULL;
}
///分配连续的物理页
VOID *LOS_PhysPagesAllocContiguous(size_t nPages)
{
LosVmPage *page = NULL;
@ -424,15 +482,15 @@ VOID *LOS_PhysPagesAllocContiguous(size_t nPages)
if (nPages == 0) {
return NULL;
}
page = OsVmPhysPagesGet(nPages);
//鸿蒙 nPages 不能大于 2^8 次方,即256个页,1M内存,仅限于内核态,用户态不限制分配大小.
page = OsVmPhysPagesGet(nPages);//通过伙伴算法获取物理上连续的页
if (page == NULL) {
return NULL;
}
return OsVmPageToVaddr(page);
return OsVmPageToVaddr(page);//通过物理页找虚拟地址
}
/// 释放指定页数地址连续的物理内存
VOID LOS_PhysPagesFreeContiguous(VOID *ptr, size_t nPages)
{
UINT32 intSave;
@ -443,17 +501,17 @@ VOID LOS_PhysPagesFreeContiguous(VOID *ptr, size_t nPages)
return;
}
page = OsVmVaddrToPage(ptr);
page = OsVmVaddrToPage(ptr);//通过虚拟地址找到页框
if (page == NULL) {
VM_ERR("vm page of ptr(%#x) is null", ptr);
return;
}
page->nPages = 0;
page->nPages = 0;//被分配的页数置为0,表示不被分配
seg = &g_vmPhysSeg[page->segID];
LOS_SpinLockSave(&seg->freeListLock, &intSave);
OsVmPhysPagesFreeContiguous(page, nPages);
OsVmPhysPagesFreeContiguous(page, nPages);//具体释放实现
LOS_SpinUnlockRestore(&seg->freeListLock, intSave);
#ifdef LOSCFG_KERNEL_PLIMITS
@ -468,7 +526,7 @@ PADDR_T OsKVaddrToPaddr(VADDR_T kvaddr)
}
return (kvaddr - KERNEL_ASPACE_BASE + SYS_MEM_BASE);
}
/// 通过物理地址获取内核虚拟地址
VADDR_T *LOS_PaddrToKVaddr(PADDR_T paddr)
{
struct VmPhysSeg *seg = NULL;
@ -484,10 +542,10 @@ VADDR_T *LOS_PaddrToKVaddr(PADDR_T paddr)
return (VADDR_T *)(UINTPTR)(paddr - SYS_MEM_BASE + KERNEL_ASPACE_BASE);
}
}
return (VADDR_T *)(UINTPTR)(paddr - SYS_MEM_BASE + KERNEL_ASPACE_BASE);
//内核
return (VADDR_T *)(UINTPTR)(paddr - SYS_MEM_BASE + KERNEL_ASPACE_BASE);//
}
///释放一个物理页框
VOID LOS_PhysPageFree(LosVmPage *page)
{
UINT32 intSave;
@ -497,12 +555,12 @@ VOID LOS_PhysPageFree(LosVmPage *page)
return;
}
if (LOS_AtomicDecRet(&page->refCounts) <= 0) {
if (LOS_AtomicDecRet(&page->refCounts) <= 0) {//减少引用数后不能小于0
seg = &g_vmPhysSeg[page->segID];
LOS_SpinLockSave(&seg->freeListLock, &intSave);
OsVmPhysPagesFreeContiguous(page, ONE_PAGE);
LOS_AtomicSet(&page->refCounts, 0);
OsVmPhysPagesFreeContiguous(page, ONE_PAGE);//释放一页
LOS_AtomicSet(&page->refCounts, 0);//只要物理内存被释放了,引用数就必须得重置为 0
LOS_SpinUnlockRestore(&seg->freeListLock, intSave);
}
@ -510,12 +568,22 @@ VOID LOS_PhysPageFree(LosVmPage *page)
OsMemLimitMemFree(PAGE_SIZE);
#endif
}
/// 申请一个物理页
LosVmPage *LOS_PhysPageAlloc(VOID)
{
return OsVmPhysPagesGet(ONE_PAGE);
return OsVmPhysPagesGet(ONE_PAGE);//分配一页物理页
}
/*!
* @brief LOS_PhysPagesAlloc nPages,list
\n ,nPages
*
* @param list
* @param nPages
* @return
*
* @see
*/
size_t LOS_PhysPagesAlloc(size_t nPages, LOS_DL_LIST *list)
{
LosVmPage *page = NULL;
@ -526,17 +594,17 @@ size_t LOS_PhysPagesAlloc(size_t nPages, LOS_DL_LIST *list)
}
while (nPages--) {
page = OsVmPhysPagesGet(ONE_PAGE);
page = OsVmPhysPagesGet(ONE_PAGE);//一页一页分配,由伙伴算法分配
if (page == NULL) {
break;
}
LOS_ListTailInsert(list, &page->node);
LOS_ListTailInsert(list, &page->node);//从参数链表list尾部挂入新页面结点
count++;
}
return count;
}
///拷贝共享页面
VOID OsPhysSharePageCopy(PADDR_T oldPaddr, PADDR_T *newPaddr, LosVmPage *newPage)
{
UINT32 intSave;
@ -550,43 +618,43 @@ VOID OsPhysSharePageCopy(PADDR_T oldPaddr, PADDR_T *newPaddr, LosVmPage *newPage
return;
}
oldPage = LOS_VmPageGet(oldPaddr);
oldPage = LOS_VmPageGet(oldPaddr);//由物理地址得到页框
if (oldPage == NULL) {
VM_ERR("invalid oldPaddr %p", oldPaddr);
return;
}
seg = &g_vmPhysSeg[oldPage->segID];
seg = &g_vmPhysSeg[oldPage->segID];//拿到物理段
LOS_SpinLockSave(&seg->freeListLock, &intSave);
if (LOS_AtomicRead(&oldPage->refCounts) == 1) {
*newPaddr = oldPaddr;
} else {
newMem = LOS_PaddrToKVaddr(*newPaddr);
oldMem = LOS_PaddrToKVaddr(oldPaddr);
if (LOS_AtomicRead(&oldPage->refCounts) == 1) {//页面引用次数仅一次,说明只有一个进程在操作
*newPaddr = oldPaddr;//新老指向同一块物理地址
} else {//是个共享内存
newMem = LOS_PaddrToKVaddr(*newPaddr); //新页虚拟地址
oldMem = LOS_PaddrToKVaddr(oldPaddr); //老页虚拟地址
if ((newMem == NULL) || (oldMem == NULL)) {
LOS_SpinUnlockRestore(&seg->freeListLock, intSave);
return;
}
if (memcpy_s(newMem, PAGE_SIZE, oldMem, PAGE_SIZE) != EOK) {
}//请记住,在保护模式下,物理地址只能用于计算,操作(包括拷贝)需要虚拟地址!
if (memcpy_s(newMem, PAGE_SIZE, oldMem, PAGE_SIZE) != EOK) {//老页内容复制给新页,需操作虚拟地址,拷贝一页数据
VM_ERR("memcpy_s failed");
}
LOS_AtomicInc(&newPage->refCounts);
LOS_AtomicDec(&oldPage->refCounts);
LOS_AtomicInc(&newPage->refCounts);//新页引用次数以原子方式自动减量
LOS_AtomicDec(&oldPage->refCounts);//老页引用次数以原子方式自动减量
}
LOS_SpinUnlockRestore(&seg->freeListLock, intSave);
return;
}
///获取物理页框所在段
struct VmPhysSeg *OsVmPhysSegGet(LosVmPage *page)
{
if ((page == NULL) || (page->segID >= VM_PHYS_SEG_MAX)) {
return NULL;
}
return (OsGVmPhysSegGet() + page->segID);
return (OsGVmPhysSegGet() + page->segID);//等用于OsGVmPhysSegGet()[page->segID]
}
///获取参数nPages对应的块组,例如 7 -> 2^3 返回 3
UINT32 OsVmPagesToOrder(size_t nPages)
{
UINT32 order;
@ -595,7 +663,7 @@ UINT32 OsVmPagesToOrder(size_t nPages)
return order;
}
///释放双链表中的所有节点内存,本质是回归到伙伴orderlist中
size_t LOS_PhysPagesFree(LOS_DL_LIST *list)
{
UINT32 intSave;
@ -608,16 +676,16 @@ size_t LOS_PhysPagesFree(LOS_DL_LIST *list)
return 0;
}
LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(page, nPage, list, LosVmPage, node) {
LOS_ListDelete(&page->node);
if (LOS_AtomicDecRet(&page->refCounts) <= 0) {
seg = &g_vmPhysSeg[page->segID];
LOS_SpinLockSave(&seg->freeListLock, &intSave);
OsVmPhysPagesFreeContiguous(page, ONE_PAGE);
LOS_AtomicSet(&page->refCounts, 0);
LOS_SpinUnlockRestore(&seg->freeListLock, intSave);
LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(page, nPage, list, LosVmPage, node) {//宏循环
LOS_ListDelete(&page->node);//先把自己摘出去
if (LOS_AtomicDecRet(&page->refCounts) <= 0) {//无引用
seg = &g_vmPhysSeg[page->segID];//获取物理段
LOS_SpinLockSave(&seg->freeListLock, &intSave);//锁住freeList
OsVmPhysPagesFreeContiguous(page, ONE_PAGE);//连续释放,注意这里的ONE_PAGE其实有误导,让人以为是释放4K,其实是指连续的物理页框,如果3页连在一块是一起释放的.
LOS_AtomicSet(&page->refCounts, 0);//引用重置为0
LOS_SpinUnlockRestore(&seg->freeListLock, intSave);//恢复锁
}
count++;
count++;//继续取下一个node
}
return count;

@ -37,6 +37,10 @@
#ifdef LOSCFG_KERNEL_VM
/* unmap a lru page by map record info caller need lru lock */
/**************************************************************************************************
(mmu)
infoMMU
**************************************************************************************************/
VOID OsUnmapPageLocked(LosFilePage *page, LosMapInfo *info)
{
if (page == NULL || info == NULL) {
@ -47,88 +51,88 @@ VOID OsUnmapPageLocked(LosFilePage *page, LosMapInfo *info)
LOS_ListDelete(&info->node);
LOS_AtomicDec(&page->vmPage->refCounts);
LOS_ArchMmuUnmap(info->archMmu, info->vaddr, 1);
LOS_MemFree(m_aucSysMem0, info);
LOS_MemFree(m_aucSysMem0, info);//释放虚拟
}
///解除文件页在所有进程的映射
VOID OsUnmapAllLocked(LosFilePage *page)
{
LosMapInfo *info = NULL;
LosMapInfo *next = NULL;
LOS_DL_LIST *immap = &page->i_mmap;
LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(info, next, immap, LosMapInfo, node) {
LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(info, next, immap, LosMapInfo, node) {//遍历 immap->info 链表
OsUnmapPageLocked(page, info);
}
}
/* add a new lru node to lru list, lruType can be file or anon */
VOID OsLruCacheAdd(LosFilePage *fpage, enum OsLruList lruType)
VOID OsLruCacheAdd(LosFilePage *fpage, enum OsLruList lruType)//在lru列表中添加一个新的lru节点lruType可以是文件或匿名
{
UINT32 intSave;
LosVmPhysSeg *physSeg = fpage->physSeg;
LosVmPage *page = fpage->vmPage;
LosVmPhysSeg *physSeg = fpage->physSeg; //得到页面对应段
LosVmPage *page = fpage->vmPage; //得到物理页面
LOS_SpinLockSave(&physSeg->lruLock, &intSave);
OsSetPageActive(page);
OsCleanPageReferenced(page);
physSeg->lruSize[lruType]++;
LOS_ListTailInsert(&physSeg->lruList[lruType], &fpage->lru);
LOS_SpinLockSave(&physSeg->lruLock, &intSave);//自旋锁:最多只能被一个内核持有CPU内核 互斥锁
OsSetPageActive(page); //设置页面为活动页
OsCleanPageReferenced(page);//清除页面被引用位
physSeg->lruSize[lruType]++; //lruType页总size++
LOS_ListTailInsert(&physSeg->lruList[lruType], &fpage->lru);//加入lruType页双循环链表中
LOS_SpinUnlockRestore(&physSeg->lruLock, intSave);
LOS_SpinUnlockRestore(&physSeg->lruLock, intSave);//解锁
}
/* delete a lru node, caller need hold lru_lock */
VOID OsLruCacheDel(LosFilePage *fpage)
/* dellete a lru node, caller need hold lru_lock */
VOID OsLruCacheDel(LosFilePage *fpage)//删除lru节点调用者需要拿到lru锁
{
LosVmPhysSeg *physSeg = fpage->physSeg;
int type = OsIsPageActive(fpage->vmPage) ? VM_LRU_ACTIVE_FILE : VM_LRU_INACTIVE_FILE;
LosVmPhysSeg *physSeg = fpage->physSeg; //得到页面对应段
int type = OsIsPageActive(fpage->vmPage) ? VM_LRU_ACTIVE_FILE : VM_LRU_INACTIVE_FILE;//得到页面LRU类型
physSeg->lruSize[type]--;
LOS_ListDelete(&fpage->lru);
physSeg->lruSize[type]--; //type页总size--
LOS_ListDelete(&fpage->lru);//将自己从lru链表中摘出来
}
///非活动文件页低于活动文件页吗
BOOL OsInactiveListIsLow(LosVmPhysSeg *physSeg)
{
return (physSeg->lruSize[VM_LRU_ACTIVE_FILE] >
physSeg->lruSize[VM_LRU_INACTIVE_FILE]) ? TRUE : FALSE;
physSeg->lruSize[VM_LRU_INACTIVE_FILE]) ? TRUE : FALSE;//直接对比size效率杠杠的
}
/* move a page from inactive list to active list head */
STATIC INLINE VOID OsMoveToActiveList(LosFilePage *fpage)
STATIC INLINE VOID OsMoveToActiveList(LosFilePage *fpage)//将页面从非活动列表移动到活动列表
{
LosVmPhysSeg *physSeg = fpage->physSeg;
LosVmPhysSeg *physSeg = fpage->physSeg; //得到页面对应段
physSeg->lruSize[VM_LRU_ACTIVE_FILE]++;
physSeg->lruSize[VM_LRU_INACTIVE_FILE]--;
LOS_ListDelete(&fpage->lru);
LOS_ListTailInsert(&physSeg->lruList[VM_LRU_ACTIVE_FILE], &fpage->lru);
physSeg->lruSize[VM_LRU_ACTIVE_FILE]++; //活动页总size++
physSeg->lruSize[VM_LRU_INACTIVE_FILE]--; //不活动页总size--
LOS_ListDelete(&fpage->lru); //将自己从lru链表中摘出来
LOS_ListTailInsert(&physSeg->lruList[VM_LRU_ACTIVE_FILE], &fpage->lru);//加入活动页双循环链表中
}
/* move a page from active list to inactive list head */
STATIC INLINE VOID OsMoveToInactiveList(LosFilePage *fpage)
STATIC INLINE VOID OsMoveToInactiveList(LosFilePage *fpage)//将页面从活动列表移动到非活动列表
{
LosVmPhysSeg *physSeg = fpage->physSeg;
LosVmPhysSeg *physSeg = fpage->physSeg; //得到页面对应段
physSeg->lruSize[VM_LRU_ACTIVE_FILE]--;
physSeg->lruSize[VM_LRU_INACTIVE_FILE]++;
LOS_ListDelete(&fpage->lru);
LOS_ListTailInsert(&physSeg->lruList[VM_LRU_INACTIVE_FILE], &fpage->lru);
physSeg->lruSize[VM_LRU_ACTIVE_FILE]--; //活动页总size--
physSeg->lruSize[VM_LRU_INACTIVE_FILE]++; //不活动页总size++
LOS_ListDelete(&fpage->lru); //将自己从lru链表中摘出来
LOS_ListTailInsert(&physSeg->lruList[VM_LRU_INACTIVE_FILE], &fpage->lru);//加入不活动页双循环链表中
}
/* move a page to the most active pos in lru list(active head) */
/* move a page to the most active pos in lru list(active head) *///将页面移至lru列表中最活跃的位置
STATIC INLINE VOID OsMoveToActiveHead(LosFilePage *fpage)
{
LosVmPhysSeg *physSeg = fpage->physSeg;
LOS_ListDelete(&fpage->lru);
LOS_ListTailInsert(&physSeg->lruList[VM_LRU_ACTIVE_FILE], &fpage->lru);
LosVmPhysSeg *physSeg = fpage->physSeg; //得到页面对应段
LOS_ListDelete(&fpage->lru); //将自己从lru链表中摘出来
LOS_ListTailInsert(&physSeg->lruList[VM_LRU_ACTIVE_FILE], &fpage->lru);//加入活动页双循环链表中
}
/* move a page to the most active pos in lru list(inactive head) */
STATIC INLINE VOID OsMoveToInactiveHead(LosFilePage *fpage)
STATIC INLINE VOID OsMoveToInactiveHead(LosFilePage *fpage)//鸿蒙会从inactive链表的尾部开始进行回收,跟linux一样
{
LosVmPhysSeg *physSeg = fpage->physSeg;
LOS_ListDelete(&fpage->lru);
LOS_ListTailInsert(&physSeg->lruList[VM_LRU_INACTIVE_FILE], &fpage->lru);
LosVmPhysSeg *physSeg = fpage->physSeg; //得到页面对应段
LOS_ListDelete(&fpage->lru); //将自己从lru链表中摘出来
LOS_ListTailInsert(&physSeg->lruList[VM_LRU_INACTIVE_FILE], &fpage->lru);//加入不活动页双循环链表中
}
/* page referced add: (call by page cache get)
@ -138,7 +142,7 @@ ref:0, act:0 --> ref:1, act:0
ref:1, act:0 --> ref:0, act:1
ref:0, act:1 --> ref:1, act:1
*/
VOID OsPageRefIncLocked(LosFilePage *fpage)
VOID OsPageRefIncLocked(LosFilePage *fpage)// ref ,act 标签转换功能
{
BOOL isOrgActive;
UINT32 intSave;
@ -148,16 +152,16 @@ VOID OsPageRefIncLocked(LosFilePage *fpage)
return;
}
LOS_SpinLockSave(&fpage->physSeg->lruLock, &intSave);
LOS_SpinLockSave(&fpage->physSeg->lruLock, &intSave);//要处理lruList,先拿锁
page = fpage->vmPage;
isOrgActive = OsIsPageActive(page);
page = fpage->vmPage;//拿到物理页框
isOrgActive = OsIsPageActive(page);//页面是否在活动
if (OsIsPageReferenced(page) && !OsIsPageActive(page)) {
OsCleanPageReferenced(page);
OsSetPageActive(page);
if (OsIsPageReferenced(page) && !OsIsPageActive(page)) {//身兼 不活动和引用标签
OsCleanPageReferenced(page);//撕掉引用标签 ref:1, act:0 --> ref:0, act:1
OsSetPageActive(page); //贴上活动标签
} else if (!OsIsPageReferenced(page)) {
OsSetPageReferenced(page);
OsSetPageReferenced(page);//ref:0, act:0 --> ref:1, act:0
}
if (!isOrgActive && OsIsPageActive(page)) {
@ -175,14 +179,14 @@ VOID OsPageRefIncLocked(LosFilePage *fpage)
LOS_SpinUnlockRestore(&fpage->physSeg->lruLock, intSave);
}
/* page referced dec: (call by shrinker)
/* page referced dec: (call by thrinker)
----------inactive----------|----------active------------
[ref:0,act:0], [ref:1,act:0]|[ref:0,act:1], [ref:1,act:1]
ref:1, act:1 --> ref:0, act:1
ref:0, act:1 --> ref:1, act:0
ref:1, act:0 --> ref:0, act:0
*/
VOID OsPageRefDecNoLock(LosFilePage *fpage)
VOID OsPageRefDecNoLock(LosFilePage *fpage) // ref ,act 标签转换功能
{
BOOL isOrgActive;
LosVmPage *page = NULL;
@ -194,7 +198,7 @@ VOID OsPageRefDecNoLock(LosFilePage *fpage)
page = fpage->vmPage;
isOrgActive = OsIsPageActive(page);
if (!OsIsPageReferenced(page) && OsIsPageActive(page)) {
if (!OsIsPageReferenced(page) && OsIsPageActive(page)) {//[ref:0,act:1]的情况
OsCleanPageActive(page);
OsSetPageReferenced(page);
} else if (OsIsPageReferenced(page)) {
@ -205,39 +209,39 @@ VOID OsPageRefDecNoLock(LosFilePage *fpage)
OsMoveToInactiveList(fpage);
}
}
///缩小活动页链表
VOID OsShrinkActiveList(LosVmPhysSeg *physSeg, int nScan)
{
LosFilePage *fpage = NULL;
LosFilePage *fnext = NULL;
LOS_DL_LIST *activeFile = &physSeg->lruList[VM_LRU_ACTIVE_FILE];
LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(fpage, fnext, activeFile, LosFilePage, lru) {
if (LOS_SpinTrylock(&fpage->mapping->list_lock) != LOS_OK) {
continue;
LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(fpage, fnext, activeFile, LosFilePage, lru) {//一页一页处理
if (LOS_SpinTrylock(&fpage->mapping->list_lock) != LOS_OK) {//尝试获取文件页所在的page_mapping锁
continue;//接着处理下一文件页
}
/* happened when caller hold cache lock and try reclaim this page */
if (OsIsPageLocked(fpage->vmPage)) {
LOS_SpinUnlock(&fpage->mapping->list_lock);
continue;
/* happend when caller hold cache lock and try reclaim this page *///调用方持有缓存锁并尝试回收此页时发生
if (OsIsPageLocked(fpage->vmPage)) {//页面是否被锁
LOS_SpinUnlock(&fpage->mapping->list_lock);//失败时,一定要释放page_mapping锁.
continue;//接着处理下一文件页
}
if (OsIsPageMapped(fpage) && (fpage->flags & VM_MAP_REGION_FLAG_PERM_EXECUTE)) {
LOS_SpinUnlock(&fpage->mapping->list_lock);
continue;
if (OsIsPageMapped(fpage) && (fpage->flags & VM_MAP_REGION_FLAG_PERM_EXECUTE)) {//文件页是否被映射而且是个可执行文件 ?
LOS_SpinUnlock(&fpage->mapping->list_lock);//是时,一定要释放page_mapping锁.
continue;//接着处理下一文件页
}
//找了可以收缩的文件页
OsPageRefDecNoLock(fpage); //将页面移到未活动文件链表
OsPageRefDecNoLock(fpage);
LOS_SpinUnlock(&fpage->mapping->list_lock);
LOS_SpinUnlock(&fpage->mapping->list_lock); //释放page_mapping锁.
if (--nScan <= 0) {
break;
}
}
}
///缩小未活动页链表
int OsShrinkInactiveList(LosVmPhysSeg *physSeg, int nScan, LOS_DL_LIST *list)
{
UINT32 nrReclaimed = 0;
@ -248,36 +252,36 @@ int OsShrinkInactiveList(LosVmPhysSeg *physSeg, int nScan, LOS_DL_LIST *list)
LosFilePage *ftemp = NULL;
LOS_DL_LIST *inactive_file = &physSeg->lruList[VM_LRU_INACTIVE_FILE];
LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(fpage, fnext, inactive_file, LosFilePage, lru) {
LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(fpage, fnext, inactive_file, LosFilePage, lru) {//遍历链表一页一页处理
flock = &fpage->mapping->list_lock;
if (LOS_SpinTrylock(flock) != LOS_OK) {
continue;
if (LOS_SpinTrylock(flock) != LOS_OK) {//尝试获取文件页所在的page_mapping锁
continue;//接着处理下一文件页
}
page = fpage->vmPage;
if (OsIsPageLocked(page)) {
page = fpage->vmPage;//获取物理页框
if (OsIsPageLocked(page)) {//页面是否被锁
LOS_SpinUnlock(flock);
continue;
continue;//接着处理下一文件页
}
if (OsIsPageMapped(fpage) && (OsIsPageDirty(page) || (fpage->flags & VM_MAP_REGION_FLAG_PERM_EXECUTE))) {
LOS_SpinUnlock(flock);
continue;
LOS_SpinUnlock(flock);//文件页是否被映射而且是个脏页获取是个可执行文件 ?
continue;//接着处理下一文件页
}
if (OsIsPageDirty(page)) {
ftemp = OsDumpDirtyPage(fpage);
if (ftemp != NULL) {
LOS_ListTailInsert(list, &ftemp->node);
if (OsIsPageDirty(page)) {//是脏页
ftemp = OsDumpDirtyPage(fpage);//备份脏页
if (ftemp != NULL) {//备份成功了
LOS_ListTailInsert(list, &ftemp->node);//将脏页挂到参数链表上带走
}
}
OsDeletePageCacheLru(fpage);
OsDeletePageCacheLru(fpage);//将文件页从LRU和pagecache上摘除
LOS_SpinUnlock(flock);
nrReclaimed++;
nrReclaimed++;//成功回收了一页
if (--nScan <= 0) {
if (--nScan <= 0) {//继续回收
break;
}
}
@ -286,48 +290,48 @@ int OsShrinkInactiveList(LosVmPhysSeg *physSeg, int nScan, LOS_DL_LIST *list)
}
#ifdef LOSCFG_FS_VFS
int OsTryShrinkMemory(size_t nPage)
int OsTryShrinkMemory(size_t nPage)//尝试收缩文件页
{
UINT32 intSave;
size_t totalPages;
size_t nReclaimed = 0;
LosVmPhysSeg *physSeg = NULL;
UINT32 index;
LOS_DL_LIST_HEAD(dirtyList);
LOS_DL_LIST_HEAD(dirtyList);//初始化脏页链表,上面将挂所有脏页用于同步到磁盘后回收
LosFilePage *fpage = NULL;
LosFilePage *fnext = NULL;
if (nPage == 0) {
nPage = VM_FILEMAP_MIN_SCAN;
nPage = VM_FILEMAP_MIN_SCAN;//
}
if (nPage > VM_FILEMAP_MAX_SCAN) {
nPage = VM_FILEMAP_MAX_SCAN;
}
for (index = 0; index < g_vmPhysSegNum; index++) {
physSeg = &g_vmPhysSeg[index];
for (index = 0; index < g_vmPhysSegNum; index++) {//遍历整个物理段组
physSeg = &g_vmPhysSeg[index];//一段段来
LOS_SpinLockSave(&physSeg->lruLock, &intSave);
totalPages = physSeg->lruSize[VM_LRU_ACTIVE_FILE] + physSeg->lruSize[VM_LRU_INACTIVE_FILE];
if (totalPages < VM_FILEMAP_MIN_SCAN) {
totalPages = physSeg->lruSize[VM_LRU_ACTIVE_FILE] + physSeg->lruSize[VM_LRU_INACTIVE_FILE];//统计所有文件页
if (totalPages < VM_FILEMAP_MIN_SCAN) {//文件页占用内存不多的情况下,怎么处理?
LOS_SpinUnlockRestore(&physSeg->lruLock, intSave);
continue;
continue;//放过这一段,找下一段
}
if (OsInactiveListIsLow(physSeg)) {
OsShrinkActiveList(physSeg, (nPage < VM_FILEMAP_MIN_SCAN) ? VM_FILEMAP_MIN_SCAN : nPage);
OsShrinkActiveList(physSeg, (nPage < VM_FILEMAP_MIN_SCAN) ? VM_FILEMAP_MIN_SCAN : nPage);//缩小活动页
}
nReclaimed += OsShrinkInactiveList(physSeg, nPage, &dirtyList);
nReclaimed += OsShrinkInactiveList(physSeg, nPage, &dirtyList);//缩小未活动页,带出脏页链表
LOS_SpinUnlockRestore(&physSeg->lruLock, intSave);
if (nReclaimed >= nPage) {
break;
if (nReclaimed >= nPage) {//够了,够了,达到目的了.
break;//退出收缩
}
}
LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(fpage, fnext, &dirtyList, LosFilePage, node) {
OsDoFlushDirtyPage(fpage);
LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(fpage, fnext, &dirtyList, LosFilePage, node) {//遍历处理脏页数据
OsDoFlushDirtyPage(fpage);//冲洗脏页数据,将脏页数据回写磁盘
}
return nReclaimed;

@ -65,7 +65,7 @@ STATUS_T OsCheckMMapParams(VADDR_T *vaddr, unsigned long flags, size_t len, unsi
return -EINVAL;
}
if ((flags & MAP_SUPPORT_MASK) == 0) {
if ((flags & MAP_SUPPORT_MASK) == 0) {//映射权限限制
return -EINVAL;
}
if (((flags & MAP_SHARED_PRIVATE) == 0) || ((flags & MAP_SHARED_PRIVATE) == MAP_SHARED_PRIVATE)) {
@ -95,20 +95,64 @@ STATUS_T OsNamedMmapingPermCheck(struct file *filep, unsigned long flags, unsign
return LOS_OK;
}
///匿名映射
STATUS_T OsAnonMMap(LosVmMapRegion *region)
{
LOS_SetRegionTypeAnon(region);
return LOS_OK;
}
/**
* @brief
@verbatim
mmap:
.
read,write
https://www.cnblogs.com/huxiao-tee/p/4660352.html
http://abcdxyzk.github.io/blog/2015/09/11/kernel-mm-mmap/
addr NULL
length
prot 访
PROT_EXEC
PROT_READ
PROT_WRITE
PROT_NONE
flags
MAP_FIXED start
MAP_SHARED
MAP_PRIVATE copy on write
MAP_ANONYMOUSfd
MAP_DENYWRITE
MAP_LOCKED swap
fd: 使flagsMAP_ANONYMOUSfd-1
使fopen/dev/zero
offset 0offsetPAGE_SIZE
(void *)-1
@endverbatim
* @param vaddr
* @param len
* @param prot
* @param flags
* @param fd
* @param pgoff
* @return VADDR_T
*/
VADDR_T LOS_MMap(VADDR_T vaddr, size_t len, unsigned prot, unsigned long flags, int fd, unsigned long pgoff)
{
STATUS_T status;
VADDR_T resultVaddr;
UINT32 regionFlags;
LosVmMapRegion *newRegion = NULL;
struct file *filep = NULL;
LosVmMapRegion *newRegion = NULL;//应用的内存分配对应到内核就是分配一个线性区
struct file *filep = NULL;// inode : file = 1:N ,一对多关系,一个inode可以被多个进程打开,返回不同的file但都指向同一个inode
LosVmSpace *vmSpace = OsCurrProcessGet()->vmSpace;
len = ROUNDUP(len, PAGE_SIZE);
@ -116,9 +160,9 @@ VADDR_T LOS_MMap(VADDR_T vaddr, size_t len, unsigned prot, unsigned long flags,
if (checkRst != LOS_OK) {
return checkRst;
}
if (LOS_IsNamedMapping(flags)) {
status = fs_getfilep(fd, &filep);
if (LOS_IsNamedMapping(flags)) {//是否文件映射
status = fs_getfilep(fd, &filep);//获取文件描述符和状态
if (status < 0) {
return -EBADF;
}
@ -131,30 +175,30 @@ VADDR_T LOS_MMap(VADDR_T vaddr, size_t len, unsigned prot, unsigned long flags,
(VOID)LOS_MuxAcquire(&vmSpace->regionMux);
/* user mode calls mmap to release heap physical memory without releasing heap virtual space */
status = OsUserHeapFree(vmSpace, vaddr, len);
if (status == LOS_OK) {
status = OsUserHeapFree(vmSpace, vaddr, len);//用户模式释放堆物理内存而不释放堆虚拟空间
if (status == LOS_OK) {//OsUserHeapFree 干两件事 1.解除映射关系 2.释放物理页
resultVaddr = vaddr;
goto MMAP_DONE;
}
regionFlags = OsCvtProtFlagsToRegionFlags(prot, flags);
newRegion = LOS_RegionAlloc(vmSpace, vaddr, len, regionFlags, pgoff);
//地址不在堆区
regionFlags = OsCvtProtFlagsToRegionFlags(prot, flags);//将参数flag转换Region的flag
newRegion = LOS_RegionAlloc(vmSpace, vaddr, len, regionFlags, pgoff);//分配一个线性区
if (newRegion == NULL) {
resultVaddr = (VADDR_T)-ENOMEM;
resultVaddr = (VADDR_T)-ENOMEM;//ENOMEM:内存溢出
goto MMAP_DONE;
}
newRegion->regionFlags |= VM_MAP_REGION_FLAG_MMAP;
resultVaddr = newRegion->range.base;
resultVaddr = newRegion->range.base;//线性区基地址为分配的地址
if (LOS_IsNamedMapping(flags)) {
status = OsNamedMMap(filep, newRegion);
status = OsNamedMMap(filep, newRegion);//文件映射
} else {
status = OsAnonMMap(newRegion);
status = OsAnonMMap(newRegion);//匿名映射
}
if (status != LOS_OK) {
LOS_RbDelNode(&vmSpace->regionRbTree, &newRegion->rbNode);
LOS_RegionFree(vmSpace, newRegion);
LOS_RbDelNode(&vmSpace->regionRbTree, &newRegion->rbNode);//从红黑树和双循环链表中删除
LOS_RegionFree(vmSpace, newRegion);//释放
resultVaddr = (VADDR_T)-ENOMEM;
goto MMAP_DONE;
}
@ -163,7 +207,7 @@ MMAP_DONE:
(VOID)LOS_MuxRelease(&vmSpace->regionMux);
return resultVaddr;
}
///解除映射关系
STATUS_T LOS_UnMMap(VADDR_T addr, size_t size)
{
if ((addr <= 0) || (size == 0)) {
@ -172,7 +216,6 @@ STATUS_T LOS_UnMMap(VADDR_T addr, size_t size)
return OsUnMMap(OsCurrProcessGet()->vmSpace, addr, size);
}
STATIC INLINE BOOL OsProtMprotectPermCheck(unsigned long prot, LosVmMapRegion *region)
{
UINT32 protFlags = 0;
@ -186,20 +229,33 @@ STATIC INLINE BOOL OsProtMprotectPermCheck(unsigned long prot, LosVmMapRegion *r
return ((protFlags & permFlags) == protFlags);
}
/// 收缩堆区
VOID *OsShrinkHeap(VOID *addr, LosVmSpace *space)
{
VADDR_T newBrk, oldBrk;
newBrk = LOS_Align((VADDR_T)(UINTPTR)addr, PAGE_SIZE);
oldBrk = LOS_Align(space->heapNow, PAGE_SIZE);
if (LOS_UnMMap(newBrk, (oldBrk - newBrk)) < 0) {
return (void *)(UINTPTR)space->heapNow;
newBrk = LOS_Align((VADDR_T)(UINTPTR)addr, PAGE_SIZE);//新堆顶
oldBrk = LOS_Align(space->heapNow, PAGE_SIZE);//旧堆顶
if (LOS_UnMMap(newBrk, (oldBrk - newBrk)) < 0) {//解除相差区的映射
return (void *)(UINTPTR)space->heapNow;//解除失败就持续现有的
}
space->heapNow = (VADDR_T)(UINTPTR)addr;
space->heapNow = (VADDR_T)(UINTPTR)addr;//返回新堆顶
return addr;
}
/**
* @brief
@verbatim
线线
线
线线线
线
@endverbatim
* @param addr
* @return VOID*
*/
VOID *LOS_DoBrk(VOID *addr)
{
LosVmSpace *space = OsCurrProcessGet()->vmSpace;
@ -209,60 +265,60 @@ VOID *LOS_DoBrk(VOID *addr)
VOID *alignAddr = NULL;
VOID *shrinkAddr = NULL;
if (addr == NULL) {
return (void *)(UINTPTR)space->heapNow;
if (addr == NULL) {//参数地址未传情况
return (void *)(UINTPTR)space->heapNow;//以现有指向地址为基础进行扩展
}
if ((UINTPTR)addr < (UINTPTR)space->heapBase) {
if ((UINTPTR)addr < (UINTPTR)space->heapBase) {//heapBase是堆区的开始地址所以参数地址不能低于它
return (VOID *)-ENOMEM;
}
size = (UINTPTR)addr - (UINTPTR)space->heapBase;
size = ROUNDUP(size, PAGE_SIZE);
alignAddr = (CHAR *)(UINTPTR)(space->heapBase) + size;
size = (UINTPTR)addr - (UINTPTR)space->heapBase;//算出大小
size = ROUNDUP(size, PAGE_SIZE); //圆整size
alignAddr = (CHAR *)(UINTPTR)(space->heapBase) + size;//得到新的线性区的结束地址
PRINT_INFO("brk addr %p , size 0x%x, alignAddr %p, align %d\n", addr, size, alignAddr, PAGE_SIZE);
(VOID)LOS_MuxAcquire(&space->regionMux);
if (addr < (VOID *)(UINTPTR)space->heapNow) {
shrinkAddr = OsShrinkHeap(addr, space);
if (addr < (VOID *)(UINTPTR)space->heapNow) {//如果地址小于堆区现地址
shrinkAddr = OsShrinkHeap(addr, space);//收缩堆区
(VOID)LOS_MuxRelease(&space->regionMux);
return shrinkAddr;
}
if ((UINTPTR)alignAddr >= space->mapBase) {
VM_ERR("Process heap memory space is insufficient");
if ((UINTPTR)alignAddr >= space->mapBase) {//参数地址 大于映射区地址
VM_ERR("Process heap memory space is insufficient");//进程堆空间不足
ret = (VOID *)-ENOMEM;
goto REGION_ALLOC_FAILED;
}
if (space->heapBase == space->heapNow) {
region = LOS_RegionAlloc(space, space->heapBase, size,
VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE |
if (space->heapBase == space->heapNow) {//往往是第一次调用本函数才会出现,因为初始化时 heapBase = heapNow
region = LOS_RegionAlloc(space, space->heapBase, size,//分配一个可读/可写/可使用的线性区,只需分配一次
VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE |//线性区的大小由range.size决定
VM_MAP_REGION_FLAG_FIXED | VM_MAP_REGION_FLAG_PERM_USER, 0);
if (region == NULL) {
ret = (VOID *)-ENOMEM;
VM_ERR("LOS_RegionAlloc failed");
goto REGION_ALLOC_FAILED;
}
region->regionFlags |= VM_MAP_REGION_FLAG_HEAP;
space->heap = region;
region->regionFlags |= VM_MAP_REGION_FLAG_HEAP;//贴上线性区类型为堆区的标签,注意一个线性区可以有多种标签
space->heap = region;//指定线性区为堆区
}
space->heapNow = (VADDR_T)(UINTPTR)alignAddr;
space->heap->range.size = size;
ret = (VOID *)(UINTPTR)space->heapNow;
space->heapNow = (VADDR_T)(UINTPTR)alignAddr;//更新堆区顶部位置
space->heap->range.size = size; //更新堆区大小,经此操作线性区变大或缩小了
ret = (VOID *)(UINTPTR)space->heapNow;//返回堆顶
REGION_ALLOC_FAILED:
(VOID)LOS_MuxRelease(&space->regionMux);
return ret;
}
/// 继承老线性区的标签
STATIC UINT32 OsInheritOldRegionName(UINT32 oldRegionFlags)
{
UINT32 vmFlags = 0;
if (oldRegionFlags & VM_MAP_REGION_FLAG_HEAP) {
vmFlags |= VM_MAP_REGION_FLAG_HEAP;
if (oldRegionFlags & VM_MAP_REGION_FLAG_HEAP) { //如果是从大堆区中申请的
vmFlags |= VM_MAP_REGION_FLAG_HEAP; //线性区则贴上堆区标签
} else if (oldRegionFlags & VM_MAP_REGION_FLAG_STACK) {
vmFlags |= VM_MAP_REGION_FLAG_STACK;
} else if (oldRegionFlags & VM_MAP_REGION_FLAG_TEXT) {
@ -277,7 +333,7 @@ STATIC UINT32 OsInheritOldRegionName(UINT32 oldRegionFlags)
return vmFlags;
}
///修改内存段的访问权限
INT32 LOS_DoMprotect(VADDR_T vaddr, size_t len, unsigned long prot)
{
LosVmSpace *space = OsCurrProcessGet()->vmSpace;
@ -287,7 +343,7 @@ INT32 LOS_DoMprotect(VADDR_T vaddr, size_t len, unsigned long prot)
int ret;
(VOID)LOS_MuxAcquire(&space->regionMux);
region = LOS_RegionFind(space, vaddr);
region = LOS_RegionFind(space, vaddr);//通过虚拟地址找到线性区
if (!IS_ALIGNED(vaddr, PAGE_SIZE) || (region == NULL) || (vaddr > vaddr + len)) {
ret = -EINVAL;
goto OUT_MPROTECT;
@ -297,19 +353,18 @@ INT32 LOS_DoMprotect(VADDR_T vaddr, size_t len, unsigned long prot)
ret = -EINVAL;
goto OUT_MPROTECT;
}
//如果是堆区或VDSO区,说明区内容是不能修改的
if ((region->regionFlags & VM_MAP_REGION_FLAG_VDSO) || (region->regionFlags & VM_MAP_REGION_FLAG_HEAP)) {
ret = -EPERM;
goto OUT_MPROTECT;
}
//如果是共享文件,说明内容也不能修改
if (LOS_IsRegionTypeFile(region) && (region->regionFlags & VM_MAP_REGION_FLAG_SHARED)) {
if (!OsProtMprotectPermCheck(prot, region)) {
ret = -EACCES;
goto OUT_MPROTECT;
}
}
len = LOS_Align(len, PAGE_SIZE);
/* can't operation cross region */
if ((region->range.base + region->range.size) < (vaddr + len)) {
@ -318,11 +373,11 @@ INT32 LOS_DoMprotect(VADDR_T vaddr, size_t len, unsigned long prot)
}
/* if only move some part of region, we need to split first */
if (region->range.size > len) {
OsVmRegionAdjust(space, vaddr, len);
if (region->range.size > len) {//如果只修改部分区域,我们需要先拆分区
OsVmRegionAdjust(space, vaddr, len);//调整下线性区范围
}
vmFlags = OsCvtProtFlagsToRegionFlags(prot, 0);
vmFlags = OsCvtProtFlagsToRegionFlags(prot, 0);//转换FLAGS
vmFlags |= (region->regionFlags & VM_MAP_REGION_FLAG_SHARED) ? VM_MAP_REGION_FLAG_SHARED : 0;
vmFlags |= OsInheritOldRegionName(region->regionFlags);
region = LOS_RegionFind(space, vaddr);
@ -332,7 +387,7 @@ INT32 LOS_DoMprotect(VADDR_T vaddr, size_t len, unsigned long prot)
}
region->regionFlags = vmFlags;
count = len >> PAGE_SHIFT;
ret = LOS_ArchMmuChangeProt(&space->archMmu, vaddr, count, region->regionFlags);
ret = LOS_ArchMmuChangeProt(&space->archMmu, vaddr, count, region->regionFlags);//修改访问权限实体函数
if (ret) {
ret = -ENOMEM;
goto OUT_MPROTECT;
@ -387,7 +442,7 @@ STATUS_T OsMremapCheck(VADDR_T addr, size_t oldLen, VADDR_T newAddr, size_t newL
}
}
/* avoid new region overlapping with the old one */
/* avoid new region overlaping with the old one */
if (flags & MREMAP_FIXED) {
if (((region->range.base + region->range.size) > newAddr) &&
(region->range.base < (newAddr + newLen))) {
@ -401,7 +456,7 @@ STATUS_T OsMremapCheck(VADDR_T addr, size_t oldLen, VADDR_T newAddr, size_t newL
return LOS_OK;
}
///重新映射虚拟内存地址。
VADDR_T LOS_DoMremap(VADDR_T oldAddress, size_t oldSize, size_t newSize, int flags, VADDR_T newAddr)
{
LosVmMapRegion *regionOld = NULL;
@ -496,7 +551,7 @@ OUT_MREMAP:
(VOID)LOS_MuxRelease(&space->regionMux);
return ret;
}
///输出内存线性区
VOID LOS_DumpMemRegion(VADDR_T vaddr)
{
LosVmSpace *space = NULL;
@ -506,12 +561,12 @@ VOID LOS_DumpMemRegion(VADDR_T vaddr)
return;
}
if (LOS_IsRangeInSpace(space, ROUNDDOWN(vaddr, MB), MB) == FALSE) {
if (LOS_IsRangeInSpace(space, ROUNDDOWN(vaddr, MB), MB) == FALSE) {//是否在空间范围内
return;
}
OsDumpPte(vaddr);
OsDumpAspace(space);
OsDumpPte(vaddr);//dump L1 L2
OsDumpAspace(space);//dump 空间
}
#endif

@ -47,8 +47,8 @@
#ifdef LOSCFG_KERNEL_VM
LITE_OS_SEC_BSS OomCB *g_oomCB = NULL;
static SPIN_LOCK_INIT(g_oomSpinLock);
LITE_OS_SEC_BSS OomCB *g_oomCB = NULL; //全局内存溢出控制块
static SPIN_LOCK_INIT(g_oomSpinLock);//内存溢出自旋锁
LITE_OS_SEC_TEXT_MINOR STATIC UINT32 OomScoreProcess(LosProcessCB *candidateProcess)
{
@ -57,20 +57,20 @@ LITE_OS_SEC_TEXT_MINOR STATIC UINT32 OomScoreProcess(LosProcessCB *candidateProc
#ifndef LOSCFG_KERNEL_SMP
(VOID)LOS_MuxAcquire(&candidateProcess->vmSpace->regionMux);
#endif
/* we only consider actual physical memory here. */
/* we only consider actual physical memory here. */ //只考虑实际的物理内存
OsUProcessPmUsage(candidateProcess->vmSpace, NULL, &actualPm);
#ifndef LOSCFG_KERNEL_SMP
(VOID)LOS_MuxRelease(&candidateProcess->vmSpace->regionMux);
#endif
return actualPm;
}
///用于设置 g_oomCB->processVictimCB 回调函数
LITE_OS_SEC_TEXT_MINOR STATIC UINT32 OomKillProcess(UINTPTR param)
{
/* we will not kill process, and do nothing here */
return LOS_OK;
}
///强制收缩内存
LITE_OS_SEC_TEXT_MINOR STATIC UINT32 OomForceShrinkMemory(VOID)
{
UINT32 i;
@ -80,13 +80,14 @@ LITE_OS_SEC_TEXT_MINOR STATIC UINT32 OomForceShrinkMemory(VOID)
* TryShrinkMemory maybe reclaim 0 pages in the first time from active list
* to inactive list, and in the second time reclaim memory from inactive list.
*/
//TryShrinkMemory可能会在第一时间从活动列表中回收0页到非活动列表并在第二次从非活动列表中回收内存。
for (i = 0; i < MAX_SHRINK_PAGECACHE_TRY; i++) {
reclaimMemPages += OsTryShrinkMemory(0);
}
return reclaimMemPages;
}
///内存不足时回收页高速缓存
LITE_OS_SEC_TEXT_MINOR STATIC BOOL OomReclaimPageCache(VOID)
{
UINT32 totalPm = 0;
@ -96,43 +97,44 @@ LITE_OS_SEC_TEXT_MINOR STATIC BOOL OomReclaimPageCache(VOID)
UINT32 i;
for (i = 0; i < MAX_SHRINK_PAGECACHE_TRY; i++) {
OsVmPhysUsedInfoGet(&usedPm, &totalPm);
isReclaimMemory = ((totalPm - usedPm) << PAGE_SHIFT) < g_oomCB->reclaimMemThreshold;
if (isReclaimMemory) {
OsVmPhysUsedInfoGet(&usedPm, &totalPm);//获取总的和已经使用的物理内存数量
isReclaimMemory = ((totalPm - usedPm) << PAGE_SHIFT) < g_oomCB->reclaimMemThreshold;//检查是否过了回收门槛
if (isReclaimMemory) {//要回收了
/*
* we do force memory reclaim from page cache here.
* if we get memory, we will reclaim pagecache memory again.
* if there is no memory to reclaim, we will return.
*/
reclaimMemPages = OomForceShrinkMemory();
if (reclaimMemPages > 0) {
//在这里强制从页缓存中回收内存,
reclaimMemPages = OomForceShrinkMemory();//强制回收内存
if (reclaimMemPages > 0) {//如果得到内存将再次回收pagecache内存
continue;
}
}
break;
break;//实在没有内存可回收
}
return isReclaimMemory;
return isReclaimMemory;//返回回收的数量
}
/*
* check is low memory or not, if low memory, try to kill process.
* return is kill process or not.
* check is low memory or not, if low memory, try to kill process.
* return is kill process or not.
*/
LITE_OS_SEC_TEXT_MINOR BOOL OomCheckProcess(VOID)
LITE_OS_SEC_TEXT_MINOR BOOL OomCheckProcess(VOID)//检查内存是否不足,如果内存不足,请尝试终止进程,返回是否kill进程
{
UINT32 totalPm;
UINT32 usedPm;
BOOL isLowMemory = FALSE;
/*
* spinlock the current core schedule, make sure oom process atomic
* spinlock other place entering OomCheckProcess, make sure oom process mutex
* spinlock the current core schedule, make sure oom process atomic //旋转锁定当前核心计划确保oom进程原子化
* spinlock other place entering OomCheckProcess, make sure oom process mutex //旋转锁定其他进入OomCheckProcess的地方确保oom进程互斥
*/
LOS_SpinLock(&g_oomSpinLock);
/* first we will check if we need to reclaim pagecache memory */
if (OomReclaimPageCache() == FALSE) {
if (OomReclaimPageCache() == FALSE) {//
LOS_SpinUnlock(&g_oomSpinLock);
goto NO_VICTIM_PROCESS;
}
@ -140,9 +142,7 @@ LITE_OS_SEC_TEXT_MINOR BOOL OomCheckProcess(VOID)
/* get free bytes */
OsVmPhysUsedInfoGet(&usedPm, &totalPm);
isLowMemory = ((totalPm - usedPm) << PAGE_SHIFT) < g_oomCB->lowMemThreshold;
LOS_SpinUnlock(&g_oomSpinLock);
if (isLowMemory) {
PRINTK("[oom] OS is in low memory state\n"
"total physical memory: %#x(byte), used: %#x(byte),"
@ -155,14 +155,14 @@ NO_VICTIM_PROCESS:
return isLowMemory;
}
#ifdef LOSCFG_ENABLE_OOM_LOOP_TASK
STATIC VOID OomWriteEvent(VOID)
#ifdef LOSCFG_ENABLE_OOM_LOOP_TASK //内存溢出监测任务开关
STATIC VOID OomWriteEvent(VOID) // OomTaskInit中创建的定时器回调
{
OsWriteResourceEvent(OS_RESOURCE_EVENT_OOM);
OsWriteResourceEvent(OS_RESOURCE_EVENT_OOM);//广播内存溢出事件
}
#endif
LITE_OS_SEC_TEXT_MINOR VOID OomInfodump(VOID)
//打印内存不足时的信息
LITE_OS_SEC_TEXT_MINOR VOID OomInfodump(VOID) //打印内存溢出信息
{
PRINTK("[oom] oom loop task status: %s\n"
" oom low memory threshold: %#x(byte)\n"
@ -172,7 +172,7 @@ LITE_OS_SEC_TEXT_MINOR VOID OomInfodump(VOID)
g_oomCB->lowMemThreshold, g_oomCB->reclaimMemThreshold,
g_oomCB->checkInterval);
}
///设置低内存门槛
LITE_OS_SEC_TEXT_MINOR VOID OomSetLowMemThreashold(UINT32 lowMemThreshold)
{
if ((lowMemThreshold > OOM_DEFAULT_LOW_MEM_THRESHOLD_MAX)) {
@ -186,7 +186,7 @@ LITE_OS_SEC_TEXT_MINOR VOID OomSetLowMemThreashold(UINT32 lowMemThreshold)
g_oomCB->lowMemThreshold);
}
}
///设置回收内存的门槛
LITE_OS_SEC_TEXT_MINOR VOID OomSetReclaimMemThreashold(UINT32 reclaimMemThreshold)
{
UINT32 totalPm = 0;
@ -204,7 +204,7 @@ LITE_OS_SEC_TEXT_MINOR VOID OomSetReclaimMemThreashold(UINT32 reclaimMemThreshol
g_oomCB->reclaimMemThreshold);
}
}
///设置监控间隔
LITE_OS_SEC_TEXT_MINOR VOID OomSetCheckInterval(UINT32 checkInterval)
{
if ((checkInterval >= OOM_CHECK_MIN) && (checkInterval <= OOM_CHECK_MAX)) {
@ -216,7 +216,7 @@ LITE_OS_SEC_TEXT_MINOR VOID OomSetCheckInterval(UINT32 checkInterval)
g_oomCB->checkInterval, OOM_CHECK_MIN, OOM_CHECK_MAX);
}
}
///内存不足监控任务初始化, OOM 通过开一个软件定时器来检查内存的使用情况
LITE_OS_SEC_TEXT_MINOR UINT32 OomTaskInit(VOID)
{
g_oomCB = (OomCB *)LOS_MemAlloc(m_aucSysMem0, sizeof(OomCB));
@ -225,28 +225,28 @@ LITE_OS_SEC_TEXT_MINOR UINT32 OomTaskInit(VOID)
return LOS_NOK;
}
g_oomCB->lowMemThreshold = OOM_DEFAULT_LOW_MEM_THRESHOLD;
g_oomCB->reclaimMemThreshold = OOM_DEFAULT_RECLAIM_MEM_THRESHOLD;
g_oomCB->checkInterval = OOM_DEFAULT_CHECK_INTERVAL;
g_oomCB->processVictimCB = (OomFn)OomKillProcess;
g_oomCB->scoreCB = (OomFn)OomScoreProcess;
g_oomCB->enabled = FALSE;
g_oomCB->lowMemThreshold = OOM_DEFAULT_LOW_MEM_THRESHOLD; //运行任务的门槛
g_oomCB->reclaimMemThreshold = OOM_DEFAULT_RECLAIM_MEM_THRESHOLD; //回收内存的门槛
g_oomCB->checkInterval = OOM_DEFAULT_CHECK_INTERVAL; //检测时间间隔 1S
g_oomCB->processVictimCB = (OomFn)OomKillProcess; //出问题时对进程的处理函数
g_oomCB->scoreCB = (OomFn)OomScoreProcess; //统计进程占用的物理内存
g_oomCB->enabled = FALSE; //是否启用监控
#ifdef LOSCFG_ENABLE_OOM_LOOP_TASK
#ifdef LOSCFG_ENABLE_OOM_LOOP_TASK //内存溢出检测开关
g_oomCB->enabled = TRUE;
UINT32 ret = LOS_SwtmrCreate(g_oomCB->checkInterval, LOS_SWTMR_MODE_PERIOD, (SWTMR_PROC_FUNC)OomWriteEvent,
&g_oomCB->swtmrID, (UINTPTR)g_oomCB);
&g_oomCB->swtmrID, (UINTPTR)g_oomCB);//创建检测定时器
if (ret != LOS_OK) {
return ret;
}
return LOS_SwtmrStart(g_oomCB->swtmrID);
return LOS_SwtmrStart(g_oomCB->swtmrID);//启动定时器
#else
return LOS_OK;
#endif
}
LOS_MODULE_INIT(OomTaskInit, LOS_INIT_LEVEL_KMOD_TASK);
LOS_MODULE_INIT(OomTaskInit, LOS_INIT_LEVEL_KMOD_TASK);//初始化内存监控模块
#endif

@ -1,3 +1,24 @@
/*!
* @file shm.c
* @brief
* @link
@verbatim
访
访C
malloc()访
访
线,使线.
@endverbatim
* @version
* @author weharmonyos.com | 鸿 |
* @date 2021-12-24
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2023 Huawei Device Co., Ltd. All rights reserved.
@ -55,9 +76,9 @@
#ifdef LOSCFG_KERNEL_SHM
#define SHM_SEG_FREE 0x2000
#define SHM_SEG_USED 0x4000
#define SHM_SEG_REMOVE 0x8000
#define SHM_SEG_FREE 0x2000 //空闲未使用
#define SHM_SEG_USED 0x4000 //已使用
#define SHM_SEG_REMOVE 0x8000 //删除
#ifndef SHM_M
#define SHM_M 010000
@ -66,21 +87,17 @@
#ifndef SHM_X
#define SHM_X 0100
#endif
#ifndef ACCESSPERMS
#define ACCESSPERMS (S_IRWXU | S_IRWXG | S_IRWXO)
#endif
#define ACCESSPERMS (S_IRWXU | S_IRWXG | S_IRWXO)//文件权限值意思就是 用户,用户组,其他可读可写.
#endif //代表含义U:user G:group O:other
#define SHM_S_IRUGO (S_IRUSR | S_IRGRP | S_IROTH)
#define SHM_S_IWUGO (S_IWUSR | S_IWGRP | S_IWOTH)
#define SHM_S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
#define SHM_GROUPE_TO_USER 3
#define SHM_OTHER_TO_USER 6
#ifndef LOSCFG_IPC_CONTAINER
STATIC LosMux g_sysvShmMux;
/* private data */
STATIC struct shminfo g_shmInfo;
STATIC struct shmIDSource *g_shmSegs = NULL;
@ -96,6 +113,60 @@ STATIC UINT32 g_shmUsedPageCount;
#define SYSV_SHM_LOCK() (VOID)LOS_MuxLock(&IPC_SHM_SYS_VSHM_MUTEX, LOS_WAIT_FOREVER)
#define SYSV_SHM_UNLOCK() (VOID)LOS_MuxUnlock(&IPC_SHM_SYS_VSHM_MUTEX)
#if 0 // @note_#if0
//内核为每一个IPC对象保存一个ipc_perm结构体该结构说明了IPC对象的权限和所有者
struct ipc_perm {
key_t __ipc_perm_key; //调用shmget()时给出的关键字
uid_t uid; //共享内存所有者的有效用户ID
gid_t gid; //共享内存所有者所属组的有效组ID
uid_t cuid; //共享内存创建 者的有效用户ID
gid_t cgid; //共享内存创建者所属组的有效组ID
mode_t mode; //权限 + SHM_DEST / SHM_LOCKED /SHM_HUGETLB 标志位
int __ipc_perm_seq; //序列号
long __pad1; //保留扩展用
long __pad2;
};
//每个共享内存段在内核中维护着一个内部结构shmid_ds
struct shmid_ds {
struct ipc_perm shm_perm;///< 操作许可里面包含共享内存的用户ID、组ID等信息
size_t shm_segsz; ///< 共享内存段的大小,单位为字节
time_t shm_atime; ///< 最后一个进程访问共享内存的时间
time_t shm_dtime; ///< 最后一个进程离开共享内存的时间
time_t shm_ctime; ///< 创建时间
pid_t shm_cpid; ///< 创建共享内存的进程ID
pid_t shm_lpid; ///< 最后操作共享内存的进程ID
unsigned long shm_nattch; ///< 当前使用该共享内存段的进程数量
unsigned long __pad1; //保留扩展用
unsigned long __pad2;
};
// 共享内存模块设置信息
struct shminfo {
unsigned long shmmax, shmmin, shmmni, shmseg, shmall, __unused[4];
};
struct shmIDSource {//共享内存描述符
struct shmid_ds ds; //是内核为每一个共享内存段维护的数据结构
UINT32 status; //状态 SHM_SEG_FREE ...
LOS_DL_LIST node; //节点,挂VmPage
#ifdef LOSCFG_SHELL
CHAR ownerName[OS_PCB_NAME_LEN];
#endif
};
/* private data */
STATIC struct shminfo g_shmInfo = { //描述共享内存范围的全局变量
.shmmax = SHM_MAX,//共享内存单个上限 4096页 即 16M
.shmmin = SHM_MIN,//共享内存单个下限 1页 即:4K
.shmmni = SHM_MNI,//共享内存总数 默认192
.shmseg = SHM_SEG,//每个用户进程可以使用的最多的共享内存段的数目 128
.shmall = SHM_ALL,//系统范围内共享内存的总页数, 4096页
};
STATIC struct shmIDSource *g_shmSegs = NULL;
STATIC UINT32 g_shmUsedPageCount;
#endif
//共享内存初始化
struct shmIDSource *OsShmCBInit(LosMux *sysvShmMux, struct shminfo *shmInfo, UINT32 *shmUsedPageCount)
{
UINT32 ret;
@ -104,7 +175,6 @@ struct shmIDSource *OsShmCBInit(LosMux *sysvShmMux, struct shminfo *shmInfo, UIN
if ((sysvShmMux == NULL) || (shmInfo == NULL) || (shmUsedPageCount == NULL)) {
return NULL;
}
ret = LOS_MuxInit(sysvShmMux, NULL);
if (ret != LOS_OK) {
goto ERROR;
@ -115,7 +185,6 @@ struct shmIDSource *OsShmCBInit(LosMux *sysvShmMux, struct shminfo *shmInfo, UIN
shmInfo->shmmni = SHM_MNI;
shmInfo->shmseg = SHM_SEG;
shmInfo->shmall = SHM_ALL;
struct shmIDSource *shmSegs = LOS_MemAlloc((VOID *)OS_SYS_MEM_ADDR, sizeof(struct shmIDSource) * shmInfo->shmmni);
if (shmSegs == NULL) {
(VOID)LOS_MuxDestroy(sysvShmMux);
@ -125,9 +194,9 @@ struct shmIDSource *OsShmCBInit(LosMux *sysvShmMux, struct shminfo *shmInfo, UIN
0, (sizeof(struct shmIDSource) * shmInfo->shmmni));
for (i = 0; i < shmInfo->shmmni; i++) {
shmSegs[i].status = SHM_SEG_FREE;
shmSegs[i].ds.shm_perm.seq = i + 1;
LOS_ListInit(&shmSegs[i].node);
shmSegs[i].status = SHM_SEG_FREE;//节点初始状态为空闲
shmSegs[i].ds.shm_perm.seq = i + 1;//struct ipc_perm shm_perm;系统为每一个IPC对象保存一个ipc_perm结构体,结构说明了IPC对象的权限和所有者
LOS_ListInit(&shmSegs[i].node);//初始化节点
}
*shmUsedPageCount = 0;
@ -137,7 +206,6 @@ ERROR:
VM_ERR("ShmInit fail\n");
return NULL;
}
UINT32 ShmInit(VOID)
{
#ifndef LOSCFG_IPC_CONTAINER
@ -149,8 +217,9 @@ UINT32 ShmInit(VOID)
return LOS_OK;
}
LOS_MODULE_INIT(ShmInit, LOS_INIT_LEVEL_VM_COMPLETE);
LOS_MODULE_INIT(ShmInit, LOS_INIT_LEVEL_VM_COMPLETE);//共享内存模块初始化
//共享内存反初始化
UINT32 ShmDeinit(VOID)
{
UINT32 ret;
@ -165,7 +234,7 @@ UINT32 ShmDeinit(VOID)
return 0;
}
///给共享段中所有物理页框贴上共享标签
STATIC inline VOID ShmSetSharedFlag(struct shmIDSource *seg)
{
LosVmPage *page = NULL;
@ -174,7 +243,7 @@ STATIC inline VOID ShmSetSharedFlag(struct shmIDSource *seg)
OsSetPageShared(page);
}
}
///给共享段中所有物理页框撕掉共享标签
STATIC inline VOID ShmClearSharedFlag(struct shmIDSource *seg)
{
LosVmPage *page = NULL;
@ -183,7 +252,7 @@ STATIC inline VOID ShmClearSharedFlag(struct shmIDSource *seg)
OsCleanPageShared(page);
}
}
///seg下所有共享页引用减少
STATIC VOID ShmPagesRefDec(struct shmIDSource *seg)
{
LosVmPage *page = NULL;
@ -193,6 +262,15 @@ STATIC VOID ShmPagesRefDec(struct shmIDSource *seg)
}
}
/**
* @brief
:size = 4097, LOS_Align(size, PAGE_SIZE) = 8192
size >> PAGE_SHIFT = 2
* @param key
* @param size
* @param shmflg
* @return STATIC
*/
STATIC INT32 ShmAllocSegCheck(key_t key, size_t *size, INT32 *segNum)
{
INT32 i;
@ -201,7 +279,7 @@ STATIC INT32 ShmAllocSegCheck(key_t key, size_t *size, INT32 *segNum)
return -EINVAL;
}
*size = LOS_Align(*size, PAGE_SIZE);
*size = LOS_Align(*size, PAGE_SIZE);//必须对齐
if ((IPC_SHM_USED_PAGE_COUNT + (*size >> PAGE_SHIFT)) > IPC_SHM_INFO.shmall) {
return -ENOMEM;
}
@ -211,11 +289,10 @@ STATIC INT32 ShmAllocSegCheck(key_t key, size_t *size, INT32 *segNum)
return -ENOMEM;
}
#endif
for (i = 0; i < IPC_SHM_INFO.shmmni; i++) {
if (IPC_SHM_SEGS[i].status & SHM_SEG_FREE) {
IPC_SHM_SEGS[i].status &= ~SHM_SEG_FREE;
*segNum = i;
for (i = 0; i < IPC_SHM_INFO.shmmni; i++) {//试图找到一个空闲段与参数key绑定
if (IPC_SHM_SEGS[i].status & SHM_SEG_FREE) {//找到空闲段
IPC_SHM_SEGS[i].status &= ~SHM_SEG_FREE;//变成非空闲状态
*segNum = i;//标号
break;
}
}
@ -236,49 +313,47 @@ STATIC INT32 ShmAllocSeg(key_t key, size_t size, INT32 shmflg)
if (ret < 0) {
return ret;
}
seg = &IPC_SHM_SEGS[segNum];
count = LOS_PhysPagesAlloc(size >> PAGE_SHIFT, &seg->node);
if (count != (size >> PAGE_SHIFT)) {
(VOID)LOS_PhysPagesFree(&seg->node);
seg->status = SHM_SEG_FREE;
count = LOS_PhysPagesAlloc(size >> PAGE_SHIFT, &seg->node);//分配共享页面,函数内部把node都挂好了.
if (count != (size >> PAGE_SHIFT)) {//当未分配到足够的内存时,处理方式是:不稀罕给那么点,舍弃!
(VOID)LOS_PhysPagesFree(&seg->node);//释放节点上的物理页框
seg->status = SHM_SEG_FREE;//共享段变回空闲状态
#ifdef LOSCFG_KERNEL_IPC_PLIMIT
OsIPCLimitShmFree(size);
#endif
return -ENOMEM;
}
ShmSetSharedFlag(seg);
ShmSetSharedFlag(seg);//将node的每个页面设置为共享页
IPC_SHM_USED_PAGE_COUNT += size >> PAGE_SHIFT;
seg->status |= SHM_SEG_USED;
seg->status |= SHM_SEG_USED; //共享段贴上已在使用的标签
seg->ds.shm_perm.mode = (UINT32)shmflg & ACCESSPERMS;
seg->ds.shm_perm.key = key;
seg->ds.shm_segsz = size;
seg->ds.shm_perm.cuid = LOS_GetUserID();
seg->ds.shm_perm.uid = LOS_GetUserID();
seg->ds.shm_perm.cgid = LOS_GetGroupID();
seg->ds.shm_perm.gid = LOS_GetGroupID();
seg->ds.shm_lpid = 0;
seg->ds.shm_nattch = 0;
seg->ds.shm_cpid = LOS_GetCurrProcessID();
seg->ds.shm_atime = 0;
seg->ds.shm_dtime = 0;
seg->ds.shm_ctime = time(NULL);
seg->ds.shm_perm.key = key;//保存参数key,如此 key 和 共享ID绑定在一块
seg->ds.shm_segsz = size; //共享段的大小
seg->ds.shm_perm.cuid = LOS_GetUserID(); //设置用户ID
seg->ds.shm_perm.uid = LOS_GetUserID(); //设置用户ID
seg->ds.shm_perm.cgid = LOS_GetGroupID(); //设置组ID
seg->ds.shm_perm.gid = LOS_GetGroupID(); //设置组ID
seg->ds.shm_lpid = 0; //最后一个操作的进程
seg->ds.shm_nattch = 0; //绑定进程的数量
seg->ds.shm_cpid = LOS_GetCurrProcessID(); //获取进程ID
seg->ds.shm_atime = 0; //访问时间
seg->ds.shm_dtime = 0; //detach 分离时间 共享内存使用完之后,需要将它从进程地址空间中分离出来;将共享内存分离并不是删除它,只是使该共享内存对当前的进程不再可用
seg->ds.shm_ctime = time(NULL);//创建时间
#ifdef LOSCFG_SHELL
(VOID)memcpy_s(seg->ownerName, OS_PCB_NAME_LEN, OsCurrProcessGet()->processName, OS_PCB_NAME_LEN);
#endif
return segNum;
}
///释放seg->node 所占物理页框,seg本身重置
STATIC INLINE VOID ShmFreeSeg(struct shmIDSource *seg, UINT32 *shmUsedPageCount)
{
UINT32 count;
ShmClearSharedFlag(seg);
count = LOS_PhysPagesFree(&seg->node);
if (count != (seg->ds.shm_segsz >> PAGE_SHIFT)) {
ShmClearSharedFlag(seg);//先撕掉 seg->node 中vmpage的共享标签
count = LOS_PhysPagesFree(&seg->node);//再挨个删除物理页框
if (count != (seg->ds.shm_segsz >> PAGE_SHIFT)) {//异常,必须要一样
VM_ERR("free physical pages failed, count = %d, size = %d", count, seg->ds.shm_segsz >> PAGE_SHIFT);
return;
}
@ -288,31 +363,31 @@ STATIC INLINE VOID ShmFreeSeg(struct shmIDSource *seg, UINT32 *shmUsedPageCount)
if (shmUsedPageCount != NULL) {
(*shmUsedPageCount) -= seg->ds.shm_segsz >> PAGE_SHIFT;
}
seg->status = SHM_SEG_FREE;
LOS_ListInit(&seg->node);
seg->status = SHM_SEG_FREE;//seg恢复自由之身
LOS_ListInit(&seg->node);//重置node
}
///通过key查找 shmId
STATIC INT32 ShmFindSegByKey(key_t key)
{
INT32 i;
struct shmIDSource *seg = NULL;
for (i = 0; i < IPC_SHM_INFO.shmmni; i++) {
for (i = 0; i < IPC_SHM_INFO.shmmni; i++) {//遍历共享段池,找到与key绑定的共享ID
seg = &IPC_SHM_SEGS[i];
if ((seg->status & SHM_SEG_USED) &&
(seg->ds.shm_perm.key == key)) {
(seg->ds.shm_perm.key == key)) {//满足两个条件,找到后返回
return i;
}
}
return -1;
}
///共享内存段有效性检查
STATIC INT32 ShmSegValidCheck(INT32 segNum, size_t size, INT32 shmFlg)
{
struct shmIDSource *seg = &IPC_SHM_SEGS[segNum];
struct shmIDSource *seg = &IPC_SHM_SEGS[segNum];//拿到shmID
if (size > seg->ds.shm_segsz) {
if (size > seg->ds.shm_segsz) {//段长
return -EINVAL;
}
@ -323,7 +398,7 @@ STATIC INT32 ShmSegValidCheck(INT32 segNum, size_t size, INT32 shmFlg)
return segNum;
}
///通过ID找到共享内存资源
STATIC struct shmIDSource *ShmFindSeg(int shmid)
{
struct shmIDSource *seg = NULL;
@ -341,7 +416,7 @@ STATIC struct shmIDSource *ShmFindSeg(int shmid)
return seg;
}
///共享内存映射
STATIC VOID ShmVmmMapping(LosVmSpace *space, LOS_DL_LIST *pageList, VADDR_T vaddr, UINT32 regionFlags)
{
LosVmPage *vmPage = NULL;
@ -349,64 +424,64 @@ STATIC VOID ShmVmmMapping(LosVmSpace *space, LOS_DL_LIST *pageList, VADDR_T vadd
PADDR_T pa;
STATUS_T ret;
LOS_DL_LIST_FOR_EACH_ENTRY(vmPage, pageList, LosVmPage, node) {
pa = VM_PAGE_TO_PHYS(vmPage);
LOS_AtomicInc(&vmPage->refCounts);
ret = LOS_ArchMmuMap(&space->archMmu, va, pa, 1, regionFlags);
LOS_DL_LIST_FOR_EACH_ENTRY(vmPage, pageList, LosVmPage, node) {//遍历一页一页映射
pa = VM_PAGE_TO_PHYS(vmPage);//拿到物理地址
LOS_AtomicInc(&vmPage->refCounts);//自增
ret = LOS_ArchMmuMap(&space->archMmu, va, pa, 1, regionFlags);//虚实映射
if (ret != 1) {
VM_ERR("LOS_ArchMmuMap failed, ret = %d", ret);
}
va += PAGE_SIZE;
}
}
///fork 一个共享线性区
VOID OsShmFork(LosVmSpace *space, LosVmMapRegion *oldRegion, LosVmMapRegion *newRegion)
{
struct shmIDSource *seg = NULL;
SYSV_SHM_LOCK();
seg = ShmFindSeg(oldRegion->shmid);
seg = ShmFindSeg(oldRegion->shmid);//通过老区ID获取对应的共享资源ID结构体
if (seg == NULL) {
SYSV_SHM_UNLOCK();
VM_ERR("shm fork failed!");
return;
}
newRegion->shmid = oldRegion->shmid;
newRegion->forkFlags = oldRegion->forkFlags;
ShmVmmMapping(space, &seg->node, newRegion->range.base, newRegion->regionFlags);
seg->ds.shm_nattch++;
newRegion->shmid = oldRegion->shmid;//一样的共享区ID
newRegion->forkFlags = oldRegion->forkFlags;//forkFlags也一样了
ShmVmmMapping(space, &seg->node, newRegion->range.base, newRegion->regionFlags);//新线性区与共享内存进行映射
seg->ds.shm_nattch++;//附在共享线性区上的进程数++
SYSV_SHM_UNLOCK();
}
///释放共享线性区
VOID OsShmRegionFree(LosVmSpace *space, LosVmMapRegion *region)
{
struct shmIDSource *seg = NULL;
SYSV_SHM_LOCK();
seg = ShmFindSeg(region->shmid);
seg = ShmFindSeg(region->shmid);//通过线性区ID获取对应的共享资源ID结构体
if (seg == NULL) {
SYSV_SHM_UNLOCK();
return;
}
LOS_ArchMmuUnmap(&space->archMmu, region->range.base, region->range.size >> PAGE_SHIFT);
ShmPagesRefDec(seg);
seg->ds.shm_nattch--;
LOS_ArchMmuUnmap(&space->archMmu, region->range.base, region->range.size >> PAGE_SHIFT);//解除线性区的映射
ShmPagesRefDec(seg);//ref --
seg->ds.shm_nattch--;//附在共享线性区上的进程数--
if (seg->ds.shm_nattch <= 0 && (seg->status & SHM_SEG_REMOVE)) {
ShmFreeSeg(seg, &IPC_SHM_USED_PAGE_COUNT);
ShmFreeSeg(seg, &IPC_SHM_USED_PAGE_COUNT);//就释放掉物理内存!注意是:物理内存
} else {
seg->ds.shm_dtime = time(NULL);
seg->ds.shm_lpid = LOS_GetCurrProcessID(); /* may not be the space's PID. */
}
SYSV_SHM_UNLOCK();
}
///是否为共享线性区,是否有标签?
BOOL OsIsShmRegion(LosVmMapRegion *region)
{
return (region->regionFlags & VM_MAP_REGION_FLAG_SHM) ? TRUE : FALSE;
}
///获取共享内存池中已被使用的段数量
STATIC INT32 ShmSegUsedCount(VOID)
{
INT32 i;
@ -415,16 +490,16 @@ STATIC INT32 ShmSegUsedCount(VOID)
for (i = 0; i < IPC_SHM_INFO.shmmni; i++) {
seg = &IPC_SHM_SEGS[i];
if (seg->status & SHM_SEG_USED) {
if (seg->status & SHM_SEG_USED) {//找到一个
count++;
}
}
return count;
}
///对共享内存段权限检查
STATIC INT32 ShmPermCheck(struct shmIDSource *seg, mode_t mode)
{
INT32 uid = LOS_GetUserID();
INT32 uid = LOS_GetUserID();//当前进程的用户ID
UINT32 tmpMode = 0;
mode_t privMode = seg->ds.shm_perm.mode;
mode_t accMode;
@ -466,6 +541,22 @@ STATIC INT32 ShmPermCheck(struct shmIDSource *seg, mode_t mode)
}
}
/*!
* @brief ShmGet
*
* @param key IPC使IPC
IPCkey,IPCmsggetsemgetshmget
IPC, key_tftok,ftok,.
* @param shmflg IPC_CREAT IPC_EXCL
IPC_CREAT IPCkeyIPC_PRIVATEIPCflagIPC_CREAT
IPCIPCIPC_CREATIPC_CREAT
IPC_EXCL IPC_CREAT使IPCIPC
EEXISTopenO_CREATO_EXCL
* @param size
* @return
*
* @see
*/
INT32 ShmGet(key_t key, size_t size, INT32 shmflg)
{
INT32 ret;
@ -476,13 +567,13 @@ INT32 ShmGet(key_t key, size_t size, INT32 shmflg)
if (key == IPC_PRIVATE) {
ret = ShmAllocSeg(key, size, shmflg);
} else {
ret = ShmFindSegByKey(key);
ret = ShmFindSegByKey(key);//通过key查找资源ID
if (ret < 0) {
if (((UINT32)shmflg & IPC_CREAT) == 0) {
if (((UINT32)shmflg & IPC_CREAT) == 0) {//
ret = -ENOENT;
goto ERROR;
} else {
ret = ShmAllocSeg(key, size, shmflg);
ret = ShmAllocSeg(key, size, shmflg);//分配一个共享内存
}
} else {
shmid = ret;
@ -491,7 +582,7 @@ INT32 ShmGet(key_t key, size_t size, INT32 shmflg)
ret = -EEXIST;
goto ERROR;
}
ret = ShmPermCheck(ShmFindSeg(shmid), (UINT32)shmflg & ACCESSPERMS);
ret = ShmPermCheck(ShmFindSeg(shmid), (UINT32)shmflg & ACCESSPERMS);//对共享内存权限检查
if (ret != 0) {
ret = -ret;
goto ERROR;
@ -526,13 +617,13 @@ INT32 ShmatParamCheck(const VOID *shmaddr, INT32 shmflg)
return 0;
}
///分配一个共享线性区并映射好
LosVmMapRegion *ShmatVmmAlloc(struct shmIDSource *seg, const VOID *shmaddr,
INT32 shmflg, UINT32 prot)
{
LosVmSpace *space = OsCurrProcessGet()->vmSpace;
LosVmMapRegion *region = NULL;
UINT32 flags = MAP_ANONYMOUS | MAP_SHARED;
UINT32 flags = MAP_ANONYMOUS | MAP_SHARED;//本线性区为共享+匿名标签
UINT32 mapFlags = flags | MAP_FIXED;
VADDR_T vaddr;
UINT32 regionFlags;
@ -543,29 +634,29 @@ LosVmMapRegion *ShmatVmmAlloc(struct shmIDSource *seg, const VOID *shmaddr,
}
regionFlags = OsCvtProtFlagsToRegionFlags(prot, flags);
(VOID)LOS_MuxAcquire(&space->regionMux);
if (shmaddr == NULL) {
region = LOS_RegionAlloc(space, 0, seg->ds.shm_segsz, regionFlags, 0);
} else {
if (shmaddr == NULL) {//未指定了共享内存连接到当前进程中的地址位置
region = LOS_RegionAlloc(space, 0, seg->ds.shm_segsz, regionFlags, 0);//分配线性区
} else {//指定时,就需要先找地址所在的线性区
if ((UINT32)shmflg & SHM_RND) {
vaddr = ROUNDDOWN((VADDR_T)(UINTPTR)shmaddr, SHMLBA);
} else {
vaddr = (VADDR_T)(UINTPTR)shmaddr;
}
}//找到线性区并重新映射,当指定地址时需贴上重新映射的标签
if (!((UINT32)shmflg & SHM_REMAP) && (LOS_RegionFind(space, vaddr) ||
LOS_RegionFind(space, vaddr + seg->ds.shm_segsz - 1) ||
LOS_RegionRangeFind(space, vaddr, seg->ds.shm_segsz - 1))) {
ret = EINVAL;
goto ERROR;
}
vaddr = (VADDR_T)LOS_MMap(vaddr, seg->ds.shm_segsz, prot, mapFlags, -1, 0);
region = LOS_RegionFind(space, vaddr);
vaddr = (VADDR_T)LOS_MMap(vaddr, seg->ds.shm_segsz, prot, mapFlags, -1, 0);//做好映射
region = LOS_RegionFind(space, vaddr);//重新查找线性区,用于返回.
}
if (region == NULL) {
ret = ENOMEM;
goto ERROR;
}
ShmVmmMapping(space, &seg->node, region->range.base, regionFlags);
ShmVmmMapping(space, &seg->node, region->range.base, regionFlags);//共享内存映射
(VOID)LOS_MuxRelease(&space->regionMux);
return region;
ERROR:
@ -574,6 +665,17 @@ ERROR:
return NULL;
}
/*!
* @brief ShmAt
* 访
* @param shm_flg 0
* @param shmaddr
* @param shmid shmget()
* @return
* shmat使shmid_dsshm_nattch1
shmid ,线ID g_shmSegs[shmid] shmid > 192
* @see
*/
VOID *ShmAt(INT32 shmid, const VOID *shmaddr, INT32 shmflg)
{
INT32 ret;
@ -582,13 +684,13 @@ VOID *ShmAt(INT32 shmid, const VOID *shmaddr, INT32 shmflg)
struct shmIDSource *seg = NULL;
LosVmMapRegion *r = NULL;
ret = ShmatParamCheck(shmaddr, shmflg);
ret = ShmatParamCheck(shmaddr, shmflg);//参数检查
if (ret != 0) {
set_errno(ret);
return (VOID *)-1;
}
if ((UINT32)shmflg & SHM_EXEC) {
if ((UINT32)shmflg & SHM_EXEC) {//flag 转换
prot |= PROT_EXEC;
acc_mode |= SHM_S_IXUGO;
} else if (((UINT32)shmflg & SHM_RDONLY) == 0) {
@ -597,7 +699,7 @@ VOID *ShmAt(INT32 shmid, const VOID *shmaddr, INT32 shmflg)
}
SYSV_SHM_LOCK();
seg = ShmFindSeg(shmid);
seg = ShmFindSeg(shmid);//找到段
if (seg == NULL) {
SYSV_SHM_UNLOCK();
return (VOID *)-1;
@ -608,18 +710,18 @@ VOID *ShmAt(INT32 shmid, const VOID *shmaddr, INT32 shmflg)
goto ERROR;
}
seg->ds.shm_nattch++;
r = ShmatVmmAlloc(seg, shmaddr, shmflg, prot);
seg->ds.shm_nattch++;//ds上记录有一个进程绑定上来
r = ShmatVmmAlloc(seg, shmaddr, shmflg, prot);//在当前进程空间分配一个线性区并映射到共享内存
if (r == NULL) {
seg->ds.shm_nattch--;
SYSV_SHM_UNLOCK();
return (VOID *)-1;
}
r->shmid = shmid;
r->regionFlags |= VM_MAP_REGION_FLAG_SHM;
seg->ds.shm_atime = time(NULL);
seg->ds.shm_lpid = LOS_GetCurrProcessID();
r->shmid = shmid;//把ID给线性区的shmid
r->regionFlags |= VM_MAP_REGION_FLAG_SHM;//这是一个共享线性区
seg->ds.shm_atime = time(NULL);//访问时间
seg->ds.shm_lpid = LOS_GetCurrProcessID();//进程ID
SYSV_SHM_UNLOCK();
return (VOID *)(UINTPTR)r->range.base;
@ -630,6 +732,19 @@ ERROR:
return (VOID *)-1;
}
/*!
* @brief ShmCtl
* shmid
* @param buf 访
* @param cmd command
IPC_STATshmid_dsshmid_ds
IPC_SETshmid_ds
IPC_RMID
* @param shmid shmget()
* @return
*
* @see
*/
INT32 ShmCtl(INT32 shmid, INT32 cmd, struct shmid_ds *buf)
{
struct shmIDSource *seg = NULL;
@ -642,7 +757,7 @@ INT32 ShmCtl(INT32 shmid, INT32 cmd, struct shmid_ds *buf)
SYSV_SHM_LOCK();
if ((cmd != IPC_INFO) && (cmd != SHM_INFO)) {
seg = ShmFindSeg(shmid);
seg = ShmFindSeg(shmid);//通过索引ID找到seg
if (seg == NULL) {
SYSV_SHM_UNLOCK();
return -1;
@ -656,13 +771,13 @@ INT32 ShmCtl(INT32 shmid, INT32 cmd, struct shmid_ds *buf)
switch (cmd) {
case IPC_STAT:
case SHM_STAT:
case SHM_STAT://取段结构
ret = ShmPermCheck(seg, SHM_S_IRUGO);
if (ret != 0) {
goto ERROR;
}
ret = LOS_ArchCopyToUser(buf, &seg->ds, sizeof(struct shmid_ds));
ret = LOS_ArchCopyToUser(buf, &seg->ds, sizeof(struct shmid_ds));//把内核空间的共享页数据拷贝到用户空间
if (ret != 0) {
ret = EFAULT;
goto ERROR;
@ -671,13 +786,13 @@ INT32 ShmCtl(INT32 shmid, INT32 cmd, struct shmid_ds *buf)
ret = (unsigned int)((unsigned int)seg->ds.shm_perm.seq << 16) | (unsigned int)((unsigned int)shmid & 0xffff); /* 16: use the seq as the upper 16 bits */
}
break;
case IPC_SET:
case IPC_SET://重置共享段
ret = ShmPermCheck(seg, SHM_M);
if (ret != 0) {
ret = EPERM;
goto ERROR;
}
//从用户空间拷贝数据到内核空间
ret = LOS_ArchCopyFromUser(&shm_perm, &buf->shm_perm, sizeof(struct ipc_perm));
if (ret != 0) {
ret = EFAULT;
@ -686,14 +801,14 @@ INT32 ShmCtl(INT32 shmid, INT32 cmd, struct shmid_ds *buf)
seg->ds.shm_perm.uid = shm_perm.uid;
seg->ds.shm_perm.gid = shm_perm.gid;
seg->ds.shm_perm.mode = (seg->ds.shm_perm.mode & ~ACCESSPERMS) |
(shm_perm.mode & ACCESSPERMS);
(shm_perm.mode & ACCESSPERMS);//可访问
seg->ds.shm_ctime = time(NULL);
#ifdef LOSCFG_SHELL
(VOID)memcpy_s(seg->ownerName, OS_PCB_NAME_LEN, OS_PCB_FROM_PID(shm_perm.uid)->processName,
OS_PCB_NAME_LEN);
#endif
break;
case IPC_RMID:
case IPC_RMID://删除共享段
ret = ShmPermCheck(seg, SHM_M);
if (ret != 0) {
ret = EPERM;
@ -701,11 +816,11 @@ INT32 ShmCtl(INT32 shmid, INT32 cmd, struct shmid_ds *buf)
}
seg->status |= SHM_SEG_REMOVE;
if (seg->ds.shm_nattch <= 0) {
if (seg->ds.shm_nattch <= 0) {//没有任何进程在使用了
ShmFreeSeg(seg, &IPC_SHM_USED_PAGE_COUNT);
}
break;
case IPC_INFO:
case IPC_INFO://把内核空间的共享页数据拷贝到用户空间
ret = LOS_ArchCopyToUser(buf, &IPC_SHM_INFO, sizeof(struct shminfo));
if (ret != 0) {
ret = EFAULT;
@ -719,8 +834,8 @@ INT32 ShmCtl(INT32 shmid, INT32 cmd, struct shmid_ds *buf)
shmInfo.shm_tot = 0;
shmInfo.swap_attempts = 0;
shmInfo.swap_successes = 0;
shmInfo.used_ids = ShmSegUsedCount();
ret = LOS_ArchCopyToUser(buf, &shmInfo, sizeof(struct shm_info));
shmInfo.used_ids = ShmSegUsedCount();//在使用的seg数
ret = LOS_ArchCopyToUser(buf, &shmInfo, sizeof(struct shm_info));//把内核空间的共享页数据拷贝到用户空间
if (ret != 0) {
ret = EFAULT;
goto ERROR;
@ -743,55 +858,63 @@ ERROR:
return -1;
}
/**
* @brief shmdt
shmat使shmid_dsshm_nattch1
* @attention
IPC_RMIDshmctl
* @param shmaddr
* @return INT32
*/
INT32 ShmDt(const VOID *shmaddr)
{
LosVmSpace *space = OsCurrProcessGet()->vmSpace;
LosVmSpace *space = OsCurrProcessGet()->vmSpace;//获取进程空间
struct shmIDSource *seg = NULL;
LosVmMapRegion *region = NULL;
INT32 shmid;
INT32 ret;
if (IS_PAGE_ALIGNED(shmaddr) == 0) {
if (IS_PAGE_ALIGNED(shmaddr) == 0) {//地址是否对齐
ret = EINVAL;
goto ERROR;
}
(VOID)LOS_MuxAcquire(&space->regionMux);
region = LOS_RegionFind(space, (VADDR_T)(UINTPTR)shmaddr);
region = LOS_RegionFind(space, (VADDR_T)(UINTPTR)shmaddr);//找到线性区
if (region == NULL) {
ret = EINVAL;
goto ERROR_WITH_LOCK;
}
shmid = region->shmid;
shmid = region->shmid;//线性区共享ID
if (region->range.base != (VADDR_T)(UINTPTR)shmaddr) {
ret = EINVAL;
if (region->range.base != (VADDR_T)(UINTPTR)shmaddr) {//这是用户空间和内核空间的一次解绑
ret = EINVAL; //shmaddr 必须要等于region->range.base
goto ERROR_WITH_LOCK;
}
/* remove it from aspace */
LOS_RbDelNode(&space->regionRbTree, &region->rbNode);
LOS_ArchMmuUnmap(&space->archMmu, region->range.base, region->range.size >> PAGE_SHIFT);
LOS_RbDelNode(&space->regionRbTree, &region->rbNode);//从红黑树和链表中摘除节点
LOS_ArchMmuUnmap(&space->archMmu, region->range.base, region->range.size >> PAGE_SHIFT);//解除线性区的映射
(VOID)LOS_MuxRelease(&space->regionMux);
/* free it */
free(region);
free(region);//释放线性区所占内存池中的内存
SYSV_SHM_LOCK();
seg = ShmFindSeg(shmid);
seg = ShmFindSeg(shmid);//找到seg,线性区和共享段的关系是 1:N 的关系,其他空间的线性区也会绑在共享段上
if (seg == NULL) {
ret = EINVAL;
SYSV_SHM_UNLOCK();
goto ERROR;
}
ShmPagesRefDec(seg);
seg->ds.shm_nattch--;
if ((seg->ds.shm_nattch <= 0) &&
(seg->status & SHM_SEG_REMOVE)) {
ShmFreeSeg(seg, &IPC_SHM_USED_PAGE_COUNT);
ShmPagesRefDec(seg);//页面引用数 --
seg->ds.shm_nattch--;//使用共享内存的进程数少了一个
if ((seg->ds.shm_nattch <= 0) && //无任何进程使用共享内存
(seg->status & SHM_SEG_REMOVE)) {//状态为删除时需要释放物理页内存了,否则其他进程还要继续使用共享内存
ShmFreeSeg(seg, &IPC_SHM_USED_PAGE_COUNT);//释放seg 页框链表中的页框内存,再重置seg状态
} else {
seg->ds.shm_dtime = time(NULL);
seg->ds.shm_lpid = LOS_GetCurrProcessID();
seg->ds.shm_dtime = time(NULL);//记录分离的时间
seg->ds.shm_lpid = LOS_GetCurrProcessID();//记录操作进程ID
}
SYSV_SHM_UNLOCK();
@ -847,7 +970,6 @@ STATIC VOID OsShmInfoCmd(VOID)
}
SYSV_SHM_UNLOCK();
}
STATIC VOID OsShmDeleteCmd(INT32 shmid)
{
struct shmIDSource *seg = NULL;
@ -876,7 +998,7 @@ STATIC VOID OsShmCmdUsage(VOID)
"\t-r [shmid], Recycle the specified shared memory about shmid\n"
"\t-h | --help, print shm command usage\n");
}
///共享内存
UINT32 OsShellCmdShm(INT32 argc, const CHAR *argv[])
{
INT32 shmid;

File diff suppressed because it is too large Load Diff

@ -1,3 +1,23 @@
/*!
* @file console.h
* @brief
* @link
@verbatim
https://www.cnblogs.com/sparkdev/p/11460821.html
TTY Teletype Teletypewriter ,
,
TTY (terminal)
TTY Linux TTY TTY Linux TTY
/dev/consoletty鸿dev/ttyS0(UART0)
@endverbatim
* @version
* @author weharmonyos.com | 鸿 |
* @date 2021-12-8
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
@ -51,55 +71,83 @@ extern "C" {
#ifdef LOSCFG_FS_VFS
/* Define two fixed console id for Console ID. */
#define CONSOLE_SERIAL 1
#define CONSOLE_TELNET 2
/* Define two fixed console id for Console ID. | 默认两种固定的控制台id */
#define CONSOLE_SERIAL 1 ///< 串行方式
#define CONSOLE_TELNET 2 ///< 远程登录
//POSIX 定义了 STDIN_FILENO、STDOUT_FILENO 和 STDERR_FILENO 来代表 0、1、2
#define LOSCFG_PLATFORM_CONSOLE
#define STDIN 0
#define STDOUT 1
#define STDERR 2
#define STDIN 0 ///< 标准输入
#define STDOUT 1 ///< 标准输出
#define STDERR 2 ///< 错误
#define CONSOLE "/dev/console"
#define CONSOLE "/dev/console"
#define CONSOLE_NAMELEN 16
#define CONSOLE_RD_BLOCK 1
#define CONSOLE_RD_NONBLOCK 0
#define CONSOLE_SHELL_KEY_EVENT 0x112
#define CONSOLE_SHELL_EXITED 0x400
#define CONSOLE_FIFO_SIZE 0x400
#define CONSOLE_SHELL_KEY_EVENT 0x112 ///< shell 键盘事件
#define CONSOLE_SHELL_EXITED 0x400 ///< shell 退出事件
#define CONSOLE_FIFO_SIZE 0x400 ///< 1K
#define CONSOLE_NUM 2
#define CONSOLE_CIRCBUF_SIZE 0x400
#define CONSOLE_CIRCBUF_SIZE 0x400 ///< 大小 1K
/**
* @brief buf,
*/
typedef struct {
CirBuf cirBufCB; /* Circular buffer CB */
EVENT_CB_S sendEvent; /* Inform telnet send task */
CirBuf cirBufCB; /* Circular buffer CB | 循环缓冲控制块 */
EVENT_CB_S sendEvent; /* Inform telnet send task | 例如: 给SendToSer任务发送事件*/
} CirBufSendCB;
/**
* @brief ()
*/
typedef struct {
UINT32 consoleID;
UINT32 consoleType;
UINT32 consoleSem;
UINT32 consoleMask;
struct Vnode *devVnode;
CHAR *name;
INT32 fd;
UINT32 refCount;
UINT32 shellEntryId;
INT32 pgrpId;
BOOL isNonBlock;
UINT32 consoleID; ///< 控制台ID 例如 : 1 | 串口 , 2 | 远程登录
UINT32 consoleType; ///< 控制台类型
UINT32 consoleSem; ///< 控制台信号量
UINT32 consoleMask; ///< 控制台掩码
struct Vnode *devVnode; ///< 索引节点
CHAR *name; ///< 名称 例如: /dev/console1
INT32 fd; ///< 系统文件句柄, 由内核分配
UINT32 refCount; ///< 引用次数,用于判断控制台是否被占用
UINT32 shellEntryId; ///< 负责接受来自终端信息的 "ShellEntry"任务,这个值在运行过程中可能会被换掉,它始终指向当前正在运行的shell客户端
INT32 pgrpId; ///< 进程组ID
BOOL isNonBlock; ///< 是否无锁方式
#ifdef LOSCFG_SHELL
VOID *shellHandle;
VOID *shellHandle; ///< shell句柄,本质是 shell控制块 ShellCB
#endif
UINT32 sendTaskID;
CirBufSendCB *cirBufSendCB;
UINT8 fifo[CONSOLE_FIFO_SIZE];
UINT32 fifoOut;
UINT32 fifoIn;
UINT32 currentLen;
struct termios consoleTermios;
UINT32 sendTaskID; ///< 创建任务通过事件接收数据, 见于OsConsoleBufInit
CirBufSendCB *cirBufSendCB; ///< 循环缓冲发送控制块
UINT8 fifo[CONSOLE_FIFO_SIZE]; ///< termios 规范模式(ICANON mode )下使用 size:1K
UINT32 fifoOut; ///< 对fifo的标记,输出位置
UINT32 fifoIn; ///< 对fifo的标记,输入位置
UINT32 currentLen; ///< 当前fifo位置
struct termios consoleTermios; ///< 行规程
} CONSOLE_CB;
/**
* @brief https://man7.org/linux/man-pages/man3/tcflow.3.html
termios POSIXtermios
struct termios
{
unsigned short c_iflag; // 输入模式标志
unsigned short c_oflag; // 输出模式标志
unsigned short c_cflag; // 控制模式标志
unsigned short c_lflag; // 本地模式标志 例如: 设置非规范模式 tios.c_lflag = ~(ICANON | ECHO | ECHOE | ISIG);
unsigned char c_line; // 线路规程
unsigned char c_cc[NCC]; // 控制特性
speed_t c_ispeed; // 输入速度
speed_t c_ospeed; // 输出速度
}
canonical mode
non-canonical mode
raw mode
https://www.jianshu.com/p/fe5812469801
https://blog.csdn.net/wumenglu1018/article/details/53098794
*/
extern INT32 system_console_init(const CHAR *deviceName);
extern INT32 system_console_deinit(const CHAR *deviceName);
extern BOOL SetSerialNonBlock(const CONSOLE_CB *consoleCB);
@ -126,15 +174,15 @@ extern VOID OsWakeConsoleSendTask(VOID);
#endif
extern VOID KillPgrp(UINT16 consoleId);
/* console ioctl */
/* console ioctl | 控制台常见控制操作*/
#define CONSOLE_IOC_MAGIC 'c'
#define CONSOLE_CMD_RD_BLOCK_SERIAL _IO(CONSOLE_IOC_MAGIC, 1)
#define CONSOLE_CMD_RD_BLOCK_TELNET _IO(CONSOLE_IOC_MAGIC, 2)
#define CONSOLE_CONTROL_RIGHTS_CAPTURE _IO(CONSOLE_IOC_MAGIC, 3)
#define CONSOLE_CMD_RD_BLOCK_SERIAL _IO(CONSOLE_IOC_MAGIC, 1) ///< 设置串口方式
#define CONSOLE_CMD_RD_BLOCK_TELNET _IO(CONSOLE_IOC_MAGIC, 2) ///< 设置远程登录方式
#define CONSOLE_CONTROL_RIGHTS_CAPTURE _IO(CONSOLE_IOC_MAGIC, 3) ///<
#define CONSOLE_CONTROL_RIGHTS_RELEASE _IO(CONSOLE_IOC_MAGIC, 4)
#define CONSOLE_CONTROL_CAPTURE_LINE _IO(CONSOLE_IOC_MAGIC, 5)
#define CONSOLE_CONTROL_CAPTURE_CHAR _IO(CONSOLE_IOC_MAGIC, 6)
#define CONSOLE_CONTROL_REG_USERTASK _IO(CONSOLE_IOC_MAGIC, 7)
#define CONSOLE_CONTROL_REG_USERTASK _IO(CONSOLE_IOC_MAGIC, 7) ///< 注册用户任务 shell 客户端
#endif

@ -53,13 +53,13 @@
#include "los_vm_boot.h"
#include "los_smp.h"
STATIC SystemRebootFunc g_rebootHook = NULL;
STATIC SystemRebootFunc g_rebootHook = NULL;///< 系统重启钩子函数
/// 设置系统重启钩子函数
VOID OsSetRebootHook(SystemRebootFunc func)
{
g_rebootHook = func;
}
///获取系统重启钩子函数
SystemRebootFunc OsGetRebootHook(VOID)
{
return g_rebootHook;
@ -67,31 +67,31 @@ SystemRebootFunc OsGetRebootHook(VOID)
LITE_OS_SEC_TEXT_INIT STATIC UINT32 EarliestInit(VOID)
{
/* Must be placed at the beginning of the boot process */
OsSetMainTask();
OsCurrTaskSet(OsGetMainTask());
OsSchedRunqueueInit();
/* Must be placed at the beginning of the boot process *///必须放在启动过程的开头
OsSetMainTask();//为每个CPU核设置临时主任务
OsCurrTaskSet(OsGetMainTask());//设置当前任务
OsSchedRunqueueInit();//初始化调度队列
g_sysClock = OS_SYS_CLOCK;
g_tickPerSecond = LOSCFG_BASE_CORE_TICK_PER_SECOND;
g_sysClock = OS_SYS_CLOCK; //设置系统时钟
g_tickPerSecond = LOSCFG_BASE_CORE_TICK_PER_SECOND; // 设置TICK间隔
return LOS_OK;
}
//硬件早期初始化
LITE_OS_SEC_TEXT_INIT STATIC UINT32 ArchEarlyInit(VOID)
{
UINT32 ret;
/* set system counter freq */
/* set system counter freq | 设置系统计数器频率*/
#ifndef LOSCFG_TEE_ENABLE
HalClockFreqWrite(OS_SYS_CLOCK);
HalClockFreqWrite(OS_SYS_CLOCK); //写寄存器 MCR p15, 0, <Rt>, c14, c0, 0 ; Write Rt to CNTFRQ
#endif
#ifdef LOSCFG_PLATFORM_HWI
OsHwiInit();
OsHwiInit(); // 硬中断初始化
#endif
OsExcInit();
OsExcInit(); // 异常初始化
ret = OsTickInit(g_sysClock, LOSCFG_BASE_CORE_TICK_PER_SECOND);
if (ret != LOS_OK) {
@ -101,11 +101,11 @@ LITE_OS_SEC_TEXT_INIT STATIC UINT32 ArchEarlyInit(VOID)
return LOS_OK;
}
//平台早期初始化
LITE_OS_SEC_TEXT_INIT STATIC UINT32 PlatformEarlyInit(VOID)
{
#if defined(LOSCFG_PLATFORM_UART_WITHOUT_VFS) && defined(LOSCFG_DRIVERS)
uart_init();
uart_init(); //初始化串口
#endif /* LOSCFG_PLATFORM_UART_WITHOUT_VFS */
return LOS_OK;
@ -145,11 +145,11 @@ LITE_OS_SEC_TEXT_INIT STATIC UINT32 PlatformInit(VOID)
{
return LOS_OK;
}
//内核关键模块初始化
LITE_OS_SEC_TEXT_INIT STATIC UINT32 KModInit(VOID)
{
#ifdef LOSCFG_BASE_CORE_SWTMR_ENABLE
OsSwtmrInit();
OsSwtmrInit(); //软件定时器模块 , 软定由专门的 0 级任务实现
#endif
return LOS_OK;
}
@ -179,10 +179,10 @@ LITE_OS_SEC_TEXT_INIT VOID OsSystemInfo(VOID)
#ifdef LOSCFG_KERNEL_SMP
LOSCFG_KERNEL_SMP_CORE_NUM,
#endif
HalIrqVersion(), __DATE__, __TIME__, \
HalIrqVersion(), __DATE__, __TIME__,\
KERNEL_NAME, KERNEL_MAJOR, KERNEL_MINOR, KERNEL_PATCH, KERNEL_ITRE, buildType);
}
///由汇编调用,鸿蒙C语言层级的入口点
LITE_OS_SEC_TEXT_INIT UINT32 OsMain(VOID)
{
UINT32 ret;
@ -190,19 +190,19 @@ LITE_OS_SEC_TEXT_INIT UINT32 OsMain(VOID)
UINT64 startNsec, endNsec, durationUsec;
#endif
ret = EarliestInit();
ret = EarliestInit();//鸿蒙初开,天地混沌
if (ret != LOS_OK) {
return ret;
}
OsInitCall(LOS_INIT_LEVEL_EARLIEST);
ret = ArchEarlyInit();
ret = ArchEarlyInit(); //架构级初始化,包括硬中断
if (ret != LOS_OK) {
return ret;
}
OsInitCall(LOS_INIT_LEVEL_ARCH_EARLY);
ret = PlatformEarlyInit();
ret = PlatformEarlyInit();//平台级初始化
if (ret != LOS_OK) {
return ret;
}
@ -224,24 +224,24 @@ LITE_OS_SEC_TEXT_INIT UINT32 OsMain(VOID)
OsInitCall(LOS_INIT_LEVEL_KMOD_PREVM);
ret = OsSysMemInit();
ret = OsSysMemInit();//系统内存初始化
if (ret != LOS_OK) {
return ret;
}
OsInitCall(LOS_INIT_LEVEL_VM_COMPLETE);
ret = OsIpcInit();
ret = OsIpcInit();//进程间通讯模块初始化
if (ret != LOS_OK) {
return ret;
}
ret = OsSystemProcessCreate();
ret = OsSystemProcessCreate();//创建系统进程
if (ret != LOS_OK) {
return ret;
}
ret = ArchInit();
ret = ArchInit(); //MMU架构初始化
if (ret != LOS_OK) {
return ret;
}
@ -285,8 +285,8 @@ STATIC VOID SystemInit(VOID)
#else
extern VOID SystemInit(VOID);
#endif
#ifndef LOSCFG_ENABLE_KERNEL_TEST
///创建系统初始任务并申请调度
STATIC UINT32 OsSystemInitTaskCreate(VOID)
{
UINT32 taskID;
@ -304,6 +304,7 @@ STATIC UINT32 OsSystemInitTaskCreate(VOID)
return LOS_TaskCreate(&taskID, &sysTask);
}
//系统任务初始化
STATIC UINT32 OsSystemInit(VOID)
{
UINT32 ret;
@ -316,5 +317,5 @@ STATIC UINT32 OsSystemInit(VOID)
return 0;
}
LOS_MODULE_INIT(OsSystemInit, LOS_INIT_LEVEL_KMOD_TASK);
LOS_MODULE_INIT(OsSystemInit, LOS_INIT_LEVEL_KMOD_TASK);//模块初始化
#endif

@ -1,6 +1,6 @@
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2022 Huawei Device Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
@ -46,35 +46,35 @@ extern "C" {
#endif /* __cplusplus */
/**
* @ingroup los_config
* int stack start addr
* @ingroup los_config
* int stack start addr | ,liteos.ld
*/
extern CHAR __int_stack_start;
extern CHAR __rodata_start;
extern CHAR __rodata_end;
extern CHAR __bss_start;
extern CHAR __bss_end;
extern CHAR __text_start;
extern CHAR __text_end;
extern CHAR __ram_data_start;
extern CHAR __ram_data_end;
extern UINT32 __heap_start;
extern UINT32 __heap_end;
extern CHAR __int_stack_start; ///< 运行系统函数栈的开始地址 值来自于 liteos.ld中的 __int_stack_start = .;
extern CHAR __rodata_start; ///< ROM开始地址 只读
extern CHAR __rodata_end; ///< ROM结束地址
extern CHAR __bss_start; ///< bss开始地址 __attribute__((section(".__bss_start")));
extern CHAR __bss_end; ///< bss结束地址 __attribute__((section(".__bss_end")));
extern CHAR __text_start; ///< 代码区开始地址
extern CHAR __text_end; ///< 代码区结束地址
extern CHAR __ram_data_start; ///< RAM开始地址 可读可写
extern CHAR __ram_data_end; ///< RAM结束地址
extern UINT32 __heap_start; ///< 堆区开始地址
extern UINT32 __heap_end; ///< 堆区结束地址
/****************************** System clock module configuration ****************************/
/**
* @ingroup los_config
* System clock (unit: HZ)
*/
#ifndef OS_SYS_CLOCK
#define OS_SYS_CLOCK (get_bus_clk())
#ifndef OS_SYS_CLOCK ///< HZ:是每秒中的周期性变动重复次数的计量
#define OS_SYS_CLOCK (get_bus_clk()) ///< 系统主时钟频率 例如:50000000 即20纳秒
#endif
/**
* @ingroup los_config
* time timer clock (unit: HZ)
*/
#ifndef OS_TIME_TIMER_CLOCK
#define OS_TIME_TIMER_CLOCK OS_SYS_CLOCK
#define OS_TIME_TIMER_CLOCK OS_SYS_CLOCK ///< 定时器频率
#endif
/**
@ -82,10 +82,10 @@ extern UINT32 __heap_end;
* limit addr range when search for 'func local(frame pointer)' or 'func name'
*/
#ifndef OS_SYS_FUNC_ADDR_START
#define OS_SYS_FUNC_ADDR_START ((UINTPTR)&__int_stack_start)
#define OS_SYS_FUNC_ADDR_START ((UINTPTR)&__int_stack_start) //
#endif
#ifndef OS_SYS_FUNC_ADDR_END
#define OS_SYS_FUNC_ADDR_END (KERNEL_VMM_BASE + SYS_MEM_SIZE_DEFAULT)
#define OS_SYS_FUNC_ADDR_END (KERNEL_VMM_BASE + SYS_MEM_SIZE_DEFAULT)
#endif
/**
@ -93,7 +93,7 @@ extern UINT32 __heap_end;
* Number of Ticks in one second
*/
#ifndef LOSCFG_BASE_CORE_TICK_PER_SECOND
#define LOSCFG_BASE_CORE_TICK_PER_SECOND 1000 /* 1ms per tick */
#define LOSCFG_BASE_CORE_TICK_PER_SECOND 1000 /* 1ms per tick | 每秒节拍数*/
#endif
/**
@ -131,14 +131,15 @@ extern UINT32 __heap_end;
* External configuration item for timer tailoring
*/
#if defined(LOSCFG_BASE_CORE_TICK_HW_TIME) && (LOSCFG_BASE_CORE_TICK_HW_TIME == 0)
#undef LOSCFG_BASE_CORE_TICK_HW_TIME
#undef LOSCFG_BASE_CORE_TICK_HW_TIME ///< 定时器裁剪的外部配置项
#endif
/****************************** Hardware interrupt module configuration ******************************/
/**
* @ingroup los_config
* Configuration item for hardware interrupt tailoring
* Configuration item for hardware interrupt tailoring
*/
#ifndef LOSCFG_PLATFORM_HWI
#ifndef LOSCFG_PLATFORM_HWI ///< 硬件中断裁剪配置项
#define LOSCFG_PLATFORM_HWI
#endif
@ -147,7 +148,7 @@ extern UINT32 __heap_end;
* Maximum number of used hardware interrupts, including Tick timer interrupts.
*/
#ifndef LOSCFG_PLATFORM_HWI_LIMIT
#define LOSCFG_PLATFORM_HWI_LIMIT 96
#define LOSCFG_PLATFORM_HWI_LIMIT 96 ///< 硬件中断最大数量
#endif
/**
@ -167,8 +168,8 @@ extern UINT32 __heap_end;
* @ingroup los_config
* Minimum stack size.
*
* 0x800 bytes, aligned on a boundary of 8.
* 0x800 bytes, aligned on a boundary of 4.
* 0x600 bytes, aligned on a boundary of 8.
* 0x600 bytes, aligned on a boundary of 4.
*/
#ifndef LOS_TASK_MIN_STACK_SIZE
#ifdef __LP64__
@ -182,7 +183,7 @@ extern UINT32 __heap_end;
* @ingroup los_config
* Default task priority
*/
#ifndef LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO
#ifndef LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO ///< 内核任务默认优先级
#define LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO 10
#endif
@ -190,7 +191,7 @@ extern UINT32 __heap_end;
* @ingroup los_config
* Maximum supported number of tasks except the idle task rather than the number of usable tasks
*/
#ifndef LOSCFG_BASE_CORE_TSK_LIMIT
#ifndef LOSCFG_BASE_CORE_TSK_LIMIT ///< 支持的最大任务数(空闲任务除外,而不是可用任务数)
#define LOSCFG_BASE_CORE_TSK_LIMIT 128
#endif
@ -198,7 +199,7 @@ extern UINT32 __heap_end;
* @ingroup los_config
* Maximum supported number of process rather than the number of usable processes.
*/
#ifndef LOSCFG_BASE_CORE_PROCESS_LIMIT
#ifndef LOSCFG_BASE_CORE_PROCESS_LIMIT ///< 支持的最大进程数,而不是可用进程数
#define LOSCFG_BASE_CORE_PROCESS_LIMIT 64
#endif
@ -210,23 +211,23 @@ extern UINT32 __heap_end;
* @ingroup los_config
* Size of the idle task stack
*/
#ifndef LOSCFG_BASE_CORE_TSK_IDLE_STACK_SIZE
#define LOSCFG_BASE_CORE_TSK_IDLE_STACK_SIZE SIZE(0x800)
#ifndef LOSCFG_BASE_CORE_TSK_IDLE_STACK_SIZE ///< 空闲任务栈大小
#define LOSCFG_BASE_CORE_TSK_IDLE_STACK_SIZE SIZE(0x800) ///< 2K
#endif
/**
* @ingroup los_config
* Default task stack size
*/
#ifndef LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE
#define LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE SIZE(0x4000)
#ifndef LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE //内核默认任务栈大小
#define LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE SIZE(0x4000) ///< 16K
#endif
/**
* @ingroup los_config
* Longest execution time of tasks with the same priorities
*/
#ifndef LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT
#ifndef LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT //相同优先级任务的最长执行时间,时间片
#define LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT 20000 /* 20ms */
#endif
@ -234,7 +235,7 @@ extern UINT32 __heap_end;
* @ingroup los_config
* Configuration item for task (stack) monitoring module tailoring
*/
#ifndef LOSCFG_BASE_CORE_TSK_MONITOR
#ifndef LOSCFG_BASE_CORE_TSK_MONITOR //任务(栈)监控模块裁剪配置项
#define LOSCFG_BASE_CORE_TSK_MONITOR
#endif
@ -244,7 +245,7 @@ extern UINT32 __heap_end;
* Configuration item for semaphore module tailoring
*/
#ifndef LOSCFG_BASE_IPC_SEM
#define LOSCFG_BASE_IPC_SEM
#define LOSCFG_BASE_IPC_SEM //信号量支持
#endif
/**
@ -252,7 +253,7 @@ extern UINT32 __heap_end;
* Maximum supported number of semaphores
*/
#ifndef LOSCFG_BASE_IPC_SEM_LIMIT
#define LOSCFG_BASE_IPC_SEM_LIMIT 1024
#define LOSCFG_BASE_IPC_SEM_LIMIT 1024 //信号量的最大个数
#endif
/**
@ -262,7 +263,6 @@ extern UINT32 __heap_end;
#ifndef OS_SEM_COUNT_MAX
#define OS_SEM_COUNT_MAX 0xFFFE
#endif
/****************************** Mutex module configuration ******************************/
/**
* @ingroup los_config
@ -295,7 +295,7 @@ extern UINT32 __heap_end;
* Maximum supported number of queues rather than the number of usable queues
*/
#ifndef LOSCFG_BASE_IPC_QUEUE_LIMIT
#define LOSCFG_BASE_IPC_QUEUE_LIMIT 1024
#define LOSCFG_BASE_IPC_QUEUE_LIMIT 1024 //队列个数
#endif
/****************************** Software timer module configuration **************************/
#ifdef LOSCFG_BASE_IPC_QUEUE
@ -319,23 +319,23 @@ extern UINT32 __heap_end;
* Maximum supported number of software timers rather than the number of usable software timers
*/
#ifndef LOSCFG_BASE_CORE_SWTMR_LIMIT
#define LOSCFG_BASE_CORE_SWTMR_LIMIT 1024
#define LOSCFG_BASE_CORE_SWTMR_LIMIT 1024 // 最大支持的软件定时器数
#endif
/**
* @ingroup los_config
* Max number of software timers ID
*
* 0xFFFF: max number of all software timers
* 0xFFFF: max number of all software timers |
*/
#ifndef OS_SWTMR_MAX_TIMERID
#define OS_SWTMR_MAX_TIMERID ((0xFFFF / LOSCFG_BASE_CORE_SWTMR_LIMIT) * LOSCFG_BASE_CORE_SWTMR_LIMIT)
#define OS_SWTMR_MAX_TIMERID ((0xFFFF / LOSCFG_BASE_CORE_SWTMR_LIMIT) * LOSCFG_BASE_CORE_SWTMR_LIMIT) ///< 65535
#endif
/**
* @ingroup los_config
* Maximum size of a software timer queue
*/
#ifndef OS_SWTMR_HANDLE_QUEUE_SIZE
#define OS_SWTMR_HANDLE_QUEUE_SIZE LOSCFG_BASE_CORE_SWTMR_LIMIT
#define OS_SWTMR_HANDLE_QUEUE_SIZE LOSCFG_BASE_CORE_SWTMR_LIMIT ///< 软时钟队列的大小
#endif
#endif
@ -346,26 +346,27 @@ extern UINT32 __heap_end;
* Starting address of the system memory
*/
#ifndef OS_SYS_MEM_ADDR
#define OS_SYS_MEM_ADDR (&m_aucSysMem1[0])
#define OS_SYS_MEM_ADDR (&m_aucSysMem1[0])//系统内存起始地址(指虚拟地址)
#endif
/**
* @ingroup los_config
* Memory size
*/
#ifndef OS_SYS_MEM_SIZE
#ifndef OS_SYS_MEM_SIZE //系统动态内存池的大小DDR自适应配置以byte为单位,从bss段末尾至系统DDR末尾
#define OS_SYS_MEM_SIZE \
((OS_SYS_FUNC_ADDR_END) - (((UINTPTR)&__bss_end + (64 - 1)) & ~(64 - 1)))
#endif
/****************************** SMP module configuration **************************/
//http://www.gotw.ca/publications/concurrency-ddj.htm 免费午餐结束了:软件并发的根本转变
#ifdef LOSCFG_KERNEL_SMP
#define LOSCFG_KERNEL_CORE_NUM LOSCFG_KERNEL_SMP_CORE_NUM
#define LOSCFG_KERNEL_CORE_NUM LOSCFG_KERNEL_SMP_CORE_NUM //多核情况下支持的CPU核数
#else
#define LOSCFG_KERNEL_CORE_NUM 1
#define LOSCFG_KERNEL_CORE_NUM 1 //单核配置
#endif
#define LOSCFG_KERNEL_CPU_MASK ((1 << LOSCFG_KERNEL_CORE_NUM) - 1)
#define LOSCFG_KERNEL_CPU_MASK ((1 << LOSCFG_KERNEL_CORE_NUM) - 1) //CPU掩码,每一个核占用一个位,用于计算和定位具体CPU核
/**
* @ingroup los_config
@ -379,11 +380,11 @@ extern UINT32 __heap_end;
/**
* @ingroup los_config
* The Version number of Public
* The Version number of Public //Public的版本号 ,每个占8位,刚好一个字节
*/
#define KERNEL_MAJOR 2
#define KERNEL_MINOR 0
#define KERNEL_PATCH 0
#define KERNEL_MAJOR 2 //主版本号
#define KERNEL_MINOR 0 //小版本号
#define KERNEL_PATCH 0 //补丁版本号
#define KERNEL_ITRE 37
#define VERSION_NUM(a, b, c, d) (((a) << 24) | ((b) << 16) | (c) << 8 | (d))
@ -403,7 +404,7 @@ extern UINT32 __heap_end;
* @ingroup los_config
* the size of space for recording exception information
*/
#define EXCINFO_RECORD_BUF_SIZE (16 * 1024)
#define EXCINFO_RECORD_BUF_SIZE (16 * 1024) //记录异常信息缓存大小 16K
/**
* @ingroup los_config
@ -411,11 +412,11 @@ extern UINT32 __heap_end;
* @attention
* <ul>
* <li> if uses, the address must be valid in flash, and it should not overlap with other addresses
* used to store valid information. </li>
* used to store valid information. </li>
* </ul>
*
*/
#define EXCINFO_RECORD_ADDR (0xffffffff)
#define EXCINFO_RECORD_ADDR (0xffffffff) //记录异常信息的空间地址
/**
* @ingroup los_config
@ -423,7 +424,7 @@ extern UINT32 __heap_end;
*
* @par Description:
* <ul>
* <li>This definition is used to declare the type of functions for reading or writing exception information</li>
* <li>This defination is used to declare the type of functions for reading or writing exception information</li>
* </ul>
* @attention
* <ul>
@ -437,9 +438,9 @@ extern UINT32 __heap_end;
*
* @retval none.
* @par Dependency:
* <ul><li>los_config.h: the header file that contains the type definition.</li></ul>
* <ul><li>los_config.h: the header file that contains the type defination.</li></ul>
* @see
*/
*/ //定义用于读取或写入异常信息的指针函数类型
typedef VOID (*log_read_write_fn)(UINT32 startAddr, UINT32 space, UINT32 rwFlag, CHAR *buf);
/**
@ -468,6 +469,13 @@ typedef VOID (*log_read_write_fn)(UINT32 startAddr, UINT32 space, UINT32 rwFlag,
* <ul><li>los_config.h: the header file that contains the API declaration.</li></ul>
* @see
*/
/**
* API
* startAddr:
* space: buf
* buf:
* hook:
*/
VOID LOS_ExcInfoRegHook(UINT32 startAddr, UINT32 space, CHAR *buf, log_read_write_fn hook);
#endif
@ -476,7 +484,6 @@ extern UINT32 OsMain(VOID);
typedef VOID (*SystemRebootFunc)(VOID);
VOID OsSetRebootHook(SystemRebootFunc func);
SystemRebootFunc OsGetRebootHook(VOID);
#ifdef __cplusplus
#if __cplusplus
}

@ -40,37 +40,37 @@
#endif
#ifdef LOSCFG_SAVE_EXCINFO
STATIC log_read_write_fn g_excInfoRW = NULL; /* the hook of read-writing exception information */
STATIC CHAR *g_excInfoBuf = NULL; /* pointer to the buffer for storing the exception information */
STATIC UINT32 g_excInfoIndex = 0xFFFFFFFF; /* the index of the buffer for storing the exception information */
STATIC UINT32 g_recordAddr = 0; /* the address of storing the exception information */
STATIC UINT32 g_recordSpace = 0; /* the size of storing the exception information */
STATIC log_read_write_fn g_excInfoRW = NULL; /* the hook of read-writing exception information */ //读写异常信息的钩子函数
STATIC CHAR *g_excInfoBuf = NULL; /* pointer to the buffer for storing the exception information */ //指向存储异常信息的缓冲区的指针
STATIC UINT32 g_excInfoIndex = 0xFFFFFFFF; /* the index of the buffer for storing the exception information */ //用于存储异常信息的缓冲区的索引
STATIC UINT32 g_recordAddr = 0; /* the address of storing the exception information */ //存储异常信息的地址
STATIC UINT32 g_recordSpace = 0; /* the size of storing the exception information */ //存储异常信息的大小
//设置异常信息的读写函数
VOID SetExcInfoRW(log_read_write_fn func)
{
g_excInfoRW = func;
}
///获取异常信息读写函数
log_read_write_fn GetExcInfoRW(VOID)
{
return g_excInfoRW;
}
///设置异常信息的缓存
VOID SetExcInfoBuf(CHAR *buf)
{
g_excInfoBuf = buf;
}
///获取异常信息的缓存
CHAR *GetExcInfoBuf(VOID)
{
return g_excInfoBuf;
}
///设置异常信息索引位
VOID SetExcInfoIndex(UINT32 index)
{
g_excInfoIndex = index;
}
///获取异常信息索引位
UINT32 GetExcInfoIndex(VOID)
{
return g_excInfoIndex;
@ -95,7 +95,7 @@ UINT32 GetRecordSpace(VOID)
{
return g_recordSpace;
}
///vsnprintf 为C标准库可变参数的实现函数 见于 ..\third_party\musl\kernel\src\stdio\vsnprintf.c
VOID WriteExcBufVa(const CHAR *format, va_list arglist)
{
errno_t ret;
@ -110,16 +110,15 @@ VOID WriteExcBufVa(const CHAR *format, va_list arglist)
g_excInfoIndex += ret;
}
}
///写异常信息到系统异常信息中心
VOID WriteExcInfoToBuf(const CHAR *format, ...)
{
va_list arglist;
va_start(arglist, format);
WriteExcBufVa(format, arglist);
va_end(arglist);
va_list arglist;//va_arg
va_start(arglist, format);//从任务栈中取出入栈参数
WriteExcBufVa(format, arglist);//入栈参数列表作为实参传入交由vsnprintf处理
va_end(arglist);//释放资源
}
///用于注册记录异常信息函数,并指定位置、空间和大小
VOID LOS_ExcInfoRegHook(UINT32 startAddr, UINT32 space, CHAR *buf, log_read_write_fn hook)
{
if ((hook == NULL) || (buf == NULL)) {
@ -133,11 +132,11 @@ VOID LOS_ExcInfoRegHook(UINT32 startAddr, UINT32 space, CHAR *buf, log_read_writ
g_excInfoRW = hook;
#ifdef LOSCFG_FS_VFS
los_vfs_init();
los_vfs_init();//初始化虚拟文件系统
#endif
}
/* Be called in the exception. */
/* Be called in the exception. */ //异常发生时回调这里
VOID OsReadWriteExceptionInfo(UINT32 startAddr, UINT32 space, UINT32 flag, CHAR *buf)
{
if ((buf == NULL) || (space == 0)) {
@ -146,7 +145,7 @@ VOID OsReadWriteExceptionInfo(UINT32 startAddr, UINT32 space, UINT32 flag, CHAR
}
// user can write exception information to files here
}
///记录异常信息产生的时间
VOID OsRecordExcInfoTime(VOID)
{
#ifdef LOSCFG_FS_VFS
@ -156,12 +155,12 @@ VOID OsRecordExcInfoTime(VOID)
CHAR nowTime[NOW_TIME_LENGTH];
(VOID)time(&t);
tmTime = localtime(&t);
tmTime = localtime(&t);//获取本地时间的标准C库函数
if (tmTime == NULL) {
return;
}
(VOID)memset_s(nowTime, sizeof(nowTime), 0, sizeof(nowTime));
(VOID)strftime(nowTime, NOW_TIME_LENGTH, "%Y-%m-%d %H:%M:%S", tmTime);
(VOID)strftime(nowTime, NOW_TIME_LENGTH, "%Y-%m-%d %H:%M:%S", tmTime);//生成时间格式
#undef NOW_TIME_LENGTH
WriteExcInfoToBuf("%s \n", nowTime);
#endif

@ -43,17 +43,18 @@
#endif
/**
* Register kernel init level labels.
* Register kernel init level labels. |
*/
OS_INIT_LEVEL_REG(kernel, 10, g_kernInitLevelList);
STATIC volatile UINT32 g_initCurrentLevel = OS_INVALID_VALUE;
STATIC volatile struct ModuleInitInfo *g_initCurrentModule = 0;
STATIC volatile UINT32 g_initCurrentLevel = OS_INVALID_VALUE; //当前等级
STATIC volatile struct ModuleInitInfo *g_initCurrentModule = 0; //当前模块
STATIC Atomic g_initCount = 0;
STATIC SPIN_LOCK_INIT(g_initLock);
/**
* It is recommended that each startup framework encapsulate a layer of its own calling interface.
*
*/
STATIC VOID InitLevelCall(const CHAR *name, const UINT32 level, struct ModuleInitInfo *initLevelList[])
{
@ -65,13 +66,13 @@ STATIC VOID InitLevelCall(const CHAR *name, const UINT32 level, struct ModuleIni
UINT32 ret = LOS_OK;
#endif
if (ArchCurrCpuid() == 0) {
if (ArchCurrCpuid() == 0) {//主CPU
#ifdef LOS_INIT_DEBUG
PRINTK("-------- %s Module Init... level = %u --------\n", name, level);
#endif
g_initCurrentLevel = level;
g_initCurrentModule = initLevelList[level];
} else {
} else {
while (g_initCurrentLevel < level) {
}
}
@ -116,6 +117,12 @@ STATIC VOID InitLevelCall(const CHAR *name, const UINT32 level, struct ModuleIni
#endif
}
/**
* @brief ,..
.
* @param level
* @return VOID
*/
VOID OsInitCall(const UINT32 level)
{
if (level >= LOS_INIT_LEVEL_FINISH) {

@ -59,10 +59,10 @@
#define INIT_SECTION(_type, _level, _hook) __attribute__((section(".rodata.init."#_type"."#_level"."#_hook)))
#define INIT_ALIGN __attribute__((aligned(alignof(struct ModuleInitInfo))))
typedef UINT32 (*OsInitHook)(VOID);
typedef UINT32 (*OsInitHook)(VOID);//初始化钩子函数
struct ModuleInitInfo {
OsInitHook hook;
struct ModuleInitInfo {//模块初始化信息
OsInitHook hook; ///< 函数指针,钩子函数
#ifdef LOS_INIT_DEBUG
const CHAR *name;
#endif
@ -94,14 +94,14 @@ struct ModuleInitInfo {
* @par Dependency:
* <ul><li>los_task_info.h: the header file that contains the API declaration.</li></ul>
* @see
*/
*/ //将注册模块添加到启动框架中的指定级别。
#define OS_INIT_HOOK_REG(_type, _hook, _level) \
STATIC const struct ModuleInitInfo ModuleInitInfo_##_hook \
USED INIT_SECTION(_type, _level, _hook) INIT_ALIGN = { \
.hook = (UINT32 (*)(VOID))&_hook, \
SET_MODULE_NAME(_hook) \
};
//注册到 .rodata.init.
#define EXTERN_LABEL(_type, _level) extern struct ModuleInitInfo __##_type##_init_level_##_level;
#define GET_LABEL(_type, _level) &__##_type##_init_level_##_level,
@ -162,7 +162,7 @@ struct ModuleInitInfo {
*/
#define OS_INIT_LEVEL_REG(_type, _num, _list) \
INIT_LABEL_REG_##_num(EXTERN_LABEL, _type) \
STATIC struct ModuleInitInfo *_list[] = { \
STATIC struct ModuleInitInfo* _list [] = { \
INIT_LABEL_REG_##_num(GET_LABEL, _type) \
}

@ -1,6 +1,6 @@
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2022 Huawei Device Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
@ -34,36 +34,39 @@
#include "los_task_pri.h"
#include "los_process_pri.h"
/// 魔法键依赖于宏LOSCFG_ENABLE_MAGICKEY使用时通过menuconfig在配置项中开启“Enable MAGIC KEY”
/// Debug ---> Enable MAGIC KEY若关闭该选项则魔法键失效。
#ifdef LOSCFG_ENABLE_MAGICKEY
#define MAGIC_KEY_NUM 5
STATIC VOID OsMagicHelp(VOID);
STATIC VOID OsMagicTaskShow(VOID);
STATIC VOID OsMagicPanic(VOID);
STATIC VOID OsMagicMemCheck(VOID);
STATIC MagicKeyOp g_magicMemCheckOp = {
.opHandler = OsMagicMemCheck,
STATIC MagicKeyOp g_magicMemCheckOp = {//快捷键内存检查
.opHandler = OsMagicMemCheck, //等于执行了一次 shell memcheck
.helpMsg = "Check system memory(ctrl+e) ",
.magicKey = 0x05 /* ctrl + e */
.magicKey = 0x05 /* ctrl + e */ //系统进行简单完整性内存池检查检查出错会输出相关错误信息检查正常会输出“system memcheck over, all passed!”
};
STATIC MagicKeyOp g_magicPanicOp = {
.opHandler = OsMagicPanic,
STATIC MagicKeyOp g_magicPanicOp = {//panic 表示kernel走到了一个不知道该怎么走下一步的状况
.opHandler = OsMagicPanic, //一旦到这个情况kernel就尽可能把它此时能获取的全部信息都打印出来.
.helpMsg = "System panic(ctrl+p) ",
.magicKey = 0x10 /* ctrl + p */
.magicKey = 0x10 /* ctrl + p */ //系统主动进入panic输出panic相关信息后系统会挂住
};
STATIC MagicKeyOp g_magicTaskShowOp = {
.opHandler = OsMagicTaskShow,
STATIC MagicKeyOp g_magicTaskShowOp = { //快捷键显示任务操作
.opHandler = OsMagicTaskShow, //等于执行了一次 shell task -a
.helpMsg = "Show task information(ctrl+t) ",
.magicKey = 0x14 /* ctrl + t */
.magicKey = 0x14 /* ctrl + t */ //输出任务相关信息;
};
STATIC MagicKeyOp g_magicHelpOp = {
STATIC MagicKeyOp g_magicHelpOp = { //快捷键帮助操作
.opHandler = OsMagicHelp,
.helpMsg = "Show all magic op key(ctrl+z) ",
.magicKey = 0x1a /* ctrl + z */
.magicKey = 0x1a /* ctrl + z */ //帮助键,输出相关魔法键简单介绍;
};
/*
@ -74,7 +77,7 @@ STATIC MagicKeyOp g_magicHelpOp = {
* ctrl+n/shift out=0xe,
* ctrl+o/shift in=0xf,
* ctrl+[/esc=0x1b,
* ctrl+] used for telnet command mode;
* ctrl+] used for telnet commond mode;
*/
STATIC MagicKeyOp *g_magicOpTable[MAGIC_KEY_NUM] = {
&g_magicMemCheckOp, /* ctrl + e */
@ -84,7 +87,7 @@ STATIC MagicKeyOp *g_magicOpTable[MAGIC_KEY_NUM] = {
NULL
};
STATIC VOID OsMagicHelp(VOID)
STATIC VOID OsMagicHelp(VOID)//遍历一下 g_magicOpTable
{
INT32 i;
PRINTK("HELP: ");
@ -94,7 +97,7 @@ STATIC VOID OsMagicHelp(VOID)
PRINTK("\n");
return;
}
///执行 shell task -a 命令
STATIC VOID OsMagicTaskShow(VOID)
{
(VOID)OsShellCmdTskInfoGet(OS_ALL_TASK_MASK, NULL, OS_PROCESS_INFO_ALL);
@ -106,7 +109,7 @@ STATIC VOID OsMagicPanic(VOID)
LOS_Panic("Magic key :\n");
return;
}
///快捷键触发内存检查
STATIC VOID OsMagicMemCheck(VOID)
{
if (LOS_MemIntegrityCheck(m_aucSysMem1) == LOS_OK) {
@ -115,10 +118,10 @@ STATIC VOID OsMagicMemCheck(VOID)
return;
}
#endif
///检查魔法键
INT32 CheckMagicKey(CHAR key, UINT16 consoleId)
{
#ifdef LOSCFG_ENABLE_MAGICKEY
#ifdef LOSCFG_ENABLE_MAGICKEY //魔法键开关
INT32 i;
STATIC UINT32 magicKeySwitch = 0;
@ -126,6 +129,8 @@ INT32 CheckMagicKey(CHAR key, UINT16 consoleId)
KillPgrp(consoleId);
return 0;
} else if (key == 0x12) { /* ctrl + r */
// 在连接UART或者USB转虚拟串口的情况下输入“ctrl + r” 键,打开魔法键检测功能,输出 “Magic key on”再输入一次后
// 则关闭魔法键检测功能输出“Magic key off”。
magicKeySwitch = ~magicKeySwitch;
if (magicKeySwitch != 0) {
PrintExcInfo("Magic key on\n");
@ -134,10 +139,10 @@ INT32 CheckMagicKey(CHAR key, UINT16 consoleId)
}
return 1;
}
if (magicKeySwitch != 0) {
if (magicKeySwitch != 0) {//打开情况下,输出魔法键各回调函数
for (i = 0; i < MAGIC_KEY_NUM; i++) {
if (g_magicOpTable[i] != NULL && key == g_magicOpTable[i]->magicKey) {
(g_magicOpTable[i])->opHandler();
(g_magicOpTable[i])->opHandler();//执行回调函数 OsMagicHelp OsMagicTaskShow ==
return 1;
}
}

@ -40,10 +40,10 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
typedef struct {
VOID (*opHandler)(VOID);
CHAR *helpMsg;
CHAR magicKey;
typedef struct { //魔法键处理结构体
VOID (*opHandler)(VOID); //触发执行函数
CHAR *helpMsg; //消息提示
CHAR magicKey; //魔法键
} MagicKeyOp;
extern INT32 CheckMagicKey(CHAR key, UINT16 consoleId);

@ -51,14 +51,14 @@
#define SIZEBUF 256
const CHAR *g_logString[] = {
"EMG",
"COMMON",
"ERR",
"WARN",
"INFO",
"DEBUG",
"TRACE"
const CHAR *g_logString[] = {//日志等级
"EMG", //紧急
"COMMON", //普通
"ERR", //错误日志
"WARN", //警告
"INFO", //信息
"DEBUG", //调试
"TRACE" //跟踪
};
const CHAR *OsLogLvGet(INT32 level)
@ -71,54 +71,54 @@ STATIC VOID ErrorMsg(VOID)
const CHAR *p = "Output illegal string! vsnprintf_s failed!\n";
UartPuts(p, (UINT32)strlen(p), UART_WITH_LOCK);
}
///串口输出,打印消息的本质就是向串口输出buf
STATIC VOID UartOutput(const CHAR *str, UINT32 len, BOOL isLock)
{
#ifdef LOSCFG_SHELL_DMESG
if (!OsCheckUartLock()) {
UartPuts(str, len, isLock);
#ifdef LOSCFG_SHELL_DMESG //是否打开了 dmesg开关,打开了会写到文件中 var/log/dmesg 文件中
if (!OsCheckUartLock()) {//是否被锁
UartPuts(str, len, isLock);//直接写串口
}
if (isLock != UART_WITHOUT_LOCK) {
(VOID)OsLogMemcpyRecord(str, len);
(VOID)OsLogMemcpyRecord(str, len);//写入dmesg缓存区
}
#else
UartPuts(str, len, isLock);
UartPuts(str, len, isLock);//没有打开dmesg开关时,直接写串口
#endif
}
///控制台输出
#ifdef LOSCFG_PLATFORM_CONSOLE
STATIC VOID ConsoleOutput(const CHAR *str, UINT32 len)
{
ssize_t written = 0;
ssize_t cnt;
ssize_t toWrite = len;
ssize_t toWrite = len;//每次写入的数量
for (;;) {
cnt = write(STDOUT_FILENO, str + written, (size_t)toWrite);
cnt = write(STDOUT_FILENO, str + written, (size_t)toWrite);//向控制台写入数据,STDOUT_FILENO = 1
if ((cnt < 0) || ((cnt == 0) && ((!OsPreemptable()) || (OS_INT_ACTIVE))) || (toWrite == cnt)) {
break;
}
written += cnt;
toWrite -= cnt;
written += cnt; //已写入数量增加
toWrite -= cnt; //要写入数量减少
}
}
#endif
VOID OutputControl(const CHAR *str, UINT32 len, OutputType type)
{
switch (type) {
case CONSOLE_OUTPUT:
switch (type) {//输出类型
case CONSOLE_OUTPUT://控制台输出
#ifdef LOSCFG_PLATFORM_CONSOLE
if (ConsoleEnable() == TRUE) {
ConsoleOutput(str, len);
if (ConsoleEnable() == TRUE) {//POSIX 定义了 STDIN_FILENO、STDOUT_FILENO 和 STDERR_FILENO 来代替 0、1、2
ConsoleOutput(str, len);//输出到控制台
break;
}
#endif
/* fall-through */
case UART_OUTPUT:
UartOutput(str, len, UART_WITH_LOCK);
/* fall-through */ //落空的情况下,会接着向串口打印数据
case UART_OUTPUT: //串口输出
UartOutput(str, len, UART_WITH_LOCK);//向串口发送数据
break;
case EXC_OUTPUT:
case EXC_OUTPUT: //异常输出
UartPuts(str, len, UART_WITH_LOCK);
break;
default:
@ -133,41 +133,42 @@ STATIC VOID OsVprintfFree(CHAR *buf, UINT32 bufLen)
(VOID)LOS_MemFree(m_aucSysMem0, buf);
}
}
///printf由 print 和 format 两个单词构成,格式化输出函数, 一般用于向标准输出设备按规定格式输出信息
//鸿蒙由OsVprintf 来实现可变参数日志格式的输入
VOID OsVprintf(const CHAR *fmt, va_list ap, OutputType type)
{
INT32 len;
const CHAR *errMsgMalloc = "OsVprintf, malloc failed!\n";
const CHAR *errMsgLen = "OsVprintf, length overflow!\n";
const CHAR *errMsgMalloc = "OsVprintf, malloc failed!\n";//内存分配失败的错误日志,注意这是在打印函数里分配内存失败的情况
const CHAR *errMsgLen = "OsVprintf, length overflow!\n";//所以要直接向串口发送字符串,不能再调用 printK(...)打印日志了.
CHAR aBuf[SIZEBUF] = {0};
CHAR *bBuf = NULL;
UINT32 bufLen = SIZEBUF;
UINT32 systemStatus;
bBuf = aBuf;
len = vsnprintf_s(bBuf, bufLen, bufLen - 1, fmt, ap);
if ((len == -1) && (*bBuf == '\0')) {
/* parameter is illegal or some features in fmt dont support */
len = vsnprintf_s(bBuf, bufLen, bufLen - 1, fmt, ap);//C语言库函数之一属于可变参数。用于向字符串中打印数据、数据格式用户自定义。
if ((len == -1) && (*bBuf == '\0')) {//直接碰到字符串结束符或长度异常
/* parameter is illegal or some features in fmt dont support */ //参数非法或fmt中的某些功能不支持
ErrorMsg();
return;
}
while (len == -1) {
while (len == -1) {//处理((len == -1) && (*bBuf != '\0'))的情况
/* bBuf is not enough */
OsVprintfFree(bBuf, bufLen);
bufLen = bufLen << 1;
if ((INT32)bufLen <= 0) {
if ((INT32)bufLen <= 0) {//异常情况下 向串口发送
UartPuts(errMsgLen, (UINT32)strlen(errMsgLen), UART_WITH_LOCK);
return;
}
bBuf = (CHAR *)LOS_MemAlloc(m_aucSysMem0, bufLen);
if (bBuf == NULL) {
if (bBuf == NULL) {//分配内存失败,直接向串口发送错误信息
UartPuts(errMsgMalloc, (UINT32)strlen(errMsgMalloc), UART_WITH_LOCK);
return;
}
len = vsnprintf_s(bBuf, bufLen, bufLen - 1, fmt, ap);
if (*bBuf == '\0') {
len = vsnprintf_s(bBuf, bufLen, bufLen - 1, fmt, ap);//将ap按格式输出到buf中
if (*bBuf == '\0') {//字符串结束符
/* parameter is illegal or some features in fmt dont support */
(VOID)LOS_MemFree(m_aucSysMem0, bBuf);
ErrorMsg();
@ -176,20 +177,20 @@ VOID OsVprintf(const CHAR *fmt, va_list ap, OutputType type)
}
*(bBuf + len) = '\0';
systemStatus = OsGetSystemStatus();
if ((systemStatus == OS_SYSTEM_NORMAL) || (systemStatus == OS_SYSTEM_EXC_OTHER_CPU)) {
OutputControl(bBuf, len, type);
} else if (systemStatus == OS_SYSTEM_EXC_CURR_CPU) {
OutputControl(bBuf, len, EXC_OUTPUT);
systemStatus = OsGetSystemStatus();//获取系统的状态
if ((systemStatus == OS_SYSTEM_NORMAL) || (systemStatus == OS_SYSTEM_EXC_OTHER_CPU)) {//当前CPU正常或其他CPU出现异常时
OutputControl(bBuf, len, type);//输出到终端
} else if (systemStatus == OS_SYSTEM_EXC_CURR_CPU) {//当前CPU出现异常
OutputControl(bBuf, len, EXC_OUTPUT);//串口以无锁的方式输出
}
OsVprintfFree(bBuf, bufLen);
}
///串口方式输入printf内容
VOID UartVprintf(const CHAR *fmt, va_list ap)
{
OsVprintf(fmt, ap, UART_OUTPUT);
}
///__attribute__((noinline)) 意思是告诉编译器 这是非内联函数
__attribute__((noinline)) VOID UartPrintf(const CHAR *fmt, ...)
{
va_list ap;
@ -197,9 +198,9 @@ __attribute__((noinline)) VOID UartPrintf(const CHAR *fmt, ...)
OsVprintf(fmt, ap, UART_OUTPUT);
va_end(ap);
}
///可变参数,输出到控制台
#ifndef LOSCFG_LIBC_NEWLIB
__attribute__((noinline)) VOID dprintf(const CHAR *fmt, ...)
__attribute__ ((noinline)) VOID dprintf(const CHAR *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
@ -212,7 +213,7 @@ __attribute__((noinline)) VOID dprintf(const CHAR *fmt, ...)
va_end(ap);
}
#endif
///LK 注者的理解是 log kernel(内核日志)
VOID LkDprintf(const CHAR *fmt, va_list ap)
{
OsVprintf(fmt, ap, CONSOLE_OUTPUT);
@ -231,7 +232,7 @@ VOID DmesgPrintf(const CHAR *fmt, va_list ap)
#endif
#ifdef LOSCFG_PLATFORM_UART_WITHOUT_VFS
__attribute__((noinline)) INT32 printf(const CHAR *fmt, ...)
__attribute__ ((noinline)) INT32 printf(const CHAR *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
@ -240,7 +241,7 @@ __attribute__((noinline)) INT32 printf(const CHAR *fmt, ...)
return 0;
}
#endif
//系统日志的输出
__attribute__((noinline)) VOID syslog(INT32 level, const CHAR *fmt, ...)
{
va_list ap;
@ -249,7 +250,7 @@ __attribute__((noinline)) VOID syslog(INT32 level, const CHAR *fmt, ...)
va_end(ap);
(VOID)level;
}
///异常信息的输出
__attribute__((noinline)) VOID ExcPrintf(const CHAR *fmt, ...)
{
va_list ap;
@ -258,20 +259,20 @@ __attribute__((noinline)) VOID ExcPrintf(const CHAR *fmt, ...)
OsVprintf(fmt, ap, EXC_OUTPUT);
va_end(ap);
}
///打印异常信息
VOID PrintExcInfo(const CHAR *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
/* uart output without print-spinlock */
OsVprintf(fmt, ap, EXC_OUTPUT);
OsVprintf(fmt, ap, EXC_OUTPUT);//异常信息打印主体函数
#ifdef LOSCFG_SAVE_EXCINFO
WriteExcBufVa(fmt, ap);
#endif
va_end(ap);
}
#ifndef LOSCFG_SHELL_LK
#ifndef LOSCFG_SHELL_LK //log kernel 内核日志
VOID LOS_LkPrint(INT32 level, const CHAR *func, INT32 line, const CHAR *fmt, ...)
{
va_list ap;
@ -287,7 +288,7 @@ VOID LOS_LkPrint(INT32 level, const CHAR *func, INT32 line, const CHAR *fmt, ...
}
va_start(ap, fmt);
OsVprintf(fmt, ap, CONSOLE_OUTPUT);
OsVprintf(fmt, ap, CONSOLE_OUTPUT);//控制台打印
#ifdef LOSCFG_SAVE_EXCINFO
if (OsGetSystemStatus() == OS_SYSTEM_EXC_CURR_CPU) {
WriteExcBufVa(fmt, ap);

@ -32,17 +32,24 @@
#include "los_config.h"
#include "los_sched_pri.h"
LITE_OS_SEC_TEXT_INIT INT32 main(VOID)
/**
* @brief
* ,,reset_vector_up.S reset_vector_mp.S
* upCPU, mpCPU bl main
* @return LITE_OS_SEC_TEXT_INIT
*/
LITE_OS_SEC_TEXT_INIT INT32 main(VOID)//由主CPU执行,默认0号CPU 为主CPU
{
UINT32 ret = OsMain();
if (ret != LOS_OK) {
return (INT32)LOS_NOK;
}
CPU_MAP_SET(0, OsHwIDGet());
OsSchedStart();
CPU_MAP_SET(0, OsHwIDGet());//设置主CPU映射信息
OsSchedStart();//调度开始
while (1) {
__asm volatile("wfi");
__asm volatile("wfi");//WFI: wait for Interrupt 等待中断即下一次中断发生前都在此hold住不干活
}
}

@ -39,24 +39,42 @@
#include "fs/driver.h"
#endif
STATIC volatile UINT32 g_serialType = 0;
STATIC struct file g_serialFilep;
/*
UART
UARTUniversal Asynchronous Receiver/TransmitterUART
使线
UART 2 线线线
UART 使 UART
-----------------------------------------------------------------
+ + (D0-D7) + + +
-----------------------------------------------------------------
0
56789 bit 8 ASCII 8
1 ()()使
1
(bit) bit/s(bps) 480096001440038400115200 115200 115200
*/
STATIC volatile UINT32 g_serialType = 0;
STATIC struct file g_serialFilep;// COM0 /dev/uartdev-0 在内核层的表述 属于 .bbs段
//获取串口类型
UINT32 SerialTypeGet(VOID)
{
return g_serialType;
}
///设置串口类型,从这里看鸿蒙暂时支持两种串口
STATIC VOID SerialTypeSet(const CHAR *deviceName)
{
{///dev/uartdev-0
if (!strncmp(deviceName, SERIAL_UARTDEV, strlen(SERIAL_UARTDEV))) {
g_serialType = SERIAL_TYPE_UART_DEV;
} else if (!strncmp(deviceName, SERIAL_TTYGS0, strlen(SERIAL_TTYGS0))) {
g_serialType = SERIAL_TYPE_USBTTY_DEV;
}
}
///打开串口设备
STATIC INT32 SerialOpen(struct file *filep)
{
INT32 ret;
@ -84,36 +102,42 @@ ERROUT:
set_errno(ret);
return VFS_ERROR;
}
///关闭串口设备
STATIC INT32 SerialClose(struct file *filep)
{
(VOID)filep;
if (g_serialType == SERIAL_TYPE_UART_DEV) {
HalIrqMask(NUM_HAL_INTERRUPT_UART);
if (g_serialType == SERIAL_TYPE_UART_DEV) {//如果是UART驱动
HalIrqMask(NUM_HAL_INTERRUPT_UART);//设置中断屏蔽
}
#if defined(LOSCFG_DRIVERS_USB_SERIAL_GADGET) || defined(LOSCFG_DRIVERS_USB_ETH_SER_GADGET)
else if (g_serialType == SERIAL_TYPE_USBTTY_DEV) {
userial_mask_set(0);
else if (g_serialType == SERIAL_TYPE_USBTTY_DEV) {//如果是USB驱动
userial_mask_set(0);//设置USB掩码为 0
}
#endif
return ENOERR;
}
///读取串口数据,参数 filep 是由 /dev/serial 打开获得的文件
STATIC ssize_t SerialRead(struct file *filep, CHAR *buffer, size_t bufLen)
{
INT32 ret;
struct file *privFilep = NULL;
const struct file_operations_vfs *fileOps = NULL;
ret = GetFilepOps(filep, &privFilep, &fileOps);
ret = GetFilepOps(filep, &privFilep, &fileOps);//通过文件获取更底层设备的文件和驱动,例如 /dev/serial ---> /dev/uart
/*以 register_driver(SERIAL, &g_serialDevOps, DEFFILEMODE, &g_serialFilep);为例
privFilep = g_serialFilep
fileOps = g_serialDevOps
*/
if (ret != ENOERR) {
ret = -EINVAL;
goto ERROUT;
}
ret = FilepRead(privFilep, fileOps, buffer, bufLen);
//@note_thinking 觉得这里实现的有点饶,容易把人看懵逼,里面存在一个再次调用SerialRead的问题
//privFilep 可能是由 /dev/uartdev-0 或者 /dev/ttyGS0 打开的文件
ret = FilepRead(privFilep, fileOps, buffer, bufLen);//从USB或者UART 读buf
if (ret < 0) {
goto ERROUT;
}
@ -123,21 +147,21 @@ ERROUT:
set_errno(-ret);
return VFS_ERROR;
}
/* Note: do not add print function in this module! */
///写入串口数据
/* Note: do not add print function in this module! */ //注意:请勿在本模块中添加打印功能!
STATIC ssize_t SerialWrite(struct file *filep, const CHAR *buffer, size_t bufLen)
{
INT32 ret;
struct file *privFilep = NULL;
const struct file_operations_vfs *fileOps = NULL;
ret = GetFilepOps(filep, &privFilep, &fileOps);
ret = GetFilepOps(filep, &privFilep, &fileOps);//获取COM口在内核的file实例
if (ret != ENOERR) {
ret = -EINVAL;
goto ERROUT;
}
ret = FilepWrite(privFilep, fileOps, buffer, bufLen);
ret = FilepWrite(privFilep, fileOps, buffer, bufLen);//向控制台文件写入数据
if (ret < 0) {
goto ERROUT;
}
@ -147,14 +171,14 @@ ERROUT:
set_errno(-ret);
return VFS_ERROR;
}
///控制串口设备
STATIC INT32 SerialIoctl(struct file *filep, INT32 cmd, unsigned long arg)
{
INT32 ret;
struct file *privFilep = NULL;
const struct file_operations_vfs *fileOps = NULL;
ret = GetFilepOps(filep, &privFilep, &fileOps);
ret = GetFilepOps(filep, &privFilep, &fileOps);//获取操作文件的驱动程序
if (ret != ENOERR) {
ret = -EINVAL;
goto ERROUT;
@ -170,7 +194,7 @@ ERROUT:
set_errno(-ret);
return VFS_ERROR;
}
/// 事件查询, UartHostPollEvent(Uart) --> Hi35xxPollEvent --> poll_wait
STATIC INT32 SerialPoll(struct file *filep, poll_table *fds)
{
INT32 ret;
@ -192,21 +216,69 @@ ERROUT:
set_errno(-ret);
return VFS_ERROR;
}
STATIC const struct file_operations_vfs g_serialDevOps = {
/*!
VFS, hi35xx,
/,UART
g_consoleDevOps()
g_serialDevOps()
g_uartDevFops
g_uartHostMethod
Pl011Read ()
memcpy_s(buf,rxTransfer->data, ... )
g_pl011Uops ()
Pl011StartTx
UartPutsReg
static int32_t UartDevIoctl(struct file *filep, int32_t cmd, unsigned long arg)
{
int32_t ret = HDF_FAILURE;
struct UartHost *host = NULL;
if (filep == NULL || filep->f_vnode == NULL) {
return HDF_ERR_INVALID_PARAM;
}
struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
host = (struct UartHost *)drv->priv;
switch (cmd) {
case UART_CFG_BAUDRATE:
ret = UartHostSetBaud(host, arg);
break;
case UART_CFG_RD_BLOCK:
if (arg == UART_RD_BLOCK) {
ret = UartHostSetTransMode(host, UART_MODE_RD_BLOCK);
} else if (arg == UART_RD_NONBLOCK) {
ret = UartHostSetTransMode(host, UART_MODE_RD_NONBLOCK);
}
break;
case UART_CFG_ATTR:
ret = UartCfgAttr(host, arg);
break;
case TIOCGWINSZ:
/* Simply support ioctl(f->fd, TIOCGWINSZ, &wsz) system call, and the detailed design will be done later * /
ret = LOS_OK;
break;
default:
HDF_LOGE("%s cmd %d not support", __func__, cmd);
ret = HDF_ERR_NOT_SUPPORT;
break;
}
return ret;
}
*/
STATIC const struct file_operations_vfs g_serialDevOps = {
SerialOpen, /* open */
SerialClose, /* close */
SerialRead, /* read */
SerialWrite,
SerialWrite, ///< 写串口
NULL,
SerialIoctl,
SerialIoctl, ///< 设置波特率,设置转换模式,各种配置 ==
NULL,
#ifndef CONFIG_DISABLE_POLL
SerialPoll,
#endif
NULL,
};
/// 虚拟串口初始化,注册驱动程序 ,例如 : deviceName = "/dev/uartdev-0"
INT32 virtual_serial_init(const CHAR *deviceName)
{
INT32 ret;
@ -217,29 +289,29 @@ INT32 virtual_serial_init(const CHAR *deviceName)
goto ERROUT;
}
SerialTypeSet(deviceName);
SerialTypeSet(deviceName);//例如: /dev/uartdev-0 为 UART串口
VnodeHold();
ret = VnodeLookup(deviceName, &vnode, V_DUMMY);
ret = VnodeLookup(deviceName, &vnode, V_DUMMY);//由deviceName查询vnode节点
if (ret != LOS_OK) {
ret = EACCES;
goto ERROUT;
}
(VOID)memset_s(&g_serialFilep, sizeof(struct file), 0, sizeof(struct file));
g_serialFilep.f_oflags = O_RDWR;
g_serialFilep.f_vnode = vnode;
g_serialFilep.ops = ((struct drv_data *)vnode->data)->ops;
if (g_serialFilep.ops->open != NULL) {
//接着是 vnode < -- > file 的绑定操作
(VOID)memset_s(&g_serialFilep, sizeof(struct file), 0, sizeof(struct file));//文件的内核层表现file为fd背后的内容
g_serialFilep.f_oflags = O_RDWR;//可读可写
g_serialFilep.f_vnode = vnode; //绑定索引节点
g_serialFilep.ops = ((struct drv_data *)vnode->data)->ops;//这里代表 访问 /dev/serial 意味着是访问 /dev/uartdev-0
if (g_serialFilep.ops->open != NULL) {//用于检测是否有默认的驱动程序
(VOID)g_serialFilep.ops->open(&g_serialFilep);
} else {
ret = EFAULT;
PRINTK("virtual_serial_init %s open is NULL\n", deviceName);
goto ERROUT;
}
(VOID)register_driver(SERIAL, &g_serialDevOps, DEFFILEMODE, &g_serialFilep);
(VOID)register_driver(SERIAL, &g_serialDevOps, DEFFILEMODE, &g_serialFilep);//注册虚拟串口驱动程序
//g_serialFilep作为私有数据给了 (drv_data)data->priv = g_serialFilep
VnodeDrop();
return ENOERR;
@ -248,9 +320,9 @@ ERROUT:
set_errno(ret);
return VFS_ERROR;
}
///串口设备去初始化,其实就是注销驱动程序
INT32 virtual_serial_deinit(VOID)
{
return unregister_driver(SERIAL);
return unregister_driver(SERIAL);//注销驱动程序
}

@ -43,14 +43,23 @@
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
/*
鸿 PINI2CSPIUSBUART
访 API 访
*/
#ifdef LOSCFG_FS_VFS //将设备虚拟为文件统一来操作,对鸿蒙来说一切皆为文件
#define SERIAL "/dev/serial" ///< 虚拟串口设备
#define SERIAL_TTYGS0 "/dev/ttyGS0" ///< USB类型的串口
#define SERIAL_UARTDEV "/dev/uartdev" ///< Uart类型的串口
#ifdef LOSCFG_FS_VFS
#define SERIAL "/dev/serial"
#define SERIAL_TTYGS0 "/dev/ttyGS0"
#define SERIAL_UARTDEV "/dev/uartdev"
//UARTUniversal Asynchronous Receiver/Transmitter通用异步收发传输器UART 作为异步串口通信协议的一种,
//工作原理是将传输数据的每个字符一位接一位地传输。是在应用程序开发过程中使用频率最高的数据总线。
#define SERIAL_TYPE_UART_DEV 1
#define SERIAL_TYPE_USBTTY_DEV 2
#define SERIAL_TYPE_UART_DEV 1 ///< 两种串口类型之 UART
#define SERIAL_TYPE_USBTTY_DEV 2 ///< 两种串口类型之 USB
extern INT32 virtual_serial_init(const CHAR *deviceName);
extern INT32 virtual_serial_deinit(VOID);

@ -217,4 +217,4 @@ int CreateLogDir(const char *dirPath)
(void)dirPath;
return -1;
}
#endif
#endif

@ -33,13 +33,13 @@
#include "los_process_pri.h"
#include "internal.h"
STATIC Container g_rootContainer;
STATIC ContainerLimit g_containerLimit;
STATIC Atomic g_containerCount = 0xF0000000U;
STATIC Container g_rootContainer;//根容器
STATIC ContainerLimit g_containerLimit;//所有类型容器上限
STATIC Atomic g_containerCount = 0xF0000000U;//容器总数量
#ifdef LOSCFG_USER_CONTAINER
STATIC Credentials *g_rootCredentials = NULL;
#endif
//分配一个容器
UINT32 OsAllocContainerID(VOID)
{
return LOS_AtomicIncRet(&g_containerCount);
@ -57,7 +57,7 @@ VOID OsContainerInitSystemProcess(LosProcessCB *processCB)
#endif
return;
}
//获取指定容器上限值
UINT32 OsGetContainerLimit(ContainerType type)
{
switch (type) {
@ -108,7 +108,7 @@ UINT32 OsContainerLimitCheck(ContainerType type, UINT32 *containerCount)
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
}
//设置容器上限
UINT32 OsSetContainerLimit(ContainerType type, UINT32 value)
{
UINT32 intSave;
@ -368,7 +368,7 @@ CREATE_CONTAINER:
COPY_CONTAINERS:
return CopyContainers(flags, child, parent, processID);
}
//释放进程容器
VOID OsContainerFree(LosProcessCB *processCB)
{
LOS_AtomicDec(&processCB->container->rc);

@ -36,9 +36,9 @@
#ifdef LOSCFG_PID_CONTAINER
STATIC UINT32 g_currentPidContainerNum;
STATIC LosProcessCB *g_defaultProcessCB = NULL;
STATIC LosTaskCB *g_defaultTaskCB = NULL;
STATIC UINT32 g_currentPidContainerNum;//进程类容器当前数量
STATIC LosProcessCB *g_defaultProcessCB = NULL;//默认进程控制块 由OsInitRootPidContainer赋初值
STATIC LosTaskCB *g_defaultTaskCB = NULL;//默认任务控制块 由OsInitRootPidContainer赋初值
STATIC VOID FreeVpid(LosProcessCB *processCB)
{
@ -252,46 +252,46 @@ VOID OsPidContainerDestroyAllProcess(LosProcessCB *curr)
}
}
}
//创建一个新的进程容器
STATIC PidContainer *CreateNewPidContainer(PidContainer *parent)
{
UINT32 index;
PidContainer *newPidContainer = (PidContainer *)LOS_MemAlloc(m_aucSysMem1, sizeof(PidContainer));
PidContainer *newPidContainer = (PidContainer *)LOS_MemAlloc(m_aucSysMem1, sizeof(PidContainer));//从内核动态内存分配
if (newPidContainer == NULL) {
return NULL;
}
(VOID)memset_s(newPidContainer, sizeof(PidContainer), 0, sizeof(PidContainer));
(VOID)memset_s(newPidContainer, sizeof(PidContainer), 0, sizeof(PidContainer));//初始化内存块
newPidContainer->containerID = OsAllocContainerID();
LOS_ListInit(&newPidContainer->pidFreeList);
for (index = 0; index < LOSCFG_BASE_CORE_PROCESS_LIMIT; index++) {
newPidContainer->containerID = OsAllocContainerID();//分配一个容器ID
LOS_ListInit(&newPidContainer->pidFreeList);//初始化虚拟进程池空闲链表
for (index = 0; index < LOSCFG_BASE_CORE_PROCESS_LIMIT; index++) {//初始化容器的虚拟进程池
ProcessVid *vpid = &newPidContainer->pidArray[index];
vpid->vid = index;
vpid->vid = index;//进程ID序号
vpid->vpid = OS_INVALID_VALUE;
vpid->cb = (UINTPTR)g_defaultProcessCB;
LOS_ListTailInsert(&newPidContainer->pidFreeList, &vpid->node);
vpid->cb = (UINTPTR)g_defaultProcessCB;//默认进程控制块
LOS_ListTailInsert(&newPidContainer->pidFreeList, &vpid->node);//挂入链表
}
LOS_ListInit(&newPidContainer->tidFreeList);
LOS_ListInit(&newPidContainer->tidFreeList);//初始化虚拟任务池空闲链表
for (index = 0; index < LOSCFG_BASE_CORE_TSK_LIMIT; index++) {
ProcessVid *vtid = &newPidContainer->tidArray[index];
vtid->vid = index;
vtid->vid = index;//任务ID序号
vtid->vpid = OS_INVALID_VALUE;
vtid->cb = (UINTPTR)g_defaultTaskCB;
LOS_ListTailInsert(&newPidContainer->tidFreeList, &vtid->node);
LOS_ListTailInsert(&newPidContainer->tidFreeList, &vtid->node);//挂入链表
}
newPidContainer->parent = parent;
newPidContainer->parent = parent;//指定父容器
if (parent != NULL) {
LOS_AtomicSet(&newPidContainer->level, parent->level + 1);
LOS_AtomicSet(&newPidContainer->level, parent->level + 1);//子比父优先级低一级
newPidContainer->referenced = FALSE;
} else {
LOS_AtomicSet(&newPidContainer->level, 0);
LOS_AtomicSet(&newPidContainer->level, 0);//此处说明0位最高优先级
newPidContainer->referenced = TRUE;
}
return newPidContainer;
}
//销毁容器
VOID OsPidContainerDestroy(Container *container, LosProcessCB *processCB)
{
if (container == NULL) {
@ -321,21 +321,21 @@ VOID OsPidContainerDestroy(Container *container, LosProcessCB *processCB)
container->pidContainer = NULL;
container->pidForChildContainer = NULL;
(VOID)LOS_MemFree(m_aucSysMem1, pidContainer->rootPGroup);
(VOID)LOS_MemFree(m_aucSysMem1, pidContainer);
(VOID)LOS_MemFree(m_aucSysMem1, pidContainer);//释放结构体内存块
}
if (processCB != NULL) {
OsContainerFree(processCB);
}
}
/// 创建进程容器
STATIC UINT32 CreatePidContainer(LosProcessCB *child, LosProcessCB *parent)
{
UINT32 ret;
UINT32 intSave;
PidContainer *parentContainer = parent->container->pidContainer;
PidContainer *newPidContainer = CreateNewPidContainer(parentContainer);
PidContainer *parentContainer = parent->container->pidContainer;//先获取父进程容器
PidContainer *newPidContainer = CreateNewPidContainer(parentContainer);//从父进程容器中创建一个新容器
if (newPidContainer == NULL) {
return ENOMEM;
}
@ -508,25 +508,25 @@ UINT32 OsSetNsPidContainer(UINT32 flags, Container *container, Container *newCon
}
return LOS_OK;
}
///初始化进程根容器
UINT32 OsInitRootPidContainer(PidContainer **pidContainer)
{
UINT32 intSave;
g_defaultTaskCB = OsGetDefaultTaskCB();
g_defaultProcessCB = OsGetDefaultProcessCB();
PidContainer *newPidContainer = CreateNewPidContainer(NULL);
PidContainer *newPidContainer = CreateNewPidContainer(NULL);//无父进程
if (newPidContainer == NULL) {
return ENOMEM;
}
SCHEDULER_LOCK(intSave);
g_currentPidContainerNum++;
*pidContainer = newPidContainer;
g_currentPidContainerNum++;//当前进程容器数量增加
*pidContainer = newPidContainer;//成为根进程容器,由参数带回
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
}
//从当前容器中获取父进程ID
UINT32 OsGetVpidFromCurrContainer(const LosProcessCB *processCB)
{
UINT32 vpid = processCB->processID;

@ -68,7 +68,7 @@ STATIC UtsContainer *CreateNewUtsContainer(UtsContainer *parent)
{
UINT32 ret;
UINT32 size = sizeof(UtsContainer);
UtsContainer *utsContainer = (UtsContainer *)LOS_MemAlloc(m_aucSysMem1, size);
UtsContainer *utsContainer = (UtsContainer *)LOS_MemAlloc(m_aucSysMem1, size);//从内核动态内存分配
if (utsContainer == NULL) {
return NULL;
}
@ -105,7 +105,7 @@ STATIC UINT32 CreateUtsContainer(LosProcessCB *child, LosProcessCB *parent)
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
}
//初始化uts容器
UINT32 OsInitRootUtsContainer(UtsContainer **utsContainer)
{
UINT32 intSave;

@ -31,10 +31,45 @@
#include "los_cppsupport.h"
#include "los_printf.h"
/**
* @brief @file los_cppsupport.c
* @verbatim
C++使广C
STLStandard Template Library
使使
make menuconfig使C++
使C++LOS_CppSystemInitC++
CC++C++CC++
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus * /
#endif /* __cplusplus * /
/* code * /
...
#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus * /
#endif /* __cplusplus * /
* @endverbatim
*/
typedef VOID (*InitFunc)(VOID);
/**
* @brief 使C++ C++
* @param initArrayStart init_array
* @param initArrayEnd init_array
* @param flag C++
* @return LITE_OS_SEC_TEXT_MINOR
*/
LITE_OS_SEC_TEXT_MINOR INT32 LOS_CppSystemInit(UINTPTR initArrayStart, UINTPTR initArrayEnd, INT32 flag)
{
UINTPTR *start = (UINTPTR *)initArrayStart;

@ -1,6 +1,6 @@
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2023 Huawei Device Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
@ -80,6 +80,31 @@ LITE_OS_SEC_TEXT STATIC VOID OsCpupCmdHelp(VOID)
" others SysCpuUsage in all time\n");
}
/**
* @brief
* @verbatim
cpupCPU
cpup [mode] [taskID]
mode
10sCPU
010sCPU
11sCPU
CPU
taskID ID [0,0xFFFFFFFF]
使
10sCPU
modeCPU
modetaskIDIDCPU
cpup 1 5 51sCPU
* @endverbatim
* @param pathname
* @return int
*/
LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdCpup(INT32 argc, const CHAR **argv)
{
size_t mode, pid;
@ -106,15 +131,15 @@ LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdCpup(INT32 argc, const CHAR **argv)
}
if (mode > CPUP_ALL_TIME) {
mode = CPUP_ALL_TIME;
mode = CPUP_ALL_TIME;//统计所有CPU的耗时
}
if (argc == 1) {
OsCmdCpupOperateOneParam(mode);
OsCmdCpupOperateOneParam(mode);//处理只有一个参数的情况 例如 cpup 1
return LOS_OK;
}
pid = strtoul(argv[1], &bufID, 0);
pid = strtoul(argv[1], &bufID, 0);//musl标准库函数,将字符串转成无符号整型
if (OsProcessIDUserCheckInvalid(pid) || (*bufID != 0)) {
PRINTK("\nUnknown pid: %s\n", argv[1]);
return LOS_OK;
@ -127,7 +152,7 @@ LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdCpup(INT32 argc, const CHAR **argv)
/* when the parameters number is two */
if (argc == 2) {
OsCmdCpupOperateTwoParam(mode, pid);
OsCmdCpupOperateTwoParam(mode, pid);//处理有两个参数的情况 例如 cpup 1 5
return LOS_OK;
}
@ -135,5 +160,5 @@ LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdCpup(INT32 argc, const CHAR **argv)
return LOS_OK;
}
SHELLCMD_ENTRY(cpup_shellcmd, CMD_TYPE_EX, "cpup", XARGS, (CmdCallBackFunc)OsShellCmdCpup);
SHELLCMD_ENTRY(cpup_shellcmd, CMD_TYPE_EX, "cpup", XARGS, (CmdCallBackFunc)OsShellCmdCpup);//采用shell命令静态注册方式
#endif /* LOSCFG_SHELL */

@ -1,6 +1,88 @@
/*!
* @file los_cpup.c
* @brief
* @link kernel-small-debug-process-cpu http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-debug-process-cpu.html @endlink
@verbatim
CPUCentral Processing UnitCPUCPUCPU
CPUCPU
//CPU//CPU
CPUCPU Percent
CPUCPUCPU
0100100
CPU
CPUCPU0100
100
CPU
CPUCPU0100
100
CPU
CPUCPU0100
100
OpenHarmony LiteOS-ACPUPCPU PercentCPU/
//退/;
OpenHarmony CPU
CPU
CPU
CPU
CPU
CPU
CPU=idle/
CPU=/
CPU=/
CPU=/
CPU
CPULOS_HistorySysCpuUsage
CPULOS_HistoryProcessCpuUsage
CPULOS_GetAllProcessCpuUsage
CPUP
CPUP
CPULOS_HistoryTaskCpuUsage
CPULOS_GetAllIrqCpuUsage
CPUP
CPUP
@endverbatim
* @image html https://gitee.com/weharmonyos/resources/raw/master/27/mux.png
* @attention
* @version
* @author weharmonyos.com | 鸿 |
* @date 2021-11-21
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2023 Huawei Device Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
@ -39,14 +121,14 @@
#ifdef LOSCFG_KERNEL_CPUP
LITE_OS_SEC_BSS STATIC UINT16 cpupSwtmrID;
LITE_OS_SEC_BSS STATIC UINT16 cpupSwtmrID; ///< 监测CPU使用情况定时器s
LITE_OS_SEC_BSS STATIC UINT16 cpupInitFlg = 0;
LITE_OS_SEC_BSS OsIrqCpupCB *g_irqCpup = NULL;
LITE_OS_SEC_BSS STATIC UINT32 cpupMaxNum;
LITE_OS_SEC_BSS STATIC UINT16 cpupHisPos = 0; /* current Sampling point of historyTime */
LITE_OS_SEC_BSS STATIC UINT64 cpuHistoryTime[OS_CPUP_HISTORY_RECORD_NUM + 1];
LITE_OS_SEC_BSS STATIC LosTaskCB *runningTasks[LOSCFG_KERNEL_CORE_NUM];
LITE_OS_SEC_BSS STATIC UINT64 cpupStartCycles = 0;
LITE_OS_SEC_BSS STATIC UINT64 cpupStartCycles = 0; ///< 记录
#ifdef LOSCFG_CPUP_INCLUDE_IRQ
LITE_OS_SEC_BSS UINT64 timeInIrqSwitch[LOSCFG_KERNEL_CORE_NUM];
LITE_OS_SEC_BSS STATIC UINT64 cpupIntTimeStart[LOSCFG_KERNEL_CORE_NUM];
@ -60,14 +142,14 @@ LITE_OS_SEC_BSS STATIC UINT64 cpupIntTimeStart[LOSCFG_KERNEL_CORE_NUM];
#define CPUP_PRE_POS(pos) (((pos) == 0) ? (OS_CPUP_HISTORY_RECORD_NUM - 1) : ((pos) - 1))
#define CPUP_POST_POS(pos) (((pos) == (OS_CPUP_HISTORY_RECORD_NUM - 1)) ? 0 : ((pos) + 1))
///< 获取CPU周期
STATIC UINT64 OsGetCpuCycle(VOID)
{
UINT32 high;
UINT32 low;
UINT64 cycles;
UINT64 cycles;//周期数用 64位计算读取分成高低位
LOS_GetCpuCycle(&high, &low);
LOS_GetCpuCycle(&high, &low);//将64位拆成两个32位
cycles = ((UINT64)high << HIGH_BITS) + low;
if (cpupStartCycles == 0) {
cpupStartCycles = cycles;
@ -140,7 +222,7 @@ LITE_OS_SEC_TEXT_INIT VOID OsCpupGuard(VOID)
SCHEDULER_UNLOCK(intSave);
}
///创建cpu使用统计定时器
LITE_OS_SEC_TEXT_INIT UINT32 OsCpupGuardCreator(VOID)
{
(VOID)LOS_SwtmrCreate(LOSCFG_BASE_CORE_TICK_PER_SECOND, LOS_SWTMR_MODE_PERIOD,
@ -287,8 +369,8 @@ LITE_OS_SEC_TEXT_MINOR STATIC VOID OsCpupGetPos(UINT16 mode, UINT16 *curPosPoint
curPos = CPUP_PRE_POS(tmpPos);
/*
* The current position has nothing to do with the CPUP modes,
* however, the previous position differs.
* The current postion has nothing to do with the CPUP modes,
* however, the previous postion differs.
*/
switch (mode) {
case CPUP_LAST_ONE_SECONDS:
@ -339,6 +421,14 @@ STATIC UINT32 OsHistorySysCpuUsageUnsafe(UINT16 mode)
return (LOS_CPUP_PRECISION - OsCalculateCpupUsage(processCpup, pos, prePos, cpuAllCycle));
}
/**
* \brief CPU
* CPUCPUCPU
* 0100100
* \param mode
*
* \return
*/
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_HistorySysCpuUsage(UINT16 mode)
{
UINT32 cpup;
@ -380,6 +470,15 @@ STATIC UINT32 OsHistoryProcessCpuUsageUnsafe(UINT32 pid, UINT16 mode)
return OsCalculateCpupUsage(processCB->processCpup, pos, prePos, cpuAllCycle);
}
/**
* \brief CPU
* CPUCPU0100
* 100
* \param pid
* \param mode
*
* \return
*/
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_HistoryProcessCpuUsage(UINT32 pid, UINT16 mode)
{
UINT32 cpup;
@ -416,6 +515,15 @@ STATIC UINT32 OsHistoryTaskCpuUsageUnsafe(UINT32 tid, UINT16 mode)
return OsCalculateCpupUsage(&taskCB->taskCpup, pos, prePos, cpuAllCycle);
}
/**
* \brief CPU
* CPUCPU0100
* 100
* \param tid
* \param mode
*
* \return
*/
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_HistoryTaskCpuUsage(UINT32 tid, UINT16 mode)
{
UINT32 intSave;
@ -469,7 +577,7 @@ STATIC UINT32 GetAllProcessCpuUsageUnsafe(UINT16 mode, CPUP_INFO_S *cpupInfo, UI
return LOS_OK;
}
/// 获取系统所有进程的历史CPU占用率
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_GetAllProcessCpuUsage(UINT16 mode, CPUP_INFO_S *cpupInfo, UINT32 len)
{
UINT32 intSave;
@ -596,6 +704,16 @@ LITE_OS_SEC_TEXT_MINOR UINT32 OsGetAllIrqCpuUsageUnsafe(UINT16 mode, CPUP_INFO_S
return LOS_OK;
}
/**
* \brief CPU
* CPUCPU0100
* 100
* \param mode
* \param cpupInfo
* \param len
*
* \return
*/
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_GetAllIrqCpuUsage(UINT16 mode, CPUP_INFO_S *cpupInfo, UINT32 len)
{
UINT32 intSave;

@ -1,6 +1,6 @@
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2023 Huawei Device Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
@ -47,7 +47,7 @@ extern "C" {
#define OS_CPUP_HISTORY_RECORD_NUM 11
typedef struct {
UINT64 allTime; /**< Total running time */
UINT64 allTime; /**< Total running time | 总运行时间*/
UINT64 startTime; /**< Time before a task is invoked */
UINT64 historyTime[OS_CPUP_HISTORY_RECORD_NUM + 1]; /**< Historical running time, the last one saves zero */
} OsCpupBase;

@ -36,25 +36,38 @@
#define AUX_VECTOR_SIZE_BASE 20
#define AUX_VECTOR_SIZE ((AUX_VECTOR_SIZE_ARCH + AUX_VECTOR_SIZE_BASE + 1) << 1)
/* AUX VECTOR */
#define AUX_NULL 0
#define AUX_IGNORE 1
#define AUX_EXECFD 2
#define AUX_PHDR 3
#define AUX_PHENT 4
#define AUX_PHNUM 5
#define AUX_PAGESZ 6
#define AUX_BASE 7
#define AUX_FLAGS 8
#define AUX_ENTRY 9
#define AUX_NOTELF 10
#define AUX_UID 11
#define AUX_EUID 12
#define AUX_GID 13
#define AUX_EGID 14
/*
http://articles.manugarg.com/aboutelfauxiliaryvectors.html
ELF
AT_SYSINFO
-linux使ELF
ELF /usr/src/linux/fs/binfmt_elf.c
ELFELF
ELFargcargvenvp
*/
/* AUX VECTOR *//* Legal values for a_type (entry type). */
#define AUX_NULL 0 /* End of vector */
#define AUX_IGNORE 1 /* Entry should be ignored */
#define AUX_EXECFD 2 /* File descriptor of program */
#define AUX_PHDR 3 /* Program headers for program */
#define AUX_PHENT 4 /* Size of program header entry */
#define AUX_PHNUM 5 /* Number of program headers */
#define AUX_PAGESZ 6 /* System page size */
#define AUX_BASE 7 /* Base address of interpreter */
#define AUX_FLAGS 8 /* Flags */
#define AUX_ENTRY 9 /* Entry point of program */
#define AUX_NOTELF 10 /* Program is not ELF */
#define AUX_UID 11 /* Real uid */
#define AUX_EUID 12 /* Effective uid */
#define AUX_GID 13 /* Real gid */
#define AUX_EGID 14 /* Effective gid */
#define AUX_PLATFORM 15
#define AUX_HWCAP 16
#define AUX_CLKTCK 17
#define AUX_CLKTCK 17 /* Frequency of times() */
#define AUX_SECURE 23
#define AUX_BASE_PLATFORM 24
#define AUX_RANDOM 25

@ -42,24 +42,47 @@ extern "C" {
/* Elf header */
#define LD_EI_NIDENT 16
/* 举例: shell elf
root@5e3abe332c5a:/home/harmony/out/hispark_aries/ipcamera_hispark_aries/bin# readelf -h shell
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: ARM
Version: 0x1
Entry point address: 0x1000
Start of program headers: 52 (bytes into file)
Start of section headers: 25268 (bytes into file)
Flags: 0x5000200, Version5 EABI, soft-float ABI
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 11
Size of section headers: 40 (bytes)
Number of section headers: 27
Section header string table index: 26
*/
typedef struct {
UINT8 elfIdent[LD_EI_NIDENT]; /* Magic number and other info */
UINT16 elfType; /* Object file type */
UINT16 elfMachine; /* Architecture */
UINT32 elfVersion; /* Object file version */
UINT32 elfEntry; /* Entry point virtual address */
UINT32 elfPhoff; /* Program header table file offset */
UINT32 elfShoff; /* Section header table file offset */
UINT32 elfFlags; /* Processor-specific flags */
UINT16 elfHeadSize; /* ELF header size in bytes */
UINT16 elfPhEntSize; /* Program header table entry size */
UINT16 elfPhNum; /* Program header table entry count */
UINT16 elfShEntSize; /* Section header table entry size */
UINT16 elfShNum; /* Section header table entry count */
UINT16 elfShStrIndex; /* Section header string table index */
UINT8 elfIdent[LD_EI_NIDENT]; /* Magic number and other info *///含前16个字节,又可细分成class、data、version等字段,具体含义不用太关心,只需知道前4个字节点包含`ELF`关键字,这样可以判断当前文件是否是ELF格式
UINT16 elfType; /* Object file type *///表示具体ELF类型,可重定位文件/可执行文件/共享库文件
UINT16 elfMachine; /* Architecture *///表示cpu架构
UINT32 elfVersion; /* Object file version *///表示文件版本号
UINT32 elfEntry; /* Entry point virtual address *///对应`Entry point address`,程序入口函数地址,通过进程虚拟地址空间地址表达
UINT32 elfPhoff; /* Program header table file offset *///对应`Start of program headers`,表示program header table在文件内的偏移位置
UINT32 elfShoff; /* Section header table file offset *///对应`Start of section headers`,表示section header table在文件内的偏移位置
UINT32 elfFlags; /* Processor-specific flags *///表示与CPU处理器架构相关的信息
UINT16 elfHeadSize; /* ELF header size in bytes *///对应`Size of this header`,表示本ELF header自身的长度
UINT16 elfPhEntSize; /* Program header table entry size *///对应`Size of program headers`,表示program header table中每个元素的大小
UINT16 elfPhNum; /* Program header table entry count *///对应`Number of program headers`,表示program header table中元素个数
UINT16 elfShEntSize; /* Section header table entry size *///对应`Size of section headers`,表示section header table中每个元素的大小
UINT16 elfShNum; /* Section header table entry count *///对应`Number of section headers`,表示section header table中元素的个数
UINT16 elfShStrIndex; /* Section header string table index *///对应`Section header string table index`,表示描述各section字符名称的string table在section header table中的下标
} LDElf32Ehdr;
typedef struct {
UINT8 elfIdent[LD_EI_NIDENT]; /* Magic number and other info */
UINT16 elfType; /* Object file type */
@ -117,23 +140,23 @@ typedef struct {
#define LD_ELF_DATA2MSB 2
/* e_type */
#define LD_ET_NONE 0
#define LD_ET_REL 1
#define LD_ET_EXEC 2
#define LD_ET_DYN 3
#define LD_ET_CORE 4
#define LD_ET_LOPROC 0xff00
#define LD_ET_HIPROC 0xffff
/* e_machine */
#define LD_EM_NONE 0 /* No machine */
#define LD_EM_M32 1 /* AT&T WE 32100 */
#define LD_EM_SPARC 2 /* SPARC */
#define LD_EM_386 3 /* Intel 80386 */
#define LD_EM_68K 4 /* Motorola 68000 */
#define LD_EM_88K 5 /* Motorola 88000 */
#define LD_EM_486 6 /* Intel 80486 */
#define LD_EM_860 7 /* Intel 80860 */
#define LD_ET_NONE 0 //未知文件类型
#define LD_ET_REL 1 //可重定向文件(Relocatable file):文件保存着代码和适当的数据,用来和其他的目标文件一起来创建一个可执行文件或者是一个共享目标文件.
#define LD_ET_EXEC 2 //可执行文件(Executable file):文件保存着一个用来执行的程序.例如bash,gcc等
#define LD_ET_DYN 3 //共享目标文件, https://my.oschina.net/weharmony/blog/5055124 例如: ./bin/weharmony
#define LD_ET_CORE 4 //Core文件
#define LD_ET_LOPROC 0xff00 //特定处理器文件扩展下边界
#define LD_ET_HIPROC 0xffff //特定处理器文件扩展上边界
//ET_LOPROC ~ ET_HIPROC (0xff00 ~ 0xffff)这一范围内的文件类型是为特定处理器而保留的,如果需要为某种处理器专门设定文件格式,可以从这一范围内选取一个做为标识.
/* e_machine */ //处理器体系结构
#define LD_EM_NONE 0 /* No machine */ //未知体系结构
#define LD_EM_M32 1 /* AT&T WE 32100 */ //AT&T WE 32100
#define LD_EM_SPARC 2 /* SPARC */ //SPARC
#define LD_EM_386 3 /* Intel 80386 */ //Intel Architecture
#define LD_EM_68K 4 /* Motorola 68000 */ //Motorola 68000
#define LD_EM_88K 5 /* Motorola 88000 */ //Motorola 88000
#define LD_EM_486 6 /* Intel 80486 */ //Intel 80486
#define LD_EM_860 7 /* Intel 80860 */ //Intel 80486
#define LD_EM_MIPS 8 /* MIPS RS3000 Big-Endian */
#define LD_EM_MIPS_RS4_BE 10 /* MIPS RS4000 Big-Endian */
#define LD_EM_PPC_OLD 17 /* PowerPC - old */
@ -146,7 +169,7 @@ typedef struct {
#define LD_EM_NEC 36992 /* NEC 850 series */
#define LD_EM_NEC_830 36 /* NEC 830 series */
#define LD_EM_SC 58 /* SC */
#define LD_EM_ARM 40 /* ARM */
#define LD_EM_ARM 40 /* ARM */ //目前支持的方式
#define LD_EM_XTENSA 0x5E /* XTENSA */
#define LD_EM_AARCH64 183 /* ARM AARCH64 */
@ -156,7 +179,7 @@ typedef struct {
#define LD_EM_TYPE LD_EM_ARM
#endif
/* e_flags */
/* e_flags */ //此字段含有处理器特定的标志位.
#define LD_EF_PPC_EMB 0x80000000
#define LD_EF_MIPS_NOREORDER 0x00000001
@ -165,14 +188,14 @@ typedef struct {
#define LD_EF_MIPS_ARCH 0xf0000000
#define LD_EF_MIPS_ARCH_MIPS_2 0x10000000
#define LD_EF_MIPS_ARCH_MIPS_3 0x20000000
#define LD_PT_NULL 0
#define LD_PT_LOAD 1
#define LD_PT_DYNAMIC 2
#define LD_PT_INTERP 3
#define LD_PT_NOTE 4
#define LD_PT_SHLIB 5
#define LD_PT_PHDR 6
//段类型
#define LD_PT_NULL 0 //表明本程序头是未使用的,本程序头内的其它成员值均无意义.具有此种类型的程序头应该被忽略.
#define LD_PT_LOAD 1 //此类型表明本程序头指向一个可装载的段.段的内容会被从文件中拷贝到内存中.如前所述,段在文件中的大小是p_filesz,在内存中的大小是p_memsz.如果p_memsz大于p_filesz,在内存中多出的存储空间应填0补充,也就是说,段在内存中可以比在文件中占用空间更大;而相反,p_filesz永远不应该比p_memsz大,因为这样的话,内存中就将无法完整地映射段的内容.在程序头表中,所有PT_LOAD类型的程序头按照p_vaddr的值做升序排列.
#define LD_PT_DYNAMIC 2 //描述了动态加载段
#define LD_PT_INTERP 3 //本段指向了一个以"null"结尾的字符串,这个字符串是一个ELF解析器的路径.这种段类型只对可执行程序有意义,当它出现在共享目标文件中时,是一个无意义的多余项.在一个ELF文件中它最多只能出现一次,而且必须出现在其它可装载段的表项之前
#define LD_PT_NOTE 4 //本段指向了一个以"null"结尾的字符串,这个字符串包含一些附加的信息
#define LD_PT_SHLIB 5 //该段类型是保留的,而且未定义语法.UNIX System V系统上的应用程序不会包含这种表项.
#define LD_PT_PHDR 6 //此类型的程序头如果存在的话,它表明的是其自身所在的程序头表在文件或内存中的位置和大小.这样的段在文件中可以不存在,只有当所在程序头表所覆盖的段只是整个程序的一部分时,才会出现一次这种表项,而且这种表项一定出现在其它可装载段的表项之前.
#define LD_PT_GNU_STACK 0x6474e551
/* e_version and EI_VERSION */
@ -181,14 +204,14 @@ typedef struct {
/* Program Header */
typedef struct {
UINT32 type; /* Segment type */
UINT32 offset; /* Segment file offset */
UINT32 vAddr; /* Segment virtual address */
UINT32 phyAddr; /* Segment physical address */
UINT32 fileSize; /* Segment size in file */
UINT32 memSize; /* Segment size in memory */
UINT32 flags; /* Segment flags */
UINT32 align; /* Segment alignment */
UINT32 type; /* Segment type */ //段类型
UINT32 offset; /* Segment file offset */ //此数据成员给出本段内容在文件中的位置,即段内容的开始位置相对于文件开头的偏移量.
UINT32 vAddr; /* Segment virtual address */ //此数据成员给出本段内容的开始位置在进程空间中的虚拟地址.
UINT32 phyAddr; /* Segment physical address */ //此数据成员给出本段内容的开始位置在进程空间中的物理地址.对于目前大多数现代操作系统而言,应用程序中段的物理地址事先是不可知的,所以目前这个成员多数情况下保留不用,或者被操作系统改作它用.
UINT32 fileSize; /* Segment size in file */ //此数据成员给出本段内容在文件中的大小,单位是字节,可以是0.
UINT32 memSize; /* Segment size in memory */ //此数据成员给出本段内容在内容镜像中的大小,单位是字节,可以是0.
UINT32 flags; /* Segment flags */ //此数据成员给出了本段内容的属性.
UINT32 align; /* Segment alignment */ //对于可装载的段来说,其p_vaddr和p_offset的值至少要向内存页面大小对齐.
} LDElf32Phdr;
typedef struct {
@ -220,18 +243,19 @@ typedef struct {
/* Section header */
typedef struct {
UINT32 shName; /* Section name (string tbl index) */
UINT32 shType; /* Section type */
UINT32 shFlags; /* Section flags */
UINT32 shAddr; /* Section virtual addr at execution */
UINT32 shOffset; /* Section file offset */
UINT32 shSize; /* Section size in bytes */
UINT32 shLink; /* Link to another section */
UINT32 shInfo; /* Additional section information */
UINT32 shAddrAlign; /* Section alignment */
UINT32 shEntSize; /* Entry size if section holds table */
UINT32 shName; /* Section name (string tbl index) *///表示每个区的名字
UINT32 shType; /* Section type *///表示每个区的功能
UINT32 shFlags; /* Section flags *///表示每个区的属性
UINT32 shAddr; /* Section virtual addr at execution *///表示每个区的进程映射地址
UINT32 shOffset; /* Section file offset *///表示文件内偏移
UINT32 shSize; /* Section size in bytes *///表示区的大小
UINT32 shLink; /* Link to another section *///Link和Info记录不同类型区的相关信息
UINT32 shInfo; /* Additional section information *///Link和Info记录不同类型区的相关信息
UINT32 shAddrAlign; /* Section alignment *///表示区的对齐单位
UINT32 shEntSize; /* Entry size if section holds table *///表示区中每个元素的大小(如果该区为一个数组的话,否则该值为0)
} LDElf32Shdr;
typedef struct {
UINT32 shName; /* Section name (string tbl index) */
UINT32 shType; /* Section type */
@ -278,14 +302,15 @@ typedef struct {
/* Symbol table */
typedef struct {
UINT32 stName; /* Symbol table name (string tbl index) */
UINT32 stValue; /* Symbol table value */
UINT32 stSize; /* Symbol table size */
UINT8 stInfo; /* Symbol table type and binding */
UINT32 stName; /* Symbol table name (string tbl index) *///表示符号对应的源码字符串,为对应String Table中的索引
UINT32 stValue; /* Symbol table value *///表示符号对应的数值
UINT32 stSize; /* Symbol table size *///表示符号对应数值的空间占用大小
UINT8 stInfo; /* Symbol table type and binding *///表示符号的相关信息 如符号类型(变量符号、函数符号)
UINT8 stOther; /* Symbol table visibility */
UINT16 stShndx; /* Section table index */
UINT16 stShndx; /* Section table index *///表示与该符号相关的区的索引,例如函数符号与对应的代码区相关
} LDElf32Sym;
typedef struct {
UINT32 stName; /* Symbol table name (string tbl index) */
UINT8 stInfo; /* Symbol table type and binding */

@ -53,12 +53,12 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
#define INTERP_FULL_PATH "/lib/libc.so"
#define INVALID_FD (-1)
#define STRINGS_COUNT_MAX 256
#define ELF_PHDR_NUM_MAX 128
#define FILE_LENGTH_MAX 0x1000000
#define MEM_SIZE_MAX 0x1000000
#define INTERP_FULL_PATH "/lib/libc.so" ///< 解析器路径
#define INVALID_FD (-1)///< 无效文件描述符,用于初始值.
#define STRINGS_COUNT_MAX 256 ///< argv[], envp[]最大数量
#define ELF_PHDR_NUM_MAX 128 ///< ELF最大段数量
#define FILE_LENGTH_MAX 0x1000000 ///< 段占用的文件大小 最大1M
#define MEM_SIZE_MAX 0x1000000 ///< 运行时占用进程空间内存大小最大1M
#ifndef FILE_PATH_MAX
#define FILE_PATH_MAX PATH_MAX
@ -67,56 +67,62 @@ extern "C" {
#define FILE_PATH_MIN 2
#endif
#define USER_STACK_SIZE 0x100000
#define USER_PARAM_BYTE_MAX 0x1000
#define USER_STACK_TOP_MAX USER_ASPACE_TOP_MAX
#define USER_STACK_SIZE 0x100000 ///< 用户态空间栈大小1M
#define USER_PARAM_BYTE_MAX 0x1000 ///< 4K
#define USER_STACK_TOP_MAX USER_ASPACE_TOP_MAX ///< 用户空间栈顶位置
#define EXEC_MMAP_BASE 0x02000000
#define EXEC_MMAP_BASE 0x02000000 //可执行文件分配基地址
#ifdef LOSCFG_ASLR
#define RANDOM_MASK ((((USER_ASPACE_TOP_MAX + GB - 1) & (-GB)) >> 3) - 1)
#endif
#define STACK_ALIGN_SIZE 0x10
#define STACK_ALIGN_SIZE 0x10 ///< 栈对齐
#define RANDOM_VECTOR_SIZE 1
/* The permissions on sections in the program header. */
#define PF_R 0x4
#define PF_W 0x2
#define PF_X 0x1
/* The permissions on sections in the program header. | 对段的操作权限*/
#define PF_R 0x4 ///< 只读
#define PF_W 0x2 ///< 只写
#define PF_X 0x1 ///< 可执行
/**@struct
* @brief ELF
*/
typedef struct {
LD_ELF_EHDR elfEhdr;
LD_ELF_PHDR *elfPhdr;
UINT32 fileLen;
INT32 procfd;
LD_ELF_EHDR elfEhdr; ///< ELF头信息
LD_ELF_PHDR *elfPhdr; ///< ELF程序头信息,也称段头信息
UINT32 fileLen; ///< 文件长度
INT32 procfd; ///< 文件描述符
} ELFInfo;
/**@struct
* @brief ELF
*/
typedef struct {
ELFInfo execInfo;
ELFInfo interpInfo;
const CHAR *fileName;
CHAR *execName;
INT32 argc;
INT32 envc;
CHAR * const *argv;
CHAR * const *envp;
UINTPTR stackTop;
UINTPTR stackTopMax;
UINTPTR stackBase;
UINTPTR stackParamBase;
UINT32 stackSize;
INT32 stackProt;
UINTPTR argStart;
UINTPTR loadAddr;
UINTPTR elfEntry;
UINTPTR topOfMem;
UINTPTR oldFiles;
LosVmSpace *newSpace;
LosVmSpace *oldSpace;
ELFInfo execInfo; ///< 可执行文件信息
ELFInfo interpInfo;///< 解析器文件信息 lib/libc.so
const CHAR *fileName; ///< 文件名称
CHAR *execName; ///< 程序名称
INT32 argc; ///< 参数个数
INT32 envc; ///< 环境变量个数
CHAR *const *argv; ///< 参数数组
CHAR *const *envp; ///< 环境变量数组
UINTPTR stackTop; ///< 栈底位置,递减满栈下,stackTop是高地址位
UINTPTR stackTopMax;///< 栈最大上限
UINTPTR stackBase; ///< 栈顶位置,栈基地址
UINTPTR stackParamBase;///< 栈参数空间,放置启动ELF时的外部参数,大小为 USER_PARAM_BYTE_MAX 4K
UINT32 stackSize; ///< 栈大小
INT32 stackProt; ///< LD_PT_GNU_STACK栈的权限 ,例如(RW)
UINTPTR argStart; ///< 开始参数位置
UINTPTR loadAddr; ///< 加载地址
UINTPTR elfEntry; ///< 装载点地址 即: _start 函数地址
UINTPTR topOfMem; ///< 虚拟空间顶部位置,loadInfo->topOfMem = loadInfo->stackTopMax - sizeof(UINTPTR);
UINTPTR oldFiles; ///< 旧空间的文件映像
LosVmSpace *newSpace; ///< 新虚拟空间
LosVmSpace *oldSpace; ///< 旧虚拟空间
INT32 randomDevFD;
} ELFLoadInfo;
/// 不超过用户空间顶部位置
STATIC INLINE BOOL OsIsBadUserAddress(VADDR_T vaddr)
{
return (vaddr >= USER_STACK_TOP_MAX);

@ -1,3 +1,41 @@
/*!
* @file los_exec_elf.c
* @brief
* @link
@verbatim
OpenHarmony
1.
2.
3.
@endverbatim
* @image html https://gitee.com/weharmonyos/resources/raw/master/51/1.png
@verbatim
1. ELFPT_LOADET_EXECPT_LOADp_vaddr
ET_DYN-fPIEmmapbaseload_addr = base + p_vaddr
2. -fPIEELFe_entry
ELFPT_INTERPET_DYNmusllibc-musl.so
libc-musl.sommapbasebase + e_entrye_entry
3. e_entrybase + e_entry
@endverbatim
* @image html https://gitee.com/weharmonyos/resources/raw/master/51/2.png
@verbatim
1. mmapPT_LOAD
2. map_pagespagecache
3. elfpagecache
4.
5.
@endverbatim
* @version
* @author weharmonyos.com | 鸿 |
* @date 2021-11-19
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
@ -36,13 +74,13 @@
#include "los_vm_phys.h"
#include "los_vm_map.h"
#include "los_vm_dump.h"
/// 运行ELF
STATIC INT32 OsExecve(const ELFLoadInfo *loadInfo)
{
if ((loadInfo == NULL) || (loadInfo->elfEntry == 0)) {
return LOS_NOK;
}
//任务运行的两个硬性要求:1.提供入口指令 2.运行栈空间.
return OsExecStart((TSK_ENTRY_FUNC)(loadInfo->elfEntry), (UINTPTR)loadInfo->stackTop,
loadInfo->stackBase, loadInfo->stackSize);
}
@ -85,23 +123,23 @@ ERR_FILE:
return -ENOENT;
}
#endif
//拷贝用户参数至内核空间
STATIC INT32 OsCopyUserParam(ELFLoadInfo *loadInfo, const CHAR *fileName, CHAR *kfileName, UINT32 maxSize)
{
UINT32 strLen;
errno_t err;
if (LOS_IsUserAddress((VADDR_T)(UINTPTR)fileName)) {
err = LOS_StrncpyFromUser(kfileName, fileName, PATH_MAX + 1);
if (LOS_IsUserAddress((VADDR_T)(UINTPTR)fileName)) {//在用户空间
err = LOS_StrncpyFromUser(kfileName, fileName, PATH_MAX + 1);//拷贝至内核空间
if (err == -EFAULT) {
return err;
} else if (err > PATH_MAX) {
PRINT_ERR("%s[%d], filename len exceeds maxlen: %d\n", __FUNCTION__, __LINE__, PATH_MAX);
return -ENAMETOOLONG;
}
} else if (LOS_IsKernelAddress((VADDR_T)(UINTPTR)fileName)) {
} else if (LOS_IsKernelAddress((VADDR_T)(UINTPTR)fileName)) {//已经在内核空间
strLen = strlen(fileName);
err = memcpy_s(kfileName, PATH_MAX, fileName, strLen);
err = memcpy_s(kfileName, PATH_MAX, fileName, strLen);//拷贝至内核空间
if (err != EOK) {
PRINT_ERR("%s[%d], Copy failed! err: %d\n", __FUNCTION__, __LINE__, err);
return -EFAULT;
@ -110,30 +148,40 @@ STATIC INT32 OsCopyUserParam(ELFLoadInfo *loadInfo, const CHAR *fileName, CHAR *
return -EINVAL;
}
loadInfo->fileName = kfileName;
loadInfo->fileName = kfileName;//文件名指向内核空间
return LOS_OK;
}
/*!
* @brief LOS_DoExecveFile
* fileName LOS_DoExecveFileexecve
* @param argv NULLNULL
* @param envp NULLNULL
* @param fileName
* @return
*
* @see
*/
INT32 LOS_DoExecveFile(const CHAR *fileName, CHAR * const *argv, CHAR * const *envp)
{
ELFLoadInfo loadInfo = { 0 };
CHAR kfileName[PATH_MAX + 1] = { 0 };
CHAR kfileName[PATH_MAX + 1] = { 0 };//此时已陷入内核态,所以局部变量都在内核空间
INT32 ret;
#ifdef LOSCFG_SHELL
CHAR buf[PATH_MAX + 1] = { 0 };
#endif
//先判断参数地址是否来自用户空间,此处必须要来自用户空间,内核是不能直接调用本函数
if ((fileName == NULL) || ((argv != NULL) && !LOS_IsUserAddress((VADDR_T)(UINTPTR)argv)) ||
((envp != NULL) && !LOS_IsUserAddress((VADDR_T)(UINTPTR)envp))) {
return -EINVAL;
}
ret = OsCopyUserParam(&loadInfo, fileName, kfileName, PATH_MAX);
ret = OsCopyUserParam(&loadInfo, fileName, kfileName, PATH_MAX);//拷贝用户空间数据至内核空间
if (ret != LOS_OK) {
return ret;
}
#ifdef LOSCFG_SHELL
if (OsGetRealPath(kfileName, buf, (PATH_MAX + 1)) != LOS_OK) {
if (OsGetRealPath(kfileName, buf, (PATH_MAX + 1)) != LOS_OK) {//获取绝对路径
return -ENOENT;
}
if (buf[0] != '\0') {
@ -141,27 +189,27 @@ INT32 LOS_DoExecveFile(const CHAR *fileName, CHAR * const *argv, CHAR * const *e
}
#endif
loadInfo.newSpace = OsCreateUserVmSpace();
loadInfo.newSpace = OsCreateUserVmSpace();//创建一个用户空间,用于开启新的进程
if (loadInfo.newSpace == NULL) {
PRINT_ERR("%s %d, failed to allocate new vm space\n", __FUNCTION__, __LINE__);
return -ENOMEM;
}
loadInfo.argv = argv;
loadInfo.envp = envp;
loadInfo.argv = argv;//参数数组
loadInfo.envp = envp;//环境数组
ret = OsLoadELFFile(&loadInfo);
ret = OsLoadELFFile(&loadInfo);//加载ELF文件
if (ret != LOS_OK) {
return ret;
}
//对当前进程旧虚拟空间和文件进行回收
ret = OsExecRecycleAndInit(OsCurrProcessGet(), loadInfo.fileName, loadInfo.oldSpace, loadInfo.oldFiles);
if (ret != LOS_OK) {
(VOID)LOS_VmSpaceFree(loadInfo.oldSpace);
(VOID)LOS_VmSpaceFree(loadInfo.oldSpace);//释放虚拟空间
goto OUT;
}
ret = OsExecve(&loadInfo);
ret = OsExecve(&loadInfo);//运行ELF内容
if (ret != LOS_OK) {
goto OUT;
}

@ -48,13 +48,13 @@
#endif
STATIC BOOL g_srandInit;
/// 打开ELF文件
STATIC INT32 OsELFOpen(const CHAR *fileName, INT32 oflags)
{
INT32 ret;
INT32 procFd;
procFd = AllocProcessFd();
procFd = AllocProcessFd();//分配一个文件描述符
if (procFd < 0) {
return -EMFILE;
}
@ -63,13 +63,13 @@ STATIC INT32 OsELFOpen(const CHAR *fileName, INT32 oflags)
SetCloexecFlag(procFd);
}
ret = open(fileName, oflags);
ret = open(fileName, oflags);//打开文件
if (ret < 0) {
FreeProcessFd(procFd);
return -get_errno();
}
AssociateSystemFd(procFd, ret);
AssociateSystemFd(procFd, ret);//分配一个系统描述符
return procFd;
}
@ -744,7 +744,7 @@ STATIC VOID OsGetStackProt(ELFLoadInfo *loadInfo)
}
}
}
/// 分配栈区
STATIC UINT32 OsStackAlloc(LosVmSpace *space, VADDR_T vaddr, UINT32 vsize, UINT32 psize, UINT32 regionFlags)
{
LosVmPage *vmPage = NULL;
@ -805,14 +805,14 @@ STATIC INT32 OsSetArgParams(ELFLoadInfo *loadInfo, CHAR *const *argv, CHAR *cons
if (((UINT32)loadInfo->stackProt & (PROT_READ | PROT_WRITE)) != (PROT_READ | PROT_WRITE)) {
return -ENOEXEC;
}
loadInfo->stackTopMax = USER_STACK_TOP_MAX - OsGetRndOffset(loadInfo->randomDevFD);
loadInfo->stackBase = loadInfo->stackTopMax - USER_STACK_SIZE;
loadInfo->stackSize = USER_STACK_SIZE;
loadInfo->stackParamBase = loadInfo->stackTopMax - USER_PARAM_BYTE_MAX;
loadInfo->stackTopMax = USER_STACK_TOP_MAX - OsGetRndOffset(loadInfo->randomDevFD);//计算栈底位置
loadInfo->stackBase = loadInfo->stackTopMax - USER_STACK_SIZE;//计算栈基位置
loadInfo->stackSize = USER_STACK_SIZE; //用户态栈大小
loadInfo->stackParamBase = loadInfo->stackTopMax - USER_PARAM_BYTE_MAX; //栈参数空间
vmFlags = OsCvtProtFlagsToRegionFlags(loadInfo->stackProt, MAP_FIXED);
vmFlags |= VM_MAP_REGION_FLAG_STACK;
vmFlags |= VM_MAP_REGION_FLAG_STACK; //标记映射区为栈区
ret = OsStackAlloc((VOID *)loadInfo->newSpace, loadInfo->stackBase, USER_STACK_SIZE,
USER_PARAM_BYTE_MAX, vmFlags);
USER_PARAM_BYTE_MAX, vmFlags);//分配映射区
if (ret != LOS_OK) {
PRINT_ERR("%s[%d], Failed to alloc memory for user stack!\n", __FUNCTION__, __LINE__);
return -ENOMEM;
@ -937,7 +937,7 @@ STATIC INT32 OsMakeArgsStack(ELFLoadInfo *loadInfo, UINTPTR interpMapBase)
AUX_VEC_ENTRY(auxVector, vecIndex, AUX_EXECFN, (UINTPTR)loadInfo->execName);
#ifdef LOSCFG_KERNEL_VDSO
vdsoLoadAddr = OsVdsoLoad(OsCurrProcessGet());
vdsoLoadAddr = OsVdsoLoad(OsCurrProcessGet());//为当前进程加载 VDSO ELF
if (vdsoLoadAddr != 0) {
AUX_VEC_ENTRY(auxVector, vecIndex, AUX_SYSINFO_EHDR, vdsoLoadAddr);
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save