更新日期: 2022/06/01 来源: https://gitee.com/weharmony/kernel_liteos_a_note
los_printf.c
浏览该文件的文档.
1/*
2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 * conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 * of conditions and the following disclaimer in the documentation and/or other materials
13 * provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16 * to endorse or promote products derived from this software without specific prior written
17 * permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include "los_base.h"
33#ifdef LOSCFG_LIB_LIBC
34#include "stdlib.h"
35#include "unistd.h"
36#endif
37#include "los_hwi.h"
38#include "los_memory_pri.h"
39#include "los_process_pri.h"
40#ifdef LOSCFG_FS_VFS
41#include "console.h"
42#endif
43#ifdef LOSCFG_SHELL_DMESG
44#include "dmesg_pri.h"
45#endif
46#ifdef LOSCFG_SAVE_EXCINFO
47#include "los_excinfo_pri.h"
48#endif
49#include "los_exc_pri.h"
50#include "los_sched_pri.h"
51
52#define SIZEBUF 256
53
54const CHAR *g_logString[] = {//日志等级
55 "EMG", //紧急
56 "COMMON", //普通
57 "ERR", //错误日志
58 "WARN", //警告
59 "INFO", //信息
60 "DEBUG", //调试
61 "TRACE" //跟踪
62};
63
64const CHAR *OsLogLvGet(INT32 level)
65{
66 return g_logString[level];
67}
68
69STATIC VOID ErrorMsg(VOID)
70{
71 const CHAR *p = "Output illegal string! vsnprintf_s failed!\n";
72 UartPuts(p, (UINT32)strlen(p), UART_WITH_LOCK);
73}
74///串口输出,打印消息的本质就是向串口输出buf
75STATIC VOID UartOutput(const CHAR *str, UINT32 len, BOOL isLock)
76{
77#ifdef LOSCFG_SHELL_DMESG //是否打开了 dmesg开关,打开了会写到文件中 var/log/dmesg 文件中
78 if (!OsCheckUartLock()) {//是否被锁
79 UartPuts(str, len, isLock);//直接写串口
80 }
81 if (isLock != UART_WITHOUT_LOCK) {
82 (VOID)OsLogMemcpyRecord(str, len);//写入dmesg缓存区
83 }
84#else
85 UartPuts(str, len, isLock);//没有打开dmesg开关时,直接写串口
86#endif
87}
88///控制台输出
89#ifdef LOSCFG_PLATFORM_CONSOLE
90STATIC VOID ConsoleOutput(const CHAR *str, UINT32 len)
91{
92 ssize_t written = 0;
93 ssize_t cnt;
94 ssize_t toWrite = len;//每次写入的数量
95
96 for (;;) {
97 cnt = write(STDOUT_FILENO, str + written, (size_t)toWrite);//向控制台写入数据,STDOUT_FILENO = 1
98 if ((cnt < 0) || ((cnt == 0) && ((!OsPreemptable()) || (OS_INT_ACTIVE))) || (toWrite == cnt)) {
99 break;
100 }
101 written += cnt; //已写入数量增加
102 toWrite -= cnt; //要写入数量减少
103 }
104}
105#endif
106
107VOID OutputControl(const CHAR *str, UINT32 len, OutputType type)
108{
109 switch (type) {//输出类型
110 case CONSOLE_OUTPUT://控制台输出
111#ifdef LOSCFG_PLATFORM_CONSOLE
112 if (ConsoleEnable() == TRUE) {//POSIX 定义了 STDIN_FILENO、STDOUT_FILENO 和 STDERR_FILENO 来代替 0、1、2
113 ConsoleOutput(str, len);//输出到控制台
114 break;
115 }
116#endif
117 /* fall-through */ //落空的情况下,会接着向串口打印数据
118 case UART_OUTPUT: //串口输出
119 UartOutput(str, len, UART_WITH_LOCK);//向串口发送数据
120 break;
121 case EXC_OUTPUT: //异常输出
122 UartPuts(str, len, UART_WITH_LOCK);
123 break;
124 default:
125 break;
126 }
127 return;
128}
129
130STATIC VOID OsVprintfFree(CHAR *buf, UINT32 bufLen)
131{
132 if (bufLen != SIZEBUF) {
133 (VOID)LOS_MemFree(m_aucSysMem0, buf);
134 }
135}
136///printf由 print 和 format 两个单词构成,格式化输出函数, 一般用于向标准输出设备按规定格式输出信息
137//鸿蒙由OsVprintf 来实现可变参数日志格式的输入
138VOID OsVprintf(const CHAR *fmt, va_list ap, OutputType type)
139{
140 INT32 len;
141 const CHAR *errMsgMalloc = "OsVprintf, malloc failed!\n";//内存分配失败的错误日志,注意这是在打印函数里分配内存失败的情况
142 const CHAR *errMsgLen = "OsVprintf, length overflow!\n";//所以要直接向串口发送字符串,不能再调用 printK(...)打印日志了.
143 CHAR aBuf[SIZEBUF] = {0};
144 CHAR *bBuf = NULL;
145 UINT32 bufLen = SIZEBUF;
146 UINT32 systemStatus;
147
148 bBuf = aBuf;
149 len = vsnprintf_s(bBuf, bufLen, bufLen - 1, fmt, ap);//C语言库函数之一,属于可变参数。用于向字符串中打印数据、数据格式用户自定义。
150 if ((len == -1) && (*bBuf == '\0')) {//直接碰到字符串结束符或长度异常
151 /* parameter is illegal or some features in fmt dont support */ //参数非法或fmt中的某些功能不支持
152 ErrorMsg();
153 return;
154 }
155
156 while (len == -1) {//处理((len == -1) && (*bBuf != '\0'))的情况
157 /* bBuf is not enough */
158 OsVprintfFree(bBuf, bufLen);
159
160 bufLen = bufLen << 1;
161 if ((INT32)bufLen <= 0) {//异常情况下 向串口发送
162 UartPuts(errMsgLen, (UINT32)strlen(errMsgLen), UART_WITH_LOCK);
163 return;
164 }
165 bBuf = (CHAR *)LOS_MemAlloc(m_aucSysMem0, bufLen);
166 if (bBuf == NULL) {//分配内存失败,直接向串口发送错误信息
167 UartPuts(errMsgMalloc, (UINT32)strlen(errMsgMalloc), UART_WITH_LOCK);
168 return;
169 }
170 len = vsnprintf_s(bBuf, bufLen, bufLen - 1, fmt, ap);//将ap按格式输出到buf中
171 if (*bBuf == '\0') {//字符串结束符
172 /* parameter is illegal or some features in fmt dont support */
173 (VOID)LOS_MemFree(m_aucSysMem0, bBuf);
174 ErrorMsg();
175 return;
176 }
177 }
178 *(bBuf + len) = '\0';
179
180 systemStatus = OsGetSystemStatus();//获取系统的状态
181 if ((systemStatus == OS_SYSTEM_NORMAL) || (systemStatus == OS_SYSTEM_EXC_OTHER_CPU)) {//当前CPU正常或其他CPU出现异常时
182 OutputControl(bBuf, len, type);//输出到终端
183 } else if (systemStatus == OS_SYSTEM_EXC_CURR_CPU) {//当前CPU出现异常
184 OutputControl(bBuf, len, EXC_OUTPUT);//串口以无锁的方式输出
185 }
186 OsVprintfFree(bBuf, bufLen);
187}
188///串口方式输入printf内容
189VOID UartVprintf(const CHAR *fmt, va_list ap)
190{
191 OsVprintf(fmt, ap, UART_OUTPUT);
192}
193///__attribute__((noinline)) 意思是告诉编译器 这是非内联函数
194__attribute__((noinline)) VOID UartPrintf(const CHAR *fmt, ...)
195{
196 va_list ap;
197 va_start(ap, fmt);
198 OsVprintf(fmt, ap, UART_OUTPUT);
199 va_end(ap);
200}
201///可变参数,输出到控制台
202#ifndef LOSCFG_LIBC_NEWLIB
203__attribute__ ((noinline)) VOID dprintf(const CHAR *fmt, ...)
204{
205 va_list ap;
206 va_start(ap, fmt);
207 OsVprintf(fmt, ap, CONSOLE_OUTPUT);
208#ifdef LOSCFG_SAVE_EXCINFO
209 if (OsGetSystemStatus() == OS_SYSTEM_EXC_CURR_CPU) {
210 WriteExcBufVa(fmt, ap);
211 }
212#endif
213 va_end(ap);
214}
215#endif
216///LK 注者的理解是 log kernel(内核日志)
217VOID LkDprintf(const CHAR *fmt, va_list ap)
218{
219 OsVprintf(fmt, ap, CONSOLE_OUTPUT);
220#ifdef LOSCFG_SAVE_EXCINFO
221 if (OsGetSystemStatus() == OS_SYSTEM_EXC_CURR_CPU) {
222 WriteExcBufVa(fmt, ap);
223 }
224#endif
225}
226
227#ifdef LOSCFG_SHELL_DMESG
228VOID DmesgPrintf(const CHAR *fmt, va_list ap)
229{
230 OsVprintf(fmt, ap, CONSOLE_OUTPUT);
231}
232#endif
233
234#ifdef LOSCFG_PLATFORM_UART_WITHOUT_VFS
235__attribute__ ((noinline)) INT32 printf(const CHAR *fmt, ...)
236{
237 va_list ap;
238 va_start(ap, fmt);
239 OsVprintf(fmt, ap, UART_OUTPUT);
240 va_end(ap);
241 return 0;
242}
243#endif
244//系统日志的输出
245__attribute__((noinline)) VOID syslog(INT32 level, const CHAR *fmt, ...)
246{
247 va_list ap;
248 va_start(ap, fmt);
249 OsVprintf(fmt, ap, CONSOLE_OUTPUT);
250 va_end(ap);
251 (VOID)level;
252}
253///异常信息的输出
254__attribute__((noinline)) VOID ExcPrintf(const CHAR *fmt, ...)
255{
256 va_list ap;
257 va_start(ap, fmt);
258 /* uart output without print-spinlock */
259 OsVprintf(fmt, ap, EXC_OUTPUT);
260 va_end(ap);
261}
262///打印异常信息
263VOID PrintExcInfo(const CHAR *fmt, ...)
264{
265 va_list ap;
266 va_start(ap, fmt);
267 /* uart output without print-spinlock */
268 OsVprintf(fmt, ap, EXC_OUTPUT);//异常信息打印主体函数
269#ifdef LOSCFG_SAVE_EXCINFO
270 WriteExcBufVa(fmt, ap);
271#endif
272 va_end(ap);
273}
274
275#ifndef LOSCFG_SHELL_LK //log kernel 内核日志
276VOID LOS_LkPrint(INT32 level, const CHAR *func, INT32 line, const CHAR *fmt, ...)
277{
278 va_list ap;
279
280 if (level > PRINT_LEVEL) {
281 return;
282 }
283
284 if ((level != LOS_COMMON_LEVEL) && ((level > LOS_EMG_LEVEL) && (level <= LOS_TRACE_LEVEL))) {
285 PRINTK("[%s][%s:%s]", g_logString[level],
286 ((OsCurrProcessGet() == NULL) ? "NULL" : OsCurrProcessGet()->processName),
287 ((OsCurrTaskGet() == NULL) ? "NULL" : OsCurrTaskGet()->taskName));
288 }
289
290 va_start(ap, fmt);
291 OsVprintf(fmt, ap, CONSOLE_OUTPUT);//控制台打印
292#ifdef LOSCFG_SAVE_EXCINFO
293 if (OsGetSystemStatus() == OS_SYSTEM_EXC_CURR_CPU) {
294 WriteExcBufVa(fmt, ap);
295 }
296#endif
297 va_end(ap);
298}
299#endif
300
BOOL ConsoleEnable(VOID)
控制台使能
Definition: console.c:1415
UINT32 OsCheckUartLock(VOID)
Definition: dmesg.c:328
INT32 OsLogMemcpyRecord(const CHAR *buf, UINT32 logLen)
内存拷贝日志
Definition: dmesg.c:508
VOID * LOS_MemAlloc(VOID *pool, UINT32 size)
从指定内存池中申请size长度的内存,注意这可不是从内核堆空间中申请内存
Definition: los_memory.c:1123
UINT32 LOS_MemFree(VOID *pool, VOID *ptr)
释放从指定动态内存中申请的内存
Definition: los_memory.c:1369
UINT8 * m_aucSysMem0
异常交互动态内存池地址的起始地址,当不支持异常交互特性时,m_aucSysMem0等于m_aucSysMem1。
Definition: los_memory.c:107
void dprintf(const char *fmt,...)
Format and print data.
VOID LOS_LkPrint(INT32 level, const CHAR *func, INT32 line, const CHAR *fmt,...)
print log.
Definition: los_printf.c:276
UINT32 OsGetSystemStatus(VOID)
获取系统状态
Definition: los_exc.c:181
VOID WriteExcBufVa(const CHAR *format, va_list arglist)
vsnprintf 为C标准库可变参数的实现函数 见于 ..\third_party\musl\kernel\src\stdio\vsnprintf.c
Definition: los_excinfo.c:99
VOID LkDprintf(const CHAR *fmt, va_list ap)
LK 注者的理解是 log kernel(内核日志)
Definition: los_printf.c:217
VOID OsVprintf(const CHAR *fmt, va_list ap, OutputType type)
printf由 print 和 format 两个单词构成,格式化输出函数, 一般用于向标准输出设备按规定格式输出信息
Definition: los_printf.c:138
VOID UartVprintf(const CHAR *fmt, va_list ap)
串口方式输入printf内容
Definition: los_printf.c:189
STATIC VOID ConsoleOutput(const CHAR *str, UINT32 len)
控制台输出
Definition: los_printf.c:90
const CHAR * OsLogLvGet(INT32 level)
Definition: los_printf.c:64
VOID PrintExcInfo(const CHAR *fmt,...)
打印异常信息
Definition: los_printf.c:263
STATIC VOID ErrorMsg(VOID)
Definition: los_printf.c:69
STATIC VOID UartOutput(const CHAR *str, UINT32 len, BOOL isLock)
串口输出,打印消息的本质就是向串口输出buf
Definition: los_printf.c:75
STATIC VOID OsVprintfFree(CHAR *buf, UINT32 bufLen)
Definition: los_printf.c:130
const CHAR * g_logString[]
Definition: los_printf.c:54
__attribute__((noinline))
attribute((noinline)) 意思是告诉编译器 这是非内联函数
Definition: los_printf.c:194
VOID OutputControl(const CHAR *str, UINT32 len, OutputType type)
Definition: los_printf.c:107
VOID DmesgPrintf(const CHAR *fmt, va_list ap)
Definition: los_printf.c:228
OutputType
Definition: los_printf.h:104
@ EXC_OUTPUT
Definition: los_printf.h:108
@ UART_OUTPUT
Definition: los_printf.h:106
@ CONSOLE_OUTPUT
Definition: los_printf.h:107
STATIC INLINE LosProcessCB * OsCurrProcessGet(VOID)
STATIC INLINE LosTaskCB * OsCurrTaskGet(VOID)
STATIC INLINE BOOL OsPreemptable(VOID)
signed int INT32
Definition: los_typedef.h:60
INT64 ssize_t
Definition: los_typedef.h:79
unsigned int UINT32
Definition: los_typedef.h:57
char CHAR
Definition: los_typedef.h:63
size_t BOOL
Definition: los_typedef.h:88
VOID UartPuts(const CHAR *s, UINT32 len, BOOL isLock)