提交 e97fa9f1 编写于 作者: 鸿蒙内核源码分析's avatar 鸿蒙内核源码分析

prinf,可变参数是如何实现的? 用到了musl的哪些标准C库代码

搜索 @note_pic 可以查看全部字符图
搜索 @note_why 是注者尚未看明白的地方,如果您看明白了,请告诉注者完善
搜索 @note_thinking 是注者的思考和吐槽的地方
上级 a40f2716
......@@ -54,7 +54,7 @@ extern "C" {
/* Define two fixed console id for Console 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 //标准输出
......
......@@ -76,37 +76,37 @@ STATIC VOID ErrorMsg(VOID)
const CHAR *p = "Output illegal string! vsnprintf_s failed!\n";
UartPuts(p, (UINT32)strlen(p), UART_WITH_LOCK);
}
//串口输出,打印消息的本质就是串口输出buf
//串口输出,打印消息的本质就是串口输出buf
STATIC VOID UartOutput(const CHAR *str, UINT32 len, BOOL isLock)
{
#ifdef LOSCFG_SHELL_DMESG
if (!OsCheckUartLock()) {
UartPuts(str, len, isLock);
#ifdef LOSCFG_SHELL_DMESG //是否打开了 dmesg开关,打开了会写到文件中 var/log/dmesg 文件中
if (!OsCheckUartLock()) {//是否被锁
UartPuts(str, len, isLock);//直接写串口
}
if (isLock != UART_WITHOUT_LOCK) {
(VOID)OsLogMemcpyRecord(str, len);
(VOID)OsLogMemcpyRecord(str, len);//写入dmesg缓存区
}
#else
UartPuts(str, len, isLock);
UartPuts(str, len, isLock);//没有打开dmesg开关时,直接写串口
#endif
}
//输出日志
//输出控制处理
VOID OutputControl(const CHAR *str, UINT32 len, OutputType type)
{
switch (type) {
case CONSOLE_OUTPUT:
#ifdef LOSCFG_PLATFORM_CONSOLE
if (ConsoleEnable() == TRUE) {
(VOID)write(STDOUT_FILENO, str, (size_t)len);
break;
if (ConsoleEnable() == TRUE) {//POSIX 定义了 STDIN_FILENO、STDOUT_FILENO 和 STDERR_FILENO 来代替 0、1、2
(VOID)write(STDOUT_FILENO, str, (size_t)len);//向控制台写日志, STDOUT_FILENO可理解为 fd = 1 的一个文件
break;//在三个文件会在 VFS中默认创建
}
#endif
/* fall-through */
/* fall-through */ //落空的情况下,会接着向串口打印数据
case UART_OUTPUT:
UartOutput(str, len, UART_WITH_LOCK);
UartOutput(str, len, UART_WITH_LOCK);//向串口发送数据
break;
case EXC_OUTPUT:
UartOutput(str, len, UART_WITHOUT_LOCK);
UartOutput(str, len, UART_WITHOUT_LOCK);//以串口不加锁的方式发送数据
break;
default:
break;
......@@ -120,41 +120,42 @@ STATIC VOID OsVprintfFree(CHAR *buf, UINT32 bufLen)
(VOID)LOS_MemFree(m_aucSysMem0, buf);
}
}
//
//printf由 print 和 format 两个单词构成,格式化输出函数, 一般用于向标准输出设备按规定格式输出信息
//鸿蒙由OsVprintf 来实现可变参数日志格式的输入
VOID OsVprintf(const CHAR *fmt, va_list ap, OutputType type)
{
INT32 len;
const CHAR *errMsgMalloc = "OsVprintf, malloc failed!\n";
const CHAR *errMsgLen = "OsVprintf, length overflow!\n";
const CHAR *errMsgMalloc = "OsVprintf, malloc failed!\n";//内存分配失败的错误日志,注意这是在打印函数里分配内存失败的情况
const CHAR *errMsgLen = "OsVprintf, length overflow!\n";//所以要直接向串口发送字符串,不能再调用 printK(...)打印日志了.
CHAR aBuf[SIZEBUF] = {0};
CHAR *bBuf = NULL;
UINT32 bufLen = SIZEBUF;
UINT32 systemStatus;
bBuf = aBuf;
len = vsnprintf_s(bBuf, bufLen, bufLen - 1, fmt, ap);
if ((len == -1) && (*bBuf == '\0')) {
/* parameter is illegal or some features in fmt dont support */
len = vsnprintf_s(bBuf, bufLen, bufLen - 1, fmt, ap);//C语言库函数之一,属于可变参数。用于向字符串中打印数据、数据格式用户自定义。
if ((len == -1) && (*bBuf == '\0')) {//直接碰到字符串结束符或长度异常
/* parameter is illegal or some features in fmt dont support */ //参数非法或fmt中的某些功能不支持
ErrorMsg();
return;
}
while (len == -1) {
while (len == -1) {//处理((len == -1) && (*bBuf != '\0'))的情况
/* bBuf is not enough */
OsVprintfFree(bBuf, bufLen);
bufLen = bufLen << 1;
if ((INT32)bufLen <= 0) {
if ((INT32)bufLen <= 0) {//异常情况下 向串口发送
UartPuts(errMsgLen, (UINT32)strlen(errMsgLen), UART_WITH_LOCK);
return;
}
bBuf = (CHAR *)LOS_MemAlloc(m_aucSysMem0, bufLen);
if (bBuf == NULL) {
if (bBuf == NULL) {//分配内存失败,直接向串口发送错误信息
UartPuts(errMsgMalloc, (UINT32)strlen(errMsgMalloc), UART_WITH_LOCK);
return;
}
len = vsnprintf_s(bBuf, bufLen, bufLen - 1, fmt, ap);
if (*bBuf == '\0') {
len = vsnprintf_s(bBuf, bufLen, bufLen - 1, fmt, ap);//将ap按格式输出到buf中
if (*bBuf == '\0') {//字符串结束符
/* parameter is illegal or some features in fmt dont support */
(VOID)LOS_MemFree(m_aucSysMem0, bBuf);
ErrorMsg();
......@@ -171,12 +172,12 @@ VOID OsVprintf(const CHAR *fmt, va_list ap, OutputType type)
}
OsVprintfFree(bBuf, bufLen);
}
//串口方式输入printf内容
VOID UartVprintf(const CHAR *fmt, va_list ap)
{
OsVprintf(fmt, ap, UART_OUTPUT);
}
//__attribute__((noinline)) 意思是告诉编译器 这是非内联函数
__attribute__((noinline)) VOID UartPrintf(const CHAR *fmt, ...)
{
va_list ap;
......@@ -192,7 +193,7 @@ __attribute__ ((noinline)) VOID dprintf(const CHAR *fmt, ...)
OsVprintf(fmt, ap, CONSOLE_OUTPUT);
va_end(ap);
}
//LK 注者的理解是 log kernel(内核日志)
VOID LkDprintf(const CHAR *fmt, va_list ap)
{
OsVprintf(fmt, ap, CONSOLE_OUTPUT);
......@@ -246,7 +247,7 @@ VOID PrintExcInfo(const CHAR *fmt, ...)
va_end(ap);
}
#ifndef LOSCFG_SHELL_LK
#ifndef LOSCFG_SHELL_LK //log kernel 内核日志
VOID LOS_LkPrint(INT32 level, const CHAR *func, INT32 line, const CHAR *fmt, ...)
{
va_list ap;
......@@ -256,9 +257,9 @@ VOID LOS_LkPrint(INT32 level, const CHAR *func, INT32 line, const CHAR *fmt, ...
}
if ((level != LOS_COMMON_LEVEL) && ((level > LOS_EMG_LEVEL) && (level <= LOS_TRACE_LEVEL))) {
dprintf("[%s]", g_logString[level]);
dprintf("[%s]", g_logString[level]);//日志格式,先打印日志头 INFO .....
}
OsVprintf(fmt, ap, CONSOLE_OUTPUT);
OsVprintf(fmt, ap, CONSOLE_OUTPUT);//控制台打印
va_end(ap);
}
#endif
......
......@@ -49,6 +49,7 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
//见于\third_party\musl\kernel\include\*.h
extern VOID LOS_LkPrint(INT32 level, const CHAR *func, INT32 line, const CHAR *fmt, ...);
#define LOS_EMG_LEVEL 0
......
......@@ -44,13 +44,13 @@ extern "C" {
* @ingroup dmesg
* Defalut dmesg buffer size.
*/
#define KERNEL_LOG_BUF_SIZE (8 * 1024)
#define KERNEL_LOG_BUF_SIZE (8 * 1024) //默认缓存区大小
/**
* @ingroup dmesg
* Max dmesg buffer size to set.
*/
#define MAX_KERNEL_LOG_BUF_SIZE (8 * 1024 * 10)
#define MAX_KERNEL_LOG_BUF_SIZE (8 * 1024 * 10) //设置缓冲区大小的上限 可以通过shell dmesg -s XX(K) 来改变缓冲区大小
/**
* @ingroup dmesg
......
......@@ -72,13 +72,13 @@ extern "C" {
LITE_OS_SEC_BSS STATIC SPIN_LOCK_INIT(g_dmesgSpin);//dmesg自旋锁初始化
STATIC DmesgInfo *g_dmesgInfo = NULL; //日志缓冲区描述符
STATIC UINT32 g_logBufSize = 0; //日志buf大小,默认8K
STATIC DmesgInfo *g_dmesgInfo = NULL; //缓存区描述符
STATIC UINT32 g_logBufSize = 0; //缓存buf大小,默认8K
STATIC VOID *g_mallocAddr = NULL; //dmesg buf地址
STATIC UINT32 g_dmesgLogLevel = 3; //默认日志等级 LOS_ERR_LEVEL = 3
STATIC UINT32 g_consoleLock = 0; //控制台锁
STATIC UINT32 g_uartLock = 0; //串口锁
STATIC const CHAR *g_levelString[] = {
STATIC const CHAR *g_levelString[] = {//缓存等级
"EMG",
"COMMON",
"ERR",
......@@ -481,7 +481,7 @@ STATIC VOID OsWriteTailToEnd(const CHAR *dst, UINT32 logLen)
g_dmesgInfo->logSize += logLen;
}
}
//dmesg中记录日志
INT32 OsLogMemcpyRecord(const CHAR *buf, UINT32 logLen)
{
UINT32 intSave;
......@@ -491,20 +491,20 @@ INT32 OsLogMemcpyRecord(const CHAR *buf, UINT32 logLen)
LOS_SpinUnlockRestore(&g_dmesgSpin, intSave);
return -1;
}
if (g_dmesgInfo->logSize < g_logBufSize) {
if (g_dmesgInfo->logHead <= g_dmesgInfo->logTail) {
OsWriteTailToEnd(buf, logLen);
if (g_dmesgInfo->logSize < g_logBufSize) {//小于缓冲区大小的情况将怎么写入数据?
if (g_dmesgInfo->logHead <= g_dmesgInfo->logTail) {//说明head位置还有未读取的数据
OsWriteTailToEnd(buf, logLen);//从写数据的位置开始写入
} else {
OsWriteTailToHead(buf, logLen);
OsWriteTailToHead(buf, logLen);//从读数据的位置开始写入
}
} else {
OsBufFullWrite(buf, logLen);
} else {//超过缓冲区大小的情况
OsBufFullWrite(buf, logLen);//全覆盖方式写buf
}
LOS_SpinUnlockRestore(&g_dmesgSpin, intSave);
return LOS_OK;
}
//显示日志,写串口
//打印缓存区内容 shell dmesg 命令调用
VOID OsLogShow(VOID)
{
UINT32 intSave;
......@@ -533,10 +533,10 @@ VOID OsLogShow(VOID)
}
}
LOS_SpinUnlockRestore(&g_dmesgSpin, intSave);
UartPuts(p, i, UART_WITH_LOCK);//串口写入数据
UartPuts(p, i, UART_WITH_LOCK);//向串口发送数据
free(p);//释放内存
}
//设置缓存等级,一共五级,默认第三级
STATIC INT32 OsDmesgLvSet(const CHAR *level)
{
UINT32 levelNum, ret;
......@@ -558,18 +558,18 @@ STATIC INT32 OsDmesgLvSet(const CHAR *level)
return -1;
}
}
//设置缓冲区大小, shell dmesg -s 16K
STATIC INT32 OsDmesgMemSizeSet(const CHAR *size)
{
UINT32 sizeVal;
CHAR *p = NULL;
sizeVal = strtoul(size, &p, 0);
if (sizeVal > MAX_KERNEL_LOG_BUF_SIZE) {
sizeVal = strtoul(size, &p, 0);//C库函数将size所指向的字符串根据给定的base转换为一个无符号长整数(类型为 unsigned long int 型)
if (sizeVal > MAX_KERNEL_LOG_BUF_SIZE) {//不能超过缓存区的上限,默认80K
goto ERR_OUT;
}
if (!(LOS_DmesgMemSet(NULL, sizeVal))) {
if (!(LOS_DmesgMemSet(NULL, sizeVal))) {//调整缓存区大小
PRINTK("Set dmesg buf size %u success\n", sizeVal);
return LOS_OK;
} else {
......@@ -619,7 +619,7 @@ UINT32 LOS_DmesgMemSet(VOID *addr, UINT32 size)
}
return ret;
}
//LOS 开头为外部接口, 封装 OsDmesgRead
INT32 LOS_DmesgRead(CHAR *buf, UINT32 len)
{
INT32 ret;
......@@ -637,13 +637,13 @@ INT32 LOS_DmesgRead(CHAR *buf, UINT32 len)
LOS_SpinUnlockRestore(&g_dmesgSpin, intSave);
return ret;
}
//将缓冲区内容写到指定文件
INT32 OsDmesgWrite2File(const CHAR *fullpath, const CHAR *buf, UINT32 logSize)
{
INT32 ret;
INT32 fd = open(fullpath, O_CREAT | O_RDWR | O_APPEND, 0644); /* 0644:file right */
if (fd < 0) {
//见于 third_party\NuttX\fs\vfs\fs_open.c
INT32 fd = open(fullpath, O_CREAT | O_RDWR | O_APPEND, 0644); /* 0644:file right */ //可读可写 ,并以append的方式写文件
if (fd < 0) { //fd必须大于0 ,并且 0,1,2 被控制台占用
return -1;
}
ret = write(fd, buf, logSize);
......@@ -651,7 +651,7 @@ INT32 OsDmesgWrite2File(const CHAR *fullpath, const CHAR *buf, UINT32 logSize)
return ret;
}
#ifdef LOSCFG_FS_VFS
#ifdef LOSCFG_FS_VFS //是否支持虚拟文件系统
INT32 LOS_DmesgToFile(const CHAR *filename)
{
CHAR *fullpath = NULL;
......@@ -706,7 +706,7 @@ ERR_OUT2:
free(fullpath);
return ret;
}
#else
#else //不支持虚拟文件系统直接串口输出
INT32 LOS_DmesgToFile(CHAR *filename)
{
(VOID)filename;
......@@ -716,6 +716,11 @@ INT32 LOS_DmesgToFile(CHAR *filename)
#endif
/****************************************************************
dmesg是一种程序,用于检测和控制内核环缓冲。程序用来帮助用户了解系统的启动信息。
Linux dmesg命令用于显示开机信息。鸿蒙沿用了linux dmesg命令
kernel会将开机信息存储在ring buffer中。您若是开机时来不及查看信息,可利用dmesg来查看。
开机信息亦保存在/var/log目录中,名称为dmesg的文件里
命令功能
dmesg命令用于控制内核dmesg缓存区。
......@@ -761,24 +766,24 @@ INT32 OsShellCmdDmesg(INT32 argc, const CHAR **argv)
goto ERR_OUT;
}
if (!strcmp(argv[1], "-c")) {
if (!strcmp(argv[1], "-c")) {//打印缓存区内容并清空缓存区。
PRINTK("\n");
OsLogShow();
LOS_DmesgClear();
return LOS_OK;
} else if (!strcmp(argv[1], "-C")) {
} else if (!strcmp(argv[1], "-C")) {//清空缓存区
LOS_DmesgClear();
return LOS_OK;
} else if (!strcmp(argv[1], "-D")) {
} else if (!strcmp(argv[1], "-D")) {//关闭控制台打印
OsLockConsole();
return LOS_OK;
} else if (!strcmp(argv[1], "-E")) {
} else if (!strcmp(argv[1], "-E")) {//开启控制台打印
OsUnlockConsole();
return LOS_OK;
} else if (!strcmp(argv[1], "-L")) {
} else if (!strcmp(argv[1], "-L")) {//关闭串口打印
OsLockUart();
return LOS_OK;
} else if (!strcmp(argv[1], "-U")) {
} else if (!strcmp(argv[1], "-U")) {//开启串口打印
OsUnlockUart();
return LOS_OK;
}
......@@ -796,9 +801,9 @@ INT32 OsShellCmdDmesg(INT32 argc, const CHAR **argv)
return LOS_OK;
}
} else if (!strcmp(argv[1], "-l")) {
return OsDmesgLvSet(argv[2]); /* 2:index of parameters */
return OsDmesgLvSet(argv[2]); /* 2:index of parameters */ //设置缓存等级,一共五级,默认第三级
} else if (!strcmp(argv[1], "-s")) {
return OsDmesgMemSizeSet(argv[2]); /* 2:index of parameters */
return OsDmesgMemSizeSet(argv[2]); /* 2:index of parameters */ //设置缓冲区大小
}
}
......
git add -A
git commit -m '内核日志缓冲区 Dmesg 实现部分代码注释
git commit -m 'prinf,可变参数是如何实现的? 用到了musl的哪些标准C库代码
搜索 @note_pic 可以查看全部字符图
搜索 @note_why 是注者尚未看明白的地方,如果您看明白了,请告诉注者完善
搜索 @note_thinking 是注者的思考和吐槽的地方
......
......@@ -12,21 +12,19 @@ typedef struct LOS_DL_LIST {
struct LOS_DL_LIST *pstNext; /**< Current node's pointer to the next node */
} LOS_DL_LIST;
//鸿蒙内核源码分析系列篇 https://blog.csdn.net/kuangyufei
void b(){
UINT8 w[3]={0};
PTE_T pte1BasePtr = 0x11100000;
VADDR_T vaddr = 0x80738903;
#define MMU_DESCRIPTOR_L1_SMALL_SIZE 0x100000 //1M
#define MMU_DESCRIPTOR_L1_SMALL_MASK (MMU_DESCRIPTOR_L1_SMALL_SIZE - 1)
#define MMU_DESCRIPTOR_L1_SMALL_FRAME (~MMU_DESCRIPTOR_L1_SMALL_MASK)
#define MMU_DESCRIPTOR_L1_SMALL_SHIFT 20
#define MMU_DESCRIPTOR_L1_SECTION_ADDR(x) ((x) & MMU_DESCRIPTOR_L1_SMALL_FRAME)
#define OS_TSK_HIGH_BITS 3U
#define OS_TSK_LOW_BITS (32U - OS_TSK_HIGH_BITS) //29
#define OS_TSK_SORTLINK_LOGLEN OS_TSK_HIGH_BITS //3U
#define MMU_DESCRIPTOR_L1_SMALL_SIZE 0x100000 //1M
#define MMU_DESCRIPTOR_L1_SMALL_MASK (MMU_DESCRIPTOR_L1_SMALL_SIZE - 1)
#define MMU_DESCRIPTOR_L1_SMALL_FRAME (~MMU_DESCRIPTOR_L1_SMALL_MASK)
#define MMU_DESCRIPTOR_L1_SMALL_SHIFT 20
#define MMU_DESCRIPTOR_L1_SECTION_ADDR(x) ((x) & MMU_DESCRIPTOR_L1_SMALL_FRAME)
#define OS_TSK_HIGH_BITS 3U
#define OS_TSK_LOW_BITS (32U - OS_TSK_HIGH_BITS) //29
#define OS_TSK_SORTLINK_LOGLEN OS_TSK_HIGH_BITS //3U
PTE_T l1Entry = pte1BasePtr + vaddr >> MMU_DESCRIPTOR_L1_SMALL_SHIFT;
printf("pte1BasePtr ad: %x\n",&pte1BasePtr);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册