diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index c796d20f..00000000
--- a/.gitignore
+++ /dev/null
@@ -1,24 +0,0 @@
-# General ignored file types
-*.o
-*.a
-*.so
-*.swp
-
-# IDE settings
-.vscode
-.idea
-.settings
-.cproject
-.project
-
-# VIM files
-cscope*
-tags
-
-# Menuconfig temp files
-/config.h
-/.config
-/.config.old
-
-# Build temp files
-/out
diff --git a/.vscode/settings.json b/.vscode/settings.json
deleted file mode 100644
index 3f272e5a..00000000
--- a/.vscode/settings.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "files.associations": {
- "los_swtmr_pri.h": "c",
- "los_vm_syscall.h": "c",
- "regex": "c"
- }
-}
\ No newline at end of file
diff --git a/README.md b/README.md
index 305ba24d..d5e25782 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,2 @@
-# Brief Intro
+# Iot_Cs_best
-LMFAO, we do this shit just for fun :)
\ No newline at end of file
diff --git a/doc/cache/UML用例图.vsdx b/doc/cache/UML用例图.vsdx
deleted file mode 100644
index d1c233bd..00000000
Binary files a/doc/cache/UML用例图.vsdx and /dev/null differ
diff --git a/doc/cache/image-1.png b/doc/cache/image-1.png
deleted file mode 100644
index 18765b3d..00000000
Binary files a/doc/cache/image-1.png and /dev/null differ
diff --git a/doc/cache/image-2.png b/doc/cache/image-2.png
deleted file mode 100644
index 18765b3d..00000000
Binary files a/doc/cache/image-2.png and /dev/null differ
diff --git a/doc/cache/image-3.png b/doc/cache/image-3.png
deleted file mode 100644
index fc5179eb..00000000
Binary files a/doc/cache/image-3.png and /dev/null differ
diff --git a/doc/cache/image-4.png b/doc/cache/image-4.png
deleted file mode 100644
index fc5179eb..00000000
Binary files a/doc/cache/image-4.png and /dev/null differ
diff --git a/doc/cache/image-5.png b/doc/cache/image-5.png
deleted file mode 100644
index 7bff255f..00000000
Binary files a/doc/cache/image-5.png and /dev/null differ
diff --git a/doc/cache/image-6.png b/doc/cache/image-6.png
deleted file mode 100644
index 7bff255f..00000000
Binary files a/doc/cache/image-6.png and /dev/null differ
diff --git a/doc/cache/image.png b/doc/cache/image.png
deleted file mode 100644
index 04b5dd2e..00000000
Binary files a/doc/cache/image.png and /dev/null differ
diff --git a/doc/cache/~$$进程控制顺序图.~vsdx b/doc/cache/~$$进程控制顺序图.~vsdx
deleted file mode 100644
index f3ad3b1e..00000000
Binary files a/doc/cache/~$$进程控制顺序图.~vsdx and /dev/null differ
diff --git a/doc/cache/学习报告.md b/doc/cache/学习报告.md
deleted file mode 100644
index 533c3037..00000000
--- a/doc/cache/学习报告.md
+++ /dev/null
@@ -1,44 +0,0 @@
-# base 下的代码阅读
-
-根据官方的README.md,kernel/base下的文件主要为**基础内核包括调度、内存等模块**
-
-# 1. brief intro
-
-OpenHarmony liteos 的进程实现方式与 linux 类似,都是通过父进程和子进程的一系列操作来达到实现一些功能的目的.
-
-## 1.1 描述各个子功能
-
-* los_bitmap.c 主要提供一些位操作
-* los_info.c 提供一些基本的方法来对进程的信息等内容进行操作
-* los_process.c 提供对于进程操作的方法包括创建切换等..
-
-
-# 2. natural expression of requirement of software
-
-作为操作系统当中的子系统,以软件的角度来看进程管理:
-
-## 2.1 一个完备的进程管理系统应当具备
-
-### (1) 进程调度
-
-鸿蒙内核的进程采用抢占式调度机制,支持时间片轮转调度方式和FIFO调度机制
-
-### (2) 进程创建
-
-
-
-
-### (3) 进程回收
-### (4)
-### (5)
-### (6)
-
-# 3. user case diagram and user case description
-
-
-
-
-# 4. software architecture
-
-
-
\ No newline at end of file
diff --git a/doc/cache/泛读报告.md b/doc/cache/泛读报告.md
deleted file mode 100644
index 769db50e..00000000
--- a/doc/cache/泛读报告.md
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-# LiteOS_kernel_a 泛读报告
-
-## 一、 软件功能的自然语言描述
-
-### 1.1 简介
-
-Huawei LiteOS是华为面向IoT领域,构建的轻量级物联网操作系统,可广泛应用于智能家居、个人穿戴、车联网、城市公共服务、制造业等领域。
-
-Huawei LiteOS发布于2015年5月的华为网络大会上。自开源社区发布以来,围绕 NB-IoT 物联网市场从技术、生态、解决方案、商用支持等多维度使能合作伙伴,构建开源的物联网生态。目前已经聚合了 50+ MCU 和解决方案合作伙伴,共同推出一批开源开发套件和行业解决方案,帮助众多行业客户快速的推出物联网产品和服务。客户涵盖抄表、停车、路灯、环保、共享单车、物流等众多行业,为开发者提供 “一站式” 完整软件平台,可大幅降低设备布置及维护成本,有效降低开发门槛、缩短开发周期。
-
-Huawei LiteOS开源项目目前支持 **ARM64、ARM Cortex-A、ARM Cortex-M0,Cortex-M3,Cortex-M4,Cortex-M7** 等芯片架构。
-
-### 1.2 软件功能
-
-#### 1.2.1 提供一个简单轻便的用户交互界面以供使用。
-
-#### 1.2.2 能够调用系统软硬件资源来完成某些操作。
-
-#### 1.2.3 进程管理
-
-#### 1.2.4 内存分配
-
-#### 1.2.5 提供并行编程
-
-## 二、 软件的用例图和用例描述
-
-
-
-## 三、 软件的体系结构
-
-
-
-
\ No newline at end of file
diff --git a/doc/cache/绘图1.vsdx b/doc/cache/绘图1.vsdx
deleted file mode 100644
index 5cec30dc..00000000
Binary files a/doc/cache/绘图1.vsdx and /dev/null differ
diff --git a/doc/cache/进程控制顺序图.vsdx b/doc/cache/进程控制顺序图.vsdx
deleted file mode 100644
index 9d0a1f31..00000000
Binary files a/doc/cache/进程控制顺序图.vsdx and /dev/null differ
diff --git a/doc/泛读报告.docx b/doc/泛读报告.docx
deleted file mode 100644
index 55b9d063..00000000
Binary files a/doc/泛读报告.docx and /dev/null differ
diff --git a/src/kernel_liteos_a/.gitignore b/src/kernel_liteos_a/.gitignore
deleted file mode 100644
index c796d20f..00000000
--- a/src/kernel_liteos_a/.gitignore
+++ /dev/null
@@ -1,24 +0,0 @@
-# General ignored file types
-*.o
-*.a
-*.so
-*.swp
-
-# IDE settings
-.vscode
-.idea
-.settings
-.cproject
-.project
-
-# VIM files
-cscope*
-tags
-
-# Menuconfig temp files
-/config.h
-/.config
-/.config.old
-
-# Build temp files
-/out
diff --git a/src/kernel_liteos_a/apps/init/src/init.c b/src/kernel_liteos_a/apps/init/src/init.c
index 784bf83d..a0420394 100644
--- a/src/kernel_liteos_a/apps/init/src/init.c
+++ b/src/kernel_liteos_a/apps/init/src/init.c
@@ -54,13 +54,13 @@ int main(int argc, char * const *argv)
const char *shellPath = "/bin/mksh";
#ifdef LOSCFG_QUICK_START
- const char *samplePath = "/dev/shm/sample_quickstart";
+ const char *samplePath = "/dev/shm/sample_quickstart";
ret = fork();
if (ret < 0) {
printf("Failed to fork for sample_quickstart\n");
} else if (ret == 0) {
- (void)execve(samplePath, NULL, NULL); // 执行可执行文件
+ (void)execve(samplePath, NULL, NULL);
exit(0);
}
@@ -72,24 +72,24 @@ int main(int argc, char * const *argv)
close(fd);
}
#endif
- ret = fork(); // 创建第一个程序来跑shell
+ ret = fork();
if (ret < 0) {
printf("Failed to fork for shell\n");
- } else if (ret == 0) {
- gid = getpgrp(); // 返回进程组ID
+ } else if (ret == 0) {
+ gid = getpgrp();
if (gid < 0) {
printf("get group id failed, pgrpid %d, errno %d\n", gid, errno);
exit(0);
}
- ret = tcsetpgrp(STDIN_FILENO, gid);
+ ret = tcsetpgrp(STDIN_FILENO, gid);
if (ret != 0) {
printf("tcsetpgrp failed, errno %d\n", errno);
exit(0);
}
- (void)execve(shellPath, NULL, NULL); // 正常执行命令行程序可执行文件
+ (void)execve(shellPath, NULL, NULL);
exit(0);
}
- // ret > 0
+
while (1) {
ret = waitpid(-1, 0, WNOHANG);
if (ret == 0) {
diff --git a/src/kernel_liteos_a/fs/jffs2/jffs2.patch b/src/kernel_liteos_a/fs/jffs2/jffs2.patch
index eba19047..073aa696 100644
--- a/src/kernel_liteos_a/fs/jffs2/jffs2.patch
+++ b/src/kernel_liteos_a/fs/jffs2/jffs2.patch
@@ -2311,7 +2311,7 @@ diff -Nupr old/fs/jffs2/erase.c new/fs/jffs2/erase.c
diff -Nupr old/fs/jffs2/file.c new/fs/jffs2/file.c
--- old/fs/jffs2/file.c 2022-05-09 17:22:53.000000000 +0800
+++ new/fs/jffs2/file.c 2022-05-10 09:43:14.250000000 +0800
-@@ -9,334 +9,31 @@
+@@ -9,335 +9,30 @@
* For licensing information, see the file 'LICENCE' in this directory.
*
*/
@@ -2348,7 +2348,7 @@ diff -Nupr old/fs/jffs2/file.c new/fs/jffs2/file.c
- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
+ /* FIXME: This works only with one file system mounted at a time */
int ret;
-
+-
- ret = file_write_and_wait_range(filp, start, end);
+ ret = jffs2_read_inode_range(c, f, gc_buffer,
+ offset & ~(PAGE_SIZE-1), PAGE_SIZE);
@@ -2361,10 +2361,8 @@ diff -Nupr old/fs/jffs2/file.c new/fs/jffs2/file.c
- inode_unlock(inode);
-
- return 0;
-+ return ERR_PTR(ret);
-+ return gc_buffer;
- }
-
+-}
+-
-const struct file_operations jffs2_file_operations =
-{
- .llseek = generic_file_llseek,
@@ -2389,10 +2387,7 @@ diff -Nupr old/fs/jffs2/file.c new/fs/jffs2/file.c
-};
-
-const struct address_space_operations jffs2_file_address_operations =
-+void jffs2_gc_release_page(struct jffs2_sb_info *c,
-+ unsigned char *ptr,
-+ unsigned long *priv)
- {
+-{
- .readpage = jffs2_readpage,
- .write_begin = jffs2_write_begin,
- .write_end = jffs2_write_end,
@@ -2448,29 +2443,35 @@ diff -Nupr old/fs/jffs2/file.c new/fs/jffs2/file.c
- ret = jffs2_do_readpage_unlock(pg->mapping->host, pg);
- mutex_unlock(&f->sem);
- return ret;
--}
--
++ return ERR_PTR(ret);
++ return gc_buffer;
+ }
+
-static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
- loff_t pos, unsigned len, unsigned flags,
- struct page **pagep, void **fsdata)
--{
++void jffs2_gc_release_page(struct jffs2_sb_info *c,
++ unsigned char *ptr,
++ unsigned long *priv)
+ {
- struct page *pg;
- struct inode *inode = mapping->host;
- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
- pgoff_t index = pos >> PAGE_SHIFT;
+- uint32_t pageofs = index << PAGE_SHIFT;
- int ret = 0;
-
- jffs2_dbg(1, "%s()\n", __func__);
-
-- if (pos > inode->i_size) {
-- /* Make new hole frag from old EOF to new position */
+- if (pageofs > inode->i_size) {
+- /* Make new hole frag from old EOF to new page */
- struct jffs2_raw_inode ri;
- struct jffs2_full_dnode *fn;
- uint32_t alloc_len;
-
-- jffs2_dbg(1, "Writing new hole frag 0x%x-0x%x between current EOF and new position\n",
-- (unsigned int)inode->i_size, (uint32_t)pos);
+- jffs2_dbg(1, "Writing new hole frag 0x%x-0x%x between current EOF and new page\n",
+- (unsigned int)inode->i_size, pageofs);
-
- ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len,
- ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
@@ -2490,10 +2491,10 @@ diff -Nupr old/fs/jffs2/file.c new/fs/jffs2/file.c
- ri.mode = cpu_to_jemode(inode->i_mode);
- ri.uid = cpu_to_je16(i_uid_read(inode));
- ri.gid = cpu_to_je16(i_gid_read(inode));
-- ri.isize = cpu_to_je32((uint32_t)pos);
+- ri.isize = cpu_to_je32(max((uint32_t)inode->i_size, pageofs));
- ri.atime = ri.ctime = ri.mtime = cpu_to_je32(JFFS2_NOW());
- ri.offset = cpu_to_je32(inode->i_size);
-- ri.dsize = cpu_to_je32((uint32_t)pos - inode->i_size);
+- ri.dsize = cpu_to_je32(pageofs - inode->i_size);
- ri.csize = cpu_to_je32(0);
- ri.compr = JFFS2_COMPR_ZERO;
- ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
@@ -2523,7 +2524,7 @@ diff -Nupr old/fs/jffs2/file.c new/fs/jffs2/file.c
- goto out_err;
- }
- jffs2_complete_reservation(c);
-- inode->i_size = pos;
+- inode->i_size = pageofs;
- mutex_unlock(&f->sem);
- }
-
diff --git a/src/kernel_liteos_a/kernel/base/core/los_bitmap.c b/src/kernel_liteos_a/kernel/base/core/los_bitmap.c
index 253af3a5..039b6637 100644
--- a/src/kernel_liteos_a/kernel/base/core/los_bitmap.c
+++ b/src/kernel_liteos_a/kernel/base/core/los_bitmap.c
@@ -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,84 +31,78 @@
#include "los_bitmap.h"
#include "los_printf.h"
-#include "los_toolchain.h"
-
-/*
- function: 这部分的代码提供了位操作
-
- interpretation: 位操作为可以提供对标志位的修改等功能
-*/
-#define OS_BITMAP_MASK 0x1FU
+#include "los_toolchain.h" //GCC 编译器的内置函数
+
+/**
+ * @brief
+ * @verbatim
+ 基本概念
+ 位操作是指对二进制数的bit位进行操作。程序可以设置某一变量为状态字,状态字中的
+ 每一bit位(标志位)可以具有自定义的含义。
+
+ 使用场景
+ 系统提供标志位的置1和清0操作,可以改变标志位的内容,同时还提供获取状态字中标志位
+ 为1的最高位和最低位的功能。用户也可以对系统的寄存器进行位操作。
+
+ 参考
+ https://www.geeksforgeeks.org/builtin-functions-gcc-compiler/
+ * @endverbatim
+ */
+#define OS_BITMAP_MASK 0x1FU //
#define OS_BITMAP_WORD_MASK ~0UL
-/*
- function: 返回从右开始第一个为1的下标
-
- interpretation:
-*/
-
-/* find first zero bit starting from LSB */
+/*! find first zero bit starting from LSB */
STATIC INLINE UINT16 Ffz(UINTPTR x)
-{
- // gcc 自带的内建函数
- return __builtin_ffsl(~x) - 1;
+{//__builtin_ffsl: 返回右起第一个1的位置,函数来自 glibc
+ return __builtin_ffsl(~x) - 1;//从LSB开始查找第一个零位 LSB(最低有效位) 对应 最高有效位(MSB)
}
-
-/*
- funciton: 对状态字某一标志位进行置1操作
-
- interpretation:
-*/
+///对状态字的某一标志位进行置1操作
VOID LOS_BitmapSet(UINT32 *bitmap, UINT16 pos)
{
if (bitmap == NULL) {
return;
}
- *bitmap |= 1U << (pos & OS_BITMAP_MASK); //00011111
+ *bitmap |= 1U << (pos & OS_BITMAP_MASK);//在对应位上置1
}
-
-/*
- function: 对某一标志位进行清0操作
-
- interpretation:
-*/
+///对状态字的某一标志位进行清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
}
-/*
- function: 用于返回参数位图当中最高的索引位
-*/
+/**
+ * @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 用于计算整数的前导零
}
-
-/*
- function: 获取参数位图中最低位为1的索引位
-*/
+/// 获取参数位图中最低位为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 用于计算给定整数的尾随零
}
-
-/*
- function: 从start位置开始设置numsSet个bit位 置1
-*/
+/// 从start位置开始设置numsSet个bit位 置1
VOID LOS_BitmapSetNBits(UINTPTR *bitmap, UINT32 start, UINT32 numsSet)
{
UINTPTR *p = bitmap + BITMAP_WORD(start);
@@ -128,10 +122,7 @@ VOID LOS_BitmapSetNBits(UINTPTR *bitmap, UINT32 start, UINT32 numsSet)
*p |= maskToSet;
}
}
-
-/*
- fuction: 从start位置开始 清除numsSet个bit位置0 ,对状态字的连续标志位进行清0操作
-*/
+///从start位置开始 清除numsSet个bit位置0 ,对状态字的连续标志位进行清0操作
VOID LOS_BitmapClrNBits(UINTPTR *bitmap, UINT32 start, UINT32 numsClear)
{
UINTPTR *p = bitmap + BITMAP_WORD(start);
@@ -151,9 +142,7 @@ VOID LOS_BitmapClrNBits(UINTPTR *bitmap, UINT32 start, UINT32 numsClear)
*p &= ~maskToClear;
}
}
-/*
- fuction: 从numBits位置开始找到第一个0位
-*/
+///从numBits位置开始找到第一个0位
INT32 LOS_BitmapFfz(UINTPTR *bitmap, UINT32 numBits)
{
INT32 bit, i;
diff --git a/src/kernel_liteos_a/kernel/base/core/los_info.c b/src/kernel_liteos_a/kernel/base/core/los_info.c
index 0999503d..85c79be3 100644
--- a/src/kernel_liteos_a/kernel/base/core/los_info.c
+++ b/src/kernel_liteos_a/kernel/base/core/los_info.c
@@ -31,17 +31,15 @@
#include "los_info_pri.h"
#include "los_task_pri.h"
#include "los_vm_dump.h"
-
-// 得到父进程的pid
+//获取当前进程的父进程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号进程(kidle)是,1,2号进程的父进程
return 0;
}
@@ -51,8 +49,7 @@ STATIC UINT32 GetCurrParentPid(UINT32 pid, const LosProcessCB *processCB)
#endif
return processCB->parentProcess->processID;
}
-
-// 得到当前任务ID
+//获取当前任务ID
STATIC INLINE UINT32 GetCurrTid(const LosTaskCB *taskCB)
{
#ifdef LOSCFG_PID_CONTAINER
@@ -63,7 +60,6 @@ STATIC INLINE UINT32 GetCurrTid(const LosTaskCB *taskCB)
return taskCB->taskID;
}
-// 得到进程的状态
STATIC UINT16 GetProcessStatus(LosProcessCB *processCB)
{
UINT16 status;
@@ -80,7 +76,6 @@ STATIC UINT16 GetProcessStatus(LosProcessCB *processCB)
return status;
}
-// 得到进程的信息
STATIC VOID GetProcessInfo(ProcessInfo *pcbInfo, const LosProcessCB *processCB)
{
SchedParam param = {0};
@@ -138,7 +133,6 @@ STATIC VOID GetProcessMemInfo(ProcessInfo *pcbInfo, const LosProcessCB *processC
}
#endif
-// 得到线程的信息
STATIC VOID GetThreadInfo(ProcessThreadInfo *threadInfo, LosProcessCB *processCB)
{
SchedParam param = {0};
diff --git a/src/kernel_liteos_a/kernel/base/core/los_process.c b/src/kernel_liteos_a/kernel/base/core/los_process.c
index 58dd593f..632190a6 100644
--- a/src/kernel_liteos_a/kernel/base/core/los_process.c
+++ b/src/kernel_liteos_a/kernel/base/core/los_process.c
@@ -1,15 +1,25 @@
-/*
-进程模块主文件
+/*!
+ * @file los_process.c
+ * @brief 进程模块主文件
+ * @link
+ @verbatim
+
并发(Concurrent):多个线程在单个核心运行,同一时间只能一个线程运行,内核不停切换线程,
看起来像同时运行,实际上是线程不停切换
并行(Parallel)每个线程分配给独立的CPU核心,线程同时运行
单核CPU多个进程或多个线程内能实现并发(微观上的串行,宏观上的并行)
多核CPU线程间可以实现宏观和微观上的并行
LITE_OS_SEC_BSS 和 LITE_OS_SEC_DATA_INIT 是告诉编译器这些全局变量放在哪个数据段
+
+ @endverbatim
+ * @version
+ * @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
+ * @date 2021-12-15
*/
+
/*
- * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
- * Copyright (c) 2020-2023 Huawei Device 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,
* are permitted provided that the following conditions are met:
@@ -68,15 +78,22 @@
#include "los_vm_phys.h"
#include "los_vm_syscall.h"
-LITE_OS_SEC_BSS LosProcessCB *g_processCBArray = NULL;//进程池数组
-LITE_OS_SEC_DATA_INIT STATIC LOS_DL_LIST g_freeProcess;//空闲状态下的进程链表,
-LITE_OS_SEC_DATA_INIT STATIC LOS_DL_LIST g_processRecycleList;//需要收回的进程列表
-LITE_OS_SEC_BSS UINT32 g_processMaxNum;//进程最大数量,默认64个
+LITE_OS_SEC_BSS LosProcessCB *g_processCBArray = NULL; ///< 进程池数组
+LITE_OS_SEC_DATA_INIT STATIC LOS_DL_LIST g_freeProcess;///< 空闲状态下的进程链表, .个人觉得应该取名为 g_freeProcessList @note_thinking
+LITE_OS_SEC_DATA_INIT STATIC LOS_DL_LIST g_processRecycleList;///< 需要回收的进程列表
+LITE_OS_SEC_BSS UINT32 g_processMaxNum;///< 进程最大数量,默认64个
#ifndef LOSCFG_PID_CONTAINER
-LITE_OS_SEC_BSS ProcessGroup *g_processGroup = NULL;//全局进程组,负责管理所有的进程组
+LITE_OS_SEC_BSS ProcessGroup *g_processGroup = NULL;///< 全局进程组,负责管理所有进程组
#define OS_ROOT_PGRP(processCB) (g_processGroup)
#endif
-
+/*
+ * @brief 将进程插入到空闲链表中
+ * @details
+ * @param argc 1
+ * @param[LosProcessCB] processCB 指定进程
+ * @return 函数执行结果
+ * - VOID 无
+*/
STATIC INLINE VOID OsInsertPCBToFreeList(LosProcessCB *processCB)
{
#ifdef LOSCFG_PID_CONTAINER
@@ -156,7 +173,7 @@ ProcessGroup *OsCreateProcessGroup(LosProcessCB *processCB)
return NULL;
}
- pgroup->pgroupLeader = (UINTPTR)processCB;//指定进程负责人
+ pgroup->pgroupLeader = (UINTPTR)processCB;//指定进程组负责人
LOS_ListInit(&pgroup->processList);//初始化组员链表
LOS_ListInit(&pgroup->exitProcessList);//初始化僵死进程链表
@@ -173,17 +190,19 @@ ProcessGroup *OsCreateProcessGroup(LosProcessCB *processCB)
}
return pgroup;
}
-//退出进程组,参数是进程地址和进程组地址的地址
+
+/*! 退出进程组,参数是进程地址和进程组地址的地址 */
STATIC VOID ExitProcessGroup(LosProcessCB *processCB, ProcessGroup **pgroup)
{
LosProcessCB *pgroupCB = OS_GET_PGROUP_LEADER(processCB->pgroup);
+
LOS_ListDelete(&processCB->subordinateGroupList);//从进程组进程链表上摘出去
- if (LOS_ListEmpty(&processCB->pgroup->processList) && LOS_ListEmpty(&processCB->pgroup->exitProcessList)) {
+ if (LOS_ListEmpty(&processCB->pgroup->processList) && LOS_ListEmpty(&processCB->pgroup->exitProcessList)) {//进程组进程链表和退出进程链表都为空时
#ifdef LOSCFG_PID_CONTAINER
if (processCB->pgroup != OS_ROOT_PGRP(processCB)) {
#endif
- LOS_ListDelete(&processCB->pgroup->groupList);//从全局进程组链表上把自己摘出去 记住它是 LOS_ListTailInsert(&g_processGroup->groupList, &group->groupList) 挂上去的
- *pgroup = processCB->pgroup;
+ LOS_ListDelete(&processCB->pgroup->groupList);//从全局进程组链表上把自己摘出去 记住它是 LOS_ListTailInsert(&g_processGroup->groupList, &group->groupList) 挂上去的
+ *pgroup = processCB->pgroup;//????? 这步操作没看明白,谁能告诉我为何要这么做?
#ifdef LOSCFG_PID_CONTAINER
}
#endif
@@ -196,6 +215,7 @@ STATIC VOID ExitProcessGroup(LosProcessCB *processCB, ProcessGroup **pgroup)
processCB->pgroup = NULL;
}
+
/*! 通过指定组ID找到进程组 */
STATIC ProcessGroup *OsFindProcessGroup(UINT32 gid)
{
@@ -216,6 +236,7 @@ STATIC ProcessGroup *OsFindProcessGroup(UINT32 gid)
PRINT_INFO("%s failed! pgroup id = %u\n", __FUNCTION__, gid);
return NULL;
}
+
/*! 给指定进程组发送信号 */
STATIC INT32 OsSendSignalToSpecifyProcessGroup(ProcessGroup *pgroup, siginfo_t *info, INT32 permission)
{
@@ -309,6 +330,7 @@ STATIC LosProcessCB *OsFindExitChildProcess(const LosProcessCB *processCB, const
return NULL;
}
+
/*! 唤醒等待wakePID结束的任务 */
VOID OsWaitWakeTask(LosTaskCB *taskCB, UINTPTR wakePID)
{
@@ -318,6 +340,7 @@ VOID OsWaitWakeTask(LosTaskCB *taskCB, UINTPTR wakePID)
LOS_MpSchedule(OS_MP_CPU_ALL);//向所有cpu发送调度指令
#endif
}
+
/*! 唤醒等待参数进程结束的任务 */
STATIC BOOL OsWaitWakeSpecifiedProcess(LOS_DL_LIST *head, const LosProcessCB *processCB, LOS_DL_LIST **anyList)
{
@@ -332,7 +355,7 @@ STATIC BOOL OsWaitWakeSpecifiedProcess(LOS_DL_LIST *head, const LosProcessCB *pr
if (processID == 0) {
processID = taskCB->waitID;
find = TRUE;//找到了
- } else {
+ } else {// @note_thinking 这个代码有点多余吧,会执行到吗?
processID = OS_INVALID_VALUE;
}
@@ -349,6 +372,7 @@ STATIC BOOL OsWaitWakeSpecifiedProcess(LOS_DL_LIST *head, const LosProcessCB *pr
return find;
}
+
/*! 检查父进程的等待任务并唤醒父进程去处理等待任务 */
STATIC VOID OsWaitCheckAndWakeParentProcess(LosProcessCB *parentCB, const LosProcessCB *processCB)
{
@@ -360,7 +384,7 @@ STATIC VOID OsWaitCheckAndWakeParentProcess(LosProcessCB *parentCB, const LosPro
if (LOS_ListEmpty(&parentCB->waitList)) {//父进程中是否有在等待子进程退出的任务?
return;//没有就退出
}
-
+ // TODO
findSpecified = OsWaitWakeSpecifiedProcess(head, processCB, &list);//找到指定的任务
if (findSpecified == TRUE) {
/* No thread is waiting for any child process to finish */
@@ -411,6 +435,7 @@ STATIC VOID OsWaitCheckAndWakeParentProcess(LosProcessCB *parentCB, const LosPro
return;
}
+
/*! 回收指定进程的资源 */
LITE_OS_SEC_TEXT VOID OsProcessResourcesToFree(LosProcessCB *processCB)
{
@@ -420,10 +445,10 @@ LITE_OS_SEC_TEXT VOID OsProcessResourcesToFree(LosProcessCB *processCB)
}
#endif
-#ifdef LOSCFG_SECURITY_CAPABILITY//安全开关
+#ifdef LOSCFG_SECURITY_CAPABILITY //安全开关
if (processCB->user != NULL) {
(VOID)LOS_MemFree(m_aucSysMem1, processCB->user);//删除用户
- processCB->user = NULL;//重置指针为空
+ processCB->user = NULL; //重置指针为空
}
#endif
@@ -480,6 +505,7 @@ LITE_OS_SEC_TEXT VOID OsProcessResourcesToFree(LosProcessCB *processCB)
processCB->resourceLimit = NULL;
}
}
+
/*! 回收僵死状态进程的资源 */
STATIC VOID OsRecycleZombiesProcess(LosProcessCB *childCB, ProcessGroup **pgroup)
{
@@ -497,9 +523,10 @@ STATIC VOID OsRecycleZombiesProcess(LosProcessCB *childCB, ProcessGroup **pgroup
} else if (OsProcessIsPGroupLeader(childCB)) {
LOS_ListTailInsert(&g_processRecycleList, &childCB->pendList);//从尾部插入,意思就是组长尽量最后一个处理
} else {
- OsInsertPCBToFreeList(childCB);//直接插到freeList中去,可用于重新分配了
+ OsInsertPCBToFreeList(childCB);//直接插到freeList中去,可用于重新分配了。
}
}
+
/*! 当一个进程自然退出的时候,它的孩子进程由两位老祖宗收养 */
STATIC VOID OsDealAliveChildProcess(LosProcessCB *processCB)
{
@@ -513,7 +540,6 @@ STATIC VOID OsDealAliveChildProcess(LosProcessCB *processCB)
return;
}
#endif
-
if (!LOS_ListEmpty(&processCB->childrenList)) {//如果存在孩子进程
childHead = processCB->childrenList.pstNext;//获取孩子链表
LOS_ListDelete(&(processCB->childrenList));//清空自己的孩子链表
@@ -537,6 +563,7 @@ STATIC VOID OsDealAliveChildProcess(LosProcessCB *processCB)
return;
}
+
/*! 回收指定进程的已经退出(死亡)的孩子进程所占资源 */
STATIC VOID OsChildProcessResourcesFree(const LosProcessCB *processCB)
{
@@ -549,11 +576,13 @@ STATIC VOID OsChildProcessResourcesFree(const LosProcessCB *processCB)
(VOID)LOS_MemFree(m_aucSysMem1, pgroup);
}
}
+
/*! 一个进程的自然消亡过程,参数是当前运行的任务*/
VOID OsProcessNaturalExit(LosProcessCB *processCB, UINT32 status)
{
OsChildProcessResourcesFree(processCB);//释放孩子进程的资源
+
/* is a child process */
if (processCB->parentProcess != NULL) {
LosProcessCB *parentCB = processCB->parentProcess;
@@ -569,8 +598,8 @@ VOID OsProcessNaturalExit(LosProcessCB *processCB, UINT32 status)
OsDealAliveChildProcess(processCB);//孩子们要怎么处理,移交给(用户态和内核态)根进程
-
processCB->processStatus |= OS_PROCESS_STATUS_ZOMBIES;//贴上僵死进程的标签
+
#ifdef LOSCFG_KERNEL_VM
(VOID)OsSendSigToProcess(parentCB, SIGCHLD, OS_KERNEL_KILL_PERMISSION);
#endif
@@ -638,6 +667,7 @@ UINT32 OsProcessInit(VOID)
SystemProcessEarlyInit(OsGetKernelInitProcess());
return LOS_OK;
}
+
/*! 进程回收再利用过程*/
LITE_OS_SEC_TEXT VOID OsProcessCBRecycleToFree(VOID)
{
@@ -647,7 +677,7 @@ LITE_OS_SEC_TEXT VOID OsProcessCBRecycleToFree(VOID)
SCHEDULER_LOCK(intSave);
while (!LOS_ListEmpty(&g_processRecycleList)) {//循环任务回收链表,直到为空
processCB = OS_PCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&g_processRecycleList));//找到回收链表中第一个进程实体
- //OS_PCB_FROM_PENDLIST 代表的是通过pendlist节点找到 PCB实体,因为g_processRecyleList上面挂的是pendlist节点位置
+ //OS_PCB_FROM_PENDLIST 代表的是通过pendlist节点找到 PCB实体,因为g_processRecyleList上面挂的是pendlist节点位置
if (!(processCB->processStatus & OS_PROCESS_FLAG_EXIT)) {//进程没有退出标签
break;
}
@@ -683,6 +713,7 @@ LITE_OS_SEC_TEXT VOID OsProcessCBRecycleToFree(VOID)
SCHEDULER_UNLOCK(intSave);
}
+
/*! 删除PCB块 其实是 PCB块回归进程池,先进入回收链表*/
STATIC VOID OsDeInitPCB(LosProcessCB *processCB)
{
@@ -698,7 +729,6 @@ STATIC VOID OsDeInitPCB(LosProcessCB *processCB)
return;
}
#endif
-
OsProcessResourcesToFree(processCB);//释放进程所占用的资源
SCHEDULER_LOCK(intSave);
@@ -712,7 +742,7 @@ STATIC VOID OsDeInitPCB(LosProcessCB *processCB)
}
processCB->processStatus &= ~OS_PROCESS_STATUS_INIT;//设置进程状态为非初始化
- processCB->processStatus |= OS_PROCESS_FLAG_EXIT;//设置进程状态为退出
+ processCB->processStatus |= OS_PROCESS_FLAG_EXIT; //设置进程状态为退出
LOS_ListHeadInsert(&g_processRecycleList, &processCB->pendList);
SCHEDULER_UNLOCK(intSave);
@@ -757,19 +787,19 @@ UINT32 OsSetProcessName(LosProcessCB *processCB, const CHAR *name)
/*! 初始化PCB(进程控制块)*/
STATIC UINT32 OsInitPCB(LosProcessCB *processCB, UINT32 mode, const CHAR *name)
{
- processCB->processMode = mode;//用户态进程还是内核态进程
- processCB->processStatus = OS_PROCESS_STATUS_INIT;//进程初始状态
+ processCB->processMode = mode; //用户态进程还是内核态进程
+ processCB->processStatus = OS_PROCESS_STATUS_INIT; //进程初始状态
processCB->parentProcess = NULL;
processCB->threadGroup = NULL;
- processCB->umask = OS_PROCESS_DEFAULT_UMASK;//掩码
+ processCB->umask = OS_PROCESS_DEFAULT_UMASK; //掩码
processCB->timerID = (timer_t)(UINTPTR)MAX_INVALID_TIMER_VID;
LOS_ListInit(&processCB->threadSiblingList);//初始化孩子任务/线程链表,上面挂的都是由此fork的孩子线程 见于 OsTaskCBInit LOS_ListTailInsert(&(processCB->threadSiblingList), &(taskCB->threadList));
- LOS_ListInit(&processCB->childrenList);//初始化孩子进程链表,上面挂的都是由此fork的孩子进程 见于 OsCopyParent LOS_ListTailInsert(&parentProcessCB->childrenList, &childProcessCB->siblingList);
- LOS_ListInit(&processCB->exitChildList);//初始化记录退出孩子进程链表,上面挂的是哪些exit 见于 OsProcessNaturalExit LOS_ListTailInsert(&parentCB->exitChildList, &processCB->siblingList);
- LOS_ListInit(&(processCB->waitList));//初始化等待任务链表 上面挂的是处于等待的 见于 OsWaitInsertWaitLIstInOrder LOS_ListHeadInsert(&processCB->waitList, &runTask->pendList);
+ LOS_ListInit(&processCB->childrenList); //初始化孩子进程链表,上面挂的都是由此fork的孩子进程 见于 OsCopyParent LOS_ListTailInsert(&parentProcessCB->childrenList, &childProcessCB->siblingList);
+ LOS_ListInit(&processCB->exitChildList); //初始化记录退出孩子进程链表,上面挂的是哪些exit 见于 OsProcessNaturalExit LOS_ListTailInsert(&parentCB->exitChildList, &processCB->siblingList);
+ LOS_ListInit(&(processCB->waitList)); //初始化等待任务链表 上面挂的是处于等待的 见于 OsWaitInsertWaitLIstInOrder LOS_ListHeadInsert(&processCB->waitList, &runTask->pendList);
-#ifdef LOSCFG_KERNEL_VM
+#ifdef LOSCFG_KERNEL_VM
if (OsProcessIsUserMode(processCB)) {//如果是用户态进程
processCB->vmSpace = OsCreateUserVmSpace();//创建用户空间
if (processCB->vmSpace == NULL) {
@@ -788,14 +818,12 @@ STATIC UINT32 OsInitPCB(LosProcessCB *processCB, UINT32 mode, const CHAR *name)
}
(VOID)memset_s(processCB->processCpup, sizeof(OsCpupBase), 0, sizeof(OsCpupBase));
#endif
-
#ifdef LOSCFG_SECURITY_VID
status_t status = VidMapListInit(processCB);
if (status != LOS_OK) {
return LOS_ENOMEM;
}
#endif
-
#ifdef LOSCFG_SECURITY_CAPABILITY
OsInitCapability(processCB);//初始化进程安全相关功能
#endif
@@ -809,7 +837,7 @@ STATIC UINT32 OsInitPCB(LosProcessCB *processCB, UINT32 mode, const CHAR *name)
//创建用户
#ifdef LOSCFG_SECURITY_CAPABILITY
STATIC User *OsCreateUser(UINT32 userID, UINT32 gid, UINT32 size)//参数size 表示组数量
-{//(size - 1) * sizeof(UINT32) 用于 user->groups[..],这种设计节约了内存,不造成不需要的浪费
+{ //(size - 1) * sizeof(UINT32) 用于 user->groups[..],这种设计节约了内存,不造成不需要的浪费
User *user = LOS_MemAlloc(m_aucSysMem1, sizeof(User) + (size - 1) * sizeof(UINT32));
if (user == NULL) {
return NULL;
@@ -820,7 +848,7 @@ STATIC User *OsCreateUser(UINT32 userID, UINT32 gid, UINT32 size)//参数size
user->gid = gid;
user->effGid = gid;
user->groupNumber = size;//用户组数量
- user->groups[0] = gid;//用户组列表,一个用户可以属于多个用户组
+ user->groups[0] = gid; //用户组列表,一个用户可以属于多个用户组
return user;
}
@@ -908,8 +936,8 @@ STATIC UINT32 OsSystemProcessInit(LosProcessCB *processCB, UINT32 flags, const C
goto EXIT;
}
-#ifdef LOSCFG_SECURITY_CAPABILITY //用户安全宏
- processCB->user = OsCreateUser(0, 0, 1); //创建用户
+#ifdef LOSCFG_SECURITY_CAPABILITY //用户安全宏
+ processCB->user = OsCreateUser(0, 0, 1);//创建用户
if (processCB->user == NULL) {
ret = LOS_ENOMEM;
goto EXIT;
@@ -917,7 +945,7 @@ STATIC UINT32 OsSystemProcessInit(LosProcessCB *processCB, UINT32 flags, const C
#endif
#ifdef LOSCFG_KERNEL_PLIMITS
- ret = OsPLimitsAddProcess(NULL, processCB);//删除进程控制块,归还内存
+ ret = OsPLimitsAddProcess(NULL, processCB);
if (ret != LOS_OK) {
ret = LOS_ENOMEM;
goto EXIT;
@@ -926,7 +954,7 @@ STATIC UINT32 OsSystemProcessInit(LosProcessCB *processCB, UINT32 flags, const C
return LOS_OK;
EXIT:
- OsDeInitPCB(processCB);
+ OsDeInitPCB(processCB);//删除进程控制块,归还内存
return ret;
}
/*! 创建2,0号进程,即内核态进程的老祖宗*/
@@ -962,7 +990,7 @@ LITE_OS_SEC_TEXT_INIT UINT32 OsSystemProcessCreate(VOID)
}
return LOS_OK;
}
-// 进程调度参数检查
+/// 进程调度参数检查
INT32 OsSchedulerParamCheck(UINT16 policy, BOOL isThread, const LosSchedParam *param)
{
if (param == NULL) {
@@ -1006,7 +1034,7 @@ STATIC INLINE INT32 ProcessSchedulerParamCheck(INT32 which, INT32 pid, UINT16 po
return OsSchedulerParamCheck(policy, FALSE, param);
}
-#ifdef LOSCFG_SECURITY_CAPABILITY//检查进程的安全许可证
+#ifdef LOSCFG_SECURITY_CAPABILITY //检查进程的安全许可证
STATIC BOOL OsProcessCapPermitCheck(const LosProcessCB *processCB, const SchedParam *param, UINT16 policy, UINT16 prio)
{
LosProcessCB *runProcess = OsCurrProcessGet();//获得当前进程
@@ -1028,7 +1056,7 @@ STATIC BOOL OsProcessCapPermitCheck(const LosProcessCB *processCB, const SchedPa
return FALSE;
}
#endif
-// 设置进程调度计划
+/// 设置进程调度计划
LITE_OS_SEC_TEXT INT32 OsSetProcessScheduler(INT32 which, INT32 pid, UINT16 policy, const LosSchedParam *schedParam)
{
SchedParam param = { 0 };
@@ -1090,12 +1118,12 @@ TO_SCHED:
}
return LOS_OK;
}
-// 设置指定进程的调度参数,包括优先级和调度策略
+/// 设置指定进程的调度参数,包括优先级和调度策略
LITE_OS_SEC_TEXT INT32 LOS_SetProcessScheduler(INT32 pid, UINT16 policy, const LosSchedParam *schedParam)
{
return OsSetProcessScheduler(LOS_PRIO_PROCESS, pid, policy, schedParam);
}
-// 获得指定进程的调度策略
+/// 获得指定进程的调度策略
LITE_OS_SEC_TEXT INT32 LOS_GetProcessScheduler(INT32 pid, INT32 *policy, LosSchedParam *schedParam)
{
UINT32 intSave;
@@ -1139,7 +1167,7 @@ LITE_OS_SEC_TEXT INT32 LOS_GetProcessScheduler(INT32 pid, INT32 *policy, LosSche
}
return LOS_OK;
}
-// 接口封装 - 设置进程优先级
+/// 接口封装 - 设置进程优先级
LITE_OS_SEC_TEXT INT32 LOS_SetProcessPriority(INT32 pid, INT32 prio)
{
INT32 ret;
@@ -1159,7 +1187,7 @@ LITE_OS_SEC_TEXT INT32 LOS_SetProcessPriority(INT32 pid, INT32 prio)
return OsSetProcessScheduler(LOS_PRIO_PROCESS, pid, (UINT16)policy, ¶m);
}
-// 接口封装 - 获取进程优先级 which:标识进程,进程组,用户
+/// 接口封装 - 获取进程优先级 which:标识进程,进程组,用户
LITE_OS_SEC_TEXT INT32 OsGetProcessPriority(INT32 which, INT32 pid)
{
UINT32 intSave;
@@ -1192,11 +1220,12 @@ LITE_OS_SEC_TEXT INT32 OsGetProcessPriority(INT32 which, INT32 pid)
SCHEDULER_UNLOCK(intSave);
return param.basePrio;
}
-// 接口封装 - 获取指定进程优先级
+/// 接口封装 - 获取指定进程优先级
LITE_OS_SEC_TEXT INT32 LOS_GetProcessPriority(INT32 pid)
{
return OsGetProcessPriority(LOS_PRIO_PROCESS, pid);
}
+
/*!
* 将任务挂入进程的waitList链表,表示这个任务在等待某个进程的退出
* 当被等待进程退出时候会将自己挂到父进程的退出子进程链表和进程组的退出进程链表.
@@ -1232,7 +1261,7 @@ STATIC VOID OsWaitInsertWaitListInOrder(LosTaskCB *runTask, LosProcessCB *proces
(VOID)runTask->ops->wait(runTask, list->pstNext, LOS_WAIT_FOREVER);
return;
}
-// 设置等待子进程退出方式方法
+/// 设置等待子进程退出方式方法
STATIC UINT32 WaitFindSpecifiedProcess(UINT32 pid, LosTaskCB *runTask,
const LosProcessCB *processCB, LosProcessCB **childCB)
{
@@ -1253,16 +1282,15 @@ STATIC UINT32 WaitFindSpecifiedProcess(UINT32 pid, LosTaskCB *runTask,
#endif
/* Wait for the child process whose process number is pid. */
*childCB = OsFindExitChildProcess(processCB, waitProcess);
- if (*childCB != NULL) {//找到了,确实有一个已经退出的PID,注意一个进程退出时会挂到父进程的exitChildList上
+ if (*childCB != NULL) {//找到了,确实有一个已经退出的PID,注意一个进程退出时会挂到父进程的exitChildList上
return LOS_OK;
- }
-
- if (OsFindChildProcess(processCB, waitProcess) != LOS_OK) {
- return LOS_ECHILD;
- }
+ }
- runTask->waitFlag = OS_PROCESS_WAIT_PRO;//设置当前任务的等待类型
- runTask->waitID = (UINTPTR)waitProcess;
+ if (OsFindChildProcess(processCB, waitProcess) != LOS_OK) {
+ return LOS_ECHILD;
+ }
+ runTask->waitFlag = OS_PROCESS_WAIT_PRO;//设置当前任务的等待类型
+ runTask->waitID = (UINTPTR)waitProcess;
return LOS_OK;
}
@@ -1294,9 +1322,9 @@ STATIC UINT32 OsWaitSetFlag(const LosProcessCB *processCB, INT32 pid, LosProcess
if (childCB != NULL) {//找到了,确实有一个已经退出的PID
goto WAIT_BACK;
}
- runTask->waitID = pid;
- runTask->waitFlag = OS_PROCESS_WAIT_ANY;
- } else { /* pid < -1 */
+ runTask->waitID = pid;//等待PID,这个PID可以和当前进程没有任何关系
+ runTask->waitFlag = OS_PROCESS_WAIT_ANY;//设置当前任务的等待类型
+ } else { /* pid < -1 */ //等待指定进程组内为|pid|的所有子进程
/* Wait for any child process whose group number is the pid absolute value. */
ProcessGroup *pgroup = OsFindProcessGroup(-pid);
if (pgroup == NULL) {
@@ -1316,7 +1344,7 @@ WAIT_BACK:
*child = childCB;
return LOS_OK;
}
-// 等待回收孩子进程
+/// 等待回收孩子进程 @note_thinking 这样写Porcess不太好吧
STATIC UINT32 OsWaitRecycleChildProcess(const LosProcessCB *childCB, UINT32 intSave, INT32 *status, siginfo_t *info)
{
ProcessGroup *pgroup = NULL;
@@ -1336,7 +1364,7 @@ STATIC UINT32 OsWaitRecycleChildProcess(const LosProcessCB *childCB, UINT32 intS
if (status != NULL) {
if (mode == OS_USER_MODE) {//孩子为用户态进程
- (VOID)LOS_ArchCopyToUser((VOID *)status, (const VOID *)(&(exitCode)), sizeof(INT32));
+ (VOID)LOS_ArchCopyToUser((VOID *)status, (const VOID *)(&(exitCode)), sizeof(INT32));//从内核空间拷贝退出码
} else {
*status = exitCode;
}
@@ -1371,9 +1399,9 @@ STATIC UINT32 OsWaitRecycleChildProcess(const LosProcessCB *childCB, UINT32 intS
(VOID)LOS_MemFree(m_aucSysMem1, pgroup);
return pid;
}
-// 检查要等待的孩子进程
+/// 检查要等待的孩子进程
STATIC UINT32 OsWaitChildProcessCheck(LosProcessCB *processCB, INT32 pid, LosProcessCB **childCB)
-{//当进程没有孩子且没有退出的孩子进程
+{ //当进程没有孩子且没有退出的孩子进程
if (LOS_ListEmpty(&(processCB->childrenList)) && LOS_ListEmpty(&(processCB->exitChildList))) {
return LOS_ECHILD;
}
@@ -1399,8 +1427,8 @@ STATIC UINT32 OsWaitOptionsCheck(UINT32 options)
}
return LOS_OK;
-}
-//等待子进程结束并回收子进程,返回已经终止的子进程的进程ID号,并清除僵死进程。
+}
+///等待子进程结束并回收子进程,返回已经终止的子进程的进程ID号,并清除僵死进程。
STATIC INT32 OsWait(INT32 pid, USER INT32 *status, USER siginfo_t *info, UINT32 options, VOID *rusage)
{
(VOID)rusage;
@@ -1429,28 +1457,28 @@ STATIC INT32 OsWait(INT32 pid, USER INT32 *status, USER siginfo_t *info, UINT32
#endif
return (INT32)OsWaitRecycleChildProcess(childCB, intSave, status, info);
}
- //没有找到,看是否要返回还是去做个登记
+ //没有找到,看是否要返回还是去做个登记
if ((options & LOS_WAIT_WNOHANG) != 0) {//有LOS_WAIT_WNOHANG标签
runTask->waitFlag = 0;//等待标识置0
pid = 0;//这里置0,是为了 return 0
goto ERROR;
}
- //等待孩子进程退出
- OsWaitInsertWaitListInOrder(runTask, processCB);
- //发起调度的目的是为了让出CPU,让其他进程/任务运行
-
+ //等待孩子进程退出
+ OsWaitInsertWaitListInOrder(runTask, processCB);//将当前任务挂入进程waitList链表
+ //发起调度的目的是为了让出CPU,让其他进程/任务运行
+
runTask->waitFlag = 0;
if (runTask->waitID == OS_INVALID_VALUE) {
pid = -LOS_ECHILD;//没有此子进程
goto ERROR;
}
- //回收僵死进程
+
childCB = (LosProcessCB *)runTask->waitID;
if (!OsProcessIsDead(childCB)) {
pid = -LOS_ESRCH;
goto ERROR;
}
-
+ //回收僵死进程
return (INT32)OsWaitRecycleChildProcess(childCB, intSave, status, info);
ERROR:
@@ -1536,7 +1564,7 @@ STATIC UINT32 OsSetProcessGroupCheck(const LosProcessCB *processCB, LosProcessCB
if (OsProcessIsInactive(processCB)) {//进程是否活动
return LOS_ESRCH;
}
- //参数进程不在用户态或者组长不在用户态
+ //参数进程不在用户态或者组长不在用户态
#ifdef LOSCFG_PID_CONTAINER
if ((processCB->processID == OS_USER_ROOT_PROCESS_ID) || OS_PROCESS_CONTAINER_CHECK(processCB, runProcessCB)) {
return LOS_EPERM;
@@ -1653,12 +1681,12 @@ EXIT:
SCHEDULER_UNLOCK(intSave);
return gid;
}
-// 获取当前进程的组ID
+/// 获取当前进程的组ID
LITE_OS_SEC_TEXT INT32 LOS_GetCurrProcessGroupID(VOID)
{
return LOS_GetProcessGroupID(OsCurrProcessGet()->processID);
}
-// 为用户态任务分配栈空间
+/// 为用户态任务分配栈空间
#ifdef LOSCFG_KERNEL_VM
STATIC LosProcessCB *OsGetFreePCB(VOID)
{
@@ -1683,7 +1711,7 @@ STATIC VOID *OsUserInitStackAlloc(LosProcessCB *processCB, UINT32 *size)
{
LosVmMapRegion *region = NULL;
UINT32 stackSize = ALIGN(OS_USER_TASK_STACK_SIZE, PAGE_SIZE);//1M栈空间 按页对齐
- //线性区分配虚拟内存
+ //线性区分配虚拟内存
region = LOS_RegionAlloc(processCB->vmSpace, 0, stackSize,
VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ |
VM_MAP_REGION_FLAG_PERM_WRITE, 0);//可使用可读可写区
@@ -1781,12 +1809,12 @@ LITE_OS_SEC_TEXT UINT32 OsExecRecycleAndInit(LosProcessCB *processCB, const CHAR
}
#endif
- processCB->processStatus &= ~OS_PROCESS_FLAG_EXIT;
- processCB->processStatus |= OS_PROCESS_FLAG_ALREADY_EXEC;
+ processCB->processStatus &= ~OS_PROCESS_FLAG_EXIT; //去掉进程退出标签
+ processCB->processStatus |= OS_PROCESS_FLAG_ALREADY_EXEC;//加上进程运行elf标签
return LOS_OK;
}
-// 执行用户态任务, entry为入口函数 ,其中 创建好task,task上下文 等待调度真正执行, sp:栈指针 mapBase:栈底 mapSize:栈大小
+/// 执行用户态任务, entry为入口函数 ,其中 创建好task,task上下文 等待调度真正执行, sp:栈指针 mapBase:栈底 mapSize:栈大小
LITE_OS_SEC_TEXT UINT32 OsExecStart(const TSK_ENTRY_FUNC entry, UINTPTR sp, UINTPTR mapBase, UINT32 mapSize)
{
UINT32 intSave;
@@ -1798,18 +1826,18 @@ LITE_OS_SEC_TEXT UINT32 OsExecStart(const TSK_ENTRY_FUNC entry, UINTPTR sp, UINT
if ((sp == 0) || (LOS_Align(sp, LOSCFG_STACK_POINT_ALIGN_SIZE) != sp)) {//对齐
return LOS_NOK;
}
- //注意 sp此时指向栈底,栈底地址要大于栈顶
+ //注意 sp此时指向栈底,栈底地址要大于栈顶
if ((mapBase == 0) || (mapSize == 0) || (sp <= mapBase) || (sp > (mapBase + mapSize))) {//参数检查
return LOS_NOK;
}
LosTaskCB *taskCB = OsCurrTaskGet();//获取当前任务
-
SCHEDULER_LOCK(intSave);//拿自旋锁
+
taskCB->userMapBase = mapBase;//用户态栈顶位置
taskCB->userMapSize = mapSize;//用户态栈
taskCB->taskEntry = (TSK_ENTRY_FUNC)entry;//任务的入口函数
- //初始化内核态栈
+ //初始化内核态栈
TaskContext *taskContext = (TaskContext *)OsTaskStackInit(taskCB->taskID, taskCB->stackSize,
(VOID *)taskCB->topOfStack, FALSE);
OsUserTaskStackInit(taskContext, (UINTPTR)taskCB->taskEntry, sp);//初始化用户栈,将内核栈中上下文的 context->R[0] = sp ,context->sp = sp
@@ -1818,7 +1846,7 @@ LITE_OS_SEC_TEXT UINT32 OsExecStart(const TSK_ENTRY_FUNC entry, UINTPTR sp, UINT
return LOS_OK;
}
#endif
-// 用户进程开始初始化
+/// 用户进程开始初始化
STATIC UINT32 OsUserInitProcessStart(LosProcessCB *processCB, TSK_INIT_PARAM_S *param)
{
UINT32 intSave;
@@ -1958,7 +1986,7 @@ ERROR:
OsDeInitPCB(processCB);
return ret;
}
-// 拷贝用户信息 直接用memcpy_s
+/// 拷贝用户信息 直接用memcpy_s
STATIC UINT32 OsCopyUser(LosProcessCB *childCB, LosProcessCB *parentCB)
{
#ifdef LOSCFG_SECURITY_CAPABILITY
@@ -1983,10 +2011,10 @@ STATIC VOID GetCopyTaskParam(LosProcessCB *childProcessCB, UINTPTR entry, UINT32
SCHEDULER_LOCK(intSave);
if (OsProcessIsUserMode(childProcessCB)) {//用户态进程
taskParam->pfnTaskEntry = runTask->taskEntry;//拷贝当前任务入口地址
- taskParam->uwStackSize = runTask->stackSize;//栈空间大小
- taskParam->userParam.userArea = runTask->userArea;//用户态栈区栈顶位置
- taskParam->userParam.userMapBase = runTask->userMapBase;//用户态栈底
- taskParam->userParam.userMapSize = runTask->userMapSize;//用户态栈大小
+ taskParam->uwStackSize = runTask->stackSize; //栈空间大小
+ taskParam->userParam.userArea = runTask->userArea; //用户态栈区栈顶位置
+ taskParam->userParam.userMapBase = runTask->userMapBase; //用户态栈底
+ taskParam->userParam.userMapSize = runTask->userMapSize; //用户态栈大小
} else {//注意内核态进程创建任务的入口由外界指定,例如 OsCreateIdleProcess 指定了OsIdleTask
taskParam->pfnTaskEntry = (TSK_ENTRY_FUNC)entry;//参数(sp)为内核态入口地址
taskParam->uwStackSize = size;//参数(size)为内核态栈大小
@@ -2028,7 +2056,7 @@ STATIC UINT32 OsCopyTask(UINT32 flags, LosProcessCB *childProcessCB, const CHAR
childTaskCB->taskStatus = runTask->taskStatus;//任务状态先同步,注意这里是赋值操作. ...01101001
childTaskCB->ops->schedParamModify(childTaskCB, ¶m);
if (childTaskCB->taskStatus & OS_TASK_STATUS_RUNNING) {//因只能有一个运行的task,所以如果一样要改4号位
- childTaskCB->taskStatus &= ~OS_TASK_STATUS_RUNNING;//将四号位清0 ,变成 ...01100001
+ childTaskCB->taskStatus &= ~OS_TASK_STATUS_RUNNING;//将四号位清0 ,变成 ...01100001
} else {//非运行状态下会发生什么?
if (OS_SCHEDULER_ACTIVE) {//克隆线程发生错误未运行
LOS_Panic("Clone thread status not running error status: 0x%x\n", childTaskCB->taskStatus);
@@ -2051,16 +2079,15 @@ STATIC UINT32 OsCopyParent(UINT32 flags, LosProcessCB *childProcessCB, LosProces
SCHEDULER_LOCK(intSave);
if (childProcessCB->parentProcess == NULL) {
- if (flags & CLONE_PARENT) { //这里指明 childProcessCB 和 runProcessCB 有同一个父亲,是兄弟关系
- parentProcessCB = runProcessCB->parentProcess;
- } else {
- parentProcessCB = runProcessCB;//指认父亲,这个赋值代表从此是你儿了
- }
- childProcessCB->parentProcess = parentProcessCB;
- LOS_ListTailInsert(&parentProcessCB->childrenList, &childProcessCB->siblingList);//通过我的兄弟姐妹节点,挂到父亲的孩子链表上,于我而言,父亲的这个链表上挂的都是我的兄弟姐妹
- //不会被排序,老大,老二,老三 老天爷指定了。
+ if (flags & CLONE_PARENT) { //这里指明 childProcessCB 和 runProcessCB 有同一个父亲,是兄弟关系
+ parentProcessCB = runProcessCB->parentProcess;
+ } else {
+ parentProcessCB = runProcessCB;
+ }
+ childProcessCB->parentProcess = parentProcessCB;//指认父亲,这个赋值代表从此是你儿了
+ LOS_ListTailInsert(&parentProcessCB->childrenList, &childProcessCB->siblingList);//通过我的兄弟姐妹节点,挂到父亲的孩子链表上,于我而言,父亲的这个链表上挂的都是我的兄弟姐妹
+ //不会被排序,老大,老二,老三 老天爷指定了。
}
-
if (childProcessCB->pgroup == NULL) {
childProcessCB->pgroup = parentProcessCB->pgroup;
LOS_ListTailInsert(&parentProcessCB->pgroup->processList, &childProcessCB->subordinateGroupList);
@@ -2086,13 +2113,13 @@ STATIC UINT32 OsCopyMM(UINT32 flags, LosProcessCB *childProcessCB, LosProcessCB
return LOS_OK;
}
- status = LOS_VmSpaceClone(flags, runProcessCB->vmSpace, childProcessCB->vmSpace);
+ status = LOS_VmSpaceClone(flags, runProcessCB->vmSpace, childProcessCB->vmSpace);//虚拟空间clone
if (status != LOS_OK) {
return LOS_ENOMEM;
}
return LOS_OK;
}
-// 拷贝进程文件描述符(proc_fd)信息
+/// 拷贝进程文件描述符(proc_fd)信息
STATIC UINT32 OsCopyFile(UINT32 flags, LosProcessCB *childProcessCB, LosProcessCB *runProcessCB)
{
#ifdef LOSCFG_FS_VFS
@@ -2163,7 +2190,7 @@ STATIC UINT32 OsChildSetProcessGroupAndSched(LosProcessCB *child, LosProcessCB *
(VOID)LOS_MemFree(m_aucSysMem1, pgroup);
return LOS_OK;
}
-// 拷贝进程资源
+/// 拷贝进程资源
STATIC UINT32 OsCopyProcessResources(UINT32 flags, LosProcessCB *child, LosProcessCB *run)
{
UINT32 ret;
@@ -2184,7 +2211,7 @@ STATIC UINT32 OsCopyProcessResources(UINT32 flags, LosProcessCB *child, LosProce
}
#ifdef LOSCFG_KERNEL_LITEIPC
- if (run->ipcInfo != NULL) {//重新初始化IPC池
+ if (run->ipcInfo != NULL) { //重新初始化IPC池
child->ipcInfo = LiteIpcPoolReInit((const ProcIpcInfo *)(run->ipcInfo));//@note_good 将沿用用户态空间地址(即线性区地址)
if (child->ipcInfo == NULL) {//因为整个进程虚拟空间都是拷贝的,ipc的用户态虚拟地址当然可以拷贝,但因进程不同了,所以需要重新申请ipc池和重新
return LOS_ENOMEM;//映射池中两个地址.
@@ -2195,9 +2222,10 @@ STATIC UINT32 OsCopyProcessResources(UINT32 flags, LosProcessCB *child, LosProce
#ifdef LOSCFG_SECURITY_CAPABILITY
OsCopyCapability(run, child);//拷贝安全能力
#endif
+
return LOS_OK;
}
-// 拷贝进程
+/// 拷贝进程
STATIC INT32 OsCopyProcess(UINT32 flags, const CHAR *name, UINTPTR sp, UINT32 size)
{
UINT32 ret, processID;
@@ -2219,7 +2247,6 @@ STATIC INT32 OsCopyProcess(UINT32 flags, const CHAR *name, UINTPTR sp, UINT32 si
if (ret != LOS_OK) {
goto ERROR_INIT;
}
-
#ifdef LOSCFG_KERNEL_PLIMITS
ret = OsPLimitsAddProcess(run->plimits, child);
if (ret != LOS_OK) {
@@ -2227,7 +2254,6 @@ STATIC INT32 OsCopyProcess(UINT32 flags, const CHAR *name, UINTPTR sp, UINT32 si
}
#endif
#endif
-
ret = OsForkInitPCB(flags, child, name, sp, size);//初始化进程控制块
if (ret != LOS_OK) {
goto ERROR_INIT;
@@ -2315,6 +2341,7 @@ LITE_OS_SEC_TEXT INT32 OsClone(UINT32 flags, UINTPTR sp, UINT32 size)
return OsCopyProcess(cloneFlag & flags, NULL, sp, size);
}
+//著名的 fork 函数 记得前往 https://gitee.com/weharmony/kernel_liteos_a_note fork一下 :)
LITE_OS_SEC_TEXT INT32 LOS_Fork(UINT32 flags, const CHAR *name, const TSK_ENTRY_FUNC entry, UINT32 stackSize)
{
UINT32 cloneFlag = CLONE_PARENT | CLONE_THREAD | CLONE_VFORK | CLONE_FILES;
@@ -2346,7 +2373,6 @@ LITE_OS_SEC_TEXT VOID LOS_Exit(INT32 status)
UINT32 intSave;
(void)status;
-
/* The exit of a kernel - state process must be kernel - state and all threads must actively exit */
LosProcessCB *processCB = OsCurrProcessGet();
SCHEDULER_LOCK(intSave);
@@ -2361,6 +2387,7 @@ LITE_OS_SEC_TEXT VOID LOS_Exit(INT32 status)
OsRunningTaskToExit(OsCurrTaskGet(), OS_PRO_EXIT_OK);
}
+
/*!
* @brief LOS_GetUsedPIDList
* 获取使用中的进程列表
@@ -2413,12 +2440,12 @@ LITE_OS_SEC_TEXT struct fd_table_s *LOS_GetFdTable(UINT32 pid)
return files->fdt;
}
#endif
-// 获取当前进程的进程ID
+/// 获取当前进程的进程ID
LITE_OS_SEC_TEXT UINT32 LOS_GetCurrProcessID(VOID)
{
return OsCurrProcessGet()->processID;
}
-// 按指定状态退出指定进程
+/// 按指定状态退出指定进程
#ifdef LOSCFG_KERNEL_VM
STATIC VOID ThreadGroupActiveTaskKilled(LosTaskCB *taskCB)
{
@@ -2491,12 +2518,12 @@ LITE_OS_SEC_TEXT VOID OsProcessThreadGroupDestroy(VOID)
#endif
return;
}
-// 获取系统支持的最大进程数目
+/// 获取系统支持的最大进程数目
LITE_OS_SEC_TEXT UINT32 LOS_GetSystemProcessMaximum(VOID)
{
return g_processMaxNum;
}
-// 获取用户态进程的根进程,所有用户进程都是g_processCBArray[g_userInitProcess] fork来的
+/// 获取用户态进程的根进程,所有用户进程都是g_processCBArray[g_userInitProcess] fork来的
LITE_OS_SEC_TEXT LosProcessCB *OsGetUserInitProcess(VOID)
{
return &g_processCBArray[OS_USER_ROOT_PROCESS_ID];
@@ -2506,7 +2533,7 @@ LITE_OS_SEC_TEXT LosProcessCB *OsGetKernelInitProcess(VOID)
{
return &g_processCBArray[OS_KERNEL_ROOT_PROCESS_ID];
}
-// 获取空闲进程,0号进程为空闲进程,该进程不干活,专给CPU休息的。
+/// 获取空闲进程,0号进程为空闲进程,该进程不干活,专给CPU休息的。
LITE_OS_SEC_TEXT LosProcessCB *OsGetIdleProcess(VOID)
{
return &g_processCBArray[OS_KERNEL_IDLE_PROCESS_ID];
diff --git a/src/kernel_liteos_a/kernel/base/core/los_smp.c b/src/kernel_liteos_a/kernel/base/core/los_smp.c
index 560e54fa..abab4853 100644
--- a/src/kernel_liteos_a/kernel/base/core/los_smp.c
+++ b/src/kernel_liteos_a/kernel/base/core/los_smp.c
@@ -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:
diff --git a/src/kernel_liteos_a/kernel/base/core/los_swtmr.c b/src/kernel_liteos_a/kernel/base/core/los_swtmr.c
index b648553c..2610e582 100644
--- a/src/kernel_liteos_a/kernel/base/core/los_swtmr.c
+++ b/src/kernel_liteos_a/kernel/base/core/los_swtmr.c
@@ -1,34 +1,9 @@
-/*
- * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
- * Copyright (c) 2020-2023 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:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this list of
- * conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice, this list
- * of conditions and the following disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 3. Neither the name of the copyright holder nor the names of its contributors may be used
- * to endorse or promote products derived from this software without specific prior written
- * permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-/*基本概念
+/*!
+* @file los_swtmr.c
+* @brief 软定时器主文件
+* @details
+* @attention @verbatim
+基本概念
软件定时器,是基于系统Tick时钟中断且由软件来模拟的定时器。当经过设定的Tick数后,会触发用户自定义的回调函数。
硬件定时器受硬件的限制,数量上不足以满足用户的实际需求。因此为了满足用户需求,提供更多的定时器,
软件定时器功能,支持如下特性:
@@ -83,7 +58,41 @@
系统可配置的软件定时器个数是指:整个系统可使用的软件定时器总个数,并非用户可使用的软件定时器个数。
例如:系统多占用一个软件定时器,那么用户能使用的软件定时器资源就会减少一个。
创建单次不自删除属性的定时器,用户需要自行调用定时器删除接口删除定时器,回收定时器资源,避免资源泄露。
- 软件定时器的定时精度与系统Tick时钟的周期有关。*/
+ 软件定时器的定时精度与系统Tick时钟的周期有关。
+ @endverbatim
+*/
+
+/*
+ * 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,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
#include "los_swtmr_pri.h"
#include "los_init.h"
#include "los_process_pri.h"
@@ -100,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);//初始化软件钟自旋锁,只有SMP情况才需要,只要是自旋锁都是由于CPU多核的同步
-#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 *///定时器任务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];
@@ -309,7 +317,11 @@ STATIC INLINE VOID ScanSwtmrTimeList(SwtmrRunqueue *srq)
LOS_SpinUnlockRestore(&swtmrSortLink->spinLock, intSave);
return;
}
-//软时钟的入口函数,拥有任务的最高优先级0级
+/**
+ * @brief 软时钟的入口函数,拥有任务的最高优先级 0 级!
+ *
+ * @return LITE_OS_SEC_TEXT
+ */
STATIC VOID SwtmrTask(VOID)
{
SwtmrHandlerItem swtmrHandle;
@@ -318,7 +330,7 @@ STATIC VOID SwtmrTask(VOID)
SwtmrRunqueue *srq = &g_swtmrRunqueue[ArchCurrCpuid()];
LOS_DL_LIST *head = &srq->swtmrHandlerQueue;
- for (;;) {//死循环获取队列item,一直读干净为止
+ for (;;) {//死循环获取队列item,一直读干净为止
waitTime = OsSortLinkGetNextExpireTime(OsGetCurrSchedTimeCycle(), &srq->swtmrSortLink);
if (waitTime != 0) {
SCHEDULER_LOCK(intSave);
@@ -334,13 +346,13 @@ 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都可以拥有自己的软时钟任务
+///创建软时钟任务,每个cpu core都可以拥有自己的软时钟任务
STATIC UINT32 SwtmrTaskCreate(UINT16 cpuid, UINT32 *swtmrTaskID)
{
UINT32 ret;
@@ -348,16 +360,16 @@ STATIC UINT32 SwtmrTaskCreate(UINT16 cpuid, UINT32 *swtmrTaskID)
(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.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;//16K默认内核任务栈
swtmrTask.pcName = "Swt_Task";//任务名称
- swtmrTask.usTaskPrio = 0;//
+ 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);//交给当前CPU执行这个任务
#endif
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;
@@ -375,7 +387,7 @@ 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++) {//一个进程往往会有多个定时器
@@ -384,7 +396,7 @@ LITE_OS_SEC_TEXT_INIT VOID OsSwtmrRecycle(UINTPTR ownerID)
}
}
}
-//软时钟初始化,注意函数在多CPU情况下会执行多次
+///软时钟初始化 ,注意函数在多CPU情况下会执行多次
STATIC UINT32 SwtmrBaseInit(VOID)
{
UINT32 ret;
@@ -396,13 +408,13 @@ STATIC UINT32 SwtmrBaseInit(VOID)
(VOID)memset_s(swtmr, size, 0, size);//清0
g_swtmrCBArray = swtmr;//软时钟
- LOS_ListInit(&g_swtmrFreeList);//初始化空间链表
+ 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);//通过sortLinkNode将节点挂到空闲链表
+ swtmr->usTimerID = index;//按顺序赋值
+ LOS_ListTailInsert(&g_swtmrFreeList, &swtmr->stSortList.sortLinkNode);//通过sortLinkNode将节点挂到空闲链表
}
- //想要用静态内存池管理,就必须要使用LOS_MEMBOX_SIZE来计算申请列表的内存大小,因为需要点前缀内存承载头部信息
- 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;
@@ -531,13 +543,13 @@ 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;//获取定时间隔
+ 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 period = (UINT64)ticks * OS_CYCLE_PER_TICK;
UINT64 responseTime = swtmr->startTime + period;
UINT64 currTime = OsGetCurrSchedTimeCycle();
if (responseTime < currTime) {
@@ -578,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);
}
@@ -697,7 +708,7 @@ LITE_OS_SEC_TEXT STATIC UINT32 OsSwtmrTimeGet(const SWTMR_CTRL_S *swtmr)
}
return (UINT32)time;
}
-//创建定时器,设置定时器的定时时长、定时模式、回调函数、并返回定时器ID
+///创建定时器,设置定时器的定时时长、定时器模式、回调函数,并返回定时器ID
LITE_OS_SEC_TEXT_INIT UINT32 LOS_SwtmrCreate(UINT32 interval,
UINT8 mode,
SWTMR_PROC_FUNC handler,
@@ -726,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->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
+///接口函数 启动定时器 参数定时任务ID
LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStart(UINT16 swtmrID)
{
SWTMR_CTRL_S *swtmr = NULL;
@@ -774,12 +785,12 @@ LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStart(UINT16 swtmrID)
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);//先停止定时器,注意这里没有break;在OsSwtmrStop中状态将会回到了OS_SWTMR_STATUS_CRWEATED接下来就是执行启动了
+ SwtmrStop(swtmr);//先停止定时器,注意这里没有break;,在OsSwtmrStop中状态将会回到了OS_SWTMR_STATUS_CREATED 接下来就是执行启动了
/* fall-through */
case OS_SWTMR_STATUS_CREATED://已经创建好了
SwtmrStart(swtmr);
@@ -793,7 +804,7 @@ LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStart(UINT16 swtmrID)
OsHookCall(LOS_HOOK_TYPE_SWTMR_START, swtmr);
return ret;
}
-//接口函数 停止计时器 参加定时任务ID
+///接口函数 停止定时器 参数定时任务ID
LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStop(UINT16 swtmrID)
{
SWTMR_CTRL_S *swtmr = NULL;
@@ -822,7 +833,7 @@ LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStop(UINT16 swtmrID)
ret = LOS_ERRNO_SWTMR_NOT_STARTED;//返回没有开始
break;
case OS_SWTMR_STATUS_TICKING://正在计数
- SwtmrStop(swtmr);//执行正在停止计时器操作
+ SwtmrStop(swtmr);//执行正在停止定时器操作
break;
default:
ret = LOS_ERRNO_SWTMR_STATUS_INVALID;
@@ -833,7 +844,7 @@ LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStop(UINT16 swtmrID)
OsHookCall(LOS_HOOK_TYPE_SWTMR_STOP, swtmr);
return ret;
}
-//接口函数 获得软件定时器剩余Tick数 通过 *tick 带走
+///接口函数 获得软件定时器剩余Tick数 通过 *tick 带走
LITE_OS_SEC_TEXT UINT32 LOS_SwtmrTimeGet(UINT16 swtmrID, UINT32 *tick)
{
SWTMR_CTRL_S *swtmr = NULL;
@@ -874,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;
@@ -899,7 +910,7 @@ 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://正在计数就先停止在删除,这里没有break
+ case OS_SWTMR_STATUS_TICKING://正在计数就先停止再删除,这里没有break;
SwtmrStop(swtmr);
/* fall-through */
case OS_SWTMR_STATUS_CREATED://再删除定时器
@@ -915,4 +926,5 @@ LITE_OS_SEC_TEXT UINT32 LOS_SwtmrDelete(UINT16 swtmrID)
return ret;
}
-#endif /* LOSCFG_BASE_CORE_SWTMR_ENABLE */
\ No newline at end of file
+#endif /* LOSCFG_BASE_CORE_SWTMR_ENABLE */
+
diff --git a/src/kernel_liteos_a/kernel/base/core/los_sys.c b/src/kernel_liteos_a/kernel/base/core/los_sys.c
index 8a9d373a..593dc25b 100644
--- a/src/kernel_liteos_a/kernel/base/core/los_sys.c
+++ b/src/kernel_liteos_a/kernel/base/core/los_sys.c
@@ -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
+ 系统最小的计时单位。Cycle的时长由系统主时钟频率决定,系统主时钟频率就是每秒钟的Cycle数。
+
+ Tick
+ Tick是操作系统的基本时间单位,由用户配置的每秒Tick数决定。
+
+ 使用场景
+ 用户需要了解当前系统运行的时间以及Tick与秒、毫秒之间的转换关系等。
+
+ 时间管理的典型开发流程
+ 根据实际需求,在板级配置适配时确认是否使能LOSCFG_BASE_CORE_TICK_HW_TIME宏选择外部定时器,
+ 并配置系统主时钟频率OS_SYS_CLOCK(单位Hz)。OS_SYS_CLOCK的默认值基于硬件平台配置。
+ 通过make menuconfig配置LOSCFG_BASE_CORE_TICK_PER_SECOND。
+
+ 参考
+ http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-basic-time.html
+ @endverbatim
+ * @attention
+ 获取系统Tick数需要在系统时钟使能之后。
+ 时间管理不是单独的功能模块,依赖于los_config.h中的OS_SYS_CLOCK和LOSCFG_BASE_CORE_TICK_PER_SECOND两个配置选项。
+ 系统的Tick数在关中断的情况下不进行计数,故系统Tick数不能作为准确时间计算。
+ */
#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 每个Tick多少Cycle数
+ *
+ * @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;
diff --git a/src/kernel_liteos_a/kernel/base/core/los_task.c b/src/kernel_liteos_a/kernel/base/core/los_task.c
index d0091651..7509eddd 100644
--- a/src/kernel_liteos_a/kernel/base/core/los_task.c
+++ b/src/kernel_liteos_a/kernel/base/core/los_task.c
@@ -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:
@@ -64,12 +64,11 @@
#ifdef LOSCFG_KERNEL_CONTAINER
#include "los_container_pri.h"
#endif
-
-#if (LOSCFG_BASE_CORE_TSK_LIMIT <= 0)
-#error "task maxnum cannot be zero"
-#endif /* LOSCFG_BASE_CORE_TSK_LIMIT <= 0 */
-/*
-基本概念
+/**
+ * @file los_task.c
+ * @brief
+ * @verbatim
+ 基本概念
从系统角度看,任务是竞争系统资源的最小运行单元。任务可以使用或等待CPU、
使用内存空间等系统资源,并独立于其它任务运行。
任务模块可以给用户提供多个任务,实现任务间的切换,帮助用户管理业务程序流程。具有如下特性:
@@ -138,12 +137,20 @@
运作机制
用户创建任务时,系统会初始化任务栈,预置上下文。此外,系统还会将“任务入口函数”
地址放在相应位置。这样在任务第一次启动进入运行态时,将会执行“任务入口函数”。
-*/
+ * @endverbatim
+ * @param pathname
+ * @return int
+ */
+
+#if (LOSCFG_BASE_CORE_TSK_LIMIT <= 0)
+#error "task maxnum cannot be zero"
+#endif /* LOSCFG_BASE_CORE_TSK_LIMIT <= 0 */
+
LITE_OS_SEC_BSS LosTaskCB *g_taskCBArray;//任务池 128个
LITE_OS_SEC_BSS LOS_DL_LIST g_losFreeTask;//空闲任务链表
LITE_OS_SEC_BSS LOS_DL_LIST g_taskRecycleList;//回收任务链表
LITE_OS_SEC_BSS UINT32 g_taskMaxNum;//任务最大个数
-LITE_OS_SEC_BSS UINT32 g_taskScheduled; /* one bit for each cores */
+LITE_OS_SEC_BSS UINT32 g_taskScheduled; /* one bit for each cores *///任务调度器,每个CPU都有对应位
LITE_OS_SEC_BSS EVENT_CB_S g_resourceEvent;//资源的事件
/* spinlock for task module, only available on SMP mode */
LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_taskSpin);
@@ -168,7 +175,7 @@ VOID OsSetMainTask(VOID)
schedParam.policy = LOS_SCHED_RR;
schedParam.basePrio = OS_PROCESS_PRIORITY_HIGHEST;
schedParam.priority = OS_TASK_PRIORITY_LOWEST;
- //为每个CPU core 设置mainTask
+ //为每个CPU core 设置mainTask
for (i = 0; i < LOSCFG_KERNEL_CORE_NUM; i++) {
g_mainTask[i].taskStatus = OS_TASK_STATUS_UNUSED;
g_mainTask[i].taskID = LOSCFG_BASE_CORE_TSK_LIMIT;//128
@@ -178,11 +185,10 @@ VOID OsSetMainTask(VOID)
g_mainTask[i].lockDep.waitLock = NULL;
#endif
(VOID)strncpy_s(g_mainTask[i].taskName, OS_TCB_NAME_LEN, name, OS_TCB_NAME_LEN - 1);
- LOS_ListInit(&g_mainTask[i].lockList);//初始化任务锁链表,上面挂的是任务已申请到的互斥锁
+ LOS_ListInit(&g_mainTask[i].lockList);//初始化任务锁链表,上面挂的是任务已申请到的互斥锁
(VOID)OsSchedParamInit(&g_mainTask[i], schedParam.policy, &schedParam, NULL);
}
}
-
VOID OsSetMainTaskProcess(UINTPTR processCB)
{
for (UINT32 i = 0; i < LOSCFG_KERNEL_CORE_NUM; i++) {
@@ -192,11 +198,11 @@ VOID OsSetMainTaskProcess(UINTPTR processCB)
#endif
}
}
-//空闲任务,每个CPU都有自己的空闲任务
+///空闲任务,每个CPU都有自己的空闲任务
LITE_OS_SEC_TEXT WEAK VOID OsIdleTask(VOID)
{
while (1) {//只有一个死循环
- WFI;//WFI指令:arm core立即进入low-power standly state,进入休眠模式,等待中断
+ WFI;//WFI指令:arm core 立即进入low-power standby state,进入休眠模式,等待中断。
}
}
@@ -204,14 +210,20 @@ VOID OsTaskInsertToRecycleList(LosTaskCB *taskCB)
{
LOS_ListTailInsert(&g_taskRecycleList, &taskCB->pendList);//将任务挂入回收链表,等待回收
}
-/*
-查找task通过OS_TCB_FROM_PENDLIST来实现,相当于由LOS_DL_LIST找到LosTaskCB,
-将这些和参数任务绑在一起的task唤醒
-*/
+
+/*!
+ * @brief OsTaskJoinPostUnsafe
+ * 查找task 通过 OS_TCB_FROM_PENDLIST 来完成,相当于由LOS_DL_LIST找到LosTaskCB,
+ * 将那些和参数任务绑在一起的task唤醒.
+ * @param taskCB
+ * @return
+ *
+ * @see
+ */
LITE_OS_SEC_TEXT_INIT VOID OsTaskJoinPostUnsafe(LosTaskCB *taskCB)
{
if (taskCB->taskStatus & OS_TASK_FLAG_PTHREAD_JOIN) {//join任务处理
- if (!LOS_ListEmpty(&taskCB->joinList)) {//joinList中的节点身上都有阻塞标签
+ if (!LOS_ListEmpty(&taskCB->joinList)) {//注意到了这里 joinList中的节点身上都有阻塞标签
LosTaskCB *resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(taskCB->joinList)));//通过贴有JOIN标签链表的第一个节点找到Task
OsTaskWakeClearPendMask(resumedTask);//清除任务的挂起标记
resumedTask->ops->wake(resumedTask);
@@ -219,7 +231,7 @@ LITE_OS_SEC_TEXT_INIT VOID OsTaskJoinPostUnsafe(LosTaskCB *taskCB)
}
taskCB->taskStatus |= OS_TASK_STATUS_EXIT;//贴上任务退出标签
}
-//挂起任务,任务进入等待链表,Join代表是支持通过的第一个任务去唤醒其他的任务
+/// 挂起任务,任务进入等待链表,Join代表是支持通过一个任务去唤醒其他的任务
LITE_OS_SEC_TEXT UINT32 OsTaskJoinPendUnsafe(LosTaskCB *taskCB)
{
if (taskCB->taskStatus & OS_TASK_STATUS_INIT) {
@@ -231,14 +243,14 @@ LITE_OS_SEC_TEXT UINT32 OsTaskJoinPendUnsafe(LosTaskCB *taskCB)
}
if ((taskCB->taskStatus & OS_TASK_FLAG_PTHREAD_JOIN) && LOS_ListEmpty(&taskCB->joinList)) {
- OsTaskWaitSetPendMask(OS_TASK_WAIT_JOIN, taskCB->taskID, LOS_WAIT_FOREVER);
+ OsTaskWaitSetPendMask(OS_TASK_WAIT_JOIN, taskCB->taskID, LOS_WAIT_FOREVER);//设置任务的等待标记
LosTaskCB *runTask = OsCurrTaskGet();
return runTask->ops->wait(runTask, &taskCB->joinList, LOS_WAIT_FOREVER);
}
return LOS_EINVAL;
}
-//任务设置分离模式Deatch和JOIN是一对有你没我的状态
+///任务设置分离模式 Deatch和JOIN是一对有你没我的状态
LITE_OS_SEC_TEXT UINT32 OsTaskSetDetachUnsafe(LosTaskCB *taskCB)
{
if (taskCB->taskStatus & OS_TASK_FLAG_PTHREAD_JOIN) {//join状态时
@@ -261,13 +273,13 @@ LITE_OS_SEC_TEXT_INIT UINT32 OsTaskInit(UINTPTR processCB)
UINT32 size;
UINT32 ret;
- g_taskMaxNum = LOSCFG_BASE_CORE_TSK_LIMIT;//任务池中最多默认128个,可谓铁打的任务池流水的线程
+ g_taskMaxNum = LOSCFG_BASE_CORE_TSK_LIMIT;//任务池中最多默认128个,可谓铁打的任务池流水的线程
size = (g_taskMaxNum + 1) * sizeof(LosTaskCB);//计算需分配内存总大小
/*
* This memory is resident memory and is used to save the system resources
* of task control block and will not be freed.
*/
- g_taskCBArray = (LosTaskCB *)LOS_MemAlloc(m_aucSysMem0, size);//任务池常驻内存,不被释放
+ g_taskCBArray = (LosTaskCB *)LOS_MemAlloc(m_aucSysMem0, size);//任务池常驻内存,不被释放
if (g_taskCBArray == NULL) {
ret = LOS_ERRNO_TSK_NO_MEMORY;
goto EXIT;
@@ -277,12 +289,11 @@ LITE_OS_SEC_TEXT_INIT UINT32 OsTaskInit(UINTPTR processCB)
LOS_ListInit(&g_losFreeTask);//初始化空闲任务链表
LOS_ListInit(&g_taskRecycleList);//初始化回收任务链表
for (index = 0; index < g_taskMaxNum; index++) {//任务挨个初始化
- g_taskCBArray[index].taskStatus = OS_TASK_STATUS_UNUSED;//默认未使用,
- g_taskCBArray[index].taskID = index;//任务ID[0~g_taskMaxNum-1]
+ g_taskCBArray[index].taskStatus = OS_TASK_STATUS_UNUSED;//默认未使用,干净.
+ g_taskCBArray[index].taskID = index;//任务ID [0 ~ g_taskMaxNum - 1]
g_taskCBArray[index].processCB = processCB;
- LOS_ListTailInsert(&g_losFreeTask, &g_taskCBArray[index].pendList);//通过pendlist节点插入空闲任务列表
- }//注意:这里挂的是pendList节点,可以取TCB也要通过OS_TCB_FROM-PENDLIST取
-
+ LOS_ListTailInsert(&g_losFreeTask, &g_taskCBArray[index].pendList);//通过pendList节点插入空闲任务列表
+ }//注意:这里挂的是pendList节点,所以取TCB也要通过 OS_TCB_FROM_PENDLIST 取.
g_taskCBArray[index].taskStatus = OS_TASK_STATUS_UNUSED;
g_taskCBArray[index].taskID = index;
g_taskCBArray[index].processCB = processCB;
@@ -295,41 +306,41 @@ EXIT:
}
return ret;
}
-//获取IdletaskId,每个CPU核都对Task进行了内部管理,做到真正的并行处理
+///获取IdletaskId,每个CPU核都对Task进行了内部管理,做到真正的并行处理
UINT32 OsGetIdleTaskId(VOID)
{
return OsSchedRunqueueIdleGet()->taskID;
}
-//创建一个空闲任务
+///创建一个空闲任务
LITE_OS_SEC_TEXT_INIT UINT32 OsIdleTaskCreate(UINTPTR processID)
{
UINT32 ret;
TSK_INIT_PARAM_S taskInitParam;
UINT32 idleTaskID;
- (VOID)memset_s((VOID *)(&taskInitParam), sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));//任务初始参数清零
+ (VOID)memset_s((VOID *)(&taskInitParam), sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));//任务初始参数清0
taskInitParam.pfnTaskEntry = (TSK_ENTRY_FUNC)OsIdleTask;//入口函数
taskInitParam.uwStackSize = LOSCFG_BASE_CORE_TSK_IDLE_STACK_SIZE;//任务栈大小 2K
- taskInitParam.pcName = "Idle";//任务名称叫pcNAME
+ taskInitParam.pcName = "Idle";//任务名称 叫pcName有点怪怪的,不能换个撒
taskInitParam.policy = LOS_SCHED_IDLE;
- taskInitParam.usTaskPrio = OS_TASK_PRIORITY_LOWEST;//默认最低优先级31
+ taskInitParam.usTaskPrio = OS_TASK_PRIORITY_LOWEST;//默认最低优先级 31
taskInitParam.processID = processID;
#ifdef LOSCFG_KERNEL_SMP
- taskInitParam.usCpuAffiMask = CPUID_TO_AFFI_MASK(ArchCurrCpuid());//每个idle任务只在单独的CPU上运行
+ taskInitParam.usCpuAffiMask = CPUID_TO_AFFI_MASK(ArchCurrCpuid());//每个idle任务只在单独的cpu上运行
#endif
ret = LOS_TaskCreateOnly(&idleTaskID, &taskInitParam);
if (ret != LOS_OK) {
return ret;
}
LosTaskCB *idleTask = OS_TCB_FROM_TID(idleTaskID);
- idleTask->taskStatus |= OS_TASK_FLAG_SYSTEM_TASK;//标记为系统任务,idle任务是给CPU休息用的,当然是个系统任务
+ idleTask->taskStatus |= OS_TASK_FLAG_SYSTEM_TASK; //标记为系统任务,idle任务是给CPU休息用的,当然是个系统任务
OsSchedRunqueueIdleInit(idleTask);
return LOS_TaskResume(idleTaskID);
}
/*
- * Description : get id of current running task. |获取当前CPU正在执行的任务ID
+ * Description : get id of current running task. | 获取当前CPU正在执行的任务ID
* Return : task id
*/
LITE_OS_SEC_TEXT UINT32 LOS_CurTaskIDGet(VOID)
@@ -341,7 +352,7 @@ LITE_OS_SEC_TEXT UINT32 LOS_CurTaskIDGet(VOID)
}
return runTask->taskID;
}
-//创建指定任务同步信号量
+/// 创建指定任务同步信号量
STATIC INLINE UINT32 TaskSyncCreate(LosTaskCB *taskCB)
{
#ifdef LOSCFG_KERNEL_SMP_TASK_SYNC
@@ -354,7 +365,7 @@ STATIC INLINE UINT32 TaskSyncCreate(LosTaskCB *taskCB)
#endif
return LOS_OK;
}
-//销毁指定任务同步信号量
+/// 销毁指定任务同步信号量
STATIC INLINE VOID OsTaskSyncDestroy(UINT32 syncSignal)
{
#ifdef LOSCFG_KERNEL_SMP_TASK_SYNC
@@ -365,7 +376,14 @@ STATIC INLINE VOID OsTaskSyncDestroy(UINT32 syncSignal)
}
#ifdef LOSCFG_KERNEL_SMP
-//任务同步等待,通过信号量保持同步
+/*!
+ * @brief OsTaskSyncWait
+ * 任务同步等待,通过信号量保持同步
+ * @param taskCB
+ * @return
+ *
+ * @see
+ */
STATIC INLINE UINT32 OsTaskSyncWait(const LosTaskCB *taskCB)
{
#ifdef LOSCFG_KERNEL_SMP_TASK_SYNC
@@ -376,9 +394,9 @@ STATIC INLINE UINT32 OsTaskSyncWait(const LosTaskCB *taskCB)
/*
* gc soft timer works every OS_MP_GC_PERIOD period, to prevent this timer
* triggered right at the timeout has reached, we set the timeout as double
- * of the gc period.
+ * of the gc peroid.
*/
- if (LOS_SemPend(taskCB->syncSignal, OS_MP_GC_PERIOD * 2) != LOS_OK) { /* 2: Wait 200 ms */
+ if (LOS_SemPend(taskCB->syncSignal, OS_MP_GC_PERIOD * 2) != LOS_OK) {
ret = LOS_ERRNO_TSK_MP_SYNC_FAILED;
}
@@ -391,7 +409,7 @@ STATIC INLINE UINT32 OsTaskSyncWait(const LosTaskCB *taskCB)
#endif
}
#endif
-//同步唤醒
+/// 同步唤醒
STATIC INLINE VOID OsTaskSyncWake(const LosTaskCB *taskCB)
{
#ifdef LOSCFG_KERNEL_SMP_TASK_SYNC
@@ -413,7 +431,7 @@ STATIC INLINE VOID OsInsertTCBToFreeList(LosTaskCB *taskCB)
taskCB->taskStatus = OS_TASK_STATUS_UNUSED;
LOS_ListAdd(&g_losFreeTask, &taskCB->pendList);
}
-//释放任务在内核状态下占用的资源
+//释放任务在内核态下占用的资源
STATIC VOID OsTaskKernelResourcesToFree(UINT32 syncSignal, UINTPTR topOfStack)
{
OsTaskSyncDestroy(syncSignal);//任务销毁,同步信息
@@ -445,19 +463,19 @@ STATIC VOID OsTaskResourcesToFree(LosTaskCB *taskCB)
}
#ifdef LOSCFG_KERNEL_LITEIPC
- LiteIpcRemoveServiceHandle(taskCB->taskID);
+ LiteIpcRemoveServiceHandle(taskCB->taskID);//详见百篇博客之IPC篇
#endif
}
#endif
- if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) {//任务还未使用情况
+ if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) {//任务还没有使用情况
topOfStack = taskCB->topOfStack;
taskCB->topOfStack = 0;
#ifdef LOSCFG_KERNEL_SMP_TASK_SYNC
syncSignal = taskCB->syncSignal;
taskCB->syncSignal = LOSCFG_BASE_IPC_SEM_LIMIT;
#endif
- OsTaskKernelResourcesToFree(syncSignal, topOfStack);//释放内核所占内存,即内核栈的栈空间
+ OsTaskKernelResourcesToFree(syncSignal, topOfStack);//释放内核态所占内存,即内核态的栈空间
SCHEDULER_LOCK(intSave);
#ifdef LOSCFG_KERNEL_VM
@@ -489,7 +507,7 @@ LITE_OS_SEC_TEXT VOID OsTaskCBRecycleToFree(void)
/*
* Description : All task entry
* Input : taskID --- The ID of the task to be run
- *///所有任务的入口函数,OsTaskEntry是new task OsTaskStackInit时指定的
+ *///所有任务的入口函数,OsTaskEntry是在new task OsTaskStackInit 时指定的
LITE_OS_SEC_TEXT_INIT VOID OsTaskEntry(UINT32 taskID)
{
LOS_ASSERT(!OS_TID_CHECK_INVALID(taskID));
@@ -503,15 +521,15 @@ LITE_OS_SEC_TEXT_INIT VOID OsTaskEntry(UINT32 taskID)
(VOID)LOS_IntUnLock();//恢复中断
LosTaskCB *taskCB = OS_TCB_FROM_TID(taskID);
- taskCB->joinRetval = taskCB->taskEntry(taskCB->args[0], taskCB->args[1],//调出任务的入口函数
+ taskCB->joinRetval = taskCB->taskEntry(taskCB->args[0], taskCB->args[1],//调用任务的入口函数
taskCB->args[2], taskCB->args[3]); /* 2 & 3: just for args array index */
if (!(taskCB->taskStatus & OS_TASK_FLAG_PTHREAD_JOIN)) {
taskCB->joinRetval = 0;//结合数为0
}
-
+
OsRunningTaskToExit(taskCB, 0);
}
-//任务创建参数检查
+///任务创建参数检查
STATIC UINT32 TaskCreateParamCheck(const UINT32 *taskID, TSK_INIT_PARAM_S *initParam)
{
UINT32 poolSize = OS_SYS_MEM_SIZE;
@@ -542,7 +560,7 @@ STATIC UINT32 TaskCreateParamCheck(const UINT32 *taskID, TSK_INIT_PARAM_S *initP
return LOS_ERRNO_TSK_STKSZ_TOO_LARGE;
}
- if (initParam->uwStackSize == 0) {//任何任务都必须由内核态栈,所以uwStackSize不能为0
+ if (initParam->uwStackSize == 0) {//任何任务都必须由内核态栈,所以uwStackSize不能为0
initParam->uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
}
initParam->uwStackSize = (UINT32)ALIGN(initParam->uwStackSize, LOSCFG_STACK_POINT_ALIGN_SIZE);
@@ -553,7 +571,7 @@ STATIC UINT32 TaskCreateParamCheck(const UINT32 *taskID, TSK_INIT_PARAM_S *initP
return LOS_OK;
}
-//任务栈(内核态)内存分配,由内核态进程空间提供,即KProcess进程空间
+///任务栈(内核态)内存分配,由内核态进程空间提供,即 KProcess 的进程空间
STATIC VOID TaskCBDeInit(LosTaskCB *taskCB)
{
UINT32 intSave;
@@ -612,7 +630,7 @@ STATIC VOID TaskCBBaseInit(LosTaskCB *taskCB, const TSK_INIT_PARAM_S *initParam)
taskCB->futex.index = OS_INVALID_VALUE;
#endif
}
-//任务初始化
+///任务初始化
STATIC UINT32 TaskCBInit(LosTaskCB *taskCB, const TSK_INIT_PARAM_S *initParam)
{
UINT32 ret;
@@ -621,7 +639,8 @@ STATIC UINT32 TaskCBInit(LosTaskCB *taskCB, const TSK_INIT_PARAM_S *initParam)
LosSchedParam initSchedParam = {0};
UINT16 policy = (initParam->policy == LOS_SCHED_NORMAL) ? LOS_SCHED_RR : initParam->policy;
- TaskCBBaseInit(taskCB, initParam);//初始化任务的基本信息,task->stackPointer指向内核态栈sp位置,该位置存着任务初始上下文
+ TaskCBBaseInit(taskCB, initParam);//初始化任务的基本信息,
+ //taskCB->stackPointer指向内核态栈 sp位置,该位置存着 任务初始上下文
schedParam.policy = policy;
ret = OsProcessAddNewTask(initParam->processID, taskCB, &schedParam, &numCount);
@@ -673,7 +692,7 @@ STATIC UINT32 TaskStackInit(LosTaskCB *taskCB, const TSK_INIT_PARAM_S *initParam
#endif
return LOS_OK;
}
-//获取一个空闲TCB
+///获取一个空闲TCB
STATIC LosTaskCB *GetFreeTaskCB(VOID)
{
UINT32 intSave;
@@ -691,9 +710,16 @@ STATIC LosTaskCB *GetFreeTaskCB(VOID)
return taskCB;
}
-/*
-创建任务,并使该任务进入suspend状态,不对该状态进行调度。如果需要调度,可以调用LOS_TaskResume使该任务进入ready状态
-*/
+
+/*!
+ * @brief LOS_TaskCreateOnly
+ * 创建任务,并使该任务进入suspend状态,不对该任务进行调度。如果需要调度,可以调用LOS_TaskResume使该任务进入ready状态
+ * @param initParam
+ * @param taskID
+ * @return
+ *
+ * @see
+ */
LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreateOnly(UINT32 *taskID, TSK_INIT_PARAM_S *initParam)
{
UINT32 errRet = TaskCreateParamCheck(taskID, initParam);
@@ -733,7 +759,7 @@ DEINIT_TCB:
TaskCBDeInit(taskCB);
return errRet;
}
-//创建任务,并使该任务进入ready状态,如果就绪队列中没有更高优先级的任务,则运行该任务
+///创建任务,并使该任务进入ready状态,如果就绪队列中没有更高优先级的任务,则运行该任务
LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreate(UINT32 *taskID, TSK_INIT_PARAM_S *initParam)
{
UINT32 ret;
@@ -747,7 +773,7 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreate(UINT32 *taskID, TSK_INIT_PARAM_S *in
return LOS_ERRNO_TSK_YIELD_IN_INT;
}
- if (OsProcessIsUserMode(OsCurrProcessGet())) {//当前进程为用户进程
+ if (OsProcessIsUserMode(OsCurrProcessGet())) { //当前进程为用户进程
initParam->processID = (UINTPTR)OsGetKernelInitProcess();
} else {
initParam->processID = (UINTPTR)OsCurrProcessGet();
@@ -773,7 +799,7 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreate(UINT32 *taskID, TSK_INIT_PARAM_S *in
return LOS_OK;
}
-//恢复挂起的任务,是该任务进入ready状态
+///恢复挂起的任务,使该任务进入ready状态
LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskResume(UINT32 taskID)
{
UINT32 intSave;
@@ -814,13 +840,13 @@ LOS_ERREND:
}
/*
- * Check if needs to do the suspend operation on the running task.//检查是否需要对正在运行的任务执行挂起操作。
- * Return TRUE, if needs to do the suspension. //如果需要暂停,返回TRUE。
- * Return FALSE, if meets following circumstances: //如果满足一下情况,则返回FALSE:
- * 1. Do the suspension across cores, if SMP is enabled //1.如果启用了SMP,则跨CPU核执行挂起操作
- * 2. Do the suspension when preemption is disabled //2.当禁用抢占时则挂起
- * 3. Do the suspension in hard-irq //3.在硬中断时则挂起
- * then LOS_TaskSuspend will directly return with 'ret' value. //那么LOS_taskssuspend将直接返回ret值。
+ * Check if needs to do the suspend operation on the running task. //检查是否需要对正在运行的任务执行挂起操作。
+ * Return TRUE, if needs to do the suspension. //如果需要暂停,返回TRUE。
+ * Rerturn FALSE, if meets following circumstances: //如果满足以下情况,则返回FALSE:
+ * 1. Do the suspension across cores, if SMP is enabled //1.如果启用了SMP,则跨CPU核执行挂起操作
+ * 2. Do the suspension when preemption is disabled //2.当禁用抢占时则挂起
+ * 3. Do the suspension in hard-irq //3.在硬中断时则挂起
+ * then LOS_TaskSuspend will directly return with 'ret' value. //那么LOS_taskssuspend将直接返回ret值。
*/
LITE_OS_SEC_TEXT_INIT STATIC BOOL OsTaskSuspendCheckOnRun(LosTaskCB *taskCB, UINT32 *ret)
{
@@ -842,7 +868,7 @@ LITE_OS_SEC_TEXT_INIT STATIC BOOL OsTaskSuspendCheckOnRun(LosTaskCB *taskCB, UIN
return FALSE;
}
- if (OS_INT_ACTIVE) {//正在硬抢断时
+ if (OS_INT_ACTIVE) {//正在硬中断中
/* suspend running task in interrupt */
taskCB->signal = SIGNAL_SUSPEND;
return FALSE;
@@ -850,7 +876,7 @@ LITE_OS_SEC_TEXT_INIT STATIC BOOL OsTaskSuspendCheckOnRun(LosTaskCB *taskCB, UIN
return TRUE;
}
-//任务暂停,参数可以不是当前任务,也就是说A任务可以让B任务处于阻塞状态,挂起指定的任务,然后切换任务
+///任务暂停,参数可以不是当前任务,也就是说 A任务可以让B任务处于阻塞状态,挂起指定的任务,然后切换任务
LITE_OS_SEC_TEXT STATIC UINT32 OsTaskSuspend(LosTaskCB *taskCB)
{
UINT32 errRet;
@@ -863,14 +889,14 @@ LITE_OS_SEC_TEXT STATIC UINT32 OsTaskSuspend(LosTaskCB *taskCB)
return LOS_ERRNO_TSK_ALREADY_SUSPENDED;
}
- if ((tempStatus & OS_TASK_STATUS_RUNNING) &&//如果参数任务正在运行,注意多Cpu core情况,贴着正在运行标签的任务并不一定是当前CPU的执行任务,
+ if ((tempStatus & OS_TASK_STATUS_RUNNING) && //如果参数任务正在运行,注意多Cpu core情况下,贴着正在运行标签的任务并不一定是当前CPU的执行任务,
!OsTaskSuspendCheckOnRun(taskCB, &errRet)) {//很有可能是别的CPU core在跑的任务
return errRet;
}
return taskCB->ops->suspend(taskCB);
}
-//外部接口,对OsTaskSuspend的封装
+///外部接口,对OsTaskSuspend的封装
LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskSuspend(UINT32 taskID)
{
UINT32 intSave;
@@ -890,7 +916,7 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskSuspend(UINT32 taskID)
SCHEDULER_UNLOCK(intSave);
return errRet;
}
-//设置任务为不使用状态
+///设置任务为不使用状态
STATIC INLINE VOID OsTaskStatusUnusedSet(LosTaskCB *taskCB)
{
taskCB->taskStatus |= OS_TASK_STATUS_UNUSED;
@@ -1002,7 +1028,6 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskDelete(UINT32 taskID)
if (!OsPreemptable()) {
return LOS_ERRNO_TSK_DELETE_LOCKED;
}
-
OsRunningTaskToExit(taskCB, OS_PRO_EXIT_OK);
return LOS_NOK;
}
@@ -1036,7 +1061,7 @@ LOS_ERREND:
}
return ret;
}
-//任务延时等待,释放CPU,等待时间到期后该任务会重新进入ready状态
+///任务延时等待,释放CPU,等待时间到期后该任务会重新进入ready状态
LITE_OS_SEC_TEXT UINT32 LOS_TaskDelay(UINT32 tick)
{
UINT32 intSave;
@@ -1066,7 +1091,7 @@ LITE_OS_SEC_TEXT UINT32 LOS_TaskDelay(UINT32 tick)
SCHEDULER_UNLOCK(intSave);
return ret;
}
-//获取任务的优先级
+///获取任务的优先级
LITE_OS_SEC_TEXT_MINOR UINT16 LOS_TaskPriGet(UINT32 taskID)
{
UINT32 intSave;
@@ -1078,7 +1103,7 @@ LITE_OS_SEC_TEXT_MINOR UINT16 LOS_TaskPriGet(UINT32 taskID)
LosTaskCB *taskCB = OS_TCB_FROM_TID(taskID);
SCHEDULER_LOCK(intSave);
- if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) {
+ if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) {//就这么一句话也要来个自旋锁,内核代码自旋锁真是无处不在啊
SCHEDULER_UNLOCK(intSave);
return (UINT16)OS_INVALID;
}
@@ -1087,7 +1112,7 @@ LITE_OS_SEC_TEXT_MINOR UINT16 LOS_TaskPriGet(UINT32 taskID)
SCHEDULER_UNLOCK(intSave);
return param.priority;
}
-//设置指定任务的优先级
+///设置指定任务的优先级
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_TaskPriSet(UINT32 taskID, UINT16 taskPrio)
{
UINT32 intSave;
@@ -1125,12 +1150,13 @@ LITE_OS_SEC_TEXT_MINOR UINT32 LOS_TaskPriSet(UINT32 taskID, UINT16 taskPrio)
}
return LOS_OK;
}
-//设置当前任务的优先级
+///设置当前任务的优先级
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_CurTaskPriSet(UINT16 taskPrio)
{
return LOS_TaskPriSet(OsCurrTaskGet()->taskID, taskPrio);
}
-//当前任务释放CPU,并将其移到具有相同优先级的就绪任务队列的末尾。
+
+//当前任务释放CPU,并将其移到具有相同优先级的就绪任务队列的末尾. 读懂这个函数 你就彻底搞懂了 yield
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_TaskYield(VOID)
{
UINT32 intSave;
@@ -1176,7 +1202,7 @@ LITE_OS_SEC_TEXT_MINOR VOID LOS_TaskUnlock(VOID)
LOS_Schedule();
}
}
-//获取任务信息,给shell使用的
+//获取任务信息,给shell使用的
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_TaskInfoGet(UINT32 taskID, TSK_INFO_S *taskInfo)
{
UINT32 intSave;
@@ -1206,7 +1232,7 @@ LITE_OS_SEC_TEXT_MINOR UINT32 LOS_TaskInfoGet(UINT32 taskID, TSK_INFO_S *taskInf
taskCB->ops->schedParamGet(taskCB, ¶m);
taskInfo->usTaskStatus = taskCB->taskStatus;
taskInfo->usTaskPrio = param.priority;
- taskInfo->uwStackSize = taskCB->stackSize;//内核态栈大小
+ taskInfo->uwStackSize = taskCB->stackSize; //内核态栈大小
taskInfo->uwTopOfStack = taskCB->topOfStack;//内核态栈顶位置
taskInfo->uwEventMask = taskCB->eventMask;
taskInfo->taskEvent = taskCB->taskEvent;
@@ -1218,7 +1244,7 @@ LITE_OS_SEC_TEXT_MINOR UINT32 LOS_TaskInfoGet(UINT32 taskID, TSK_INFO_S *taskInf
}
taskInfo->acName[LOS_TASK_NAMELEN - 1] = '\0';
- taskInfo->uwBottomOfStack = TRUNCATE(((UINTPTR)taskCB->topOfStack + taskCB->stackSize),//这里可以看出栈顶地址是高于栈顶
+ taskInfo->uwBottomOfStack = TRUNCATE(((UINTPTR)taskCB->topOfStack + taskCB->stackSize),//这里可以看出栈底地址是高于栈顶
OS_TASK_STACK_ADDR_ALIGN);
taskInfo->uwCurrUsed = (UINT32)(taskInfo->uwBottomOfStack - taskInfo->uwSP);//当前任务栈已使用了多少
@@ -1227,7 +1253,7 @@ LITE_OS_SEC_TEXT_MINOR UINT32 LOS_TaskInfoGet(UINT32 taskID, TSK_INFO_S *taskInf
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
}
-//CPU亲和性(affinity)将任务绑定在指定CPU上,用于多核CPU情况,(该函数仅在SMP模式下支持)
+///CPU亲和性(affinity)将任务绑在指定CPU上,用于多核CPU情况,(该函数仅在SMP模式下支持)
LITE_OS_SEC_TEXT BOOL OsTaskCpuAffiSetUnsafe(UINT32 taskID, UINT16 newCpuAffiMask, UINT16 *oldCpuAffiMask)
{
#ifdef LOSCFG_KERNEL_SMP
@@ -1253,7 +1279,7 @@ LITE_OS_SEC_TEXT_MINOR UINT32 LOS_TaskCpuAffiSet(UINT32 taskID, UINT16 cpuAffiMa
UINT32 intSave;
UINT16 currCpuMask;
- if (OS_TID_CHECK_INVALID(taskID)) {//检测taskid是否有效,task由task池分配,鸿蒙默认128个任务 ID范围[0:127]
+ if (OS_TID_CHECK_INVALID(taskID)) {//检测taskid是否有效,task由task池分配,鸿蒙默认128个任务 ID范围[0:127]
return LOS_ERRNO_TSK_ID_INVALID;
}
@@ -1270,14 +1296,15 @@ LITE_OS_SEC_TEXT_MINOR UINT32 LOS_TaskCpuAffiSet(UINT32 taskID, UINT16 cpuAffiMa
needSched = OsTaskCpuAffiSetUnsafe(taskID, cpuAffiMask, &currCpuMask);
SCHEDULER_UNLOCK(intSave);
+
if (needSched && OS_SCHEDULER_ACTIVE) {
- LOS_MpSchedule(currCpuMask);//发送信号调度信号给目标cpu
+ LOS_MpSchedule(currCpuMask);//发送信号调度信号给目标CPU
LOS_Schedule();//申请调度
}
return LOS_OK;
}
-//查询任务被绑在哪个cpu上
+///查询任务被绑在哪个CPU上
LITE_OS_SEC_TEXT_MINOR UINT16 LOS_TaskCpuAffiGet(UINT32 taskID)
{
#ifdef LOSCFG_KERNEL_SMP
@@ -1291,50 +1318,54 @@ LITE_OS_SEC_TEXT_MINOR UINT16 LOS_TaskCpuAffiGet(UINT32 taskID)
LosTaskCB *taskCB = OS_TCB_FROM_TID(taskID);
SCHEDULER_LOCK(intSave);
- if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) {//任务必须在使用
+ if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) { //任务必须在使用
SCHEDULER_UNLOCK(intSave);
return INVALID_CPU_AFFI_MASK;
}
- cpuAffiMask = taskCB->cpuAffiMask;//获取亲和力掩码
+ cpuAffiMask = taskCB->cpuAffiMask; //获取亲和力掩码
SCHEDULER_UNLOCK(intSave);
return cpuAffiMask;
#else
(VOID)taskID;
- return 1;//单核情况直接返回1,0号cpu对应0x01
+ return 1;//单核情况直接返回1 ,0号cpu对应0x01
#endif
}
/*
* Description : Process pending signals tagged by others cores
*/
+ /*!
+ 由其他CPU核触发阻塞进程的信号
+ 函数由汇编代码调用 ..\arch\arm\arm\src\los_dispatch.S
+*/
LITE_OS_SEC_TEXT_MINOR VOID OsTaskProcSignal(VOID)
{
UINT32 ret;
- //私有且不可中断,无需保护。这个任务在其他cpu核看到它时总是在运行,所以它在执行代码的同时也可以继续接收信号
+ //私有且不可中断,无需保护。这个任务在其他CPU核看到它时总是在运行,所以它在执行代码的同时也可以继续接收信号
/*
* private and uninterruptable, no protection needed.
* while this task is always running when others cores see it,
* so it keeps receiving signals while follow code executing.
*/
LosTaskCB *runTask = OsCurrTaskGet();
- if (runTask->signal == SIGNAL_NONE) {//意思是其他cpu发起了要干掉你的信号
+ if (runTask->signal == SIGNAL_NONE) {
return;
}
- if (runTask->signal & SIGNAL_KILL) {
+ if (runTask->signal & SIGNAL_KILL) {//意思是其他cpu发起了要干掉你的信号
/*
* clear the signal, and do the task deletion. if the signaled task has been
* scheduled out, then this deletion will wait until next run.
- *///如果发出信号的任务以出调度就绪队列,则此删除将等待下次运行
- runTask->signal = SIGNAL_NONE;//清除信号
+ *///如果发出信号的任务已出调度就绪队列,则此删除将等待下次运行
+ runTask->signal = SIGNAL_NONE;//清除信号,
ret = LOS_TaskDelete(runTask->taskID);
if (ret != LOS_OK) {
PRINT_ERR("Task proc signal delete task(%u) failed err:0x%x\n", runTask->taskID, ret);
}
} else if (runTask->signal & SIGNAL_SUSPEND) {//意思是其他cpu发起了要挂起你的信号
- runTask->signal &= ~SIGNAL_SUSPEND;//任务贴在被其他cpu挂起的标签
+ runTask->signal &= ~SIGNAL_SUSPEND;//任务贴上被其他CPU挂起的标签
/* suspend killed task may fail, ignore the result */
(VOID)LOS_TaskSuspend(runTask->taskID);
@@ -1342,7 +1373,7 @@ LITE_OS_SEC_TEXT_MINOR VOID OsTaskProcSignal(VOID)
} else if (runTask->signal & SIGNAL_AFFI) {//意思是下次调度其他cpu要媾和你
runTask->signal &= ~SIGNAL_AFFI;//任务贴上被其他CPU媾和的标签
- /* priority queue has updated, notify the target cpu */
+ /* pri-queue has updated, notify the target cpu */
LOS_MpSchedule((UINT32)runTask->cpuAffiMask);//发生调度,此任务将移交给媾和CPU运行.
#endif
}
@@ -1416,7 +1447,7 @@ INT32 OsUserProcessOperatePermissionsCheck(const LosTaskCB *taskCB, UINTPTR proc
return LOS_OK;
}
-//创建任务之前,检查用户态任务栈的参数,是否地址在用户空间
+///创建任务之前,检查用户态任务栈的参数,是否地址在用户空间
LITE_OS_SEC_TEXT_INIT STATIC UINT32 OsCreateUserTaskParamCheck(UINT32 processID, TSK_INIT_PARAM_S *param)
{
UserTaskParam *userParam = NULL;
@@ -1433,18 +1464,18 @@ LITE_OS_SEC_TEXT_INIT STATIC UINT32 OsCreateUserTaskParamCheck(UINT32 processID,
if (!LOS_IsUserAddress((UINTPTR)param->pfnTaskEntry)) {//入口函数必须在用户空间
return OS_INVALID_VALUE;
}
- //堆栈必须在用户空间
+ //堆栈必须在用户空间
if (userParam->userMapBase && !LOS_IsUserAddressRange(userParam->userMapBase, userParam->userMapSize)) {
return OS_INVALID_VALUE;
}
- //检查堆,栈范围
+ //检查堆,栈范围
if (!LOS_IsUserAddress(userParam->userSP)) {
return OS_INVALID_VALUE;
}
return LOS_OK;
}
-//创建一个用户态任务
+///创建一个用户态任务
LITE_OS_SEC_TEXT_INIT UINT32 OsCreateUserTask(UINTPTR processID, TSK_INIT_PARAM_S *initParam)
{
UINT32 taskID;
@@ -1457,9 +1488,9 @@ LITE_OS_SEC_TEXT_INIT UINT32 OsCreateUserTask(UINTPTR processID, TSK_INIT_PARAM_
if (ret != LOS_OK) {
return ret;
}
- //这里可看出一个任务有两个栈,内核态栈(内核指定栈大小)和用户态栈(用户指定栈大小)
+ //这里可看出一个任务有两个栈,内核态栈(内核指定栈大小)和用户态栈(用户指定栈大小)
initParam->uwStackSize = OS_USER_TASK_SYSCALL_STACK_SIZE;
- initParam->usTaskPrio = OS_TASK_PRIORITY_LOWEST;//设置最低优先级31级
+ initParam->usTaskPrio = OS_TASK_PRIORITY_LOWEST;//设置最低优先级 31级
if (processID == OS_INVALID_VALUE) {//外面没指定进程ID的处理
SCHEDULER_LOCK(intSave);
LosProcessCB *processCB = OsCurrProcessGet();
@@ -1478,19 +1509,19 @@ LITE_OS_SEC_TEXT_INIT UINT32 OsCreateUserTask(UINTPTR processID, TSK_INIT_PARAM_
initParam->periodUs = param.periodUs;
}
} else {//进程已经创建
- initParam->policy = LOS_SCHED_RR;//调度方式为抢占式,注意鸿蒙不仅仅只支持抢占式调度方式
+ initParam->policy = LOS_SCHED_RR;//调度方式为抢占式,注意鸿蒙不仅仅只支持抢占式调度方式
initParam->processID = processID;//进程ID赋值
initParam->consoleID = 0;//默认0号控制台
}
- ret = LOS_TaskCreateOnly(&taskID, initParam);//只创建task实体,不申请调度
+ ret = LOS_TaskCreateOnly(&taskID, initParam);//只创建task实体,不申请调度
if (ret != LOS_OK) {
return OS_INVALID_VALUE;
}
return taskID;
}
-//获取任务的调度方式
+///获取任务的调度方式
LITE_OS_SEC_TEXT INT32 LOS_GetTaskScheduler(INT32 taskID)
{
UINT32 intSave;
@@ -1503,7 +1534,7 @@ LITE_OS_SEC_TEXT INT32 LOS_GetTaskScheduler(INT32 taskID)
LosTaskCB *taskCB = OS_TCB_FROM_TID(taskID);
SCHEDULER_LOCK(intSave);
- if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) {//任务不能是没有在使用
+ if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) {//状态不能是没有在使用
policy = -LOS_EINVAL;
OS_GOTO_ERREND();
}
@@ -1515,6 +1546,7 @@ LOS_ERREND:
SCHEDULER_UNLOCK(intSave);
return policy;
}
+
//设置任务的调度信息
LITE_OS_SEC_TEXT INT32 LOS_SetTaskScheduler(INT32 taskID, UINT16 policy, UINT16 priority)
{
@@ -1540,7 +1572,7 @@ LITE_OS_SEC_TEXT INT32 LOS_SetTaskScheduler(INT32 taskID, UINT16 policy, UINT16
SCHEDULER_LOCK(intSave);
if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) {
- SCHEDULER_UNLOCK(intSave);
+ SCHEDULER_UNLOCK(intSave);
return LOS_EINVAL;
}
@@ -1664,7 +1696,7 @@ LITE_OS_SEC_TEXT UINT32 LOS_GetSystemTaskMaximum(VOID)
{
return g_taskMaxNum;
}
-//任务池中最后一个
+/// 任务池中最后一个
LosTaskCB *OsGetDefaultTaskCB(VOID)
{
return &g_taskCBArray[g_taskMaxNum];
@@ -1679,28 +1711,27 @@ LITE_OS_SEC_TEXT VOID OsWriteResourceEventUnsafe(UINT32 events)
{
(VOID)OsEventWriteUnsafe(&g_resourceEvent, events, FALSE, NULL);
}
-//资源回收任务
+///资源回收任务
STATIC VOID OsResourceRecoveryTask(VOID)
{
UINT32 ret;
- while (1) {//死循环,回收资源不存在退出情况,只要系统在运行资源就需要回收
+ while (1) {//死循环,回收资源不存在退出情况,只要系统在运行资源就需要回收
ret = LOS_EventRead(&g_resourceEvent, OS_RESOURCE_EVENT_MASK,
LOS_WAITMODE_OR | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER);//读取资源事件
if (ret & (OS_RESOURCE_EVENT_FREE | OS_RESOURCE_EVENT_OOM)) {//收到资源释放或内存异常情况
OsTaskCBRecycleToFree();
-
OsProcessCBRecycleToFree();//回收进程到空闲进程池
}
-#ifdef LOSCFG_ENABLE_OOM_LOOP_TASK//内存溢出检测任务开关
+#ifdef LOSCFG_ENABLE_OOM_LOOP_TASK //内存溢出监测任务开关
if (ret & OS_RESOURCE_EVENT_OOM) {//触发了这个事件
(VOID)OomCheckProcess();//检查进程的内存溢出情况
}
#endif
}
}
-//创建一个回收资源的任务
+///创建一个回收资源的任务
LITE_OS_SEC_TEXT UINT32 OsResourceFreeTaskCreate(VOID)
{
UINT32 ret;
@@ -1716,7 +1747,7 @@ LITE_OS_SEC_TEXT UINT32 OsResourceFreeTaskCreate(VOID)
taskInitParam.pfnTaskEntry = (TSK_ENTRY_FUNC)OsResourceRecoveryTask;//入口函数
taskInitParam.uwStackSize = OS_TASK_RESOURCE_STATIC_SIZE;
taskInitParam.pcName = "ResourcesTask";
- taskInitParam.usTaskPrio = OS_TASK_RESOURCE_FREE_PRIORITY;//5,优先级很高
+ taskInitParam.usTaskPrio = OS_TASK_RESOURCE_FREE_PRIORITY;// 5 ,优先级很高
ret = LOS_TaskCreate(&taskID, &taskInitParam);
if (ret == LOS_OK) {
OS_TCB_FROM_TID(taskID)->taskStatus |= OS_TASK_FLAG_NO_DELETE;
@@ -1725,4 +1756,3 @@ LITE_OS_SEC_TEXT UINT32 OsResourceFreeTaskCreate(VOID)
}
LOS_MODULE_INIT(OsResourceFreeTaskCreate, LOS_INIT_LEVEL_KMOD_TASK);//资源回收任务初始化
-
diff --git a/src/kernel_liteos_a/kernel/base/core/los_tick.c b/src/kernel_liteos_a/kernel/base/core/los_tick.c
index 4e9c4575..0584b7ea 100644
--- a/src/kernel_liteos_a/kernel/base/core/los_tick.c
+++ b/src/kernel_liteos_a/kernel/base/core/los_tick.c
@@ -37,24 +37,24 @@
#endif
-LITE_OS_SEC_DATA_INIT UINT32 g_sysClock; //系统时钟,绝大部分部件工作的时钟源,以及所有外设的始终来源
-LITE_OS_SEC_DATA_INIT UINT32 g_tickPerSecond; //每秒Tick数,harmony默认为每秒100次即10ms
-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)//节拍中断处理函数,harmony默认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(); //更新vdso数据页时间,vsdo可以直接在用户进程空间绕过系统调用获取系统时间
+ OsVdsoTimevalUpdate();//更新vdso数据页时间,vdso可以直接在用户进程空间绕过系统调用获取系统时间(例如:gettimeofday)
#endif
#ifdef LOSCFG_BASE_CORE_TICK_HW_TIME
diff --git a/src/kernel_liteos_a/kernel/base/include/los_container_pri.h b/src/kernel_liteos_a/kernel/base/include/los_container_pri.h
index d7b72c70..db10f529 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_container_pri.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_container_pri.h
@@ -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;
diff --git a/src/kernel_liteos_a/kernel/base/include/los_futex_pri.h b/src/kernel_liteos_a/kernel/base/include/los_futex_pri.h
index 7671115b..a315013d 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_futex_pri.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_futex_pri.h
@@ -1,3 +1,31 @@
+/*!
+ * @file los_futex_pri.h
+ * @brief
+ * @link
+ @verbatim
+ FUTEX_WAIT
+ 这个操作用来检测有uaddr指向的futex是否包含关心的数值val,如果是,则继续sleep直到FUTEX_WAKE操作触发。
+ 加载futex的操作是原子的。这个加载,从比较关心的数值,到开始sleep,都是原子的,与另外一个对于同一个
+ futex的操作是线性的,串行的,严格按照顺序来执行的。如果线程开始sleep,就表示有一个waiter在futex上。
+ 如果futex的值不匹配,回调直接返回失败,错误代码是EAGAIN。
+
+ 与期望值对比的目的是为了防止丢失唤醒的操作。如果另一个线程在基于前面的数值阻塞调用之后,修改了这个值,
+ 另一个线程在数值改变之后,调用FUTEX_WAIT之前执行了FUTEX_WAKE操作,这个调用的线程就会观察到数值变换并且无法唤醒。
+ 这里的意思是,调用FUTEX_WAIT需要做上面的一个操作,就是检测一下这个值是不是我们需要的,如果不是就等待,
+ 如果是就直接运行下去。之所以检测是为了避免丢失唤醒,也就是防止一直等待下去,比如我们在调用FUTEX_WAIT之前,
+ 另一个线程已经调用了FUTEX_WAKE,那么就不会有线程调用FUTEX_WAKE,调用FUTEX_WAIT的线程就永远等不到信号了,也就永远唤醒不了了。
+
+ 如果timeout不是NULL,就表示指向了一个特定的超时时钟。这个超时间隔使用系统时钟的颗粒度四舍五入,
+ 可以保证触发不会比定时的时间早。默认情况通过CLOCK_MONOTONIC测量,但是从Linux 4.5开始,可以在futex_op中设置
+ FUTEX_CLOCK_REALTIME使用CLOCK_REALTIME测量。如果timeout是NULL,将会永远阻塞。
+
+ 注意:对于FUTEX_WAIT,timeout是一个关联的值。与其他的futex设置不同,timeout被认为是一个绝对值。
+ 使用通过FUTEX_BITSET_MATCH_ANY特殊定义的val3传入FUTEX_WAIT_BITSET可以获得附带timeout的FUTEX_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);
diff --git a/src/kernel_liteos_a/kernel/base/include/los_ipc_container_pri.h b/src/kernel_liteos_a/kernel/base/include/los_ipc_container_pri.h
index 42ccbf3e..d46bd84b 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_ipc_container_pri.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_ipc_container_pri.h
@@ -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;
diff --git a/src/kernel_liteos_a/kernel/base/include/los_memstat_pri.h b/src/kernel_liteos_a/kernel/base/include/los_memstat_pri.h
index a2a9f581..7f3aee4b 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_memstat_pri.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_memstat_pri.h
@@ -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);
diff --git a/src/kernel_liteos_a/kernel/base/include/los_mux_pri.h b/src/kernel_liteos_a/kernel/base/include/los_mux_pri.h
index 8837114c..ebab2648 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_mux_pri.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_mux_pri.h
@@ -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:
diff --git a/src/kernel_liteos_a/kernel/base/include/los_percpu_pri.h b/src/kernel_liteos_a/kernel/base/include/los_percpu_pri.h
index 8a824ffd..e561c03d 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_percpu_pri.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_percpu_pri.h
@@ -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];
diff --git a/src/kernel_liteos_a/kernel/base/include/los_pid_container_pri.h b/src/kernel_liteos_a/kernel/base/include/los_pid_container_pri.h
index cc047e68..eed94630 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_pid_container_pri.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_pid_container_pri.h
@@ -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)
diff --git a/src/kernel_liteos_a/kernel/base/include/los_process_pri.h b/src/kernel_liteos_a/kernel/base/include/los_process_pri.h
index e100438d..d8152854 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_process_pri.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_process_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:
@@ -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; */ // 用戶模式1 内核模式0
+ 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 */ // 进程是组长时有哪些组员进程
- LosTaskCB *threadGroup; // 哪个线程组是进程的主线程ID
- 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 */ // 进程持有等待链表以支持wait/waitpid
+ 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 | 父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息*/
#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 */ //用于进程间通讯的虚拟设备文件系统,设备装载点为 /dev/lite_ipc
+ ProcIpcInfo *ipcInfo; /**< Memory pool for lite ipc | 用于进程间通讯的虚拟设备文件系统,设备装载点为 /dev/lite_ipc*/
#endif
#ifdef LOSCFG_KERNEL_VM
- LosVmSpace *vmSpace; /**< VMM space for processes */ //虚拟空间,描述进程虚拟内存的数据结构,linux称为内存描述符
+ 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);
diff --git a/src/kernel_liteos_a/kernel/base/include/los_queue_pri.h b/src/kernel_liteos_a/kernel/base/include/los_queue_pri.h
index 4efafe23..4b035457 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_queue_pri.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_queue_pri.h
@@ -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
+ | 队列中可写或可读消息数,0表示可读,1表示可写*/
+ LOS_DL_LIST readWriteList[OS_QUEUE_N_RW]; /**< the linked list to be read or written, 0:readlist, 1:writelist
+ | 挂的都是等待读/写消息的任务链表,0表示读消息的链表,1表示写消息的任务链表*/
+ 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
diff --git a/src/kernel_liteos_a/kernel/base/include/los_rwlock_pri.h b/src/kernel_liteos_a/kernel/base/include/los_rwlock_pri.h
index 4b0711f7..e0536bb2 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_rwlock_pri.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_rwlock_pri.h
@@ -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);
diff --git a/src/kernel_liteos_a/kernel/base/include/los_sched_pri.h b/src/kernel_liteos_a/kernel/base/include/los_sched_pri.h
index 1bbf0070..d86bf5b7 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_sched_pri.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_sched_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:
@@ -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-First,HPF)
};
} 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
diff --git a/src/kernel_liteos_a/kernel/base/include/los_sem_debug_pri.h b/src/kernel_liteos_a/kernel/base/include/los_sem_debug_pri.h
index f58d4bca..36bc7ace 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_sem_debug_pri.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_sem_debug_pri.h
@@ -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
diff --git a/src/kernel_liteos_a/kernel/base/include/los_sem_pri.h b/src/kernel_liteos_a/kernel/base/include/los_sem_pri.h
index 8476a1bc..568d24a0 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_sem_pri.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_sem_pri.h
@@ -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;
/**
diff --git a/src/kernel_liteos_a/kernel/base/include/los_signal.h b/src/kernel_liteos_a/kernel/base/include/los_signal.h
index ce39c484..17341dcf 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_signal.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_signal.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:
@@ -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/
+ musl是构建在Linux系统调用API之上的C标准库的实现,包括在基本语言标准POSIX中定义的接口,
+ 以及广泛认可的扩展。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);
diff --git a/src/kernel_liteos_a/kernel/base/include/los_sortlink_pri.h b/src/kernel_liteos_a/kernel/base/include/los_sortlink_pri.h
index 788947d3..e0aa4522 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_sortlink_pri.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_sortlink_pri.h
@@ -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;
diff --git a/src/kernel_liteos_a/kernel/base/include/los_stackinfo_pri.h b/src/kernel_liteos_a/kernel/base/include/los_stackinfo_pri.h
index 74eb7ee9..b89eeb35 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_stackinfo_pri.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_stackinfo_pri.h
@@ -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 */
\ No newline at end of file
diff --git a/src/kernel_liteos_a/kernel/base/include/los_swtmr_pri.h b/src/kernel_liteos_a/kernel/base/include/los_swtmr_pri.h
index 02d6c0db..f2df6dbd 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_swtmr_pri.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_swtmr_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))
/**
diff --git a/src/kernel_liteos_a/kernel/base/include/los_sys_pri.h b/src/kernel_liteos_a/kernel/base/include/los_sys_pri.h
index 01a90e8b..75ab6ddb 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_sys_pri.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_sys_pri.h
@@ -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
diff --git a/src/kernel_liteos_a/kernel/base/include/los_task_pri.h b/src/kernel_liteos_a/kernel/base/include/los_task_pri.h
index fd487a0c..5cf54fa7 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_task_pri.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_task_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:
@@ -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:
*
- los_task_pri.h: the header file that contains the API declaration.
* @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;
diff --git a/src/kernel_liteos_a/kernel/base/include/los_user_container_pri.h b/src/kernel_liteos_a/kernel/base/include/los_user_container_pri.h
index a073599b..83d78445 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_user_container_pri.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_user_container_pri.h
@@ -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;
diff --git a/src/kernel_liteos_a/kernel/base/include/los_uts_container_pri.h b/src/kernel_liteos_a/kernel/base/include/los_uts_container_pri.h
index 5642286c..cc560d22 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_uts_container_pri.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_uts_container_pri.h
@@ -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);
diff --git a/src/kernel_liteos_a/kernel/base/include/los_vm_boot.h b/src/kernel_liteos_a/kernel/base/include/los_vm_boot.h
index fb6e714a..6ec88028 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_vm_boot.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_vm_boot.h
@@ -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;
diff --git a/src/kernel_liteos_a/kernel/base/include/los_vm_common.h b/src/kernel_liteos_a/kernel/base/include/los_vm_common.h
index f2dd70bf..17b3f34c 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_vm_common.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_vm_common.h
@@ -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)
diff --git a/src/kernel_liteos_a/kernel/base/include/los_vm_fault.h b/src/kernel_liteos_a/kernel/base/include/los_vm_fault.h
index d3c650a2..bd6d271b 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_vm_fault.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_vm_fault.h
@@ -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
diff --git a/src/kernel_liteos_a/kernel/base/include/los_vm_filemap.h b/src/kernel_liteos_a/kernel/base/include/los_vm_filemap.h
index c8cceb21..3aa50a0c 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_vm_filemap.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_vm_filemap.h
@@ -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);
diff --git a/src/kernel_liteos_a/kernel/base/include/los_vm_iomap.h b/src/kernel_liteos_a/kernel/base/include/los_vm_iomap.h
index bf5fea03..d041b036 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_vm_iomap.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_vm_iomap.h
@@ -41,9 +41,19 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
-enum DmaMemType {
- DMA_CACHE,
- DMA_NOCACHE
+/**
+ * @brief
+ * @verbatim
+ DMA,全称Direct Memory Access,即直接存储器访问。
+ DMA传输将数据从一个地址空间复制到另一个地址空间,提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。
+ DMA的作用就是实现数据的直接传输,而去掉了传统数据传输需要CPU寄存器参与的环节,主要涉及四种情况的数据传输,
+ 但本质上是一样的,都是从内存的某一区域传输到内存的另一区域(外设的数据寄存器本质上就是内存的一个存储单元)
+ * @endverbatim
+ */
+
+enum DmaMemType {
+ DMA_CACHE, ///< 有缓存的DMA
+ DMA_NOCACHE ///< 无缓存的DMA
};
/* thread safety */
diff --git a/src/kernel_liteos_a/kernel/base/include/los_vm_map.h b/src/kernel_liteos_a/kernel/base/include/los_vm_map.h
index 344e1ad8..6ad8167d 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_vm_map.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_vm_map.h
@@ -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 {//
+ 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 | 虚拟空间映射区基地址,L1,L2表存放在这个区 */
+ 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) ///< VDSO(Virtual 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.
diff --git a/src/kernel_liteos_a/kernel/base/include/los_vm_page.h b/src/kernel_liteos_a/kernel/base/include/los_vm_page.h
index c1aa9413..22dc31f5 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_vm_page.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_vm_page.h
@@ -44,21 +44,28 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
+/*!
+ * @brief 物理页框描述符 虚拟内存体现的是程序对内存资源的需求,而物理内存是对该请求的供应。
+ 伙伴算法的思想是:把内存中连续的空闲页框空间看成是空闲页框块,并按照它们的大小(连续页框的数目)分组
+ * @attention vmPage 中并没有虚拟地址,只有物理地址
+ \n 关于nPages和order的关系说明,当请求分配为5页时,order是等于3的,因为只有2^3才能满足5页的请求
+ */
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);
diff --git a/src/kernel_liteos_a/kernel/base/include/los_vm_phys.h b/src/kernel_liteos_a/kernel/base/include/los_vm_phys.h
index 75bcab08..ef362177 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_vm_phys.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_vm_phys.h
@@ -43,52 +43,65 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
-#define VM_LIST_ORDER_MAX 9
-#define VM_PHYS_SEG_MAX 32
+/*!
+ * @brief
+ * @verbatim
+ LRU是Least 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 Lru全称是Least 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);
diff --git a/src/kernel_liteos_a/kernel/base/include/los_vm_syscall.h b/src/kernel_liteos_a/kernel/base/include/los_vm_syscall.h
index dbcb3d12..2744db83 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_vm_syscall.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_vm_syscall.h
@@ -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);
diff --git a/src/kernel_liteos_a/kernel/base/include/los_vm_zone.h b/src/kernel_liteos_a/kernel/base/include/los_vm_zone.h
index 3e3a9938..b8fb1280 100644
--- a/src/kernel_liteos_a/kernel/base/include/los_vm_zone.h
+++ b/src/kernel_liteos_a/kernel/base/include/los_vm_zone.h
@@ -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_a中,内核运行基址是在各个板子的board.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
+
+ cached地址和uncached地址的区别是
+ 对cached地址的访问是委托给CPU进行的,也就是说你的操作到底是提交给真正的外设或内存,还是转到CPU缓存,
+ 是由CPU决定的。CPU有一套缓存策略来决定什么时候从缓存中读取数据,什么时候同步缓存。
+ 对unchached地址的访问是告诉CPU忽略缓存,访问操作直接反映到外设或内存上。
+ 对于IO设备一定要用uncached地址访问,是因为你的IO输出操作肯定是希望立即反映到IO设备上,不希望让CPU缓存你的操作;
+ 另一方面,IO设备的状态是独立于CPU的,也就是说IO口状态的改变CPU是不知道,这样就导致缓存和外设的内容不一致,
+ 你从IO设备读取数据时,肯定是希望直接读取IO设备的当前状态,而不是CPU缓存的过期值。
+
+ @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)
diff --git a/src/kernel_liteos_a/kernel/base/ipc/los_event.c b/src/kernel_liteos_a/kernel/base/ipc/los_event.c
index 1503c7fb..81a6dd5a 100644
--- a/src/kernel_liteos_a/kernel/base/ipc/los_event.c
+++ b/src/kernel_liteos_a/kernel/base/ipc/los_event.c
@@ -1,6 +1,57 @@
+/*!
+ * @file los_event.c
+ * @brief
+ * @link
+ @verbatim
+ 事件(Event)是一种任务间通信的机制,可用于任务间的同步。
+ 多任务环境下,任务之间往往需要同步操作,一个等待即是一个同步。事件可以提供一对多、多对多的同步操作。
+ 一对多同步模型:一个任务等待多个事件的触发。可以是任意一个事件发生时唤醒任务处理事件,也可以是几个事件都发生后才唤醒任务处理事件。
+ 多对多同步模型:多个任务等待多个事件的触发。
+
+ 事件特点
+ 任务通过创建事件控制块来触发事件或等待事件。
+ 事件间相互独立,内部实现为一个32位无符号整型,每一位标识一种事件类型。第25位不可用,因此最多可支持31种事件类型。
+ 事件仅用于任务间的同步,不提供数据传输功能。
+ 多次向事件控制块写入同一事件类型,在被清零前等效于只写入一次。
+ 多个任务可以对同一事件进行读写操作。
+ 支持事件读写超时机制。
+
+ 事件读取模式
+ 在读事件时,可以选择读取模式。读取模式如下:
+ 所有事件(LOS_WAITMODE_AND):逻辑与,基于接口传入的事件类型掩码eventMask,
+ 只有这些事件都已经发生才能读取成功,否则该任务将阻塞等待或者返回错误码。
+ 任一事件(LOS_WAITMODE_OR):逻辑或,基于接口传入的事件类型掩码eventMask,
+ 只要这些事件中有任一种事件发生就可以读取成功,否则该任务将阻塞等待或者返回错误码。
+ 清除事件(LOS_WAITMODE_CLR):这是一种附加读取模式,需要与所有事件模式或任一事件模式结合
+ 使用(LOS_WAITMODE_AND | LOS_WAITMODE_CLR或 LOS_WAITMODE_OR | LOS_WAITMODE_CLR)。在这种模式下,
+ 当设置的所有事件模式或任一事件模式读取成功后,会自动清除事件控制块中对应的事件类型位。
+
+ 运作机制
+ 任务在调用LOS_EventRead接口读事件时,可以根据入参事件掩码类型eventMask读取事件的单个或者多个事件类型。
+ 事件读取成功后,如果设置LOS_WAITMODE_CLR会清除已读取到的事件类型,反之不会清除已读到的事件类型,需显式清除。
+ 可以通过入参选择读取模式,读取事件掩码类型中所有事件还是读取事件掩码类型中任意事件。
+ 任务在调用LOS_EventWrite接口写事件时,对指定事件控制块写入指定的事件类型,
+ 可以一次同时写多个事件类型。写事件会触发任务调度。
+ 任务在调用LOS_EventClear接口清除事件时,根据入参事件和待清除的事件类型,
+ 对事件对应位进行清0操作。
+
+ 使用场景
+ 事件可应用于多种任务同步场景,在某些同步场景下可替代信号量。
+
+ 注意事项
+ 在系统初始化之前不能调用读写事件接口。如果调用,系统运行会不正常。
+ 在中断中,可以对事件对象进行写操作,但不能进行读操作。
+ 在锁任务调度状态下,禁止任务阻塞于读事件。
+ LOS_EventClear 入参值是:要清除的指定事件类型的反码(~events)。
+ 为了区别LOS_EventRead接口返回的是事件还是错误码,事件掩码的第25位不能使用。
+ @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:
@@ -39,8 +90,8 @@
#ifdef LOSCFG_BASE_CORE_SWTMR_ENABLE
#include "los_exc.h"
#endif
-/*
-*/
+
+/// 初始化一个事件控制块
LITE_OS_SEC_TEXT_INIT UINT32 LOS_EventInit(PEVENT_CB_S eventCB)
{
UINT32 intSave;
@@ -49,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) {
@@ -78,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)
{
@@ -132,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);
@@ -191,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;
@@ -231,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;
@@ -299,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;
@@ -314,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)
diff --git a/src/kernel_liteos_a/kernel/base/ipc/los_futex.c b/src/kernel_liteos_a/kernel/base/ipc/los_futex.c
index 384bb483..8c968b81 100644
--- a/src/kernel_liteos_a/kernel/base/ipc/los_futex.c
+++ b/src/kernel_liteos_a/kernel/base/ipc/los_futex.c
@@ -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,用户态快速互斥锁)是内核提供的一种系统调用能力,通常作为基础组件与用户态的相关
+ 锁逻辑结合组成用户态锁,是一种用户态与内核态共同作用的锁,例如用户态mutex锁、barrier与cond同步锁、读写锁。
+ 其用户态部分负责锁逻辑,内核态部分负责锁调度。
+
+ 当用户态线程请求锁时,先在用户态进行锁状态的判断维护,若此时不产生锁的竞争,则直接在用户态进行上锁返回;
+ 反之,则需要进行线程的挂起操作,通过Futex系统调用请求内核介入来挂起线程,并维护阻塞队列。
+
+ 当用户态线程释放锁时,先在用户态进行锁状态的判断维护,若此时没有其他线程被该锁阻塞,则直接在用户态进行解锁返回;
+ 反之,则需要进行阻塞线程的唤醒操作,通过Futex系统调用请求内核介入来唤醒阻塞队列中的线程。
+ 历史
+ futex (fast userspace mutex) 是Linux的一个基础组件,可以用来构建各种更高级别的同步机制,比如锁或者信号量等等,
+ POSIX信号量就是基于futex构建的。大多数时候编写应用程序并不需要直接使用futex,一般用基于它所实现的系统库就够了。
+
+ 传统的SystemV IPC(inter process communication)进程间同步机制都是通过内核对象来实现的,以 semaphore 为例,
+ 当进程间要同步的时候,必须通过系统调用semop(2)进入内核进行PV操作。系统调用的缺点是开销很大,需要从user mode
+ 切换到kernel mode、保存寄存器状态、从user stack切换到kernel stack、等等,通常要消耗上百条指令。事实上,
+ 有一部分系统调用是可以避免的,因为现实中很多同步操作进行的时候根本不存在竞争,即某个进程从持有semaphore直至
+ 释放semaphore的这段时间内,常常没有其它进程对同一semaphore有需求,在这种情况下,内核的参与本来是不必要的,
+ 可是在传统机制下,持有semaphore必须先调用semop(2)进入内核去看看有没有人和它竞争,释放semaphore也必须调用semop(2)
+ 进入内核去看看有没有人在等待同一semaphore,这些不必要的系统调用造成了大量的性能损耗。
+ 设计思想
+ futex的解决思路是:在无竞争的情况下操作完全在user space进行,不需要系统调用,仅在发生竞争的时候进入内核去完成
+ 相应的处理(wait 或者 wake up)。所以说,futex是一种user mode和kernel mode混合的同步机制,需要两种模式合作才能完成,
+ futex变量必须位于user space,而不是内核对象,futex的代码也分为user mode和kernel mode两部分,无竞争的情况下在user mode,
+ 发生竞争时则通过sys_futex系统调用进入kernel mode进行处理
+ 运行机制
+ 当用户态产生锁的竞争或释放需要进行相关线程的调度操作时,会触发Futex系统调用进入内核,此时会将用户态锁的地址
+ 传入内核,并在内核的Futex中以锁地址来区分用户态的每一把锁,因为用户态可用虚拟地址空间为1GiB,为了便于查找、
+ 管理,内核Futex采用哈希桶来存放用户态传入的锁。
+
+ 当前哈希桶共有80个,0~63号桶用于存放私有锁(以虚拟地址进行哈希),64~79号桶用于存放共享锁(以物理地址进行哈希),
+ 私有/共享属性通过用户态锁的初始化以及Futex系统调用入参确定。
+
+ 如下图: 每个futex哈希桶中存放被futex_list串联起来的哈希值相同的futex node,每个futex node对应一个被挂起的task,
+ node中key值唯一标识一把用户态锁,具有相同key值的node被queue_list串联起来表示被同一把锁阻塞的task队列。
+ @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;
}
diff --git a/src/kernel_liteos_a/kernel/base/ipc/los_mux.c b/src/kernel_liteos_a/kernel/base/ipc/los_mux.c
index fa4a67b8..8a87eb54 100644
--- a/src/kernel_liteos_a/kernel/base/ipc/los_mux.c
+++ b/src/kernel_liteos_a/kernel/base/ipc/los_mux.c
@@ -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, ¶m);
}
}
-
+///恢复互斥锁位图
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, ¶m);
}
+/// 最坏情况就是拿锁失败,让出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
+ * 是否有其他任务持有互斥锁而处于阻塞状,如果是就要唤醒它,注意唤醒一个任务的操作是由别的任务完成的
+ * OsMuxPostOp只由OsMuxUnlockUnsafe,参数任务归还锁了,自然就会遇到锁要给谁用的问题, 因为很多任务在申请锁,由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, ¶m);
taskCB->ops->priorityRestore(taskCB, NULL, ¶m);
}
- /* 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) */
diff --git a/src/kernel_liteos_a/kernel/base/ipc/los_queue.c b/src/kernel_liteos_a/kernel/base/ipc/los_queue.c
index 8fe06ba2..d3d0de7e 100644
--- a/src/kernel_liteos_a/kernel/base/ipc/los_queue.c
+++ b/src/kernel_liteos_a/kernel/base/ipc/los_queue.c
@@ -1,519 +1,612 @@
-/*
- * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
- * Copyright (c) 2020-2023 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:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this list of
- * conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice, this list
- * of conditions and the following disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 3. Neither the name of the copyright holder nor the names of its contributors may be used
- * to endorse or promote products derived from this software without specific prior written
- * permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "los_queue_pri.h"
-#include "los_queue_debug_pri.h"
-#include "los_task_pri.h"
-#include "los_sched_pri.h"
-#include "los_spinlock.h"
-#include "los_mp.h"
-#include "los_percpu_pri.h"
-#include "los_hook.h"
-#ifdef LOSCFG_IPC_CONTAINER
-#include "los_ipc_container_pri.h"
-#endif
-
-#ifdef LOSCFG_BASE_IPC_QUEUE
-#if (LOSCFG_BASE_IPC_QUEUE_LIMIT <= 0)
-#error "queue maxnum cannot be zero"
-#endif /* LOSCFG_BASE_IPC_QUEUE_LIMIT <= 0 */
-
-#ifndef LOSCFG_IPC_CONTAINER
-LITE_OS_SEC_BSS LosQueueCB *g_allQueue = NULL;
-LITE_OS_SEC_BSS STATIC LOS_DL_LIST g_freeQueueList;
-#define FREE_QUEUE_LIST g_freeQueueList
-#endif
-
-LITE_OS_SEC_TEXT_INIT LosQueueCB *OsAllQueueCBInit(LOS_DL_LIST *freeQueueList)
-{
- UINT32 index;
-
- if (freeQueueList == NULL) {
- return NULL;
- }
-
- UINT32 size = LOSCFG_BASE_IPC_QUEUE_LIMIT * sizeof(LosQueueCB);
- /* system resident memory, don't free */
- LosQueueCB *allQueue = (LosQueueCB *)LOS_MemAlloc(m_aucSysMem0, size);
- if (allQueue == NULL) {
- return NULL;
- }
- (VOID)memset_s(allQueue, size, 0, size);
- LOS_ListInit(freeQueueList);
- for (index = 0; index < LOSCFG_BASE_IPC_QUEUE_LIMIT; index++) {
- LosQueueCB *queueNode = ((LosQueueCB *)allQueue) + index;
- queueNode->queueID = index;
- LOS_ListTailInsert(freeQueueList, &queueNode->readWriteList[OS_QUEUE_WRITE]);
- }
-
-#ifndef LOSCFG_IPC_CONTAINER
- if (OsQueueDbgInitHook() != LOS_OK) {
- (VOID)LOS_MemFree(m_aucSysMem0, allQueue);
- return NULL;
- }
-#endif
- return allQueue;
-}
-
-/*
- * Description : queue initial
- * Return : LOS_OK on success or error code on failure
- */
-LITE_OS_SEC_TEXT_INIT UINT32 OsQueueInit(VOID)
-{
-#ifndef LOSCFG_IPC_CONTAINER
- g_allQueue = OsAllQueueCBInit(&g_freeQueueList);
- if (g_allQueue == NULL) {
- return LOS_ERRNO_QUEUE_NO_MEMORY;
- }
-#endif
- return LOS_OK;
-}
-
-LITE_OS_SEC_TEXT_INIT UINT32 LOS_QueueCreate(CHAR *queueName, UINT16 len, UINT32 *queueID,
- UINT32 flags, UINT16 maxMsgSize)
-{
- LosQueueCB *queueCB = NULL;
- UINT32 intSave;
- LOS_DL_LIST *unusedQueue = NULL;
- UINT8 *queue = NULL;
- UINT16 msgSize;
-
- (VOID)queueName;
- (VOID)flags;
-
- if (queueID == NULL) {
- return LOS_ERRNO_QUEUE_CREAT_PTR_NULL;
- }
-
- if (maxMsgSize > (OS_NULL_SHORT - sizeof(UINT32))) {
- return LOS_ERRNO_QUEUE_SIZE_TOO_BIG;
- }
-
- if ((len == 0) || (maxMsgSize == 0)) {
- return LOS_ERRNO_QUEUE_PARA_ISZERO;
- }
-
- msgSize = maxMsgSize + sizeof(UINT32);
- /*
- * Memory allocation is time-consuming, to shorten the time of disable interrupt,
- * move the memory allocation to here.
- */
- queue = (UINT8 *)LOS_MemAlloc(m_aucSysMem1, (UINT32)len * msgSize);
- if (queue == NULL) {
- return LOS_ERRNO_QUEUE_CREATE_NO_MEMORY;
- }
-
- SCHEDULER_LOCK(intSave);
- if (LOS_ListEmpty(&FREE_QUEUE_LIST)) {
- SCHEDULER_UNLOCK(intSave);
- OsQueueCheckHook();
- (VOID)LOS_MemFree(m_aucSysMem1, queue);
- return LOS_ERRNO_QUEUE_CB_UNAVAILABLE;
- }
-
- unusedQueue = LOS_DL_LIST_FIRST(&FREE_QUEUE_LIST);
- LOS_ListDelete(unusedQueue);
- queueCB = GET_QUEUE_LIST(unusedQueue);
- queueCB->queueLen = len;
- queueCB->queueSize = msgSize;
- queueCB->queueHandle = queue;
- queueCB->queueState = OS_QUEUE_INUSED;
- queueCB->readWriteableCnt[OS_QUEUE_READ] = 0;
- queueCB->readWriteableCnt[OS_QUEUE_WRITE] = len;
- queueCB->queueHead = 0;
- queueCB->queueTail = 0;
- LOS_ListInit(&queueCB->readWriteList[OS_QUEUE_READ]);
- LOS_ListInit(&queueCB->readWriteList[OS_QUEUE_WRITE]);
- LOS_ListInit(&queueCB->memList);
-
- OsQueueDbgUpdateHook(queueCB->queueID, OsCurrTaskGet()->taskEntry);
- SCHEDULER_UNLOCK(intSave);
-
- *queueID = queueCB->queueID;
- OsHookCall(LOS_HOOK_TYPE_QUEUE_CREATE, queueCB);
- return LOS_OK;
-}
-
-STATIC LITE_OS_SEC_TEXT UINT32 OsQueueReadParameterCheck(UINT32 queueID, const VOID *bufferAddr,
- const UINT32 *bufferSize, UINT32 timeout)
-{
- if (GET_QUEUE_INDEX(queueID) >= LOSCFG_BASE_IPC_QUEUE_LIMIT) {
- return LOS_ERRNO_QUEUE_INVALID;
- }
- if ((bufferAddr == NULL) || (bufferSize == NULL)) {
- return LOS_ERRNO_QUEUE_READ_PTR_NULL;
- }
-
- if ((*bufferSize == 0) || (*bufferSize > (OS_NULL_SHORT - sizeof(UINT32)))) {
- return LOS_ERRNO_QUEUE_READSIZE_IS_INVALID;
- }
-
- OsQueueDbgTimeUpdateHook(queueID);
-
- if (timeout != LOS_NO_WAIT) {
- if (OS_INT_ACTIVE) {
- return LOS_ERRNO_QUEUE_READ_IN_INTERRUPT;
- }
- }
- return LOS_OK;
-}
-
-STATIC LITE_OS_SEC_TEXT UINT32 OsQueueWriteParameterCheck(UINT32 queueID, const VOID *bufferAddr,
- const UINT32 *bufferSize, UINT32 timeout)
-{
- if (GET_QUEUE_INDEX(queueID) >= LOSCFG_BASE_IPC_QUEUE_LIMIT) {
- return LOS_ERRNO_QUEUE_INVALID;
- }
-
- if (bufferAddr == NULL) {
- return LOS_ERRNO_QUEUE_WRITE_PTR_NULL;
- }
-
- if (*bufferSize == 0) {
- return LOS_ERRNO_QUEUE_WRITESIZE_ISZERO;
- }
-
- OsQueueDbgTimeUpdateHook(queueID);
-
- if (timeout != LOS_NO_WAIT) {
- if (OS_INT_ACTIVE) {
- return LOS_ERRNO_QUEUE_WRITE_IN_INTERRUPT;
- }
- }
- return LOS_OK;
-}
-
-STATIC VOID OsQueueBufferOperate(LosQueueCB *queueCB, UINT32 operateType, VOID *bufferAddr, UINT32 *bufferSize)
-{
- UINT8 *queueNode = NULL;
- UINT32 msgDataSize;
- UINT16 queuePosition;
-
- /* get the queue position */
- switch (OS_QUEUE_OPERATE_GET(operateType)) {
- case OS_QUEUE_READ_HEAD:
- queuePosition = queueCB->queueHead;
- ((queueCB->queueHead + 1) == queueCB->queueLen) ? (queueCB->queueHead = 0) : (queueCB->queueHead++);
- break;
- case OS_QUEUE_WRITE_HEAD:
- (queueCB->queueHead == 0) ? (queueCB->queueHead = queueCB->queueLen - 1) : (--queueCB->queueHead);
- queuePosition = queueCB->queueHead;
- break;
- case OS_QUEUE_WRITE_TAIL:
- queuePosition = queueCB->queueTail;
- ((queueCB->queueTail + 1) == queueCB->queueLen) ? (queueCB->queueTail = 0) : (queueCB->queueTail++);
- break;
- default: /* read tail, reserved. */
- PRINT_ERR("invalid queue operate type!\n");
- return;
- }
-
- queueNode = &(queueCB->queueHandle[(queuePosition * (queueCB->queueSize))]);
-
- if (OS_QUEUE_IS_READ(operateType)) {
- if (memcpy_s(&msgDataSize, sizeof(UINT32), queueNode + queueCB->queueSize - sizeof(UINT32),
- sizeof(UINT32)) != EOK) {
- PRINT_ERR("get msgdatasize failed\n");
- return;
- }
- msgDataSize = (*bufferSize < msgDataSize) ? *bufferSize : msgDataSize;
- if (memcpy_s(bufferAddr, *bufferSize, queueNode, msgDataSize) != EOK) {
- PRINT_ERR("copy message to buffer failed\n");
- return;
- }
-
- *bufferSize = msgDataSize;
- } else {
- if (memcpy_s(queueNode, queueCB->queueSize, bufferAddr, *bufferSize) != EOK) {
- PRINT_ERR("store message failed\n");
- return;
- }
- if (memcpy_s(queueNode + queueCB->queueSize - sizeof(UINT32), sizeof(UINT32), bufferSize,
- sizeof(UINT32)) != EOK) {
- PRINT_ERR("store message size failed\n");
- return;
- }
- }
-}
-
-STATIC UINT32 OsQueueOperateParamCheck(const LosQueueCB *queueCB, UINT32 queueID,
- UINT32 operateType, const UINT32 *bufferSize)
-{
- if ((queueCB->queueID != queueID) || (queueCB->queueState == OS_QUEUE_UNUSED)) {
- return LOS_ERRNO_QUEUE_NOT_CREATE;
- }
-
- if (OS_QUEUE_IS_WRITE(operateType) && (*bufferSize > (queueCB->queueSize - sizeof(UINT32)))) {
- return LOS_ERRNO_QUEUE_WRITE_SIZE_TOO_BIG;
- }
- return LOS_OK;
-}
-
-UINT32 OsQueueOperate(UINT32 queueID, UINT32 operateType, VOID *bufferAddr, UINT32 *bufferSize, UINT32 timeout)
-{
- UINT32 ret;
- UINT32 readWrite = OS_QUEUE_READ_WRITE_GET(operateType);
- UINT32 intSave;
- OsHookCall(LOS_HOOK_TYPE_QUEUE_READ, (LosQueueCB *)GET_QUEUE_HANDLE(queueID), operateType, *bufferSize, timeout);
-
- SCHEDULER_LOCK(intSave);
- LosQueueCB *queueCB = (LosQueueCB *)GET_QUEUE_HANDLE(queueID);
- ret = OsQueueOperateParamCheck(queueCB, queueID, operateType, bufferSize);
- if (ret != LOS_OK) {
- goto QUEUE_END;
- }
-
- if (queueCB->readWriteableCnt[readWrite] == 0) {
- if (timeout == LOS_NO_WAIT) {
- ret = OS_QUEUE_IS_READ(operateType) ? LOS_ERRNO_QUEUE_ISEMPTY : LOS_ERRNO_QUEUE_ISFULL;
- goto QUEUE_END;
- }
-
- if (!OsPreemptableInSched()) {
- ret = LOS_ERRNO_QUEUE_PEND_IN_LOCK;
- goto QUEUE_END;
- }
-
- LosTaskCB *runTask = OsCurrTaskGet();
- OsTaskWaitSetPendMask(OS_TASK_WAIT_QUEUE, queueCB->queueID, timeout);
- ret = runTask->ops->wait(runTask, &queueCB->readWriteList[readWrite], timeout);
- if (ret == LOS_ERRNO_TSK_TIMEOUT) {
- ret = LOS_ERRNO_QUEUE_TIMEOUT;
- goto QUEUE_END;
- }
- } else {
- queueCB->readWriteableCnt[readWrite]--;
- }
-
- OsQueueBufferOperate(queueCB, operateType, bufferAddr, bufferSize);
-
- if (!LOS_ListEmpty(&queueCB->readWriteList[!readWrite])) {
- LosTaskCB *resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&queueCB->readWriteList[!readWrite]));
- OsTaskWakeClearPendMask(resumedTask);
- resumedTask->ops->wake(resumedTask);
- SCHEDULER_UNLOCK(intSave);
- LOS_MpSchedule(OS_MP_CPU_ALL);
- LOS_Schedule();
- return LOS_OK;
- } else {
- queueCB->readWriteableCnt[!readWrite]++;
- }
-
-QUEUE_END:
- SCHEDULER_UNLOCK(intSave);
- return ret;
-}
-
-LITE_OS_SEC_TEXT UINT32 LOS_QueueReadCopy(UINT32 queueID,
- VOID *bufferAddr,
- UINT32 *bufferSize,
- UINT32 timeout)
-{
- UINT32 ret;
- UINT32 operateType;
-
- ret = OsQueueReadParameterCheck(queueID, bufferAddr, bufferSize, timeout);
- if (ret != LOS_OK) {
- return ret;
- }
-
- operateType = OS_QUEUE_OPERATE_TYPE(OS_QUEUE_READ, OS_QUEUE_HEAD);
- return OsQueueOperate(queueID, operateType, bufferAddr, bufferSize, timeout);
-}
-
-LITE_OS_SEC_TEXT UINT32 LOS_QueueWriteHeadCopy(UINT32 queueID,
- VOID *bufferAddr,
- UINT32 bufferSize,
- UINT32 timeout)
-{
- UINT32 ret;
- UINT32 operateType;
-
- ret = OsQueueWriteParameterCheck(queueID, bufferAddr, &bufferSize, timeout);
- if (ret != LOS_OK) {
- return ret;
- }
-
- operateType = OS_QUEUE_OPERATE_TYPE(OS_QUEUE_WRITE, OS_QUEUE_HEAD);
- return OsQueueOperate(queueID, operateType, bufferAddr, &bufferSize, timeout);
-}
-
-LITE_OS_SEC_TEXT UINT32 LOS_QueueWriteCopy(UINT32 queueID,
- VOID *bufferAddr,
- UINT32 bufferSize,
- UINT32 timeout)
-{
- UINT32 ret;
- UINT32 operateType;
-
- ret = OsQueueWriteParameterCheck(queueID, bufferAddr, &bufferSize, timeout);
- if (ret != LOS_OK) {
- return ret;
- }
-
- operateType = OS_QUEUE_OPERATE_TYPE(OS_QUEUE_WRITE, OS_QUEUE_TAIL);
- return OsQueueOperate(queueID, operateType, bufferAddr, &bufferSize, timeout);
-}
-
-LITE_OS_SEC_TEXT UINT32 LOS_QueueRead(UINT32 queueID, VOID *bufferAddr, UINT32 bufferSize, UINT32 timeout)
-{
- return LOS_QueueReadCopy(queueID, bufferAddr, &bufferSize, timeout);
-}
-
-LITE_OS_SEC_TEXT UINT32 LOS_QueueWrite(UINT32 queueID, VOID *bufferAddr, UINT32 bufferSize, UINT32 timeout)
-{
- if (bufferAddr == NULL) {
- return LOS_ERRNO_QUEUE_WRITE_PTR_NULL;
- }
- bufferSize = sizeof(CHAR *);
- return LOS_QueueWriteCopy(queueID, &bufferAddr, bufferSize, timeout);
-}
-
-LITE_OS_SEC_TEXT UINT32 LOS_QueueWriteHead(UINT32 queueID,
- VOID *bufferAddr,
- UINT32 bufferSize,
- UINT32 timeout)
-{
- if (bufferAddr == NULL) {
- return LOS_ERRNO_QUEUE_WRITE_PTR_NULL;
- }
- bufferSize = sizeof(CHAR *);
- return LOS_QueueWriteHeadCopy(queueID, &bufferAddr, bufferSize, timeout);
-}
-
-LITE_OS_SEC_TEXT_INIT UINT32 LOS_QueueDelete(UINT32 queueID)
-{
- LosQueueCB *queueCB = NULL;
- UINT8 *queue = NULL;
- UINT32 intSave;
- UINT32 ret;
-
- if (GET_QUEUE_INDEX(queueID) >= LOSCFG_BASE_IPC_QUEUE_LIMIT) {
- return LOS_ERRNO_QUEUE_NOT_FOUND;
- }
-
- SCHEDULER_LOCK(intSave);
- queueCB = (LosQueueCB *)GET_QUEUE_HANDLE(queueID);
- if ((queueCB->queueID != queueID) || (queueCB->queueState == OS_QUEUE_UNUSED)) {
- ret = LOS_ERRNO_QUEUE_NOT_CREATE;
- goto QUEUE_END;
- }
-
- if (!LOS_ListEmpty(&queueCB->readWriteList[OS_QUEUE_READ])) {
- ret = LOS_ERRNO_QUEUE_IN_TSKUSE;
- goto QUEUE_END;
- }
-
- if (!LOS_ListEmpty(&queueCB->readWriteList[OS_QUEUE_WRITE])) {
- ret = LOS_ERRNO_QUEUE_IN_TSKUSE;
- goto QUEUE_END;
- }
-
- if (!LOS_ListEmpty(&queueCB->memList)) {
- ret = LOS_ERRNO_QUEUE_IN_TSKUSE;
- goto QUEUE_END;
- }
-
- if ((queueCB->readWriteableCnt[OS_QUEUE_WRITE] + queueCB->readWriteableCnt[OS_QUEUE_READ]) !=
- queueCB->queueLen) {
- ret = LOS_ERRNO_QUEUE_IN_TSKWRITE;
- goto QUEUE_END;
- }
-
- queue = queueCB->queueHandle;
- queueCB->queueHandle = NULL;
- queueCB->queueState = OS_QUEUE_UNUSED;
- queueCB->queueID = SET_QUEUE_ID(GET_QUEUE_COUNT(queueCB->queueID) + 1, GET_QUEUE_INDEX(queueCB->queueID));
- OsQueueDbgUpdateHook(queueCB->queueID, NULL);
-
- LOS_ListTailInsert(&FREE_QUEUE_LIST, &queueCB->readWriteList[OS_QUEUE_WRITE]);
- SCHEDULER_UNLOCK(intSave);
- OsHookCall(LOS_HOOK_TYPE_QUEUE_DELETE, queueCB);
- ret = LOS_MemFree(m_aucSysMem1, (VOID *)queue);
- return ret;
-
-QUEUE_END:
- SCHEDULER_UNLOCK(intSave);
- return ret;
-}
-
-LITE_OS_SEC_TEXT_MINOR UINT32 LOS_QueueInfoGet(UINT32 queueID, QUEUE_INFO_S *queueInfo)
-{
- UINT32 intSave;
- UINT32 ret = LOS_OK;
- LosQueueCB *queueCB = NULL;
- LosTaskCB *tskCB = NULL;
-
- if (queueInfo == NULL) {
- return LOS_ERRNO_QUEUE_PTR_NULL;
- }
-
- if (GET_QUEUE_INDEX(queueID) >= LOSCFG_BASE_IPC_QUEUE_LIMIT) {
- return LOS_ERRNO_QUEUE_INVALID;
- }
-
- (VOID)memset_s((VOID *)queueInfo, sizeof(QUEUE_INFO_S), 0, sizeof(QUEUE_INFO_S));
- SCHEDULER_LOCK(intSave);
-
- queueCB = (LosQueueCB *)GET_QUEUE_HANDLE(queueID);
- if ((queueCB->queueID != queueID) || (queueCB->queueState == OS_QUEUE_UNUSED)) {
- ret = LOS_ERRNO_QUEUE_NOT_CREATE;
- goto QUEUE_END;
- }
-
- queueInfo->uwQueueID = queueID;
- queueInfo->usQueueLen = queueCB->queueLen;
- queueInfo->usQueueSize = queueCB->queueSize;
- queueInfo->usQueueHead = queueCB->queueHead;
- queueInfo->usQueueTail = queueCB->queueTail;
- queueInfo->usReadableCnt = queueCB->readWriteableCnt[OS_QUEUE_READ];
- queueInfo->usWritableCnt = queueCB->readWriteableCnt[OS_QUEUE_WRITE];
-
- LOS_DL_LIST_FOR_EACH_ENTRY(tskCB, &queueCB->readWriteList[OS_QUEUE_READ], LosTaskCB, pendList) {
- queueInfo->uwWaitReadTask |= 1ULL << tskCB->taskID;
- }
-
- LOS_DL_LIST_FOR_EACH_ENTRY(tskCB, &queueCB->readWriteList[OS_QUEUE_WRITE], LosTaskCB, pendList) {
- queueInfo->uwWaitWriteTask |= 1ULL << tskCB->taskID;
- }
-
- LOS_DL_LIST_FOR_EACH_ENTRY(tskCB, &queueCB->memList, LosTaskCB, pendList) {
- queueInfo->uwWaitMemTask |= 1ULL << tskCB->taskID;
- }
-
-QUEUE_END:
- SCHEDULER_UNLOCK(intSave);
- return ret;
-}
-
-#endif /* LOSCFG_BASE_IPC_QUEUE */
-
+/**
+ * @file los_queue.c
+ * @brief
+ * @verbatim
+ 基本概念
+ 队列又称消息队列,是一种常用于任务间通信的数据结构。队列接收来自任务或中断的
+ 不固定长度消息,并根据不同的接口确定传递的消息是否存放在队列空间中。
+
+ 任务能够从队列里面读取消息,当队列中的消息为空时,挂起读取任务;当队列中有新消息时,
+ 挂起的读取任务被唤醒并处理新消息。任务也能够往队列里写入消息,当队列已经写满消息时,
+ 挂起写入任务;当队列中有空闲消息节点时,挂起的写入任务被唤醒并写入消息。如果将
+ 读队列和写队列的超时时间设置为0,则不会挂起任务,接口会直接返回,这就是非阻塞模式。
+
+ 消息队列提供了异步处理机制,允许将一个消息放入队列,但不立即处理。同时队列还有缓冲消息的作用。
+
+ 队列特性
+ 消息以先进先出的方式排队,支持异步读写。
+ 读队列和写队列都支持超时机制。
+ 每读取一条消息,就会将该消息节点设置为空闲。
+ 发送消息类型由通信双方约定,可以允许不同长度(不超过队列的消息节点大小)的消息。
+ 一个任务能够从任意一个消息队列接收和发送消息。
+ 多个任务能够从同一个消息队列接收和发送消息。
+ 创建队列时所需的队列空间,默认支持接口内系统自行动态申请内存的方式,同时也支持将用户分配的队列空间作为接口入参传入的方式。
+
+ 队列运作原理
+ 创建队列时,创建队列成功会返回队列ID。
+
+ 在队列控制块中维护着一个消息头节点位置Head和一个消息尾节点位置Tail来,用于表示当前
+ 队列中消息的存储情况。Head表示队列中被占用的消息节点的起始位置。Tail表示被占用的
+ 消息节点的结束位置,也是空闲消息节点的起始位置。队列刚创建时,Head和Tail均指向队列起始位置。
+
+ 写队列时,根据readWriteableCnt[1]判断队列是否可以写入,不能对已满(readWriteableCnt[1]为0)
+ 队列进行写操作。写队列支持两种写入方式:向队列尾节点写入,也可以向队列头节点写入。尾节点写入时,
+ 根据Tail找到起始空闲消息节点作为数据写入对象,如果Tail已经指向队列尾部则采用回卷方式。头节点写入时,
+ 将Head的前一个节点作为数据写入对象,如果Head指向队列起始位置则采用回卷方式。
+
+ 读队列时,根据readWriteableCnt[0]判断队列是否有消息需要读取,对全部空闲(readWriteableCnt[0]为0)
+ 队列进行读操作会引起任务挂起。如果队列可以读取消息,则根据Head找到最先写入队列的消息节点进行读取。
+ 如果Head已经指向队列尾部则采用回卷方式。
+
+ 删除队列时,根据队列ID找到对应队列,把队列状态置为未使用,把队列控制块置为初始状态。
+ 如果是通过系统动态申请内存方式创建的队列,还会释放队列所占内存。
+
+ 使用场景
+ 队列用于任务间通信,可以实现消息的异步处理。同时消息的发送方和接收方不需要彼此联系,两者间是解耦的。
+
+ 队列错误码
+ 对存在失败可能性的操作返回对应的错误码,以便快速定位错误原因。
+ * @endverbatim
+ */
+
+
+/*
+ * 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,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "los_queue_pri.h"
+#include "los_queue_debug_pri.h"
+#include "los_task_pri.h"
+#include "los_sched_pri.h"
+#include "los_spinlock.h"
+#include "los_mp.h"
+#include "los_percpu_pri.h"
+#include "los_hook.h"
+#ifdef LOSCFG_IPC_CONTAINER
+#include "los_ipc_container_pri.h"
+#endif
+
+#ifdef LOSCFG_BASE_IPC_QUEUE
+#if (LOSCFG_BASE_IPC_QUEUE_LIMIT <= 0)
+#error "queue maxnum cannot be zero"
+#endif /* LOSCFG_BASE_IPC_QUEUE_LIMIT <= 0 */
+
+#ifndef LOSCFG_IPC_CONTAINER
+LITE_OS_SEC_BSS LosQueueCB *g_allQueue = NULL;///< 消息队列池
+LITE_OS_SEC_BSS STATIC LOS_DL_LIST g_freeQueueList;///< 空闲队列链表,管分配的,需要队列从这里申请
+#define FREE_QUEUE_LIST g_freeQueueList
+#endif
+
+LITE_OS_SEC_TEXT_INIT LosQueueCB *OsAllQueueCBInit(LOS_DL_LIST *freeQueueList)
+{
+ UINT32 index;
+
+ if (freeQueueList == NULL) {
+ return NULL;
+ }
+
+ UINT32 size = LOSCFG_BASE_IPC_QUEUE_LIMIT * sizeof(LosQueueCB);
+ /* system resident memory, don't free */
+ LosQueueCB *allQueue = (LosQueueCB *)LOS_MemAlloc(m_aucSysMem0, size);
+ if (allQueue == NULL) {
+ return NULL;
+ }
+ (VOID)memset_s(allQueue, size, 0, size);
+ LOS_ListInit(freeQueueList);
+ for (index = 0; index < LOSCFG_BASE_IPC_QUEUE_LIMIT; index++) {
+ LosQueueCB *queueNode = ((LosQueueCB *)allQueue) + index;
+ queueNode->queueID = index;
+ LOS_ListTailInsert(freeQueueList, &queueNode->readWriteList[OS_QUEUE_WRITE]);
+ }
+
+#ifndef LOSCFG_IPC_CONTAINER
+ if (OsQueueDbgInitHook() != LOS_OK) {
+ (VOID)LOS_MemFree(m_aucSysMem0, allQueue);
+ return NULL;
+ }
+#endif
+ return allQueue;
+}
+/*
+ * Description : queue initial | 消息队列模块初始化
+ * Return : LOS_OK on success or error code on failure
+ */
+LITE_OS_SEC_TEXT_INIT UINT32 OsQueueInit(VOID)
+{
+#ifndef LOSCFG_IPC_CONTAINER
+ g_allQueue = OsAllQueueCBInit(&g_freeQueueList);
+ if (g_allQueue == NULL) {
+ return LOS_ERRNO_QUEUE_NO_MEMORY;
+ }
+#endif
+ return LOS_OK;
+}
+///创建一个队列,根据用户传入队列长度和消息节点大小来开辟相应的内存空间以供该队列使用,参数queueID带走队列ID
+LITE_OS_SEC_TEXT_INIT UINT32 LOS_QueueCreate(CHAR *queueName, UINT16 len, UINT32 *queueID,
+ UINT32 flags, UINT16 maxMsgSize)
+{
+ LosQueueCB *queueCB = NULL;
+ UINT32 intSave;
+ LOS_DL_LIST *unusedQueue = NULL;
+ UINT8 *queue = NULL;
+ UINT16 msgSize;
+
+ (VOID)queueName;
+ (VOID)flags;
+
+ if (queueID == NULL) {
+ return LOS_ERRNO_QUEUE_CREAT_PTR_NULL;
+ }
+
+ if (maxMsgSize > (OS_NULL_SHORT - sizeof(UINT32))) {// maxMsgSize上限 为啥要减去 sizeof(UINT32) ,因为前面存的是队列的大小
+ return LOS_ERRNO_QUEUE_SIZE_TOO_BIG;
+ }
+
+ if ((len == 0) || (maxMsgSize == 0)) {
+ return LOS_ERRNO_QUEUE_PARA_ISZERO;
+ }
+
+ msgSize = maxMsgSize + sizeof(UINT32);//总size = 消息体内容长度 + 消息大小(UINT32)
+ /*
+ * Memory allocation is time-consuming, to shorten the time of disable interrupt,
+ * move the memory allocation to here.
+ *///内存分配非常耗时,为了缩短禁用中断的时间,将内存分配移到此处,用的时候分配队列内存
+ queue = (UINT8 *)LOS_MemAlloc(m_aucSysMem1, (UINT32)len * msgSize);//从系统内存池中分配,由这里提供读写队列的内存
+ if (queue == NULL) {//这里是一次把队列要用到的所有最大内存都申请下来了,能保证不会出现后续使用过程中内存不够的问题出现
+ return LOS_ERRNO_QUEUE_CREATE_NO_MEMORY;//调用处有 OsSwtmrInit sys_mbox_new DoMqueueCreate ==
+ }
+
+ SCHEDULER_LOCK(intSave);
+ if (LOS_ListEmpty(&FREE_QUEUE_LIST)) {//没有空余的队列ID的处理,注意软时钟定时器是由 g_swtmrCBArray统一管理的,里面有正在使用和可分配空闲的队列
+ SCHEDULER_UNLOCK(intSave);//g_freeQueueList是管理可用于分配的队列链表,申请消息队列的ID需要向它要
+ OsQueueCheckHook();
+ (VOID)LOS_MemFree(m_aucSysMem1, queue);//没有就要释放 queue申请的内存
+ return LOS_ERRNO_QUEUE_CB_UNAVAILABLE;
+ }
+
+ unusedQueue = LOS_DL_LIST_FIRST(&FREE_QUEUE_LIST);//找到一个没有被使用的队列
LOS_ListDelete(unusedQueue);//将自己从g_freeQueueList中摘除, unusedQueue只是个 LOS_DL_LIST 结点.
+ queueCB = GET_QUEUE_LIST(unusedQueue);//通过unusedQueue找到整个消息队列(LosQueueCB)
+ queueCB->queueLen = len; //队列中消息的总个数,注意这个一旦创建是不能变的.
+ queueCB->queueSize = msgSize;//消息节点的大小,注意这个一旦创建也是不能变的.
+ queueCB->queueHandle = queue; //队列句柄,队列内容存储区.
+ queueCB->queueState = OS_QUEUE_INUSED; //队列状态使用中
+ queueCB->readWriteableCnt[OS_QUEUE_READ] = 0;//可读资源计数,OS_QUEUE_READ(0):可读.
+ queueCB->readWriteableCnt[OS_QUEUE_WRITE] = len;//可些资源计数 OS_QUEUE_WRITE(1):可写, 默认len可写.
+ queueCB->queueHead = 0;//队列头节点
+ queueCB->queueTail = 0;//队列尾节点
+ LOS_ListInit(&queueCB->readWriteList[OS_QUEUE_READ]);//初始化可读队列任务链表
+ LOS_ListInit(&queueCB->readWriteList[OS_QUEUE_WRITE]);//初始化可写队列任务链表
+ LOS_ListInit(&queueCB->memList);//
+
+ OsQueueDbgUpdateHook(queueCB->queueID, OsCurrTaskGet()->taskEntry);//在创建或删除队列调试信息时更新任务条目
+ SCHEDULER_UNLOCK(intSave);
+
+ *queueID = queueCB->queueID;//带走队列ID
+ OsHookCall(LOS_HOOK_TYPE_QUEUE_CREATE, queueCB);
+ return LOS_OK;
+}
+///读队列参数检查
+STATIC LITE_OS_SEC_TEXT UINT32 OsQueueReadParameterCheck(UINT32 queueID, const VOID *bufferAddr,
+ const UINT32 *bufferSize, UINT32 timeout)
+{
+ if (GET_QUEUE_INDEX(queueID) >= LOSCFG_BASE_IPC_QUEUE_LIMIT) {//队列ID不能超上限
+ return LOS_ERRNO_QUEUE_INVALID;
+ }
+ if ((bufferAddr == NULL) || (bufferSize == NULL)) {//缓存地址和大小参数判断
+ return LOS_ERRNO_QUEUE_READ_PTR_NULL;
+ }
+
+ if ((*bufferSize == 0) || (*bufferSize > (OS_NULL_SHORT - sizeof(UINT32)))) {//限制了读取数据的上限64K, sizeof(UINT32)代表的是队列的长度
+ return LOS_ERRNO_QUEUE_READSIZE_IS_INVALID; //所以要减去
+ }
+
+ OsQueueDbgTimeUpdateHook(queueID);
+
+ if (timeout != LOS_NO_WAIT) {//等待一定时间再读取
+ if (OS_INT_ACTIVE) {//如果碰上了硬中断
+ return LOS_ERRNO_QUEUE_READ_IN_INTERRUPT;//意思是:硬中断发生时是不能读消息队列的
+ }
+ }
+ return LOS_OK;
+}
+///写队列参数检查
+STATIC LITE_OS_SEC_TEXT UINT32 OsQueueWriteParameterCheck(UINT32 queueID, const VOID *bufferAddr,
+ const UINT32 *bufferSize, UINT32 timeout)
+{
+ if (GET_QUEUE_INDEX(queueID) >= LOSCFG_BASE_IPC_QUEUE_LIMIT) {//队列ID不能超上限
+ return LOS_ERRNO_QUEUE_INVALID;
+ }
+
+ if (bufferAddr == NULL) {//没有数据源
+ return LOS_ERRNO_QUEUE_WRITE_PTR_NULL;
+ }
+
+ if (*bufferSize == 0) {//这里没有限制写队列的大小,如果写入一个很大buf 会怎样?
+ return LOS_ERRNO_QUEUE_WRITESIZE_ISZERO;
+ }
+
+ OsQueueDbgTimeUpdateHook(queueID);
+
+ if (timeout != LOS_NO_WAIT) {
+ if (OS_INT_ACTIVE) {
+ return LOS_ERRNO_QUEUE_WRITE_IN_INTERRUPT;
+ }
+ }
+ return LOS_OK;
+}
+///队列buf操作,注意队列数据是按顺序来读取的,要不从头,要不从尾部,不会出现从中间读写,所有可由 head 和 tail 来管理队列.
+STATIC VOID OsQueueBufferOperate(LosQueueCB *queueCB, UINT32 operateType, VOID *bufferAddr, UINT32 *bufferSize)
+{
+ UINT8 *queueNode = NULL;
+ UINT32 msgDataSize;
+ UINT16 queuePosition;
+
+ /* get the queue position | 先找到队列的位置*/
+ switch (OS_QUEUE_OPERATE_GET(operateType)) {//获取操作类型
+ case OS_QUEUE_READ_HEAD://从列队头开始读
+ queuePosition = queueCB->queueHead;//拿到头部位置
+ ((queueCB->queueHead + 1) == queueCB->queueLen) ? (queueCB->queueHead = 0) : (queueCB->queueHead++);//调整队列头部位置
+ break;
+ case OS_QUEUE_WRITE_HEAD://从列队头开始写
+ (queueCB->queueHead == 0) ? (queueCB->queueHead = queueCB->queueLen - 1) : (--queueCB->queueHead);//调整队列头部位置
+ queuePosition = queueCB->queueHead;//拿到头部位置
+ break;
+ case OS_QUEUE_WRITE_TAIL://从列队尾部开始写
+ queuePosition = queueCB->queueTail;//设置队列位置为尾部位置
+ ((queueCB->queueTail + 1) == queueCB->queueLen) ? (queueCB->queueTail = 0) : (queueCB->queueTail++);//调整队列尾部位置
+ break;
+ default: /* read tail, reserved. */
+ PRINT_ERR("invalid queue operate type!\n");
+ return;
+ }
+ //queueHandle是create队列时,由外界参数申请的一块内存. 用于copy 使用
+ queueNode = &(queueCB->queueHandle[(queuePosition * (queueCB->queueSize))]);//拿到队列节点
+
+ if (OS_QUEUE_IS_READ(operateType)) {//读操作处理,读队列分两步走
+ if (memcpy_s(&msgDataSize, sizeof(UINT32), queueNode + queueCB->queueSize - sizeof(UINT32),
+ sizeof(UINT32)) != EOK) {//1.先读出队列大小,由队列头四个字节表示
+ PRINT_ERR("get msgdatasize failed\n");
+ return;
+ }
+ msgDataSize = (*bufferSize < msgDataSize) ? *bufferSize : msgDataSize;
+ if (memcpy_s(bufferAddr, *bufferSize, queueNode, msgDataSize) != EOK) {//2.读表示读走已有数据,所以相当于bufferAddr接着了queueNode的数据
+ PRINT_ERR("copy message to buffer failed\n");
+ return;
+ }
+
+ *bufferSize = msgDataSize;//通过入参 带走消息的大小
+ } else {//只有读写两种操作,这里就是写队列了.写也分两步走 , @note_thinking 这里建议鸿蒙加上 OS_QUEUE_IS_WRITE 判断
+ if (memcpy_s(queueNode, queueCB->queueSize, bufferAddr, *bufferSize) != EOK) {//1.写入消息内容
+ PRINT_ERR("store message failed\n");//表示把外面数据写进来,所以相当于queueNode接着了bufferAddr的数据
+ return;
+ }
+ if (memcpy_s(queueNode + queueCB->queueSize - sizeof(UINT32), sizeof(UINT32), bufferSize,
+ sizeof(UINT32)) != EOK) {//2.写入消息数据的长度,sizeof(UINT32)
+ PRINT_ERR("store message size failed\n");
+ return;
+ }
+ }
+}
+///队列操作参数检查
+STATIC UINT32 OsQueueOperateParamCheck(const LosQueueCB *queueCB, UINT32 queueID,
+ UINT32 operateType, const UINT32 *bufferSize)
+{
+ if ((queueCB->queueID != queueID) || (queueCB->queueState == OS_QUEUE_UNUSED)) {//队列ID和状态判断
+ return LOS_ERRNO_QUEUE_NOT_CREATE;
+ }
+
+ if (OS_QUEUE_IS_WRITE(operateType) && (*bufferSize > (queueCB->queueSize - sizeof(UINT32)))) {//写时判断
+ return LOS_ERRNO_QUEUE_WRITE_SIZE_TOO_BIG;//塞进来的数据太大,大于队列节点能承受的范围
+ }
+ return LOS_OK;
+}
+
+/**
+ * @brief 队列操作.是读是写由operateType定
+ 本函数是消息队列最重要的一个函数,可以分析出读取消息过程中
+ 发生的细节,涉及任务的唤醒和阻塞,阻塞链表任务的相互提醒.
+ * @param queueID
+ * @param operateType
+ * @param bufferAddr
+ * @param bufferSize
+ * @param timeout
+ * @return UINT32
+ */
+UINT32 OsQueueOperate(UINT32 queueID, UINT32 operateType, VOID *bufferAddr, UINT32 *bufferSize, UINT32 timeout)
+{
+ UINT32 ret;
+ UINT32 readWrite = OS_QUEUE_READ_WRITE_GET(operateType);//获取读/写操作标识
+ UINT32 intSave;
+ OsHookCall(LOS_HOOK_TYPE_QUEUE_READ, (LosQueueCB *)GET_QUEUE_HANDLE(queueID), operateType, *bufferSize, timeout);
+
+ SCHEDULER_LOCK(intSave);
+ LosQueueCB *queueCB = (LosQueueCB *)GET_QUEUE_HANDLE(queueID);//获取对应的队列控制块
+ ret = OsQueueOperateParamCheck(queueCB, queueID, operateType, bufferSize);//参数检查
+ if (ret != LOS_OK) {
+ goto QUEUE_END;
+ }
+
+ if (queueCB->readWriteableCnt[readWrite] == 0) {//根据readWriteableCnt判断队列是否有消息读/写
+ if (timeout == LOS_NO_WAIT) {//不等待直接退出
+ ret = OS_QUEUE_IS_READ(operateType) ? LOS_ERRNO_QUEUE_ISEMPTY : LOS_ERRNO_QUEUE_ISFULL;
+ goto QUEUE_END;
+ }
+
+ if (!OsPreemptableInSched()) {//不支持抢占式调度
+ ret = LOS_ERRNO_QUEUE_PEND_IN_LOCK;
+ goto QUEUE_END;
+ }
+ //任务等待,这里很重要啊,将自己从就绪列表摘除,让出了CPU并发起了调度,并挂在readWriteList[readWrite]上,挂的都等待读/写消息的task
+ LosTaskCB *runTask = OsCurrTaskGet();
+ OsTaskWaitSetPendMask(OS_TASK_WAIT_QUEUE, queueCB->queueID, timeout);
+ ret = runTask->ops->wait(runTask, &queueCB->readWriteList[readWrite], timeout);
+ if (ret == LOS_ERRNO_TSK_TIMEOUT) {//唤醒后如果超时了,返回读/写消息失败
+ ret = LOS_ERRNO_QUEUE_TIMEOUT;
+ goto QUEUE_END;//
+ }
+ } else {
+ queueCB->readWriteableCnt[readWrite]--;//对应队列中计数器--,说明一条消息只能被读/写一次
+ }
+
+ OsQueueBufferOperate(queueCB, operateType, bufferAddr, bufferSize);//发起读或写队列操作
+
+ if (!LOS_ListEmpty(&queueCB->readWriteList[!readWrite])) {//如果还有任务在排着队等待读/写入消息(当时不能读/写的原因有可能当时队列满了==)
+ LosTaskCB *resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&queueCB->readWriteList[!readWrite]));//取出要读/写消息的任务
+ OsTaskWakeClearPendMask(resumedTask);
+ resumedTask->ops->wake(resumedTask);
+ SCHEDULER_UNLOCK(intSave);
+ LOS_MpSchedule(OS_MP_CPU_ALL);//让所有CPU发出调度申请,因为很可能那个要读/写消息的队列是由其他CPU执行
+ LOS_Schedule();//申请调度
+ return LOS_OK;
+ } else {
+ queueCB->readWriteableCnt[!readWrite]++;//对应队列读/写中计数器++
+ }
+
+QUEUE_END:
+ SCHEDULER_UNLOCK(intSave);
+ return ret;
+}
+///接口函数定时读取消息队列
+LITE_OS_SEC_TEXT UINT32 LOS_QueueReadCopy(UINT32 queueID,
+ VOID *bufferAddr,
+ UINT32 *bufferSize,
+ UINT32 timeout)
+{
+ UINT32 ret;
+ UINT32 operateType;
+
+ ret = OsQueueReadParameterCheck(queueID, bufferAddr, bufferSize, timeout);//参数检查
+ if (ret != LOS_OK) {
+ return ret;
+ }
+
+ operateType = OS_QUEUE_OPERATE_TYPE(OS_QUEUE_READ, OS_QUEUE_HEAD);//从头开始读
+ return OsQueueOperate(queueID, operateType, bufferAddr, bufferSize, timeout);//定时执行读操作
+}
+///接口函数从队列头开始写
+LITE_OS_SEC_TEXT UINT32 LOS_QueueWriteHeadCopy(UINT32 queueID,
+ VOID *bufferAddr,
+ UINT32 bufferSize,
+ UINT32 timeout)
+{
+ UINT32 ret;
+ UINT32 operateType;
+
+ ret = OsQueueWriteParameterCheck(queueID, bufferAddr, &bufferSize, timeout);//参数检查
+ if (ret != LOS_OK) {
+ return ret;
+ }
+
+ operateType = OS_QUEUE_OPERATE_TYPE(OS_QUEUE_WRITE, OS_QUEUE_HEAD);//从头开始写
+ return OsQueueOperate(queueID, operateType, bufferAddr, &bufferSize, timeout);//执行写操作
+}
+///接口函数 从队列尾部开始写
+LITE_OS_SEC_TEXT UINT32 LOS_QueueWriteCopy(UINT32 queueID,
+ VOID *bufferAddr,
+ UINT32 bufferSize,
+ UINT32 timeout)
+{
+ UINT32 ret;
+ UINT32 operateType;
+
+ ret = OsQueueWriteParameterCheck(queueID, bufferAddr, &bufferSize, timeout);//参数检查
+ if (ret != LOS_OK) {
+ return ret;
+ }
+
+ operateType = OS_QUEUE_OPERATE_TYPE(OS_QUEUE_WRITE, OS_QUEUE_TAIL);//从尾部开始写
+ return OsQueueOperate(queueID, operateType, bufferAddr, &bufferSize, timeout);//执行写操作
+}
+
+/**
+ * @brief
+ * @verbatim
+ 外部接口 读一个队列数据
+ 读队列时,根据Head找到最先写入队列中的消息节点进行读取。如果Head已经指向队列尾则采用回卷方式。
+ 根据usReadableCnt判断队列是否有消息读取,对全部空闲(usReadableCnt为0)队列进行读队列操作会引起任务挂起。
+ * @endverbatim
+ */
+LITE_OS_SEC_TEXT UINT32 LOS_QueueRead(UINT32 queueID, VOID *bufferAddr, UINT32 bufferSize, UINT32 timeout)
+{
+ return LOS_QueueReadCopy(queueID, bufferAddr, &bufferSize, timeout);
+}
+
+/**
+ * @brief
+ * @verbatim
+ 外部接口 写一个队列数据
+ 根据Tail找到被占用消息节点末尾的空闲节点作为数据写入对象。如果Tail已经指向队列尾则采用回卷方式。
+ 根据usWritableCnt判断队列是否可以写入,不能对已满(usWritableCnt为0)队列进行写队列操作
+ * @endverbatim
+ */
+LITE_OS_SEC_TEXT UINT32 LOS_QueueWrite(UINT32 queueID, VOID *bufferAddr, UINT32 bufferSize, UINT32 timeout)
+{
+ if (bufferAddr == NULL) {
+ return LOS_ERRNO_QUEUE_WRITE_PTR_NULL;
+ }
+ bufferSize = sizeof(CHAR *);
+ return LOS_QueueWriteCopy(queueID, &bufferAddr, bufferSize, timeout);
+}
+
+/**
+ * @brief
+ * @verbatim
+ 外部接口 从头部写入
+ 写队列时,根据Tail找到被占用消息节点末尾的空闲节点作为数据写入对象。如果Tail已经指向队列尾则采用回卷方式。
+ 根据usWritableCnt判断队列是否可以写入,不能对已满(usWritableCnt为0)队列进行写队列操作
+ * @endverbatim
+ */
+LITE_OS_SEC_TEXT UINT32 LOS_QueueWriteHead(UINT32 queueID,
+ VOID *bufferAddr,
+ UINT32 bufferSize,
+ UINT32 timeout)
+{
+ if (bufferAddr == NULL) {
+ return LOS_ERRNO_QUEUE_WRITE_PTR_NULL;
+ }
+ bufferSize = sizeof(CHAR *);
+ return LOS_QueueWriteHeadCopy(queueID, &bufferAddr, bufferSize, timeout);
+}
+
+/**
+ * @brief
+ * @verbatim
+ 外部接口 删除队列,还有任务要读/写消息时不能删除
+ 删除队列时,根据传入的队列ID寻找到对应的队列,把队列状态置为未使用,
+ 释放原队列所占的空间,对应的队列控制头置为初始状态。
+ * @endverbatim
+ */
+LITE_OS_SEC_TEXT_INIT UINT32 LOS_QueueDelete(UINT32 queueID)
+{
+ LosQueueCB *queueCB = NULL;
+ UINT8 *queue = NULL;
+ UINT32 intSave;
+ UINT32 ret;
+
+ if (GET_QUEUE_INDEX(queueID) >= LOSCFG_BASE_IPC_QUEUE_LIMIT) {
+ return LOS_ERRNO_QUEUE_NOT_FOUND;
+ }
+
+ SCHEDULER_LOCK(intSave);
+ queueCB = (LosQueueCB *)GET_QUEUE_HANDLE(queueID);//拿到队列实体
+ if ((queueCB->queueID != queueID) || (queueCB->queueState == OS_QUEUE_UNUSED)) {
+ ret = LOS_ERRNO_QUEUE_NOT_CREATE;
+ goto QUEUE_END;
+ }
+
+ if (!LOS_ListEmpty(&queueCB->readWriteList[OS_QUEUE_READ])) {//尚有任务要读数据
+ ret = LOS_ERRNO_QUEUE_IN_TSKUSE;
+ goto QUEUE_END;
+ }
+
+ if (!LOS_ListEmpty(&queueCB->readWriteList[OS_QUEUE_WRITE])) {//尚有任务要写数据
+ ret = LOS_ERRNO_QUEUE_IN_TSKUSE;
+ goto QUEUE_END;
+ }
+
+ if (!LOS_ListEmpty(&queueCB->memList)) {//
+ ret = LOS_ERRNO_QUEUE_IN_TSKUSE;
+ goto QUEUE_END;
+ }
+
+ if ((queueCB->readWriteableCnt[OS_QUEUE_WRITE] + queueCB->readWriteableCnt[OS_QUEUE_READ]) !=
+ queueCB->queueLen) {//读写队列的内容长度不等于总长度
+ ret = LOS_ERRNO_QUEUE_IN_TSKWRITE;
+ goto QUEUE_END;
+ }
+
+ queue = queueCB->queueHandle; //队列buf
+ queueCB->queueHandle = NULL; //
+ queueCB->queueState = OS_QUEUE_UNUSED;//重置队列状态
+ queueCB->queueID = SET_QUEUE_ID(GET_QUEUE_COUNT(queueCB->queueID) + 1, GET_QUEUE_INDEX(queueCB->queueID));//@note_why 这里需要这样做吗?
+ OsQueueDbgUpdateHook(queueCB->queueID, NULL);
+
+ LOS_ListTailInsert(&FREE_QUEUE_LIST, &queueCB->readWriteList[OS_QUEUE_WRITE]);//回收,将节点挂入可分配链表,等待重新被分配再利用
+ SCHEDULER_UNLOCK(intSave);
+ OsHookCall(LOS_HOOK_TYPE_QUEUE_DELETE, queueCB);
+ ret = LOS_MemFree(m_aucSysMem1, (VOID *)queue);//释放队列句柄
+ return ret;
+
+QUEUE_END:
+ SCHEDULER_UNLOCK(intSave);
+ return ret;
+}
+///外部接口, 获取队列信息,用queueInfo 把 LosQueueCB数据接走,QUEUE_INFO_S对内部数据的封装
+LITE_OS_SEC_TEXT_MINOR UINT32 LOS_QueueInfoGet(UINT32 queueID, QUEUE_INFO_S *queueInfo)
+{
+ UINT32 intSave;
+ UINT32 ret = LOS_OK;
+ LosQueueCB *queueCB = NULL;
+ LosTaskCB *tskCB = NULL;
+
+ if (queueInfo == NULL) {
+ return LOS_ERRNO_QUEUE_PTR_NULL;
+ }
+
+ if (GET_QUEUE_INDEX(queueID) >= LOSCFG_BASE_IPC_QUEUE_LIMIT) {//1024
+ return LOS_ERRNO_QUEUE_INVALID;
+ }
+
+ (VOID)memset_s((VOID *)queueInfo, sizeof(QUEUE_INFO_S), 0, sizeof(QUEUE_INFO_S));//接走数据之前先清0
+ SCHEDULER_LOCK(intSave);
+
+ queueCB = (LosQueueCB *)GET_QUEUE_HANDLE(queueID);//通过队列ID获取 QCB
+ if ((queueCB->queueID != queueID) || (queueCB->queueState == OS_QUEUE_UNUSED)) {
+ ret = LOS_ERRNO_QUEUE_NOT_CREATE;
+ goto QUEUE_END;
+ }
+
+ queueInfo->uwQueueID = queueID;
+ queueInfo->usQueueLen = queueCB->queueLen;
+ queueInfo->usQueueSize = queueCB->queueSize;
+ queueInfo->usQueueHead = queueCB->queueHead;
+ queueInfo->usQueueTail = queueCB->queueTail;
+ queueInfo->usReadableCnt = queueCB->readWriteableCnt[OS_QUEUE_READ];//可读数
+ queueInfo->usWritableCnt = queueCB->readWriteableCnt[OS_QUEUE_WRITE];//可写数
+
+ LOS_DL_LIST_FOR_EACH_ENTRY(tskCB, &queueCB->readWriteList[OS_QUEUE_READ], LosTaskCB, pendList) {//找出哪些task需要读消息
+ queueInfo->uwWaitReadTask |= 1ULL << tskCB->taskID;//记录等待读消息的任务号, uwWaitReadTask 每一位代表一个任务编号
+ }//0b..011011011 代表 0,1,3,4,6,7 号任务有数据等待读消息.
+
+ LOS_DL_LIST_FOR_EACH_ENTRY(tskCB, &queueCB->readWriteList[OS_QUEUE_WRITE], LosTaskCB, pendList) {//找出哪些task需要写消息
+ queueInfo->uwWaitWriteTask |= 1ULL << tskCB->taskID;//记录等待写消息的任务号, uwWaitWriteTask 每一位代表一个任务编号
+ }////0b..011011011 代表 0,1,3,4,6,7 号任务有数据等待写消息.
+
+ LOS_DL_LIST_FOR_EACH_ENTRY(tskCB, &queueCB->memList, LosTaskCB, pendList) {//同上
+ queueInfo->uwWaitMemTask |= 1ULL << tskCB->taskID; //MailBox模块使用
+ }
+
+QUEUE_END:
+ SCHEDULER_UNLOCK(intSave);
+ return ret;
+}
+
+#endif /* (LOSCFG_BASE_IPC_QUEUE == YES) */
+
diff --git a/src/kernel_liteos_a/kernel/base/ipc/los_rwlock.c b/src/kernel_liteos_a/kernel/base/ipc/los_rwlock.c
index 546fe831..1cdda60f 100644
--- a/src/kernel_liteos_a/kernel/base/ipc/los_rwlock.c
+++ b/src/kernel_liteos_a/kernel/base/ipc/los_rwlock.c
@@ -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;
}
diff --git a/src/kernel_liteos_a/kernel/base/ipc/los_sem.c b/src/kernel_liteos_a/kernel/base/ipc/los_sem.c
index 31d484a1..9f3b43c4 100644
--- a/src/kernel_liteos_a/kernel/base/ipc/los_sem.c
+++ b/src/kernel_liteos_a/kernel/base/ipc/los_sem.c
@@ -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时,建议使用二值信号量,一种类似于互斥锁的机制。
+ 用作同步时,初始信号量计数值为0。任务1获取信号量而阻塞,直到任务2或者某中断释放信号量,任务1才得以进入Ready或Running态,从而达到了任务间的同步。
+
+ 信号量运作原理
+ 信号量初始化,为配置的N个信号量申请内存(N值可以由用户自行配置,通过LOSCFG_BASE_IPC_SEM_LIMIT宏实现),并把所有信号量初始化成未使用,
+ 加入到未使用链表中供系统使用。
+
+ 信号量创建,从未使用的信号量链表中获取一个信号量,并设定初值。
+
+ 信号量申请,若其计数器值大于0,则直接减1返回成功。否则任务阻塞,等待其它任务释放该信号量,等待的超时时间可设定。
+ 当任务被一个信号量阻塞时,将该任务挂到信号量等待任务队列的队尾。
+
+ 信号量释放,若没有任务等待该信号量,则直接将计数器加1返回。否则唤醒该信号量等待任务队列上的第一个任务。
+
+ 信号量删除,将正在使用的信号量置为未使用信号量,并挂回到未使用链表。
+
+ 信号量允许多个任务在同一时刻访问共享资源,但会限制同一时刻访问此资源的最大任务数目。当访问资源的任务数达到该资源允许的最大数量时,
+ 会阻塞其他试图获取该资源的任务,直到有任务释放该信号量。
+
+ 开发流程
+ 创建信号量LOS_SemCreate,若要创建二值信号量则调用LOS_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) */
diff --git a/src/kernel_liteos_a/kernel/base/ipc/los_sem_debug.c b/src/kernel_liteos_a/kernel/base/ipc/los_sem_debug.c
index 1ed42515..284a800d 100644
--- a/src/kernel_liteos_a/kernel/base/ipc/los_sem_debug.c
+++ b/src/kernel_liteos_a/kernel/base/ipc/los_sem_debug.c
@@ -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
diff --git a/src/kernel_liteos_a/kernel/base/ipc/los_signal.c b/src/kernel_liteos_a/kernel/base/ipc/los_signal.c
index bb7bd2f7..3a130e56 100644
--- a/src/kernel_liteos_a/kernel/base/ipc/los_signal.c
+++ b/src/kernel_liteos_a/kernel/base/ipc/los_signal.c
@@ -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 判定信号signo是否存在信号集中。如果信号集里已有该信号则返回1,否则返回0。如果有错误则返回-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_BLOCK:将set指向信号集中的信号,添加到进程阻塞信号集;
+ SIG_UNBLOCK:将set指向信号集中的信号,从进程阻塞信号集删除;
+ SIG_SETMASK:将set指向信号集中的信号,设置成进程阻塞信号集;
+ * @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 7(kill -14 7效果相同)
+ 发送信号14(SIGALRM默认行为为进程终止)给7号进程
+ * @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:信号的值,可以为除SIGKILL及SIGSTOP外的任何一个特定有效的信号(为这两个信号定义自己的处理函数,将导致信号安装错误)。
+ 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;
}
diff --git a/src/kernel_liteos_a/kernel/base/mem/membox/los_membox.c b/src/kernel_liteos_a/kernel/base/mem/membox/los_membox.c
index 4180d3bd..01328435 100644
--- a/src/kernel_liteos_a/kernel/base/mem/membox/los_membox.c
+++ b/src/kernel_liteos_a/kernel/base/mem/membox/los_membox.c
@@ -1,22 +1,35 @@
+/*!
+ * @file los_membox.c
+ * @brief 静态内存池主文件
+ * @link
+ @verbatim
+
+ 使用场景
+ 当用户需要使用固定长度的内存时,可以通过静态内存分配的方式获取内存,一旦使用完毕,
+ 通过静态内存释放函数归还所占用内存,使之可以重复使用。
+
+ 开发流程
+ 通过make menuconfig配置静态内存管理模块。
+ 规划一片内存区域作为静态内存池。
+ 调用LOS_MemboxInit初始化静态内存池。
+ 初始化会将入参指定的内存区域分割为N块(N值取决于静态内存总大小和块大小),将所有内存块挂到空闲链表,在内存起始处放置控制头。
+ 调用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.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this list of
- * conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice, this list
- * of conditions and the following disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 3. Neither the name of the copyright holder nor the names of its contributors may be used
- * to endorse or promote products derived from this software without specific prior written
- * permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CON/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
@@ -52,7 +65,7 @@
#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
#endif
@@ -62,7 +75,7 @@
((((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)) //节块 = (节头 + 节体) addr = 节体
/* spinlock for mem module, only available on SMP mode */
@@ -239,208 +252,3 @@ LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemboxStatisticsGet(const VOID *boxMem, UINT32
return LOS_OK;
}
-TRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "los_membox.h"
-#include "los_hwi.h"
-#include "los_spinlock.h"
-
-
-#ifdef LOSCFG_AARCH64
-#define OS_MEMBOX_MAGIC 0xa55a5aa5a55a5aa5
-#else
-#define OS_MEMBOX_MAGIC 0xa55a5aa5
-#endif
-#define OS_MEMBOX_SET_MAGIC(addr) \
- ((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))
-#define OS_MEMBOX_NODE_ADDR(addr) \
- ((LOS_MEMBOX_NODE *)(VOID *)((UINT8 *)(addr) - OS_MEMBOX_NODE_HEAD_SIZE))
-/* 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))
-
-STATIC INLINE UINT32 OsCheckBoxMem(const LOS_MEMBOX_INFO *boxInfo, const VOID *node)
-{
- UINT32 offset;
-
- if (boxInfo->uwBlkSize == 0) {
- return LOS_NOK;
- }
-
- offset = (UINT32)((UINTPTR)node - (UINTPTR)(boxInfo + 1));
- if ((offset % boxInfo->uwBlkSize) != 0) {
- return LOS_NOK;
- }
-
- if ((offset / boxInfo->uwBlkSize) >= boxInfo->uwBlkNum) {
- return LOS_NOK;
- }
-
- 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_NODE *node = NULL;
- UINT32 index;
- UINT32 intSave;
-
- if (pool == NULL) {
- return LOS_NOK;
- }
-
- if (blkSize == 0) {
- return LOS_NOK;
- }
-
- if (poolSize < sizeof(LOS_MEMBOX_INFO)) {
- return LOS_NOK;
- }
-
- 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) {
- MEMBOX_UNLOCK(intSave);
- return LOS_NOK;
- }
-
- node = (LOS_MEMBOX_NODE *)(boxInfo + 1);
-
- boxInfo->stFreeList.pstNext = node;
-
- for (index = 0; index < boxInfo->uwBlkNum - 1; ++index) {
- node->pstNext = OS_MEMBOX_NEXT(node, boxInfo->uwBlkSize);
- node = node->pstNext;
- }
-
- node->pstNext = NULL;
-
- MEMBOX_UNLOCK(intSave);
-
- return LOS_OK;
-}
-
-LITE_OS_SEC_TEXT VOID *LOS_MemboxAlloc(VOID *pool)
-{
- LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool;
- LOS_MEMBOX_NODE *node = NULL;
- LOS_MEMBOX_NODE *nodeTmp = NULL;
- UINT32 intSave;
-
- if (pool == NULL) {
- return NULL;
- }
-
- MEMBOX_LOCK(intSave);
- 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);
-}
-
-LITE_OS_SEC_TEXT UINT32 LOS_MemboxFree(VOID *pool, VOID *box)
-{
- LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool;
- UINT32 ret = LOS_NOK;
- UINT32 intSave;
-
- if ((pool == NULL) || (box == NULL)) {
- return LOS_NOK;
- }
-
- MEMBOX_LOCK(intSave);
- do {
- 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--;
- ret = LOS_OK;
- } 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;
-
- 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));
-}
-
-LITE_OS_SEC_TEXT_MINOR VOID LOS_ShowBox(VOID *pool)
-{
- UINT32 index;
- UINT32 intSave;
- LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool;
- LOS_MEMBOX_NODE *node = NULL;
-
- if (pool == NULL) {
- return;
- }
- MEMBOX_LOCK(intSave);
- PRINT_INFO("membox(%p,0x%x,0x%x):\r\n", pool, boxInfo->uwBlkSize, boxInfo->uwBlkNum);
- PRINT_INFO("free node list:\r\n");
-
- for (node = boxInfo->stFreeList.pstNext, index = 0; node != NULL;
- node = node->pstNext, ++index) {
- PRINT_INFO("(%u,%p)\r\n", index, node);
- }
-
- PRINT_INFO("all node list:\r\n");
- node = (LOS_MEMBOX_NODE *)(boxInfo + 1);
- for (index = 0; index < boxInfo->uwBlkNum; ++index, node = OS_MEMBOX_NEXT(node, boxInfo->uwBlkSize)) {
- PRINT_INFO("(%u,%p,%p)\r\n", index, node, node->pstNext);
- }
- MEMBOX_UNLOCK(intSave);
-}
-
-LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemboxStatisticsGet(const VOID *boxMem, UINT32 *maxBlk,
- UINT32 *blkCnt, UINT32 *blkSize)
-{
- if ((boxMem == NULL) || (maxBlk == NULL) || (blkCnt == NULL) || (blkSize == NULL)) {
- return LOS_NOK;
- }
-
- *maxBlk = ((OS_MEMBOX_S *)boxMem)->uwBlkNum;
- *blkCnt = ((OS_MEMBOX_S *)boxMem)->uwBlkCnt;
- *blkSize = ((OS_MEMBOX_S *)boxMem)->uwBlkSize;
-
- return LOS_OK;
-}
-
diff --git a/src/kernel_liteos_a/kernel/base/mem/tlsf/los_memory.c b/src/kernel_liteos_a/kernel/base/mem/tlsf/los_memory.c
index 5086ca7b..cfd75971 100644
--- a/src/kernel_liteos_a/kernel/base/mem/tlsf/los_memory.c
+++ b/src/kernel_liteos_a/kernel/base/mem/tlsf/los_memory.c
@@ -1,3 +1,51 @@
+/*!
+ * @file los_memory.c
+ * @brief
+ * @link tlsf算法论文 http://www.gii.upv.es/tlsf/files/ecrts04_tlsf.pdf @endlink
+ @verbatim
+ https://www.codenong.com/cs106845116/ TLSF算法(一)分配中的位图计算
+ 基本概念
+ 内存管理模块管理系统的内存资源,它是操作系统的核心模块之一,主要包括内存的初始化、分配以及释放。
+ OpenHarmony LiteOS-A的堆内存管理提供内存初始化、分配、释放等功能。在系统运行过程中,堆内存管理
+ 模块通过对内存的申请/释放来管理用户和OS对内存的使用,使内存的利用率和使用效率达到最优,同时最大限度地解决系统的内存碎片问题。
+
+ 运行机制
+ 堆内存管理,即在内存资源充足的情况下,根据用户需求,从系统配置的一块比较大的连续内存
+ (内存池,也是堆内存)中分配任意大小的内存块。当用户不需要该内存块时,又可以释放回系统供下一次使用。
+ 与静态内存相比,动态内存管理的优点是按需分配,缺点是内存池中容易出现碎片。
+ OpenHarmony LiteOS-A堆内存在TLSF算法的基础上,对区间的划分进行了优化,获得更优的性能,降低了碎片率。
+ 动态内存核心算法框图如下:
+ @endverbatim
+ * @image html https://gitee.com/weharmonyos/resources/raw/master/11/1.png
+ @verbatim
+ 根据空闲内存块的大小,使用多个空闲链表来管理。根据内存空闲块大小分为两个部分:[4, 127]和[27, 231],如上图size class所示:
+
+ 1. 对[4,127]区间的内存进行等分,如上图下半部分所示,分为31个小区间,每个小区间对应内存块大小为4字节的倍数。
+ 每个小区间对应一个空闲内存链表和用于标记对应空闲内存链表是否为空的一个比特位,值为1时,空闲链表非空。
+ [4,127]区间的31个小区间内存对应31个比特位进行标记链表是否为空。
+ 2. 大于127字节的空闲内存块,按照2的次幂区间大小进行空闲链表管理。总共分为24个小区间,每个小区间又等分为8个二级小区间,
+ 见上图上半部分的Size Class和Size SubClass部分。每个二级小区间对应一个空闲链表和用于标记对应空闲内存链表是否为空的一个比特位。
+ 总共24*8=192个二级小区间,对应192个空闲链表和192个比特位进行标记链表是否为空。
+ 例如,当有40字节的空闲内存需要插入空闲链表时,对应小区间[40,43],第10个空闲链表,位图标记的第10比特位。
+ 把40字节的空闲内存挂载第10个空闲链表上,并判断是否需要更新位图标记。当需要申请40字节的内存时,
+ 根据位图标记获取存在满足申请大小的内存块的空闲链表,从空闲链表上获取空闲内存节点。如果分配的节点大于需要申请的内存大小,
+ 进行分割节点操作,剩余的节点重新挂载到相应的空闲链表上。当有580字节的空闲内存需要插入空闲链表时,对应二级小区间[29,29+2^6],
+ 第31+2*8=47个空闲链表,并使用位图的第47个比特位来标记链表是否为空。把580字节的空闲内存挂载第47个空闲链表上,并判断是否需要更新位图标记。
+ 当需要申请580字节的内存时,根据位图标记获取存在满足申请大小的内存块的空闲链表,从空闲链表上获取空闲内存节点。
+ 如果分配的节点大于需要申请的内存大小,进行分割节点操作,剩余的节点重新挂载到相应的空闲链表上。如果对应的空闲链表为空,
+ 则向更大的内存区间去查询是否有满足条件的空闲链表,实际计算时,会一次性查找到满足申请大小的空闲链表。
+
+ 内存信息包括内存池大小、内存使用量、剩余内存大小、最大空闲内存、内存水线、内存节点数统计、碎片率等。
+ 内存水线:即内存池的最大使用量,每次申请和释放时,都会更新水线值,实际业务可根据该值,优化内存池大小;
+ 碎片率:衡量内存池的碎片化程度,碎片率高表现为内存池剩余内存很多,但是最大空闲内存块很小,可以用公式(fragment=100-最大空闲内存块大小/剩余内存大小)来度量;
+
+ 内存管理结构如下图所示:
+ @endverbatim
+ * @image html https://gitee.com/weharmonyos/resources/raw/master/11/2.png
+ * @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.
@@ -57,7 +105,7 @@
#define OS_MEM_COLUMN_NUM 8
UINT8 *m_aucSysMem0 = NULL; ///< 异常交互动态内存池地址的起始地址,当不支持异常交互特性时,m_aucSysMem0等于m_aucSysMem1。
-UINT8 *m_aucSysMem1 = NULL; ///< (内核态)系统动态内存池地址的起始地址
+UINT8 *m_aucSysMem1 = NULL; ///< (内核态)系统动态内存池地址的起始地址 @note_thinking 能否不要用 0,1来命名核心变量 ???
#ifdef LOSCFG_MEM_MUL_POOL
VOID *g_poolHead = NULL; ///内存池头,由它牵引多个内存池
@@ -241,8 +289,8 @@ STATIC INLINE VOID OsMemWaterUsedRecord(struct OsMemPoolHead *pool, UINT32 size)
#else
STATIC INLINE VOID OsMemWaterUsedRecord(struct OsMemPoolHead *pool, UINT32 size)
{
- (VOID)pool;
- (VOID)size;
+ (VOID)pool; // @note_thinking 为何要这么写 ,因为格式规范吗 ? 直接啥也不写不行吗 ?
+ (VOID)size; // 编译器会优化掉这种代码
}
#endif
diff --git a/src/kernel_liteos_a/kernel/base/misc/kill_shellcmd.c b/src/kernel_liteos_a/kernel/base/misc/kill_shellcmd.c
index e21dca7d..ee4ac314 100644
--- a/src/kernel_liteos_a/kernel/base/misc/kill_shellcmd.c
+++ b/src/kernel_liteos_a/kernel/base/misc/kill_shellcmd.c
@@ -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],其余为保留内容。
+
+使用指南
+必须指定发送的信号编号及进程号。
+进程编号取值范围根据系统配置变化,例如系统最大支持pid为256,则取值范围缩小为[1-256]。
+*********************************************/
LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdKill(INT32 argc, const CHAR **argv)
{
#define ARG_NUM 2
diff --git a/src/kernel_liteos_a/kernel/base/misc/los_stackinfo.c b/src/kernel_liteos_a/kernel/base/misc/los_stackinfo.c
index 9eb7a9c0..ae3950dc 100644
--- a/src/kernel_liteos_a/kernel/base/misc/los_stackinfo.c
+++ b/src/kernel_liteos_a/kernel/base/misc/los_stackinfo.c
@@ -38,6 +38,31 @@
#include "shell.h"
#endif
+/**
+ * @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所有工作模式的栈数量
diff --git a/src/kernel_liteos_a/kernel/base/mp/los_mp.c b/src/kernel_liteos_a/kernel/base/mp/los_mp.c
index e2a13431..41825f20 100644
--- a/src/kernel_liteos_a/kernel/base/mp/los_mp.c
+++ b/src/kernel_liteos_a/kernel/base/mp/los_mp.c
@@ -1,3 +1,32 @@
+/*!
+ * @file los_mp.c
+ * @brief
+ * @link
+ * @verbatim
+ 多CPU核的操作系统3种处理模式(SMP+AMP+BMP) 鸿蒙实现的是 SMP 的方式
+ 非对称多处理(Asymmetric multiprocessing,AMP)每个CPU内核
+ 运行一个独立的操作系统或同一操作系统的独立实例(instantiation)。
+
+ 对称多处理(Symmetric multiprocessing,SMP)一个操作系统的实例
+ 可以同时管理所有CPU内核,且应用并不绑定某一个内核。
+
+ 混合多处理(Bound multiprocessing,BMP)一个操作系统的实例可以
+ 同时管理所有CPU内核,但每个应用被锁定于某个指定的核心。
+
+ 多核多线程处理器的中断
+ 由 PIC(Programmable Interrupt Controller)统一控制。PIC 允许一个
+ 硬件线程中断其他的硬件线程,这种方式被称为核间中断(Inter-Processor Interrupts,IPI)
+
+ SGI:软件触发中断(Software Generated Interrupt)。在arm处理器中,
+ SGI共有16个,硬件中断号分别为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.
@@ -101,7 +130,17 @@ VOID OsMpCollectTasks(VOID)
}
#ifdef LOSCFG_KERNEL_SMP_CALL
-
+/*!
+ * @brief OsMpFuncCall
+ * 向指定CPU的funcLink上注册回调函数, 该怎么理解这个函数呢 ? 具体有什么用呢 ?
+ * \n 可由CPU a核向b核发起一个请求,让b核去执行某个函数, 这是否是分布式调度的底层实现基础 ?
+ * @param args
+ * @param func
+ * @param target
+ * @return
+ *
+ * @see
+ */
VOID OsMpFuncCall(UINT32 target, SMP_FUNC_CALL func, VOID *args)
{
UINT32 index;
diff --git a/src/kernel_liteos_a/kernel/base/om/los_err.c b/src/kernel_liteos_a/kernel/base/om/los_err.c
index f3ad8a21..c8973dc5 100644
--- a/src/kernel_liteos_a/kernel/base/om/los_err.c
+++ b/src/kernel_liteos_a/kernel/base/om/los_err.c
@@ -32,6 +32,9 @@
#include "los_err.h"
/**
+ * @file los_err.c
+ * @brief
+ * @verbatim
基本概念
错误处理指程序运行错误时,调用错误处理模块的接口函数,上报错误信息,并调用注册的钩子函数
进行特定处理,保存现场以便定位问题。通过错误处理,可以控制和提示程序中的非法输入,防止程序崩溃。
@@ -41,6 +44,7 @@
此外,如果注册了相应的错误处理函数,则会执行这个函数。
系统中只有一个错误处理的钩子函数。当多次注册钩子函数时,最后一次注册的钩子函数会覆盖前一次注册的函数
+ * @endverbatim
*/
LITE_OS_SEC_BSS STATIC LOS_ERRORHANDLE_FUNC g_errHandleHook = NULL;///< 错误接管钩子函数
diff --git a/src/kernel_liteos_a/kernel/base/sched/los_idle.c b/src/kernel_liteos_a/kernel/base/sched/los_idle.c
index d2538595..0ba434dc 100644
--- a/src/kernel_liteos_a/kernel/base/sched/los_idle.c
+++ b/src/kernel_liteos_a/kernel/base/sched/los_idle.c
@@ -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,
diff --git a/src/kernel_liteos_a/kernel/base/sched/los_priority.c b/src/kernel_liteos_a/kernel/base/sched/los_priority.c
index 610ba119..5f1c858d 100644
--- a/src/kernel_liteos_a/kernel/base/sched/los_priority.c
+++ b/src/kernel_liteos_a/kernel/base/sched/los_priority.c
@@ -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) {
diff --git a/src/kernel_liteos_a/kernel/base/sched/los_sortlink.c b/src/kernel_liteos_a/kernel/base/sched/los_sortlink.c
index 4f68436f..7dcfce04 100644
--- a/src/kernel_liteos_a/kernel/base/sched/los_sortlink.c
+++ b/src/kernel_liteos_a/kernel/base/sched/los_sortlink.c
@@ -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)
diff --git a/src/kernel_liteos_a/kernel/base/vm/los_vm_boot.c b/src/kernel_liteos_a/kernel/base/vm/los_vm_boot.c
index 81287a26..b4b04eb1 100644
--- a/src/kernel_liteos_a/kernel/base/vm/los_vm_boot.c
+++ b/src/kernel_liteos_a/kernel/base/vm/los_vm_boot.c
@@ -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;
}
+
diff --git a/src/kernel_liteos_a/kernel/base/vm/los_vm_dump.c b/src/kernel_liteos_a/kernel/base/vm/los_vm_dump.c
index 1fbc80b9..c1b190b8 100644
--- a/src/kernel_liteos_a/kernel/base/vm/los_vm_dump.c
+++ b/src/kernel_liteos_a/kernel/base/vm/los_vm_dump.c
@@ -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,7 +158,7 @@ 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) {//遍历链表
@@ -170,9 +169,9 @@ UINT32 OsKProcessPmUsage(LosVmSpace *kSpace, UINT32 *actualPm)
}
(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;
@@ -194,7 +193,7 @@ UINT32 OsShellCmdProcessPmUsage(LosVmSpace *space, UINT32 *sharePm, UINT32 *actu
}
return OsUProcessPmUsage(space, sharePm, actualPm);
}
-///虚拟空间物理内存的使用情况,参数同时带走共享物理内存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);//ref 大于1 说明page被其他空间也引用了
+ shareRef = LOS_AtomicRead(&page->refCounts);//ref 大于1 说明page被其他空间也引用了,这就是共享内存核心定义!
if (shareRef > 1) {
if (sharePm != NULL) {
- *sharePm += PAGE_SIZE;//一页4K字节
+ *sharePm += PAGE_SIZE;//一页 4K 字节
}
pmSize += PAGE_SIZE / shareRef;
} else {
@@ -250,9 +249,7 @@ UINT32 OsUProcessPmUsage(LosVmSpace *space, UINT32 *sharePm, UINT32 *actualPm)
return pmSize;
}
-/// @brief 通过虚拟空间获取进程实体
-/// @param space
-/// @return
+///通过虚拟空间获取进程实体
LosProcessCB *OsGetPIDByAspace(const LosVmSpace *space)
{
UINT32 pid;
@@ -263,7 +260,7 @@ LosProcessCB *OsGetPIDByAspace(const LosVmSpace *space)
for (pid = 0; pid < g_processMaxNum; ++pid) {//循环进程池,进程池本质是个数组
processCB = g_processCBArray + pid;
if (OsProcessIsUnused(processCB)) {//进程还没被分配使用
- continue;
+ continue;//继续找呗
}
if (processCB->vmSpace == space) {//找到了
@@ -274,11 +271,7 @@ LosProcessCB *OsGetPIDByAspace(const LosVmSpace *space)
SCHEDULER_UNLOCK(intSave);
return NULL;
}
-/// @brief 统计虚拟空间中某个线性区的页数
-/// @param space
-/// @param region
-/// @param pssPages
-/// @return
+///统计虚拟空间中某个线性区的页数
UINT32 OsCountRegionPages(LosVmSpace *space, LosVmMapRegion *region, UINT32 *pssPages)
{
UINT32 regionPages = 0;
@@ -307,7 +300,7 @@ 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;
@@ -408,16 +401,16 @@ VOID OsDumpAspace(LosVmSpace *space)
if (pcb == NULL) {
return;
}
- //进程ID | 进程虚拟内存控制块地址信息 | 虚拟内存起始地址 | 虚拟内存大小 | 已使用的物理页数量
+ //进程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);
+
+ //虚拟区间控制块地址信息 | 虚拟区间类型 | 虚拟区间起始地址 | 虚拟区间大小 | 虚拟区间mmu映射属性 | 已使用的物理页数量(包括共享内存部分 | 已使用的物理页数量
- //虚拟区间控制块地址信息 | 虚拟区间类型 | 虚拟区间起始地址 | 虚拟区间大小 | 虚拟区间mmu映射属性 | 已使用的物理页数量(包括共享内存部分 | 已使用的物理页数量
-
- PRINTK("\r\n\t region name base size mmu_flags pages pg/ref\n");
+ PRINTK("\r\n\t region name base size mmu_flags pages pg/ref\n");
PRINTK("\t ------ ---- ---- ---- --------- ----- -----\n");
RB_SCAN_SAFE(&space->regionRbTree, pstRbNode, pstRbNodeNext)//按region 轮询统计
region = (LosVmMapRegion *)pstRbNode;
@@ -435,7 +428,7 @@ 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_FOR_EACH_ENTRY(space, aspaceList, LosVmSpace, node) {//循环取出进程虚拟空间
(VOID)LOS_MuxAcquire(&space->regionMux);
OsDumpAspace(space);//dump 空间
(VOID)LOS_MuxRelease(&space->regionMux);
diff --git a/src/kernel_liteos_a/kernel/base/vm/los_vm_fault.c b/src/kernel_liteos_a/kernel/base/vm/los_vm_fault.c
index 902f84ea..5e584ef9 100644
--- a/src/kernel_liteos_a/kernel/base/vm/los_vm_fault.c
+++ b/src/kernel_liteos_a/kernel/base/vm/los_vm_fault.c
@@ -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) {
@@ -96,7 +95,7 @@ STATIC VOID OsFaultTryFixup(ExcContext *frame, VADDR_T excVaddr, STATUS_T *statu
}
}
-#ifdef LOSCFG_FS_VFS
+#ifdef LOSCFG_FS_VFS
//读页时发生缺页的处理
STATIC STATUS_T OsDoReadFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault)//读缺页
{
@@ -141,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;
@@ -287,7 +286,7 @@ status_t OsDoSharedFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault)
return LOS_OK;
}
- //以下是没有映射到物理地址的处理
+ //以下是没有映射到物理地址的处理
(VOID)LOS_MuxAcquire(®ion->unTypeData.rf.vnode->mapping.mux_lock);
ret = region->unTypeData.rf.vmFOps->fault(region, vmPgFault);//函数指针,执行的是g_commVmOps.OsVmmFileFault
if (ret == LOS_OK) {
@@ -352,7 +351,7 @@ STATIC STATUS_T OsDoFileFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault, U
*/
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;
@@ -404,7 +403,7 @@ STATUS_T OsVmPageFaultHandler(VADDR_T vaddr, UINT32 flags, ExcContext *frame)
}
vaddr = ROUNDDOWN(vaddr, PAGE_SIZE);//为啥要向下圆整,因为这一页要重新使用,需找到页面基地址
-#ifdef LOSCFG_FS_VFS
+#ifdef LOSCFG_FS_VFS
if (LOS_IsRegionFileValid(region)) {//是否为文件线性区
if (region->unTypeData.rf.vnode == NULL) {
goto CHECK_FAILED;
@@ -422,7 +421,7 @@ STATUS_T OsVmPageFaultHandler(VADDR_T vaddr, UINT32 flags, ExcContext *frame)
goto DONE;
}
#endif
- //请求调页:推迟到不能再推迟为止
+ //请求调页:推迟到不能再推迟为止
newPage = LOS_PhysPageAlloc();//分配一个新的物理页
if (newPage == NULL) {
status = LOS_ERRNO_VM_NO_MEMORY;
@@ -432,7 +431,7 @@ STATUS_T OsVmPageFaultHandler(VADDR_T vaddr, UINT32 flags, ExcContext *frame)
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) {
+ if (status >= 0) {//已经映射过了,@note_thinking 不是缺页吗,怎么会有页的情况?
LOS_ArchMmuUnmap(&space->archMmu, vaddr, 1);//解除映射关系
OsPhysSharePageCopy(oldPaddr, &newPaddr, newPage);//将oldPaddr的数据拷贝到newPage
/* use old page free the new one */
@@ -451,7 +450,7 @@ 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);//映射新物理地址,如此下次就不会缺页了
diff --git a/src/kernel_liteos_a/kernel/base/vm/los_vm_filemap.c b/src/kernel_liteos_a/kernel/base/vm/los_vm_filemap.c
index 2da700d8..1e396f43 100644
--- a/src/kernel_liteos_a/kernel/base/vm/los_vm_filemap.c
+++ b/src/kernel_liteos_a/kernel/base/vm/los_vm_filemap.c
@@ -644,4 +644,4 @@ INT32 OsVfsFileMmap(struct file *filep, LosVmMapRegion *region)
}
#endif
-#endif
\ No newline at end of file
+#endif
diff --git a/src/kernel_liteos_a/kernel/base/vm/los_vm_iomap.c b/src/kernel_liteos_a/kernel/base/vm/los_vm_iomap.c
index 0d076a53..17898e5b 100644
--- a/src/kernel_liteos_a/kernel/base/vm/los_vm_iomap.c
+++ b/src/kernel_liteos_a/kernel/base/vm/los_vm_iomap.c
@@ -1,4 +1,8 @@
-/*
+/*!
+ * @file los_vm_iomap.c
+ * @brief DMA
+ * @link
+ @verbatim
直接内存访问
直接内存访问(Direct Memory Access,DMA)是计算机科学中的一种内存访问技术。它允许某些电脑内部的
硬件子系统(电脑外设),可以独立地直接读写系统内存,而不需中央处理器(CPU)介入处理
@@ -34,9 +38,12 @@
非同调系统(Non-coherent system):以软件方法来完成,操作系统必须确认缓存读取时,DMA程序已经
开始或是禁止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.
@@ -75,7 +82,7 @@
#include "los_vm_map.h"
#include "los_memory.h"
-///分配DMA空间
+/// 分配DMA空间
VOID *LOS_DmaMemAlloc(DMA_ADDR_T *dmaAddr, size_t size, size_t align, enum DmaMemType type)
{
VOID *kVaddr = NULL;
@@ -90,12 +97,12 @@ 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);//从内存池中申请
+ VM_ERR("failed, size = %u, align = %u", size, align);
return NULL;
}
@@ -109,7 +116,7 @@ VOID *LOS_DmaMemAlloc(DMA_ADDR_T *dmaAddr, size_t size, size_t align, enum DmaMe
return kVaddr;
}
-///释放DMA指针
+/// 释放 DMA指针
VOID LOS_DmaMemFree(VOID *vaddr)
{
UINTPTR addr;
@@ -118,11 +125,11 @@ 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);//内存池方式释放
#endif
@@ -137,7 +144,7 @@ VOID LOS_DmaMemFree(VOID *vaddr)
}
return;
}
-
+/// 将DMA虚拟地址转成物理地址
DMA_ADDR_T LOS_DmaVaddrToPaddr(VOID *vaddr)
{
return (DMA_ADDR_T)LOS_PaddrQuery(vaddr);
diff --git a/src/kernel_liteos_a/kernel/base/vm/los_vm_map.c b/src/kernel_liteos_a/kernel/base/vm/los_vm_map.c
index 4aeef716..c18c751b 100644
--- a/src/kernel_liteos_a/kernel/base/vm/los_vm_map.c
+++ b/src/kernel_liteos_a/kernel/base/vm/los_vm_map.c
@@ -1,4 +1,8 @@
-/*
+/*!
+ * @file los_vm_map.c
+ * @brief 虚拟内存管理
+ * @link vm http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-basic-memory-virtual.html @endlink
+ @verbatim
基本概念
虚拟内存管理是计算机系统管理内存的一种技术。每个进程都有连续的虚拟地址空间,虚拟地址空间的大小由CPU的位数决定,
32位的硬件平台可以提供的最大的寻址空间为0-4GiB。整个4GiB空间分成两部分,LiteOS-A内核占据3GiB的高地址空间,
@@ -36,11 +40,15 @@
2. CPU访问的虚拟地址所在的页,如V2,没有与具体的物理页做映射,系统会触发缺页异常,系统申请一个物理页,
并把相应的信息拷贝到物理页中,并且把物理页的起始地址更新到页表条目中。此时CPU重新执行访问虚拟内存的指令
便能够访问到具体的代码或数据。
- */
+ @endverbatim
+ * @version
+ * @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
+ * @date 2021-11-25
+ */
/*
* 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:
@@ -1281,4 +1289,6 @@ VOID LOS_KernelFree(VOID *ptr)
{
(VOID)LOS_MemFree(OS_SYS_MEM_ADDR, ptr);//从内存池中释放
}
-}
\ No newline at end of file
+}
+
+
diff --git a/src/kernel_liteos_a/kernel/base/vm/los_vm_page.c b/src/kernel_liteos_a/kernel/base/vm/los_vm_page.c
index a711ea7c..bb134206 100644
--- a/src/kernel_liteos_a/kernel/base/vm/los_vm_page.c
+++ b/src/kernel_liteos_a/kernel/base/vm/los_vm_page.c
@@ -45,12 +45,12 @@ 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);//引用次数0
- page->physAddr = pa;//物理地址
- page->segID = segID;//物理地址使用段管理,段ID
- 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);
@@ -61,7 +61,6 @@ STATIC INLINE VOID OsVmPageOrderListInit(LosVmPage *page, size_t nPages)
{//@note_why 此时所有页面 page->order = VM_LIST_ORDER_MAX,能挂入伙伴算法的链表吗?
OsVmPhysPagesFreeContiguous(page, nPages);//释放连续的物理页框
}
-
#define VMPAGEINIT(page, pa, segID) do { \
OsVmPageInit(page, pa, segID); \
(page)++; \
@@ -92,7 +91,7 @@ VOID OsVmPageStartup(VOID)
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();// 加入空闲链表和设置置换算法,LRU(最近最久未使用)算法
diff --git a/src/kernel_liteos_a/kernel/base/vm/los_vm_phys.c b/src/kernel_liteos_a/kernel/base/vm/los_vm_phys.c
index 3dc182e6..837b41b0 100644
--- a/src/kernel_liteos_a/kernel/base/vm/los_vm_phys.c
+++ b/src/kernel_liteos_a/kernel/base/vm/los_vm_phys.c
@@ -1,4 +1,8 @@
/*!
+ * @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内核管理物理内存是通过分页实现的,除了内核堆占用的一部分内存外,
@@ -22,8 +26,13 @@
系统释放12KiB内存,即3个页帧,将3个页帧分成2的幂次方之和,即2跟1,尝试查找伙伴进行合并,索引为1的链表上有1个内存块,
若地址连续则合并,并将合并后的内存块挂到索引为2的链表上,索引为0的链表上此时也有1个,如果地址连续则进行合并,
并将合并后的内存块挂到索引为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.
@@ -691,3 +700,4 @@ VADDR_T *LOS_PaddrToKVaddr(PADDR_T paddr)
return (VADDR_T *)DMA_TO_VMM_ADDR(paddr);
}
#endif
+
diff --git a/src/kernel_liteos_a/kernel/base/vm/los_vm_scan.c b/src/kernel_liteos_a/kernel/base/vm/los_vm_scan.c
index 01624eac..0482932f 100644
--- a/src/kernel_liteos_a/kernel/base/vm/los_vm_scan.c
+++ b/src/kernel_liteos_a/kernel/base/vm/los_vm_scan.c
@@ -344,4 +344,4 @@ int OsTryShrinkMemory(size_t nPage)
#endif
#endif
-#endif
\ No newline at end of file
+#endif
diff --git a/src/kernel_liteos_a/kernel/base/vm/los_vm_syscall.c b/src/kernel_liteos_a/kernel/base/vm/los_vm_syscall.c
index 72bdd10b..483b48cf 100644
--- a/src/kernel_liteos_a/kernel/base/vm/los_vm_syscall.c
+++ b/src/kernel_liteos_a/kernel/base/vm/los_vm_syscall.c
@@ -103,6 +103,8 @@ STATUS_T OsAnonMMap(LosVmMapRegion *region)
}
/**
+ * @brief
+ @verbatim
mmap基础概念:
一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系.
实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,
@@ -135,6 +137,14 @@ STATUS_T OsAnonMMap(LosVmMapRegion *region)
offset 文件映射的偏移量,通常设置为0,代表从文件最前方开始对应,offset必须是PAGE_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)
{
@@ -234,12 +244,17 @@ VOID *OsShrinkHeap(VOID *addr, LosVmSpace *space)
}
/**
+ * @brief
+ @verbatim
用户进程向内核申请空间,进一步说用于扩展用户堆栈空间,或者回收用户堆栈空间
扩展当前进程的堆空间
一个进程所有的线性区都在进程指定的线性地址范围内,
线性区之间是不会有地址的重叠的,开始都是连续的,随着进程的运行出现了释放再分配的情况
由此出现了断断续续的线性区,内核回收线性区时会检测是否和周边的线性区可合并成一个更大
的线性区用于分配。
+ @endverbatim
+ * @param addr
+ * @return VOID*
*/
VOID *LOS_DoBrk(VOID *addr)
{
@@ -553,4 +568,5 @@ VOID LOS_DumpMemRegion(VADDR_T vaddr)
OsDumpPte(vaddr);//dump L1 L2
OsDumpAspace(space);//dump 空间
}
-#endif
\ No newline at end of file
+#endif
+
diff --git a/src/kernel_liteos_a/kernel/base/vm/oom.c b/src/kernel_liteos_a/kernel/base/vm/oom.c
index 60d80128..c8091250 100644
--- a/src/kernel_liteos_a/kernel/base/vm/oom.c
+++ b/src/kernel_liteos_a/kernel/base/vm/oom.c
@@ -248,4 +248,5 @@ LITE_OS_SEC_TEXT_MINOR UINT32 OomTaskInit(VOID)
LOS_MODULE_INIT(OomTaskInit, LOS_INIT_LEVEL_KMOD_TASK);//初始化内存监控模块
-#endif
\ No newline at end of file
+#endif
+
diff --git a/src/kernel_liteos_a/kernel/base/vm/shm.c b/src/kernel_liteos_a/kernel/base/vm/shm.c
index a61cb0f4..9c4ad450 100644
--- a/src/kernel_liteos_a/kernel/base/vm/shm.c
+++ b/src/kernel_liteos_a/kernel/base/vm/shm.c
@@ -1,4 +1,8 @@
/*!
+ * @file shm.c
+ * @brief
+ * @link
+ @verbatim
什么是共享内存
顾名思义,共享内存就是允许两个不相关的进程访问同一个物理内存。共享内存是在两个正在运行的进程之间
共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常安排为同一段物理内存。进程可以将同
@@ -10,8 +14,11 @@
可以阻止第二个进程开始对它进行读取。所以我们通常需要用其他的机制来同步对共享内存的访问
共享线性区可以由任意的进程创建,每个使用共享线性区都必须经过映射.
+ @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.
@@ -1026,3 +1033,4 @@ DONE:
SHELLCMD_ENTRY(shm_shellcmd, CMD_TYPE_SHOW, "shm", 2, (CmdCallBackFunc)OsShellCmdShm);
#endif
#endif
+
diff --git a/src/kernel_liteos_a/kernel/common/console.c b/src/kernel_liteos_a/kernel/common/console.c
index bfaa4c59..6320a888 100644
--- a/src/kernel_liteos_a/kernel/common/console.c
+++ b/src/kernel_liteos_a/kernel/common/console.c
@@ -54,24 +54,30 @@
#define UART_IOC_MAGIC 'u'
#define UART_CFG_ATTR _IOW(UART_IOC_MAGIC, 5, int)
#define UART_CFG_PRIVATE _IOW(UART_IOC_MAGIC, 6, int)
-/* Inter-module variable */
+/* 直接写在数据区的变量
+#ifdef LOSCFG_QUICK_START
+__attribute__ ((section(".data"))) UINT32 g_uart_fputc_en = 0;
+#else
+__attribute__ ((section(".data"))) UINT32 g_uart_fputc_en = 1;
+#endif
+*/
+/* Inter-module variable */ //模块间变量
extern UINT32 g_uart_fputc_en;
STATIC UINT32 ConsoleSendTask(UINTPTR param);
-STATIC UINT8 g_taskConsoleIDArray[LOSCFG_BASE_CORE_TSK_LIMIT];
-STATIC SPIN_LOCK_INIT(g_consoleSpin);
+STATIC UINT8 g_taskConsoleIDArray[LOSCFG_BASE_CORE_TSK_LIMIT];///< task 控制台ID池,同步task数量,理论上每个task都可以有一个自己的控制台
+STATIC SPIN_LOCK_INIT(g_consoleSpin);///< 初始化控制台自旋锁
STATIC SPIN_LOCK_INIT(g_consoleWriteSpinLock);
-#define SHELL_ENTRYID_INVALID 0xFFFFFFFF
-#define SHELL_TASK_PRIORITY 9
-#define CONSOLE_CIRBUF_EVENT 0x02U
-#define CONSOLE_SEND_TASK_EXIT 0x04U
-#define CONSOLE_SEND_TASK_RUNNING 0x10U
+#define SHELL_ENTRYID_INVALID 0xFFFFFFFF ///< 默认值,SHELL_ENTRYID 一般为 任务ID
+#define SHELL_TASK_PRIORITY 9 ///< shell 的优先级为 9
+#define CONSOLE_CIRBUF_EVENT 0x02U ///< 控制台循环buffer事件
+#define CONSOLE_SEND_TASK_EXIT 0x04U ///< 控制台发送任务退出事件
+#define CONSOLE_SEND_TASK_RUNNING 0x10U ///< 控制台发送任务正在执行事件
#define SHELL_ENTRY_NAME "ShellEntry"
#define SHELL_ENTRY_NAME_LEN 10
-
-CONSOLE_CB *g_console[CONSOLE_NUM];
+CONSOLE_CB *g_console[CONSOLE_NUM];///< 控制台全局变量,控制台是共用的, 默认为 2个
#define MIN(a, b) ((a) < (b) ? (a) : (b))
/*
@@ -79,6 +85,11 @@ CONSOLE_CB *g_console[CONSOLE_NUM];
* then store uart driver function in *filepOps
* and store filep of /dev/console in *privFilep.
*/
+/*
+* 获取/dev/console的uart驱动函数和filep,
+* 然后将 uart 驱动函数存储在 *filepOps 中
+* 并将 /dev/console 的文件存储在 *privFilep 中。
+*/
INT32 GetFilepOps(const struct file *filep, struct file **privFilep, const struct file_operations_vfs **filepOps)
{
INT32 ret;
@@ -87,27 +98,27 @@ INT32 GetFilepOps(const struct file *filep, struct file **privFilep, const struc
ret = EINVAL;
goto ERROUT;
}
-
- /* to find console device's filep(now it is *privFilep) through i_private */
+ //通过 is_private 查找控制台设备的文件(现在是 *privFile)
+ /* to find console device's filep(now it is *privFilep) throught i_private */
struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
- *privFilep = (struct file *)drv->priv;
+ *privFilep = (struct file *)drv->priv;// file 例如 g_serialFilep
if (((*privFilep)->f_vnode == NULL) || ((*privFilep)->f_vnode->data == NULL)) {
ret = EINVAL;
goto ERROUT;
}
- /* to find uart driver operation function through u.i_opss */
+ /* to find uart driver operation function throutht u.i_opss */
drv = (struct drv_data *)(*privFilep)->f_vnode->data;
- *filepOps = (const struct file_operations_vfs *)drv->ops;
+ *filepOps = (const struct file_operations_vfs *)drv->ops;//拿到串口驱动程序
return ENOERR;
ERROUT:
set_errno(ret);
return VFS_ERROR;
}
-
+///获取控制台 模式值
INT32 ConsoleTcGetAttr(INT32 fd, struct termios *termios)
{
struct file *filep = NULL;
@@ -126,7 +137,7 @@ INT32 ConsoleTcGetAttr(INT32 fd, struct termios *termios)
(VOID)memcpy_s(termios, sizeof(struct termios), &consoleCB->consoleTermios, sizeof(struct termios));
return LOS_OK;
}
-
+///设置控制台 模式值
INT32 ConsoleTcSetAttr(INT32 fd, INT32 actions, const struct termios *termios)
{
struct file *filep = NULL;
@@ -152,12 +163,13 @@ STATIC UINT32 ConsoleRefcountGet(const CONSOLE_CB *consoleCB)
{
return consoleCB->refCount;
}
-
+///设置控制台引用次数,也表示占用控制台的数量
STATIC VOID ConsoleRefcountSet(CONSOLE_CB *consoleCB, BOOL flag)
{
(consoleCB->refCount) += flag ? 1 : -1;
}
+///控制台是否被占用
BOOL IsConsoleOccupied(const CONSOLE_CB *consoleCB)
{
return ConsoleRefcountGet(consoleCB);
@@ -176,7 +188,7 @@ STATIC INT32 ConsoleCtrlCaptureLine(CONSOLE_CB *consoleCB)
return LOS_OK;
}
-
+///< 铺捉到 ctrl + 字符, 例如 ctrl + c
STATIC INT32 ConsoleCtrlCaptureChar(CONSOLE_CB *consoleCB)
{
struct termios consoleTermios = {0};
@@ -190,16 +202,17 @@ STATIC INT32 ConsoleCtrlCaptureChar(CONSOLE_CB *consoleCB)
return LOS_OK;
}
-
+///< 铺捉到 ctrl + 右方向键(>)
STATIC INT32 ConsoleCtrlRightsCapture(CONSOLE_CB *consoleCB)
{
(VOID)LOS_SemPend(consoleCB->consoleSem, LOS_WAIT_FOREVER);
if ((ConsoleRefcountGet(consoleCB) == 0) &&
- (OsCurrTaskGet()->taskID != consoleCB->shellEntryId)) {
- /* not 0:indicate that shellentry is in uart_read, suspend shellentry task directly */
- (VOID)LOS_TaskSuspend(consoleCB->shellEntryId);
+ (OsCurrTaskGet()->taskID != consoleCB->shellEntryId)) { //控制台没有任务使用且当前任务不是接收终端输入的shell entry 任务
+ /* not 0:indicate that shellentry is in uart_read, suspend shellentry task directly
+ | 表示shellentry在uart_read中,直接挂起shellentry任务*/
+ (VOID)LOS_TaskSuspend(consoleCB->shellEntryId);//挂起任务,意味着不接受输入
}
- ConsoleRefcountSet(consoleCB, TRUE);
+ ConsoleRefcountSet(consoleCB, TRUE); //占用控制台
return LOS_OK;
}
@@ -210,7 +223,7 @@ STATIC INT32 ConsoleCtrlRightsRelease(CONSOLE_CB *consoleCB)
(VOID)LOS_SemPost(consoleCB->consoleSem);
return LOS_NOK;
} else {
- ConsoleRefcountSet(consoleCB, FALSE);
+ ConsoleRefcountSet(consoleCB, FALSE);//释放控制台
if ((ConsoleRefcountGet(consoleCB) == 0) &&
(OsCurrTaskGet()->taskID != consoleCB->shellEntryId)) {
(VOID)LOS_TaskResume(consoleCB->shellEntryId);
@@ -242,24 +255,24 @@ STATIC CONSOLE_CB *OsGetConsoleByDevice(const CHAR *deviceName)
return NULL;
}
}
-
+///获取控制台ID,(/dev/console1 = SERIAL, /dev/console2 = telnet)
STATIC INT32 OsGetConsoleID(const CHAR *deviceName)
{
if ((deviceName != NULL) &&
(strlen(deviceName) == strlen(SERIAL)) &&
(!strncmp(deviceName, SERIAL, strlen(SERIAL)))) {
- return CONSOLE_SERIAL;
+ return CONSOLE_SERIAL;//1 串口
}
#ifdef LOSCFG_NET_TELNET
else if ((deviceName != NULL) &&
(strlen(deviceName) == strlen(TELNET)) &&
(!strncmp(deviceName, TELNET, strlen(TELNET)))) {
- return CONSOLE_TELNET;
+ return CONSOLE_TELNET;//2 远程登录
}
#endif
return -1;
}
-
+///通过路径找到控制台ID
STATIC INT32 OsConsoleFullpathToID(const CHAR *fullpath)
{
#define CONSOLE_SERIAL_1 "/dev/console1"
@@ -296,12 +309,12 @@ STATIC VOID ConsoleFifoClearup(CONSOLE_CB *console)
console->fifoIn = 0;
(VOID)memset_s(console->fifo, CONSOLE_FIFO_SIZE, 0, CONSOLE_FIFO_SIZE);
}
-
+///控制台buf长度更新
STATIC VOID ConsoleFifoLenUpdate(CONSOLE_CB *console)
{
console->currentLen = console->fifoIn - console->fifoOut;
}
-
+///读取
STATIC INT32 ConsoleReadFifo(CHAR *buffer, CONSOLE_CB *console, size_t bufLen)
{
INT32 ret;
@@ -320,14 +333,14 @@ STATIC INT32 ConsoleReadFifo(CHAR *buffer, CONSOLE_CB *console, size_t bufLen)
ConsoleFifoLenUpdate(console);
return (INT32)readNum;
}
-
+///打开串口或远程登录
INT32 FilepOpen(struct file *filep, const struct file_operations_vfs *fops)
{
INT32 ret;
if (fops->open == NULL) {
return -EFAULT;
}
-
+ //使用 uart open函数打开filep(filep是对应 /dev/console 的 filep)
/*
* adopt uart open function to open filep (filep is
* corresponding to filep of /dev/console)
@@ -336,6 +349,7 @@ INT32 FilepOpen(struct file *filep, const struct file_operations_vfs *fops)
return (ret < 0) ? -EPERM : ret;
}
+///向控制台buf中写入结束字符
STATIC INLINE VOID UserEndOfRead(CONSOLE_CB *consoleCB, struct file *filep,
const struct file_operations_vfs *fops)
{
@@ -348,21 +362,21 @@ STATIC INLINE VOID UserEndOfRead(CONSOLE_CB *consoleCB, struct file *filep,
consoleCB->fifo[consoleCB->fifoIn] = '\0';
consoleCB->currentLen = consoleCB->fifoIn;
}
-
+///根据VT终端标准 [37m 为设置前景色
enum {
- STAT_NORMAL_KEY,
- STAT_ESC_KEY,
- STAT_MULTI_KEY
+ STAT_NORMAL_KEY,///< 普通按键
+ STAT_ESC_KEY, ///< 控制按键,只有 ESC 是
+ STAT_MULTI_KEY ///< 多个按键,只有 [ 是
};
-
+///用户shell检查上下左右键
STATIC INT32 UserShellCheckUDRL(const CHAR ch, INT32 *lastTokenType)
{
INT32 ret = LOS_OK;
if (ch == 0x1b) { /* 0x1b: ESC */
- *lastTokenType = STAT_ESC_KEY;
+ *lastTokenType = STAT_ESC_KEY;// vt 的控制字符
return ret;
} else if (ch == 0x5b) { /* 0x5b: first Key combination */
- if (*lastTokenType == STAT_ESC_KEY) {
+ if (*lastTokenType == STAT_ESC_KEY) { //遇到 [
*lastTokenType = STAT_MULTI_KEY;
return ret;
}
@@ -389,7 +403,7 @@ STATIC INT32 UserShellCheckUDRL(const CHAR ch, INT32 *lastTokenType)
}
return LOS_NOK;
}
-
+///是否需要继续
STATIC INT32 IsNeedContinue(CONSOLE_CB *consoleCB, char ch, INT32 *lastTokenType)
{
if (((ch == '\b') && (consoleCB->consoleTermios.c_lflag & ECHO) && (ConsoleFifoEmpty(consoleCB))) ||
@@ -399,47 +413,45 @@ STATIC INT32 IsNeedContinue(CONSOLE_CB *consoleCB, char ch, INT32 *lastTokenType
return LOS_OK;
}
-
+///输出到终端
STATIC VOID EchoToTerminal(CONSOLE_CB *consoleCB, struct file *filep, const struct file_operations_vfs *fops, char ch)
{
if (consoleCB->consoleTermios.c_lflag & ECHO) {
- if (ch == '\b') {
- (VOID)fops->write(filep, "\b \b", 3); // 3: length of "\b \b"
+ if (ch == '\b') {//遇到回退字符
+ (VOID)fops->write(filep, "\b \b", 3);//回退
} else {
- (VOID)fops->write(filep, &ch, EACH_CHAR);
+ (VOID)fops->write(filep, &ch, EACH_CHAR);//向终端写入字符
}
}
}
-
+///存储读取的字符
STATIC VOID StoreReadChar(CONSOLE_CB *consoleCB, char ch, INT32 readcount)
-{
- /* 3, store read char len need to minus \b */
+{ //读取字符
if ((readcount == EACH_CHAR) && (consoleCB->fifoIn <= (CONSOLE_FIFO_SIZE - 3))) {
if (ch == '\b') {
if (!ConsoleFifoEmpty(consoleCB)) {
consoleCB->fifo[--consoleCB->fifoIn] = '\0';
}
} else {
- consoleCB->fifo[consoleCB->fifoIn] = (UINT8)ch;
+ consoleCB->fifo[consoleCB->fifoIn] = (UINT8)ch;//将字符读入缓冲区
consoleCB->fifoIn++;
}
}
}
-
+///杀死进程组
VOID KillPgrp(UINT16 consoleId)
{
if ((consoleId > CONSOLE_NUM) || (consoleId <= 0)) {
return;
}
-
- CONSOLE_CB *consoleCB = g_console[consoleId - 1];
+ CONSOLE_CB *consoleCB = g_console[consoleId-1];
/* the default of consoleCB->pgrpId is -1, may not be set yet, avoid killing all processes */
if (consoleCB->pgrpId < 0) {
return;
}
- (VOID)OsKillLock(consoleCB->pgrpId, SIGINT);
+ (VOID)OsKillLock(consoleCB->pgrpId, SIGINT);//发送信号 SIGINT对应 键盘中断(ctrl + c)信号
}
-
+///使用参数buffer将控制台的buf接走
STATIC INT32 UserFilepRead(CONSOLE_CB *consoleCB, struct file *filep, const struct file_operations_vfs *fops,
CHAR *buffer, size_t bufLen)
{
@@ -451,51 +463,57 @@ STATIC INT32 UserFilepRead(CONSOLE_CB *consoleCB, struct file *filep, const stru
if (fops->read == NULL) {
return -EFAULT;
}
-
- /* Non-ICANON mode */
+
+ /* Non-ICANON mode | 非规范模式 所有的输入即时有效,用户不需要另外输入行结束符,不能进行行编辑*/
if ((consoleCB->consoleTermios.c_lflag & ICANON) == 0) {
ret = fops->read(filep, buffer, bufLen);
return (ret < 0) ? -EPERM : ret;
}
+ /**
+ 在规范模式下,输入数据基于行进行处理。
+ 在用户输入一个行结束符(回车符、EOF等)之前,系统调用read()读不到用户输入的任何字符。
+ 除了EOF之外的行结束符(回车符等),与普通字符一样会被read()读到缓冲区中。
+ 在规范模式中,可以进行行编辑,而且一次调用read()最多只能读取一行数据。
+ 如果read()请求读取的数据字节少于当前行可读取的字节,则read()只读取被请求的字节数,剩下的字节下次再读。
+ */
/* ICANON mode: store data to console buffer, read data and stored data into console fifo */
- if (consoleCB->currentLen == 0) {
- while (1) {
- ret = fops->read(filep, &ch, EACH_CHAR);
+ if (consoleCB->currentLen == 0) {//如果没有数据
+ while (1) {//存储数据到控制台buf中
+ ret = fops->read(filep, &ch, EACH_CHAR);//一个个字符读
if (ret <= 0) {
return ret;
}
- if (IsNeedContinue(consoleCB, ch, &lastTokenType))
+ if (IsNeedContinue(consoleCB, ch, &lastTokenType))//是否继续读
continue;
switch (ch) {
case '\r':
- ch = '\n';
+ ch = '\n';//回车换行
case '\n':
- EchoToTerminal(consoleCB, filep, fops, ch);
- UserEndOfRead(consoleCB, filep, fops);
- ret = ConsoleReadFifo(buffer, consoleCB, bufLen);
-
- needreturn = LOS_OK;
+ EchoToTerminal(consoleCB, filep, fops, ch);//输出到终端
+ UserEndOfRead(consoleCB, filep, fops);//给控制台buf加上结束字符
+ ret = ConsoleReadFifo(buffer, consoleCB, bufLen);//读取控制台buf的信息到参数buffer中
+ needreturn = LOS_OK;//直接返回
break;
case '\b':
default:
- EchoToTerminal(consoleCB, filep, fops, ch);
- StoreReadChar(consoleCB, ch, ret);
+ EchoToTerminal(consoleCB, filep, fops, ch);//输出到终端
+ StoreReadChar(consoleCB, ch, ret);//将字符保存到控制台的buf中
break;
}
if (needreturn == LOS_OK)
break;
}
- } else {
- /* if data is already in console fifo, we return them immediately */
- ret = ConsoleReadFifo(buffer, consoleCB, bufLen);
+ } else {//如果数据准备好了,立即返回
+ /* if data is already in console fifo, we returen them immediately */
+ ret = ConsoleReadFifo(buffer, consoleCB, bufLen);//读取控制台buf的信息到参数buffer中
}
return ret;
}
-
+///从串口或远程登录中读数据
INT32 FilepRead(struct file *filep, const struct file_operations_vfs *fops, CHAR *buffer, size_t bufLen)
{
INT32 ret;
@@ -506,11 +524,12 @@ INT32 FilepRead(struct file *filep, const struct file_operations_vfs *fops, CHAR
* adopt uart read function to read data from filep
* and write data to buffer (filep is
* corresponding to filep of /dev/console)
- */
+ *///采用uart read函数从文件中读取数据,将数据写入缓冲区(文件对应/dev/console的filep)
ret = fops->read(filep, buffer, bufLen);
return (ret < 0) ? -EPERM : ret;
}
+///写数据到串口或远程登录
INT32 FilepWrite(struct file *filep, const struct file_operations_vfs *fops, const CHAR *buffer, size_t bufLen)
{
INT32 ret;
@@ -522,6 +541,7 @@ INT32 FilepWrite(struct file *filep, const struct file_operations_vfs *fops, con
return (ret < 0) ? -EPERM : ret;
}
+///关闭串口或远程登录
INT32 FilepClose(struct file *filep, const struct file_operations_vfs *fops)
{
INT32 ret;
@@ -563,6 +583,7 @@ INT32 FilepPoll(struct file *filep, const struct file_operations_vfs *fops, poll
return (ret < 0) ? -EPERM : ret;
}
+///对 file_operations_vfs->open 的实现函数,也就是说这是 打开控制台的实体函数.
STATIC INT32 ConsoleOpen(struct file *filep)
{
INT32 ret;
@@ -570,19 +591,19 @@ STATIC INT32 ConsoleOpen(struct file *filep)
struct file *privFilep = NULL;
const struct file_operations_vfs *fileOps = NULL;
- consoleID = (UINT32)OsConsoleFullpathToID(filep->f_path);
+ consoleID = (UINT32)OsConsoleFullpathToID(filep->f_path);//先找到控制台ID返回 (1,2,-1)
if (consoleID == (UINT32)-1) {
ret = EPERM;
goto ERROUT;
}
- filep->f_priv = g_console[consoleID - 1];
+ filep->f_priv = g_console[consoleID - 1]; //f_priv 每种文件系统对应结构体都同,所以是void的类型,如一张白纸,画什么模块自己定
- ret = GetFilepOps(filep, &privFilep, &fileOps);
+ ret = GetFilepOps(filep, &privFilep, &fileOps);//获取文件系统的驱动程序
if (ret != ENOERR) {
ret = EINVAL;
goto ERROUT;
}
- ret = FilepOpen(privFilep, fileOps);
+ ret = FilepOpen(privFilep, fileOps);//打开文件,其实调用的是 串口底层驱动程序
if (ret < 0) {
ret = EPERM;
goto ERROUT;
@@ -593,7 +614,7 @@ ERROUT:
set_errno(ret);
return VFS_ERROR;
}
-
+///关闭控制台
STATIC INT32 ConsoleClose(struct file *filep)
{
INT32 ret;
@@ -625,9 +646,9 @@ STATIC ssize_t DoRead(CONSOLE_CB *consoleCB, CHAR *buffer, size_t bufLen,
INT32 ret;
#ifdef LOSCFG_SHELL
- if (OsCurrTaskGet()->taskID == consoleCB->shellEntryId) {
- ret = FilepRead(privFilep, fileOps, buffer, bufLen);
- } else {
+ if (OsCurrTaskGet()->taskID == consoleCB->shellEntryId) {//shell Entry 任务读取内容
+ ret = FilepRead(privFilep, fileOps, buffer, bufLen);//直接从串口中读数据
+ } else {//其他任务读取内容,需经过行规程处理
#endif
(VOID)ConsoleCtrlRightsCapture(consoleCB);
ret = UserFilepRead(consoleCB, privFilep, fileOps, buffer, bufLen);
@@ -638,7 +659,7 @@ STATIC ssize_t DoRead(CONSOLE_CB *consoleCB, CHAR *buffer, size_t bufLen,
return ret;
}
-
+///任务从控制台读数据,例如 Shell Entry 任务会从此读数据
STATIC ssize_t ConsoleRead(struct file *filep, CHAR *buffer, size_t bufLen)
{
INT32 ret;
@@ -656,7 +677,7 @@ STATIC ssize_t ConsoleRead(struct file *filep, CHAR *buffer, size_t bufLen)
if (bufLen > CONSOLE_FIFO_SIZE) {
bufLen = CONSOLE_FIFO_SIZE;
}
-
+ //检查buffer是否在用户区
userBuf = LOS_IsUserAddressRange((vaddr_t)(UINTPTR)buffer, bufLen);
ret = GetFilepOps(filep, &privFilep, &fileOps);
if (ret != ENOERR) {
@@ -681,7 +702,7 @@ STATIC ssize_t ConsoleRead(struct file *filep, CHAR *buffer, size_t bufLen)
goto ERROUT;
}
- ret = DoRead(consoleCB, sbuffer, bufLen, privFilep, fileOps);
+ ret = DoRead(consoleCB, sbuffer, bufLen, privFilep, fileOps);//从 console buf中取数据
if (ret < 0) {
goto ERROUT;
}
@@ -711,8 +732,8 @@ STATIC ssize_t DoWrite(CirBufSendCB *cirBufSendCB, CHAR *buffer, size_t bufLen)
size_t written = 0;
UINT32 intSave;
-#ifdef LOSCFG_SHELL_DMESG
- (VOID)OsLogMemcpyRecord(buffer, bufLen);
+#ifdef LOSCFG_SHELL_DMESG
+ (VOID)OsLogMemcpyRecord(buffer, bufLen); //同时写到内核缓冲区中,这也导致 OHOS# dmesg 会输出相同的内容
if (OsCheckConsoleLock()) {
return 0;
}
@@ -720,7 +741,7 @@ STATIC ssize_t DoWrite(CirBufSendCB *cirBufSendCB, CHAR *buffer, size_t bufLen)
LOS_SpinLockSave(&g_consoleWriteSpinLock, &intSave);
while (written < (INT32)bufLen) {
- /* Transform for CR/LR mode */
+ /* Transform for CR/LR mode | 回车(CR, ASCII 13, \r) 换行(LF, ASCII 10, \n)*/
if ((buffer[written] == '\n') || (buffer[written] == '\r')) {
(VOID)LOS_CirBufWrite(&cirBufSendCB->cirBufCB, "\r", 1);
}
@@ -735,12 +756,12 @@ STATIC ssize_t DoWrite(CirBufSendCB *cirBufSendCB, CHAR *buffer, size_t bufLen)
/* Log is cached but not printed when a system exception occurs */
if (OsGetSystemStatus() == OS_SYSTEM_NORMAL) {
- (VOID)LOS_EventWrite(&cirBufSendCB->sendEvent, CONSOLE_CIRBUF_EVENT);
+ (VOID)LOS_EventWrite(&cirBufSendCB->sendEvent, CONSOLE_CIRBUF_EVENT);//发送数据事件
}
return written;
}
-
+///用户任务写数据到控制台
STATIC ssize_t ConsoleWrite(struct file *filep, const CHAR *buffer, size_t bufLen)
{
INT32 ret;
@@ -758,7 +779,7 @@ STATIC ssize_t ConsoleWrite(struct file *filep, const CHAR *buffer, size_t bufLe
if (bufLen > CONSOLE_FIFO_SIZE) {
bufLen = CONSOLE_FIFO_SIZE;
}
-
+ //检测buffer是否在用户空间
userBuf = LOS_IsUserAddressRange((vaddr_t)(UINTPTR)buffer, bufLen);
ret = GetFilepOps(filep, &privFilep, &fileOps);
@@ -769,8 +790,8 @@ STATIC ssize_t ConsoleWrite(struct file *filep, const CHAR *buffer, size_t bufLe
cirBufSendCB = ((CONSOLE_CB *)filep->f_priv)->cirBufSendCB;
/*
- * adopt uart open function to read data from buffer
- * and write data to filep (filep is
+ * adopt uart open function to read data from buffer | 用uart open函数从buffer中读取数据
+ * and write data to filep (filep is | 向filep写入数据(filep对应/dev/console的filep)
* corresponding to filep of /dev/console)
*/
sbuffer = userBuf ? LOS_MemAlloc(m_aucSysMem0, bufLen) : (CHAR *)buffer;
@@ -778,12 +799,12 @@ STATIC ssize_t ConsoleWrite(struct file *filep, const CHAR *buffer, size_t bufLe
ret = ENOMEM;
goto ERROUT;
}
-
+ //将用户空间的数据拷贝进内核空间
if (userBuf && (LOS_ArchCopyFromUser(sbuffer, buffer, bufLen) != 0)) {
ret = EFAULT;
goto ERROUT;
}
- ret = DoWrite(cirBufSendCB, sbuffer, bufLen);
+ ret = DoWrite(cirBufSendCB, sbuffer, bufLen);//真正的写操作,向控制台任务发起写入事件
if (userBuf) {
LOS_MemFree(m_aucSysMem0, sbuffer);
@@ -860,6 +881,7 @@ INT32 ConsoleGetPgrp(CONSOLE_CB *consoleCB, unsigned long arg)
return (LOS_ArchCopyToUser((VOID *)arg, &consoleCB->pgrpId, sizeof(INT32)) != 0) ? -EFAULT : LOS_OK;
}
+///< 对控制台i/o操作
STATIC INT32 ConsoleIoctl(struct file *filep, INT32 cmd, unsigned long arg)
{
INT32 ret;
@@ -897,7 +919,7 @@ STATIC INT32 ConsoleIoctl(struct file *filep, INT32 cmd, unsigned long arg)
case CONSOLE_CONTROL_CAPTURE_CHAR:
ret = ConsoleCtrlCaptureChar(consoleCB);
break;
- case CONSOLE_CONTROL_REG_USERTASK:
+ case CONSOLE_CONTROL_REG_USERTASK: //注册shell 客户端 http://weharmonyos.com/blog/72.html
ret = ConsoleTaskReg(consoleCB->consoleID, arg);
break;
case TIOCGWINSZ:
@@ -960,7 +982,7 @@ ERROUT:
return VFS_ERROR;
}
-/* console device driver function structure */
+/*! console device driver function structure | 控制台设备驱动程序,对统一的vfs接口的实现 */
STATIC const struct file_operations_vfs g_consoleDevOps = {
.open = ConsoleOpen, /* open */
.close = ConsoleClose, /* close */
@@ -974,10 +996,18 @@ STATIC const struct file_operations_vfs g_consoleDevOps = {
#endif
};
+/**
+ * @brief termios 结构是在POSIX规范中定义的标准接口,它类似于系统V中的termio接口,
+通过设置termios类型的数据结构中的值和使用一小组函数调用,你就可以对终端接口进行控制。
+ * @param consoleCB
+ * @param deviceName
+ * @return STATIC
+ */
STATIC VOID OsConsoleTermiosInit(CONSOLE_CB *consoleCB, const CHAR *deviceName)
{
struct termios consoleTermios = {0};
-
+//c_cc[VINTR] 默认对应的控制符是^C,作用是清空输入和输出队列的数据并且向tty设备的前台进程组中的
+//每一个程序发送一个SIGINT信号,对SIGINT信号没有定义处理程序的进程会马上退出。
if ((deviceName != NULL) &&
(strlen(deviceName) == strlen(SERIAL)) &&
(!strncmp(deviceName, SERIAL, strlen(SERIAL)))) {
@@ -985,8 +1015,8 @@ STATIC VOID OsConsoleTermiosInit(CONSOLE_CB *consoleCB, const CHAR *deviceName)
/* set console to have a buffer for user */
(VOID)ConsoleTcGetAttr(consoleCB->fd, &consoleTermios);
- consoleTermios.c_lflag |= ICANON | ECHO;
- consoleTermios.c_cc[VINTR] = 3; /* /003 for ^C */
+ consoleTermios.c_lflag |= ICANON | ECHO;//控制模式标志 ICANON:使用标准输入模式 ECHO:显示输入字符
+ consoleTermios.c_cc[VINTR] = 3; /* /003 for ^C */ //控制字符
(VOID)ConsoleTcSetAttr(consoleCB->fd, 0, &consoleTermios);
}
#ifdef LOSCFG_NET_TELNET
@@ -996,13 +1026,13 @@ STATIC VOID OsConsoleTermiosInit(CONSOLE_CB *consoleCB, const CHAR *deviceName)
consoleCB->isNonBlock = SetTelnetBlock(consoleCB);
/* set console to have a buffer for user */
(VOID)ConsoleTcGetAttr(consoleCB->fd, &consoleTermios);
- consoleTermios.c_lflag |= ICANON | ECHO;
- consoleTermios.c_cc[VINTR] = 3; /* /003 for ^C */
+ consoleTermios.c_lflag |= ICANON | ECHO;//控制模式标志 ICANON:使用标准输入模式 ECHO:显示输入字符
+ consoleTermios.c_cc[VINTR] = 3; /* /003 for ^C */ //控制字符
(VOID)ConsoleTcSetAttr(consoleCB->fd, 0, &consoleTermios);
}
#endif
}
-
+///控制台文件实例初始化
STATIC INT32 OsConsoleFileInit(CONSOLE_CB *consoleCB)
{
INT32 ret;
@@ -1016,12 +1046,12 @@ STATIC INT32 OsConsoleFileInit(CONSOLE_CB *consoleCB)
goto ERROUT;
}
- filep = files_allocate(vnode, O_RDWR, 0, consoleCB, FILE_START_FD);
+ filep = files_allocate(vnode, O_RDWR, 0, consoleCB, FILE_START_FD);//分配FD给了控制台
if (filep == NULL) {
ret = EMFILE;
goto ERROUT;
}
- filep->ops = (struct file_operations_vfs *)((struct drv_data *)vnode->data)->ops;
+ filep->ops = (struct file_operations_vfs *)((struct drv_data *)vnode->data)->ops;//关联驱动程序
consoleCB->fd = filep->fd;
ERROUT:
@@ -1031,7 +1061,7 @@ ERROUT:
/*
* Initialized console control platform so that when we operate /dev/console
- * as if we are operating /dev/ttyS0 (uart0).
+ * as if we are operating /dev/ttyS0 (uart0). | 初始化控制台以此来控制平台,以便在操作/dev/console时,就好像我们在操作/dev/ttyS0(uart0)
*/
STATIC INT32 OsConsoleDevInit(CONSOLE_CB *consoleCB, const CHAR *deviceName)
{
@@ -1048,7 +1078,7 @@ STATIC INT32 OsConsoleDevInit(CONSOLE_CB *consoleCB, const CHAR *deviceName)
}
VnodeHold();
- ret = VnodeLookup(deviceName, &vnode, V_DUMMY);
+ ret = VnodeLookup(deviceName, &vnode, V_DUMMY); //找到对应 vnode节点
VnodeDrop(); // not correct, but can't fix perfectly here
if (ret != LOS_OK) {
ret = EACCES;
@@ -1056,25 +1086,30 @@ STATIC INT32 OsConsoleDevInit(CONSOLE_CB *consoleCB, const CHAR *deviceName)
goto ERROUT;
}
- consoleCB->devVnode = vnode;
+ consoleCB->devVnode = vnode;//关联vnode节点
/*
* initialize the console filep which is associated with /dev/console,
- * assign the uart0 vnode of /dev/ttyS0 to console inod of /dev/console,
+ * assign the uart0 inode of /dev/ttyS0 to console inod of /dev/console,
* then we can operate console's filep as if we operate uart0 filep of
* /dev/ttyS0.
*/
+ /*
+ 初始化与/dev/console关联的console filep,将/dev/ttyS0的uart0 inode赋给
+ /dev/console的console inod,就可以像操作/dev/ttyS0的uart0 filep一样操作控制台的filep
+ */
(VOID)memset_s(filep, sizeof(struct file), 0, sizeof(struct file));
- filep->f_oflags = O_RDWR;
- filep->f_pos = 0;
- filep->f_vnode = vnode;
- filep->f_path = NULL;
- filep->f_priv = NULL;
+ filep->f_oflags = O_RDWR; //读写模式
+ filep->f_pos = 0; //偏移位置,默认为0
+ filep->f_vnode = vnode; //节点关联
+ filep->f_path = NULL; //
+ filep->f_priv = NULL; //
/*
- * Use filep to connect console and uart, we can find uart driver function through filep.
+ * Use filep to connect console and uart, we can find uart driver function throught filep.
* now we can operate /dev/console to operate /dev/ttyS0 through filep.
*/
- devOps = (struct file_operations_vfs *)((struct drv_data*)vnode->data)->ops;
+ //使用filep连接控制台和uart,通过它可以找到uart驱动函数, 可以通过filep操作/dev/console
+ devOps = (struct file_operations_vfs *)((struct drv_data*)vnode->data)->ops;//获取默认驱动程序
if (devOps != NULL && devOps->open != NULL) {
(VOID)devOps->open(filep);
} else {
@@ -1082,7 +1117,7 @@ STATIC INT32 OsConsoleDevInit(CONSOLE_CB *consoleCB, const CHAR *deviceName)
goto ERROUT;
}
- ret = register_driver(consoleCB->name, &g_consoleDevOps, DEFFILEMODE, filep);
+ ret = register_driver(consoleCB->name, &g_consoleDevOps, DEFFILEMODE, filep);//注册控制台设备驱动程序
if (ret != LOS_OK) {
goto ERROUT;
}
@@ -1097,12 +1132,13 @@ ERROUT:
set_errno(ret);
return LOS_NOK;
}
-
+/// 注销控制台设备
STATIC UINT32 OsConsoleDevDeinit(const CONSOLE_CB *consoleCB)
{
- return unregister_driver(consoleCB->name);
+ return unregister_driver(consoleCB->name);//注销驱动
}
+/// 创建一个控制台循环buf
STATIC CirBufSendCB *ConsoleCirBufCreate(VOID)
{
UINT32 ret;
@@ -1110,25 +1146,25 @@ STATIC CirBufSendCB *ConsoleCirBufCreate(VOID)
CirBufSendCB *cirBufSendCB = NULL;
CirBuf *cirBufCB = NULL;
- cirBufSendCB = (CirBufSendCB *)LOS_MemAlloc(m_aucSysMem0, sizeof(CirBufSendCB));
+ cirBufSendCB = (CirBufSendCB *)LOS_MemAlloc(m_aucSysMem0, sizeof(CirBufSendCB));//分配一个循环buf发送控制块
if (cirBufSendCB == NULL) {
return NULL;
}
(VOID)memset_s(cirBufSendCB, sizeof(CirBufSendCB), 0, sizeof(CirBufSendCB));
- fifo = (CHAR *)LOS_MemAlloc(m_aucSysMem0, CONSOLE_CIRCBUF_SIZE);
+ fifo = (CHAR *)LOS_MemAlloc(m_aucSysMem0, CONSOLE_CIRCBUF_SIZE);//分配FIFO buf 1K
if (fifo == NULL) {
goto ERROR_WITH_SENDCB;
}
(VOID)memset_s(fifo, CONSOLE_CIRCBUF_SIZE, 0, CONSOLE_CIRCBUF_SIZE);
cirBufCB = &cirBufSendCB->cirBufCB;
- ret = LOS_CirBufInit(cirBufCB, fifo, CONSOLE_CIRCBUF_SIZE);
+ ret = LOS_CirBufInit(cirBufCB, fifo, CONSOLE_CIRCBUF_SIZE);//环形BUF初始化
if (ret != LOS_OK) {
goto ERROR_WITH_FIFO;
}
- (VOID)LOS_EventInit(&cirBufSendCB->sendEvent);
+ (VOID)LOS_EventInit(&cirBufSendCB->sendEvent);//事件初始化
return cirBufSendCB;
ERROR_WITH_FIFO:
@@ -1137,66 +1173,66 @@ ERROR_WITH_SENDCB:
(VOID)LOS_MemFree(m_aucSysMem0, cirBufSendCB);
return NULL;
}
-
+/// 删除循环buf
STATIC VOID ConsoleCirBufDelete(CirBufSendCB *cirBufSendCB)
{
CirBuf *cirBufCB = &cirBufSendCB->cirBufCB;
- (VOID)LOS_MemFree(m_aucSysMem0, cirBufCB->fifo);
- LOS_CirBufDeinit(cirBufCB);
- (VOID)LOS_EventDestroy(&cirBufSendCB->sendEvent);
- (VOID)LOS_MemFree(m_aucSysMem0, cirBufSendCB);
+ (VOID)LOS_MemFree(m_aucSysMem0, cirBufCB->fifo);//释放内存 8K
+ LOS_CirBufDeinit(cirBufCB);//清除初始化操作
+ (VOID)LOS_EventDestroy(&cirBufSendCB->sendEvent);//销毁事件
+ (VOID)LOS_MemFree(m_aucSysMem0, cirBufSendCB);//释放循环buf发送控制块
}
-
+/// 控制台缓存初始化,创建一个 发送任务
STATIC UINT32 OsConsoleBufInit(CONSOLE_CB *consoleCB)
{
UINT32 ret;
TSK_INIT_PARAM_S initParam = {0};
- consoleCB->cirBufSendCB = ConsoleCirBufCreate();
+ consoleCB->cirBufSendCB = ConsoleCirBufCreate();//创建控制台
if (consoleCB->cirBufSendCB == NULL) {
return LOS_NOK;
}
- initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ConsoleSendTask;
- initParam.usTaskPrio = SHELL_TASK_PRIORITY;
- initParam.auwArgs[0] = (UINTPTR)consoleCB;
- initParam.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
- initParam.pcName = (consoleCB->consoleID == CONSOLE_SERIAL) ? "SendToSer" : "SendToTelnet";
- initParam.uwResved = LOS_TASK_STATUS_DETACHED;
+ initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ConsoleSendTask;//控制台发送任务入口函数
+ initParam.usTaskPrio = SHELL_TASK_PRIORITY; //优先级9
+ initParam.auwArgs[0] = (UINTPTR)consoleCB; //入口函数的参数
+ initParam.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; //16K
+ initParam.pcName = (consoleCB->consoleID == CONSOLE_SERIAL) ? "SendToSer" : "SendToTelnet"; //控制台的两种方式
+ initParam.uwResved = LOS_TASK_STATUS_DETACHED; //使用任务分离模式
- ret = LOS_TaskCreate(&consoleCB->sendTaskID, &initParam);
- if (ret != LOS_OK) {
- ConsoleCirBufDelete(consoleCB->cirBufSendCB);
- consoleCB->cirBufSendCB = NULL;
+ ret = LOS_TaskCreate(&consoleCB->sendTaskID, &initParam);//创建task 并加入就绪队列,申请立即调度
+ if (ret != LOS_OK) { //创建失败处理
+ ConsoleCirBufDelete(consoleCB->cirBufSendCB);//释放循环buf
+ consoleCB->cirBufSendCB = NULL;//置NULL
return LOS_NOK;
- }
+ }//永久等待读取 CONSOLE_SEND_TASK_RUNNING 事件,CONSOLE_SEND_TASK_RUNNING 由 ConsoleSendTask 发出.
(VOID)LOS_EventRead(&consoleCB->cirBufSendCB->sendEvent, CONSOLE_SEND_TASK_RUNNING,
LOS_WAITMODE_OR | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER);
-
+ // ... 读取到 CONSOLE_SEND_TASK_RUNNING 事件才会往下执行
return LOS_OK;
}
-
+/// 控制台buf去初始化
STATIC VOID OsConsoleBufDeinit(CONSOLE_CB *consoleCB)
{
CirBufSendCB *cirBufSendCB = consoleCB->cirBufSendCB;
consoleCB->cirBufSendCB = NULL;
- (VOID)LOS_EventWrite(&cirBufSendCB->sendEvent, CONSOLE_SEND_TASK_EXIT);
+ (VOID)LOS_EventWrite(&cirBufSendCB->sendEvent, CONSOLE_SEND_TASK_EXIT);//写任务退出事件 ConsoleSendTask将会收到事件,退出死循环
}
-
+/// 控制台描述符初始化
STATIC CONSOLE_CB *OsConsoleCBInit(UINT32 consoleID)
{
- CONSOLE_CB *consoleCB = (CONSOLE_CB *)LOS_MemAlloc((VOID *)m_aucSysMem0, sizeof(CONSOLE_CB));
+ CONSOLE_CB *consoleCB = (CONSOLE_CB *)LOS_MemAlloc((VOID *)m_aucSysMem0, sizeof(CONSOLE_CB));//内核空间分配控制台描述符
if (consoleCB == NULL) {
return NULL;
}
- (VOID)memset_s(consoleCB, sizeof(CONSOLE_CB), 0, sizeof(CONSOLE_CB));
+ (VOID)memset_s(consoleCB, sizeof(CONSOLE_CB), 0, sizeof(CONSOLE_CB));//清0
- consoleCB->consoleID = consoleID;
+ consoleCB->consoleID = consoleID;//记录控制台ID
consoleCB->pgrpId = -1;
- consoleCB->shellEntryId = SHELL_ENTRYID_INVALID; /* initialize shellEntryId to an invalid value */
- consoleCB->name = LOS_MemAlloc((VOID *)m_aucSysMem0, CONSOLE_NAMELEN);
+ consoleCB->shellEntryId = SHELL_ENTRYID_INVALID; /* initialize shellEntryId to an invalid value *///将shellEntryId初始化为无效值
+ consoleCB->name = LOS_MemAlloc((VOID *)m_aucSysMem0, CONSOLE_NAMELEN);//控制台名称 不能多于16个字符
if (consoleCB->name == NULL) {
PRINT_ERR("consoleCB->name malloc failed\n");
(VOID)LOS_MemFree((VOID *)m_aucSysMem0, consoleCB);
@@ -1204,91 +1240,91 @@ STATIC CONSOLE_CB *OsConsoleCBInit(UINT32 consoleID)
}
return consoleCB;
}
-
+/// 释放控制台描述符初始化时所占用的内核空间
STATIC VOID OsConsoleCBDeinit(CONSOLE_CB *consoleCB)
{
- (VOID)LOS_MemFree((VOID *)m_aucSysMem0, consoleCB->name);
+ (VOID)LOS_MemFree((VOID *)m_aucSysMem0, consoleCB->name);//释放控制台名称占用的内核内存
consoleCB->name = NULL;
- (VOID)LOS_MemFree((VOID *)m_aucSysMem0, consoleCB);
+ (VOID)LOS_MemFree((VOID *)m_aucSysMem0, consoleCB);//释放控制台描述符所占用的内核内存
}
-
+/// 创建一个控制台,这个函数的goto语句贼多
STATIC CONSOLE_CB *OsConsoleCreate(UINT32 consoleID, const CHAR *deviceName)
{
INT32 ret;
- CONSOLE_CB *consoleCB = OsConsoleCBInit(consoleID);
+ CONSOLE_CB *consoleCB = OsConsoleCBInit(consoleID);//初始化控制台
if (consoleCB == NULL) {
PRINT_ERR("console malloc error.\n");
return NULL;
}
ret = snprintf_s(consoleCB->name, CONSOLE_NAMELEN, CONSOLE_NAMELEN - 1,
- "%s%u", CONSOLE, consoleCB->consoleID);
+ "%s%u", CONSOLE, consoleCB->consoleID);//通过printf方式得到name 例如: /dev/console1
if (ret == -1) {
PRINT_ERR("consoleCB->name snprintf_s failed\n");
goto ERR_WITH_NAME;
}
- ret = (INT32)OsConsoleBufInit(consoleCB);
+ ret = (INT32)OsConsoleBufInit(consoleCB);//控制台buf初始化,创建 ConsoleSendTask 任务
if (ret != LOS_OK) {
PRINT_ERR("console OsConsoleBufInit error. %d\n", ret);
goto ERR_WITH_NAME;
}
- ret = (INT32)LOS_SemCreate(1, &consoleCB->consoleSem);
+ ret = (INT32)LOS_SemCreate(1, &consoleCB->consoleSem);//创建控制台信号量
if (ret != LOS_OK) {
PRINT_ERR("create sem for uart failed\n");
goto ERR_WITH_BUF;
}
- ret = OsConsoleDevInit(consoleCB, deviceName);
- if (ret != LOS_OK) {
+ ret = OsConsoleDevInit(consoleCB, deviceName);//控制台设备初始化,注意这步要在 OsConsoleFileInit 的前面.
+ if (ret != LOS_OK) {//先注册驱动程序
PRINT_ERR("console OsConsoleDevInit error. %d\n", ret);
goto ERR_WITH_SEM;
}
- ret = OsConsoleFileInit(consoleCB);
+ ret = OsConsoleFileInit(consoleCB); //为 /dev/console(n|1:2)分配fd(n)
if (ret != LOS_OK) {
PRINT_ERR("console OsConsoleFileInit error. %d\n", ret);
goto ERR_WITH_DEV;
}
- OsConsoleTermiosInit(consoleCB, deviceName);
+ OsConsoleTermiosInit(consoleCB, deviceName);//控制台行规程初始化
return consoleCB;
ERR_WITH_DEV:
- ret = (INT32)OsConsoleDevDeinit(consoleCB);
+ ret = (INT32)OsConsoleDevDeinit(consoleCB);//控制台设备注销
if (ret != LOS_OK) {
PRINT_ERR("OsConsoleDevDeinit failed!\n");
}
ERR_WITH_SEM:
- (VOID)LOS_SemDelete(consoleCB->consoleSem);
+ (VOID)LOS_SemDelete(consoleCB->consoleSem);//控制台信号量删除
ERR_WITH_BUF:
- OsConsoleBufDeinit(consoleCB);
+ OsConsoleBufDeinit(consoleCB);//控制台buf取消初始化
ERR_WITH_NAME:
- OsConsoleCBDeinit(consoleCB);
+ OsConsoleCBDeinit(consoleCB);//控制块取消初始化
return NULL;
}
-
+/// 删除控制台
STATIC UINT32 OsConsoleDelete(CONSOLE_CB *consoleCB)
{
UINT32 ret;
- (VOID)files_close(consoleCB->fd);
- ret = OsConsoleDevDeinit(consoleCB);
+ (VOID)files_close(consoleCB->fd);//回收系统文件句柄
+ ret = OsConsoleDevDeinit(consoleCB);//注销驱动程序
if (ret != LOS_OK) {
PRINT_ERR("OsConsoleDevDeinit failed!\n");
}
- OsConsoleBufDeinit((CONSOLE_CB *)consoleCB);
- (VOID)LOS_SemDelete(consoleCB->consoleSem);
- (VOID)LOS_MemFree(m_aucSysMem0, consoleCB->name);
+ OsConsoleBufDeinit((CONSOLE_CB *)consoleCB);//回收环形缓存区
+ (VOID)LOS_SemDelete(consoleCB->consoleSem);//删除信号量
+ (VOID)LOS_MemFree(m_aucSysMem0, consoleCB->name);//回收控制台名称,此名称占用内核内存
consoleCB->name = NULL;
- (VOID)LOS_MemFree(m_aucSysMem0, consoleCB);
+ (VOID)LOS_MemFree(m_aucSysMem0, consoleCB);//回收控制块本身占用的内存
return ret;
}
-
+///初始化系统控制台并返回 stdinfd stdoutfd stderrfd ,和system_console_deinit成对出现,像控制台的构造函数
/* Initialized system console and return stdinfd stdoutfd stderrfd */
-INT32 system_console_init(const CHAR *deviceName)
+INT32 system_console_init(const CHAR *deviceName)//deviceName: /dev/serial /dev/telnet
{
#ifdef LOSCFG_SHELL
UINT32 ret;
@@ -1297,34 +1333,34 @@ INT32 system_console_init(const CHAR *deviceName)
UINT32 intSave;
CONSOLE_CB *consoleCB = NULL;
- consoleID = OsGetConsoleID(deviceName);
+ consoleID = OsGetConsoleID(deviceName);//获取控制台ID 返回[ CONSOLE_SERIAL(1) | CONSOLE_TELNET(2) | -1 ]三种结果
if (consoleID == -1) {
PRINT_ERR("device is full.\n");
return VFS_ERROR;
}
- consoleCB = OsConsoleCreate((UINT32)consoleID, deviceName);
+ consoleCB = OsConsoleCreate((UINT32)consoleID, deviceName);//创建一个控制台
if (consoleCB == NULL) {
PRINT_ERR("%s, %d\n", __FUNCTION__, __LINE__);
return VFS_ERROR;
}
LOS_SpinLockSave(&g_consoleSpin, &intSave);
- g_console[consoleID - 1] = consoleCB;
- if (OsCurrTaskGet() != NULL) {
- g_taskConsoleIDArray[OsCurrTaskGet()->taskID] = (UINT8)consoleID;
+ g_console[consoleID - 1] = consoleCB;//全局变量, g_console最大值只有2 ,所有任务共用控制台.
+ if (OsCurrTaskGet() != NULL) {//当前task
+ g_taskConsoleIDArray[OsCurrTaskGet()->taskID] = (UINT8)consoleID;//任务绑定控制台ID
}
LOS_SpinUnlockRestore(&g_consoleSpin, intSave);
-#ifdef LOSCFG_SHELL
- ret = OsShellInit(consoleID);
- if (ret != LOS_OK) {
+#ifdef LOSCFG_SHELL //shell支持
+ ret = OsShellInit(consoleID);//初始化shell
+ if (ret != LOS_OK) {//初始化shell失败
PRINT_ERR("%s, %d\n", __FUNCTION__, __LINE__);
LOS_SpinLockSave(&g_consoleSpin, &intSave);
- (VOID)OsConsoleDelete(consoleCB);
+ (VOID)OsConsoleDelete(consoleCB);//删除控制台
g_console[consoleID - 1] = NULL;
if (OsCurrTaskGet() != NULL) {
- g_taskConsoleIDArray[OsCurrTaskGet()->taskID] = 0;
+ g_taskConsoleIDArray[OsCurrTaskGet()->taskID] = 0;//表示当前任务还没有控制台。
}
LOS_SpinUnlockRestore(&g_consoleSpin, intSave);
return VFS_ERROR;
@@ -1333,7 +1369,7 @@ INT32 system_console_init(const CHAR *deviceName)
return ENOERR;
}
-
+///控制台结束前的处理 和 system_console_init成对出现,像控制台的析构函数
INT32 system_console_deinit(const CHAR *deviceName)
{
UINT32 ret;
@@ -1342,29 +1378,30 @@ INT32 system_console_deinit(const CHAR *deviceName)
LosTaskCB *taskCB = NULL;
UINT32 intSave;
- consoleCB = OsGetConsoleByDevice(deviceName);
+ consoleCB = OsGetConsoleByDevice(deviceName);//通过设备名称获取控制台描述符
if (consoleCB == NULL) {
return VFS_ERROR;
}
#ifdef LOSCFG_SHELL
- (VOID)OsShellDeinit((INT32)consoleCB->consoleID);
+ (VOID)OsShellDeinit((INT32)consoleCB->consoleID);//shell结束前的处理,shell的析构函数
#endif
LOS_SpinLockSave(&g_consoleSpin, &intSave);
/* Redirect all tasks to serial as telnet was unavailable after deinitializing */
- for (taskIdx = 0; taskIdx < g_taskMaxNum; taskIdx++) {
+ //在远程登陆去初始化后变成无效时,将所有任务的控制台重定向到串口方式。
+ for (taskIdx = 0; taskIdx < g_taskMaxNum; taskIdx++) {//这里是对所有的任务控制台方式设为串口化
taskCB = ((LosTaskCB *)g_taskCBArray) + taskIdx;
- if (OsTaskIsUnused(taskCB)) {
- continue;
+ if (OsTaskIsUnused(taskCB)) {//任务还没被使用过
+ continue;//继续
} else {
- g_taskConsoleIDArray[taskCB->taskID] = CONSOLE_SERIAL;
+ g_taskConsoleIDArray[taskCB->taskID] = CONSOLE_SERIAL;//任务对于的控制台变成串口方式
}
}
g_console[consoleCB->consoleID - 1] = NULL;
LOS_SpinUnlockRestore(&g_consoleSpin, intSave);
- ret = OsConsoleDelete(consoleCB);
+ ret = OsConsoleDelete(consoleCB);//删除控制台
if (ret != LOS_OK) {
PRINT_ERR("%s, Failed to system_console_deinit\n", __FUNCTION__);
return VFS_ERROR;
@@ -1372,13 +1409,13 @@ INT32 system_console_deinit(const CHAR *deviceName)
return ENOERR;
}
-
+///控制台使能
BOOL ConsoleEnable(VOID)
{
INT32 consoleID;
- if (OsCurrTaskGet() != NULL) {
- consoleID = g_taskConsoleIDArray[OsCurrTaskGet()->taskID];
+ if (OsCurrTaskGet() != NULL) {//有当前任务的情况下
+ consoleID = g_taskConsoleIDArray[OsCurrTaskGet()->taskID];//获取当前任务的控制台ID
if (g_uart_fputc_en == 0) {
if ((g_console[CONSOLE_TELNET - 1] != NULL) && OsPreemptable()) {
return TRUE;
@@ -1399,26 +1436,26 @@ BOOL ConsoleEnable(VOID)
return FALSE;
}
-
+///< ShellEntry是否在运行,其为负责接受来自终端敲入的一个个字符
BOOL IsShellEntryRunning(UINT32 shellEntryId)
{
LosTaskCB *taskCB = NULL;
if (shellEntryId == SHELL_ENTRYID_INVALID) {
return FALSE;
}
- taskCB = OsGetTaskCB(shellEntryId);
- return !OsTaskIsUnused(taskCB) &&
+ taskCB = OsGetTaskCB(shellEntryId);//获取任务
+ return !OsTaskIsUnused(taskCB) && //确定名为"ShellEntry"的任务
(strlen(taskCB->taskName) == SHELL_ENTRY_NAME_LEN &&
strncmp(taskCB->taskName, SHELL_ENTRY_NAME, SHELL_ENTRY_NAME_LEN) == 0);
}
-
+///任务注册控制台,每个shell任务都有属于自己的控制台
INT32 ConsoleTaskReg(INT32 consoleID, UINT32 taskID)
{
UINT32 intSave;
LOS_SpinLockSave(&g_consoleSpin, &intSave);
- if (!IsShellEntryRunning(g_console[consoleID - 1]->shellEntryId)) {
- g_console[consoleID - 1]->shellEntryId = taskID;
+ if (!IsShellEntryRunning(g_console[consoleID - 1]->shellEntryId)) {//如果控制台还没有捆绑shell客户端任务
+ g_console[consoleID - 1]->shellEntryId = taskID; //给控制台捆绑一个shell客户端任务,接受终端输入.
LOS_SpinUnlockRestore(&g_consoleSpin, intSave);
(VOID)OsSetCurrProcessGroupID(OS_USER_ROOT_PROCESS_ID);
return LOS_OK;
@@ -1426,7 +1463,7 @@ INT32 ConsoleTaskReg(INT32 consoleID, UINT32 taskID)
LOS_SpinUnlockRestore(&g_consoleSpin, intSave);
return (g_console[consoleID - 1]->shellEntryId == taskID) ? LOS_OK : LOS_NOK;
}
-
+///无锁方式设置串口
BOOL SetSerialNonBlock(const CONSOLE_CB *consoleCB)
{
if (consoleCB == NULL) {
@@ -1436,6 +1473,7 @@ BOOL SetSerialNonBlock(const CONSOLE_CB *consoleCB)
return ioctl(consoleCB->fd, CONSOLE_CMD_RD_BLOCK_SERIAL, CONSOLE_RD_NONBLOCK) == 0;
}
+///锁方式设置串口
BOOL SetSerialBlock(const CONSOLE_CB *consoleCB)
{
if (consoleCB == NULL) {
@@ -1445,6 +1483,7 @@ BOOL SetSerialBlock(const CONSOLE_CB *consoleCB)
return ioctl(consoleCB->fd, CONSOLE_CMD_RD_BLOCK_SERIAL, CONSOLE_RD_BLOCK) != 0;
}
+///无锁方式设置远程登录
BOOL SetTelnetNonBlock(const CONSOLE_CB *consoleCB)
{
if (consoleCB == NULL) {
@@ -1454,6 +1493,7 @@ BOOL SetTelnetNonBlock(const CONSOLE_CB *consoleCB)
return ioctl(consoleCB->fd, CONSOLE_CMD_RD_BLOCK_TELNET, CONSOLE_RD_NONBLOCK) == 0;
}
+///锁方式设置远程登录
BOOL SetTelnetBlock(const CONSOLE_CB *consoleCB)
{
if (consoleCB == NULL) {
@@ -1471,13 +1511,13 @@ BOOL is_nonblock(const CONSOLE_CB *consoleCB)
}
return consoleCB->isNonBlock;
}
-
+///控制台更新文件句柄
INT32 ConsoleUpdateFd(VOID)
{
INT32 consoleID;
if (OsCurrTaskGet() != NULL) {
- consoleID = g_taskConsoleIDArray[(OsCurrTaskGet())->taskID];
+ consoleID = g_taskConsoleIDArray[(OsCurrTaskGet())->taskID];//获取当前任务的控制台 (1,2,-1)
} else {
return -1;
}
@@ -1500,21 +1540,22 @@ INT32 ConsoleUpdateFd(VOID)
return (g_console[consoleID - 1] != NULL) ? g_console[consoleID - 1]->fd : -1;
}
+///获取参数控制台ID 获取对应的控制台控制块(描述符)
CONSOLE_CB *OsGetConsoleByID(INT32 consoleID)
{
- if (consoleID != CONSOLE_TELNET) {
+ if (consoleID != CONSOLE_TELNET) {//只允许 1,2存在,> 3 时统统变成1
consoleID = CONSOLE_SERIAL;
}
return g_console[consoleID - 1];
}
-
+///获取参数任务的控制台控制块(描述符)
CONSOLE_CB *OsGetConsoleByTaskID(UINT32 taskID)
{
INT32 consoleID = g_taskConsoleIDArray[taskID];
return OsGetConsoleByID(consoleID);
}
-
+///设置控制台ID
VOID OsSetConsoleID(UINT32 newTaskID, UINT32 curTaskID)
{
if ((newTaskID >= LOSCFG_BASE_CORE_TSK_LIMIT) || (curTaskID >= LOSCFG_BASE_CORE_TSK_LIMIT)) {
@@ -1523,7 +1564,7 @@ VOID OsSetConsoleID(UINT32 newTaskID, UINT32 curTaskID)
g_taskConsoleIDArray[newTaskID] = g_taskConsoleIDArray[curTaskID];
}
-
+///将buf内容写到终端设备
STATIC ssize_t WriteToTerminal(const CONSOLE_CB *consoleCB, const CHAR *buffer, size_t bufLen)
{
INT32 ret, fd;
@@ -1532,13 +1573,13 @@ STATIC ssize_t WriteToTerminal(const CONSOLE_CB *consoleCB, const CHAR *buffer,
struct file *filep = NULL;
const struct file_operations_vfs *fileOps = NULL;
- fd = consoleCB->fd;
- ret = fs_getfilep(fd, &filep);
+ fd = consoleCB->fd;//获取文件描述符
+ ret = fs_getfilep(fd, &filep);//获取文件指针
if (ret < 0) {
ret = -EPERM;
goto ERROUT;
}
- ret = GetFilepOps(filep, &privFilep, &fileOps);
+ ret = GetFilepOps(filep, &privFilep, &fileOps);//获取终端设备私有操作方法
if (ret != ENOERR) {
ret = -EINVAL;
goto ERROUT;
@@ -1548,7 +1589,7 @@ STATIC ssize_t WriteToTerminal(const CONSOLE_CB *consoleCB, const CHAR *buffer,
ret = EFAULT;
goto ERROUT;
}
- (VOID)fileOps->write(privFilep, buffer, bufLen);
+ (VOID)fileOps->write(privFilep, buffer, bufLen);//写入终端设备,在终端设备上呈现出来
return cnt;
@@ -1556,7 +1597,7 @@ ERROUT:
set_errno(ret);
return VFS_ERROR;
}
-
+///控制台发送任务
STATIC UINT32 ConsoleSendTask(UINTPTR param)
{
CONSOLE_CB *consoleCB = (CONSOLE_CB *)param;
@@ -1565,44 +1606,44 @@ STATIC UINT32 ConsoleSendTask(UINTPTR param)
UINT32 ret, size;
CHAR *buf = NULL;
- (VOID)LOS_EventWrite(&cirBufSendCB->sendEvent, CONSOLE_SEND_TASK_RUNNING);
+ (VOID)LOS_EventWrite(&cirBufSendCB->sendEvent, CONSOLE_SEND_TASK_RUNNING);//发送一个控制台任务正在运行的事件
- while (1) {
+ while (1) {//读取 CONSOLE_CIRBUF_EVENT | CONSOLE_SEND_TASK_EXIT 这两个事件
ret = LOS_EventRead(&cirBufSendCB->sendEvent, CONSOLE_CIRBUF_EVENT | CONSOLE_SEND_TASK_EXIT,
- LOS_WAITMODE_OR | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER);
- if (ret == CONSOLE_CIRBUF_EVENT) {
- size = LOS_CirBufUsedSize(cirBufCB);
+ LOS_WAITMODE_OR | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER);//读取循环buf或任务退出的事件
+ if (ret == CONSOLE_CIRBUF_EVENT) {//控制台循环buf事件发生
+ size = LOS_CirBufUsedSize(cirBufCB);//循环buf使用大小
if (size == 0) {
continue;
}
- buf = (CHAR *)LOS_MemAlloc(m_aucSysMem1, size + 1);
+ buf = (CHAR *)LOS_MemAlloc(m_aucSysMem1, size + 1);//分配接收cirbuf的内存
if (buf == NULL) {
continue;
}
- (VOID)memset_s(buf, size + 1, 0, size + 1);
+ (VOID)memset_s(buf, size + 1, 0, size + 1);//清0
- (VOID)LOS_CirBufRead(cirBufCB, buf, size);
+ (VOID)LOS_CirBufRead(cirBufCB, buf, size);//读取循环cirBufCB至 buf
- (VOID)WriteToTerminal(consoleCB, buf, size);
- (VOID)LOS_MemFree(m_aucSysMem1, buf);
- } else if (ret == CONSOLE_SEND_TASK_EXIT) {
- break;
+ (VOID)WriteToTerminal(consoleCB, buf, size);//将buf数据写到控制台终端设备
+ (VOID)LOS_MemFree(m_aucSysMem1, buf);//清除buf
+ } else if (ret == CONSOLE_SEND_TASK_EXIT) {//收到任务退出的事件, 由 OsConsoleBufDeinit 发出事件.
+ break;//退出循环
}
}
- ConsoleCirBufDelete(cirBufSendCB);
+ ConsoleCirBufDelete(cirBufSendCB);//删除循环buf,归还内存
return LOS_OK;
}
#ifdef LOSCFG_KERNEL_SMP
-VOID OsWaitConsoleSendTaskPend(UINT32 taskID)
+VOID OsWaitConsoleSendTaskPend(UINT32 taskID)//等待控制台发送任务结束
{
UINT32 i;
CONSOLE_CB *console = NULL;
LosTaskCB *taskCB = NULL;
INT32 waitTime = 3000; /* 3000: 3 seconds */
- for (i = 0; i < CONSOLE_NUM; i++) {
+ for (i = 0; i < CONSOLE_NUM; i++) {//轮询控制台
console = g_console[i];
if (console == NULL) {
continue;
@@ -1614,25 +1655,25 @@ VOID OsWaitConsoleSendTaskPend(UINT32 taskID)
taskCB = OS_TCB_FROM_TID(console->sendTaskID);
while ((waitTime > 0) && (taskCB->taskEvent == NULL) && (taskID != console->sendTaskID)) {
- LOS_Mdelay(1); /* 1: wait console task pend */
+ LOS_Mdelay(1); /* 1: wait console task pend */ //等待控制台任务挂起/待办
--waitTime;
}
}
}
-
+///唤醒控制台发送任务
VOID OsWakeConsoleSendTask(VOID)
{
UINT32 i;
CONSOLE_CB *console = NULL;
- for (i = 0; i < CONSOLE_NUM; i++) {
+ for (i = 0; i < CONSOLE_NUM; i++) {//循环控制台数量,只有2个
console = g_console[i];
if (console == NULL) {
continue;
}
- if (console->cirBufSendCB != NULL) {
- (VOID)LOS_EventWrite(&console->cirBufSendCB->sendEvent, CONSOLE_CIRBUF_EVENT);
+ if (console->cirBufSendCB != NULL) {//循环缓存描述符
+ (VOID)LOS_EventWrite(&console->cirBufSendCB->sendEvent, CONSOLE_CIRBUF_EVENT);//写循环缓存区buf事件
}
}
}
diff --git a/src/kernel_liteos_a/kernel/common/console.h b/src/kernel_liteos_a/kernel/common/console.h
index b95ac48a..89b18f25 100644
--- a/src/kernel_liteos_a/kernel/common/console.h
+++ b/src/kernel_liteos_a/kernel/common/console.h
@@ -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/console是一个虚拟的tty,在鸿蒙它映射到真正的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 是在POSIX规范中定义的标准接口,表示终端设备,包括虚拟终端、串口等。串口通过termios进行配置。
+ 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
diff --git a/src/kernel_liteos_a/kernel/common/los_config.c b/src/kernel_liteos_a/kernel/common/los_config.c
index 02723ee0..2003b314 100644
--- a/src/kernel_liteos_a/kernel/common/los_config.c
+++ b/src/kernel_liteos_a/kernel/common/los_config.c
@@ -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,