更新日期: 2022/06/01 来源: https://gitee.com/weharmony/kernel_liteos_a_note
los_hilog.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_hilog.h"
33#include "los_init.h"
34#include "los_mp.h"
35#include "los_mux.h"
36#include "los_process_pri.h"
37#include "los_task_pri.h"
38#include "fs/file.h"
39#include "fs/driver.h"
40#include "los_vm_map.h"
41#include "los_vm_lock.h"
42#include "user_copy.h"
43//hilog是鸿蒙的一个用于输出的功能模块
44#define HILOG_BUFFER LOSCFG_HILOG_BUFFER_SIZE// 4K缓存, ring buf 方式管理
45#define DRIVER_MODE 0666 //权限 chmod 666
46#define HILOG_DRIVER "/dev/hilog" // 可以看出hilog是当一种字符设备来实现
47
48struct HiLogEntry { //hilog 实体
49 unsigned int len; //写入buffer的内容长度
50 unsigned int hdrSize; // sizeof(struct HiLogEntry) ,为何命名hdr @note_why
51 unsigned int pid : 16; //进程ID
52 unsigned int taskId : 16; //任务ID
53 unsigned int sec; //秒级
54 unsigned int nsec; //纳秒级,提供给外部准确分析和定位问题
55 unsigned int reserved;//保留位
56 char msg[0]; //消息内容
57};
58
59ssize_t HilogRead(struct file *filep, char __user *buf, size_t count);
60ssize_t HilogWrite(struct file *filep, const char __user *buf, size_t count);
61int HiLogOpen(struct file *filep);
62int HiLogClose(struct file *filep);
63
64static ssize_t HiLogWrite(struct file *filep, const char *buffer, size_t bufLen);
65static ssize_t HiLogRead(struct file *filep, char *buffer, size_t bufLen);
66//实现VFS接口函数,对hilog进行操作
67STATIC struct file_operations_vfs g_hilogFops = {
68 HiLogOpen, /* open */
69 HiLogClose, /* close */
70 HiLogRead, /* read */
71 HiLogWrite, /* write */
72 NULL, /* seek */
73 NULL, /* ioctl */
74 NULL, /* mmap */
75#ifndef CONFIG_DISABLE_POLL
76 NULL, /* poll */
77#endif
78 NULL, /* unlink */
79};
80
82 int flag; //设备标签
83 LosMux mtx; //读写buf的互斥量
84 unsigned char *buffer;//采用 ring buffer 管理
85 wait_queue_head_t wq;
86 size_t writeOffset;//用于写操作,不断累加
87 size_t headOffset;//用于读操作,不断累加
88 size_t size;//记录buffer使用的大小, 读写操作会返回 +-这个size
89 size_t count;//读写操作的次数对冲
91
92static inline unsigned char *HiLogBufferHead(void)
93{
95}
96///为支持VFS,作打开状
97int HiLogOpen(struct file *filep)
98{
99 (void)filep;
100 return 0;
101}
102///为支持VFS,作关闭状
103int HiLogClose(struct file *filep)
104{
105 (void)filep;
106 return 0;
107}
108///读写对冲,对hilog的写操作,更新相关变量内容
109static void HiLogBufferInc(size_t sz)
110{
111 if (g_hiLogDev.size + sz <= HILOG_BUFFER) {
112 g_hiLogDev.size += sz; //已使用buf的size
113 g_hiLogDev.writeOffset += sz;//大小是不断累加
114 g_hiLogDev.writeOffset %= HILOG_BUFFER;//ring buf
115 g_hiLogDev.count++;//读写对冲
116 }
117}
118///读写对冲,对hilog的读操作,更新相关变量内容
119static void HiLogBufferDec(size_t sz)
120{
121 if (g_hiLogDev.size >= sz) {
122 g_hiLogDev.size -= sz;//维持可使用buf size
124 g_hiLogDev.headOffset %= HILOG_BUFFER;
125 g_hiLogDev.count--;//读写对冲
126 }
127}
128
129static int HiLogBufferCopy(unsigned char *dst, unsigned dstLen, const unsigned char *src, size_t srcLen)
130{
131 int retval = -1;
132 size_t minLen = (dstLen > srcLen) ? srcLen : dstLen;
133
134 if (LOS_IsUserAddressRange((VADDR_T)(UINTPTR)dst, minLen) &&
135 LOS_IsUserAddressRange((VADDR_T)(UINTPTR)src, minLen)) {
136 return retval;
137 }
138
139 if (LOS_IsUserAddressRange((VADDR_T)(UINTPTR)dst, minLen)) {
140 retval = LOS_ArchCopyToUser(dst, src, minLen);
141 } else if (LOS_IsUserAddressRange((VADDR_T)(UINTPTR)src, minLen)) {
142 retval = LOS_ArchCopyFromUser(dst, src, minLen);
143 } else {
144 retval = memcpy_s(dst, dstLen, src, srcLen);
145 }
146 return retval;
147}
148///读取ring buffer
149static int HiLogReadRingBuffer(unsigned char *buffer, size_t bufLen)
150{
151 int retval;
152 size_t bufLeft = HILOG_BUFFER - g_hiLogDev.headOffset;
153 if (bufLeft > bufLen) {//计算出读取方向
154 retval = HiLogBufferCopy(buffer, bufLen, HiLogBufferHead(), bufLen);
155 } else {
156 retval = HiLogBufferCopy(buffer, bufLen, HiLogBufferHead(), bufLeft);
157 if (retval < 0) {
158 return retval;
159 }
160
161 retval = HiLogBufferCopy(buffer + bufLeft, bufLen - bufLeft, g_hiLogDev.buffer, bufLen - bufLeft);
162 }
163 return retval;
164}
165
166static ssize_t HiLogRead(struct file *filep, char *buffer, size_t bufLen)
167{
168 int retval;
169 struct HiLogEntry header;
170
171 (void)filep;
172
173 wait_event_interruptible(g_hiLogDev.wq, (g_hiLogDev.size > 0));
174
175 (VOID)LOS_MuxAcquire(&g_hiLogDev.mtx);//临界区操作开始
176 retval = HiLogReadRingBuffer((unsigned char *)&header, sizeof(header));
177 if (retval < 0) {
178 retval = -EINVAL;
179 goto out;
180 }
181
182 if (bufLen < header.len + sizeof(header)) {
183 PRINTK("buffer too small,bufLen=%d, header.len=%d,%d\n", bufLen, header.len, header.hdrSize);
184 retval = -ENOMEM;
185 goto out;
186 }
187
188 HiLogBufferDec(sizeof(header));
189
190 retval = HiLogBufferCopy((unsigned char *)buffer, bufLen, (unsigned char *)&header, sizeof(header));
191 if (retval < 0) {
192 retval = -EINVAL;
193 goto out;
194 }
195
196 retval = HiLogReadRingBuffer((unsigned char *)(buffer + sizeof(header)), header.len);
197 if (retval < 0) {
198 retval = -EINVAL;
199 goto out;
200 }
201
202 HiLogBufferDec(header.len);
203 retval = header.len + sizeof(header);
204out:
205 if (retval == -ENOMEM) {
206 // clean ring buffer
209 g_hiLogDev.size = 0;
210 g_hiLogDev.count = 0;
211 }
212 (VOID)LOS_MuxRelease(&g_hiLogDev.mtx);//临界区操作结束
213 return (ssize_t)retval;
214}
215///写入 RingBuffer环形缓冲,也叫 circleBuffer
216static int HiLogWriteRingBuffer(unsigned char *buffer, size_t bufLen)
217{
218 int retval;
219 size_t bufLeft = HILOG_BUFFER - g_hiLogDev.writeOffset;
220 if (bufLen > bufLeft) {
221 retval = HiLogBufferCopy(g_hiLogDev.buffer + g_hiLogDev.writeOffset, bufLeft, buffer, bufLeft);
222 if (retval) {
223 return -1;
224 }
225 retval = HiLogBufferCopy(g_hiLogDev.buffer, HILOG_BUFFER, buffer + bufLeft, bufLen - bufLeft);
226 } else {
227 retval = HiLogBufferCopy(g_hiLogDev.buffer + g_hiLogDev.writeOffset, bufLeft, buffer, bufLen);
228 }
229 if (retval < 0) {
230 return -1;
231 }
232 return 0;
233}
234///hilog实体初始化
235static void HiLogHeadInit(struct HiLogEntry *header, size_t len)
236{
237 struct timespec now;//标准C库函数,时间格式,包含秒数和纳秒数
238 int ret;
239
240 ret = clock_gettime(CLOCK_REALTIME, &now);//获取系统实时时间
241 if (ret != 0) {
242 PRINTK("In %s line %d,clock_gettime fail\n", __FUNCTION__, __LINE__);
243 return;
244 }
245
246 header->len = len;//写入buffer的内容长度
247 header->pid = LOS_GetCurrProcessID();//当前进程ID
248 header->taskId = LOS_CurTaskIDGet(); //当前任务ID
249 header->sec = now.tv_sec; //秒级记录
250 header->nsec = now.tv_nsec; //纳秒级记录
251 header->hdrSize = sizeof(struct HiLogEntry);
252}
253
254static void HiLogCoverOldLog(size_t bufLen)
255{
256 int retval;
257 struct HiLogEntry header;
258 size_t totalSize = bufLen + sizeof(struct HiLogEntry);
259 static int dropLogLines = 0;
260 static int isLastTimeFull = 0;
261 int isThisTimeFull = 0;
262
263 while (totalSize + g_hiLogDev.size > HILOG_BUFFER) {
264 retval = HiLogReadRingBuffer((unsigned char *)&header, sizeof(header));
265 if (retval < 0) {
266 break;
267 }
268
269 dropLogLines++;
270 isThisTimeFull = 1;
271 isLastTimeFull = 1;
272 HiLogBufferDec(sizeof(header));
273 HiLogBufferDec(header.len);
274 }
275 if (isLastTimeFull == 1 && isThisTimeFull == 0) {
276 /* so we can only print one log if hilog ring buffer is full in a short time */
277 if (dropLogLines > 0) {
278 PRINTK("hilog ringbuffer full, drop %d line(s) log\n", dropLogLines);
279 }
280 isLastTimeFull = 0;
281 dropLogLines = 0;
282 }
283}
284///将外部buf写入hilog设备分两步完成
285int HiLogWriteInternal(const char *buffer, size_t bufLen)
286{
287 struct HiLogEntry header;
288 int retval;
289 LosTaskCB *runTask = (LosTaskCB *)OsCurrTaskGet();
290
291 if ((g_hiLogDev.buffer == NULL) || (OS_INT_ACTIVE) || (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK)) {
292 PRINTK("%s\n", buffer);
293 return -EAGAIN;
294 }
295
297 HiLogCoverOldLog(bufLen);
298 HiLogHeadInit(&header, bufLen);
299
300 retval = HiLogWriteRingBuffer((unsigned char *)&header, sizeof(header));//1.先写入头部内容
301 if (retval) {
302 retval = -ENODATA;
303 goto out;
304 }
305 HiLogBufferInc(sizeof(header));//
306
307 retval = HiLogWriteRingBuffer((unsigned char *)(buffer), header.len);//2.再写入实际buf内容
308 if (retval) {
309 retval = -ENODATA;
310 goto out;
311 }
312
313 HiLogBufferInc(header.len);
314
315 retval = header.len;
316
317out:
319 if (retval > 0) {
320 wake_up_interruptible(&g_hiLogDev.wq);
321 }
322 if (retval < 0) {
323 PRINTK("write fail retval=%d\n", retval);
324 }
325 return retval;
326}
327///写hilog,外部以VFS方式写入
328static ssize_t HiLogWrite(struct file *filep, const char *buffer, size_t bufLen)
329{
330 (void)filep;
331 if (bufLen + sizeof(struct HiLogEntry) > HILOG_BUFFER) {
332 PRINTK("input too large\n");
333 return -ENOMEM;
334 }
335
336 return HiLogWriteInternal(buffer, bufLen);
337}
338///初始化全局变量g_hiLogDev
339static void HiLogDeviceInit(void)
340{
341 g_hiLogDev.buffer = LOS_MemAlloc((VOID *)OS_SYS_MEM_ADDR, HILOG_BUFFER);//分配内核空间
342 if (g_hiLogDev.buffer == NULL) {
343 PRINTK("In %s line %d,LOS_MemAlloc fail\n", __FUNCTION__, __LINE__);
344 }
345 //初始化waitqueue头,请确保输入参数wait有效,否则系统将崩溃。
346 init_waitqueue_head(&g_hiLogDev.wq);//见于..\third_party\FreeBSD\sys\compat\linuxkpi\common\src\linux_semaphore.c
347 LOS_MuxInit(&g_hiLogDev.mtx, NULL);//初始化hilog互斥量
348
349 g_hiLogDev.writeOffset = 0;//写g_hiLogDev.buffer偏移地址
351 g_hiLogDev.size = 0; //
352 g_hiLogDev.count = 0;
353}
354///初始化hilog驱动
356{
357 HiLogDeviceInit();//初始化全局变量g_hiLogDev
358 return register_driver(HILOG_DRIVER, &g_hilogFops, DRIVER_MODE, NULL);//注册字符设备驱动程序,生成inode节点
359}
360
361LOS_MODULE_INIT(OsHiLogDriverInit, LOS_INIT_LEVEL_KMOD_EXTENDED);//日志模块初始化
VOID * LOS_MemAlloc(VOID *pool, UINT32 size)
从指定内存池中申请size长度的内存,注意这可不是从内核堆空间中申请内存
Definition: los_memory.c:1123
LITE_OS_SEC_TEXT UINT32 LOS_MuxInit(LosMux *mutex, const LosMuxAttr *attr)
初始化互斥锁
Definition: los_mux.c:262
LITE_OS_SEC_TEXT UINT32 LOS_CurTaskIDGet(VOID)
Obtain current running task ID.
Definition: los_task.c:331
static void HiLogBufferInc(size_t sz)
读写对冲,对hilog的写操作,更新相关变量内容
Definition: los_hilog.c:109
static int HiLogBufferCopy(unsigned char *dst, unsigned dstLen, const unsigned char *src, size_t srcLen)
Definition: los_hilog.c:129
static void HiLogBufferDec(size_t sz)
读写对冲,对hilog的读操作,更新相关变量内容
Definition: los_hilog.c:119
static unsigned char * HiLogBufferHead(void)
Definition: los_hilog.c:92
static ssize_t HiLogRead(struct file *filep, char *buffer, size_t bufLen)
Definition: los_hilog.c:166
int HiLogClose(struct file *filep)
为支持VFS,作关闭状
Definition: los_hilog.c:103
int OsHiLogDriverInit(VOID)
初始化hilog驱动
Definition: los_hilog.c:355
ssize_t HilogRead(struct file *filep, char __user *buf, size_t count)
static void HiLogDeviceInit(void)
初始化全局变量g_hiLogDev
Definition: los_hilog.c:339
static void HiLogCoverOldLog(size_t bufLen)
Definition: los_hilog.c:254
STATIC struct file_operations_vfs g_hilogFops
Definition: los_hilog.c:67
static ssize_t HiLogWrite(struct file *filep, const char *buffer, size_t bufLen)
写hilog,外部以VFS方式写入
Definition: los_hilog.c:328
static int HiLogReadRingBuffer(unsigned char *buffer, size_t bufLen)
读取ring buffer
Definition: los_hilog.c:149
static int HiLogWriteRingBuffer(unsigned char *buffer, size_t bufLen)
写入 RingBuffer环形缓冲,也叫 circleBuffer
Definition: los_hilog.c:216
int HiLogWriteInternal(const char *buffer, size_t bufLen)
将外部buf写入hilog设备分两步完成
Definition: los_hilog.c:285
ssize_t HilogWrite(struct file *filep, const char __user *buf, size_t count)
static void HiLogHeadInit(struct HiLogEntry *header, size_t len)
hilog实体初始化
Definition: los_hilog.c:235
int HiLogOpen(struct file *filep)
为支持VFS,作打开状
Definition: los_hilog.c:97
LOS_MODULE_INIT(OsHiLogDriverInit, LOS_INIT_LEVEL_KMOD_EXTENDED)
struct HiLogCharDevice g_hiLogDev
LITE_OS_SEC_TEXT UINT32 LOS_GetCurrProcessID(VOID)
获取当前进程的进程ID
Definition: los_process.c:2161
STATIC INLINE LosTaskCB * OsCurrTaskGet(VOID)
unsigned long VADDR_T
Definition: los_typedef.h:208
INT64 ssize_t
Definition: los_typedef.h:79
unsigned long UINTPTR
Definition: los_typedef.h:68
STATIC INLINE STATUS_T LOS_MuxAcquire(LosMux *m)
Definition: los_vm_lock.h:48
STATIC INLINE STATUS_T LOS_MuxRelease(LosMux *m)
Definition: los_vm_lock.h:53
STATIC INLINE BOOL LOS_IsUserAddressRange(VADDR_T vaddr, size_t len)
虚拟地址[vaddr,vaddr + len]是否在用户空间
Definition: los_vm_map.h:281
wait_queue_head_t wq
Definition: los_hilog.c:85
size_t count
Definition: los_hilog.c:89
size_t headOffset
Definition: los_hilog.c:87
size_t writeOffset
Definition: los_hilog.c:86
unsigned char * buffer
Definition: los_hilog.c:84
Definition: los_hilog.c:48
unsigned int taskId
Definition: los_hilog.c:52
unsigned int nsec
Definition: los_hilog.c:54
unsigned int hdrSize
Definition: los_hilog.c:50
unsigned int pid
Definition: los_hilog.c:51
unsigned int sec
Definition: los_hilog.c:53
unsigned int reserved
Definition: los_hilog.c:55
unsigned int len
Definition: los_hilog.c:49
char msg[0]
Definition: los_hilog.c:56
Definition: los_mux.h:73
UINT16 taskStatus
ARG_NUM_3 ARG_NUM_1 ARG_NUM_2 ARG_NUM_2 ARG_NUM_3 ARG_NUM_1 ARG_NUM_4 ARG_NUM_2 ARG_NUM_2 ARG_NUM_5 ARG_NUM_2 void
int clock_gettime(clockid_t clockID, struct timespec *tp)
当用户程序进行特定系统调用时(例如clock_gettime(CLOCK_REALTIME_COARSE, &ts)),VDSO代码页会将其拦截;
Definition: time.c:614
size_t LOS_ArchCopyToUser(void *dst, const void *src, size_t len)
从内核空间拷贝到用户空间
Definition: user_copy.c:79
size_t LOS_ArchCopyFromUser(void *dst, const void *src, size_t len)
Definition: user_copy.c:58