los_hilog.c 10.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
/*
 * 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:
 *
 * 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_hilog.h"
#include "los_mp.h"
#include "los_mux.h"
#include "los_process_pri.h"
#include "los_task_pri.h"
#include "fs/fs.h"
#include "los_vm_map.h"
#include "los_vm_lock.h"
#include "user_copy.h"
41 42 43 44 45 46 47 48 49 50 51 52 53 54
//hilog是鸿蒙的一个用于输出的功能模块
#define HILOG_BUFFER 1024 // 1K缓存, ring buf 方式管理
#define DRIVER_MODE 0666 //权限 chmod 666
#define HILOG_DRIVER "/dev/hilog" // 可以看出hilog是当一种字符设备来实现

struct HiLogEntry { //hilog 实体
    unsigned int len;	//写入buffer的内容长度
    unsigned int hdrSize;	// sizeof(struct HiLogEntry) ,为何命名hdr @note_why
    unsigned int pid : 16;	//进程ID
    unsigned int taskId : 16;	//任务ID
    unsigned int sec;	//秒级
    unsigned int nsec;	//纳秒级,提供给外部准确分析和定位问题
    unsigned int reserved;//保留位
    char msg[0];	//消息内容
55 56 57 58 59 60 61 62 63
};

ssize_t HilogRead(struct file *filep, char __user *buf, size_t count);
ssize_t HilogWrite(struct file *filep, const char __user *buf, size_t count);
int HiLogOpen(FAR struct file *filep);
int HiLogClose(FAR struct file *filep);

static ssize_t HiLogWrite(FAR struct file *filep, const char *buffer, size_t bufLen);
static ssize_t HiLogRead(FAR struct file *filep, char *buffer, size_t bufLen);
64
//实现VFS接口函数,对hilog进行操作
65 66 67 68 69 70 71 72 73 74 75 76 77 78
STATIC struct file_operations_vfs g_hilogFops = {
    HiLogOpen,  /* open */
    HiLogClose, /* close */
    HiLogRead,  /* read */
    HiLogWrite, /* write */
    NULL,       /* seek */
    NULL,       /* ioctl */
    NULL,       /* mmap */
#ifndef CONFIG_DISABLE_POLL
    NULL, /* poll */
#endif
    NULL, /* unlink */
};

79 80 81 82
FAR struct HiLogCharDevice {//hilog 本质上是个字符设备
    int flag;	//设备标签
    LosMux mtx;	//读写buf的互斥量
    unsigned char *buffer;//采用 ring buffer 管理
83
    wait_queue_head_t wq;
84 85 86 87
    size_t writeOffset;//用于写操作,不断累加
    size_t headOffset;//用于读操作,不断累加
    size_t size;//记录buffer使用的大小, 读写操作会返回 +-这个size
    size_t count;//读写操作的次数对冲
88 89 90 91 92 93
} g_hiLogDev;

static inline unsigned char *HiLogBufferHead(void)
{
    return g_hiLogDev.buffer + g_hiLogDev.headOffset;
}
94
//为支持VFS,作打开状
95 96 97 98 99
int HiLogOpen(FAR struct file *filep)
{
    (void)filep;
    return 0;
}
100
//为支持VFS,作关闭状
101 102 103 104 105
int HiLogClose(FAR struct file *filep)
{
    (void)filep;
    return 0;
}
106
//读写对冲,对hilog的写操作,更新相关变量内容
107 108 109
static void HiLogBufferInc(size_t sz)
{
    if (g_hiLogDev.size + sz <= HILOG_BUFFER) {
110 111 112 113
        g_hiLogDev.size += sz;	//已使用buf的size 
        g_hiLogDev.writeOffset += sz;//大小是不断累加
        g_hiLogDev.writeOffset %= HILOG_BUFFER;//ring buf
        g_hiLogDev.count++;//读写对冲
114 115
    }
}
116
//读写对冲,对hilog的读操作,更新相关变量内容
117 118 119
static void HiLogBufferDec(size_t sz)
{
    if (g_hiLogDev.size >= sz) {
120
        g_hiLogDev.size -= sz;//维持可使用buf size
121 122
        g_hiLogDev.headOffset += sz;
        g_hiLogDev.headOffset %= HILOG_BUFFER;
123
        g_hiLogDev.count--;//读写对冲
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
    }
}

static int HiLogBufferCopy(unsigned char *dst, unsigned dstLen, unsigned char *src, size_t srcLen)
{
    int retval = -1;

    size_t minLen = (dstLen > srcLen) ? srcLen : dstLen;

    if (LOS_IsUserAddressRange((VADDR_T)dst, minLen) && LOS_IsUserAddressRange((VADDR_T)src, minLen)) {
        return retval;
    }

    if (LOS_IsUserAddressRange((VADDR_T)dst, minLen)) {
        retval = LOS_ArchCopyToUser(dst, src, minLen);
    } else if (LOS_IsUserAddressRange((VADDR_T)src, minLen)) {
        retval = LOS_ArchCopyFromUser(dst, src, minLen);
    } else {
        retval = memcpy_s(dst, dstLen, src, srcLen);
    }
    return retval;
}

static int HiLogReadRingBuffer(unsigned char *buffer, size_t bufLen)
{
    size_t retval;
    size_t bufLeft = HILOG_BUFFER - g_hiLogDev.headOffset;
    if (bufLeft > bufLen) {
        retval = HiLogBufferCopy(buffer, bufLen, HiLogBufferHead(), bufLen);
    } else {
        retval = HiLogBufferCopy(buffer, bufLen, HiLogBufferHead(), bufLeft);
        if (retval < 0) {
            return retval;
        }

        retval = HiLogBufferCopy(buffer + bufLeft, bufLen - bufLeft, g_hiLogDev.buffer, bufLen - bufLeft);
    }
    return retval;
}

static ssize_t HiLogRead(FAR struct file *filep, char *buffer, size_t bufLen)
{
    size_t retval;
    struct HiLogEntry header;

    (void)filep;

    wait_event_interruptible(g_hiLogDev.wq, (g_hiLogDev.size > 0));

173
    (VOID)LOS_MuxAcquire(&g_hiLogDev.mtx);//临界区操作开始
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
    retval = HiLogReadRingBuffer((unsigned char *)&header, sizeof(header));
    if (retval < 0) {
        retval = -EINVAL;
        goto out;
    }

    if (bufLen < header.len + sizeof(header)) {
        dprintf("buffer too small,bufLen=%d, header.len=%d,%d\n", bufLen, header.len, header.hdrSize, header.nsec);
        retval = -ENOMEM;
        goto out;
    }

    HiLogBufferDec(sizeof(header));

    retval = HiLogBufferCopy((unsigned char *)buffer, bufLen, (unsigned char *)&header, sizeof(header));
    if (retval < 0) {
        retval = -EINVAL;
        goto out;
    }

    retval = HiLogReadRingBuffer((unsigned char *)(buffer + sizeof(header)), header.len);
    if (retval < 0) {
        retval = -EINVAL;
        goto out;
    }

    HiLogBufferDec(header.len);
    retval = header.len + sizeof(header);
out:
203
    (VOID)LOS_MuxRelease(&g_hiLogDev.mtx);//临界区操作结束
204 205
    return retval;
}
206
//写入 RingBuffer环形缓冲,也叫 circleBuffer
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
static int HiLogWriteRingBuffer(unsigned char *buffer, size_t bufLen)
{
    int retval;
    size_t bufLeft = HILOG_BUFFER - g_hiLogDev.writeOffset;
    if (bufLen > bufLeft) {
        retval = HiLogBufferCopy(g_hiLogDev.buffer + g_hiLogDev.writeOffset, bufLeft, buffer, bufLeft);
        if (retval) {
            return -1;
        }
        retval = HiLogBufferCopy(g_hiLogDev.buffer, HILOG_BUFFER, buffer + bufLeft, bufLen - bufLeft);
    } else {
        retval = HiLogBufferCopy(g_hiLogDev.buffer + g_hiLogDev.writeOffset, bufLeft, buffer, bufLen);
    }
    if (retval < 0) {
        return -1;
    }
    return 0;
}
225
//hilog实体初始化
226 227
static void HiLogHeadInit(struct HiLogEntry *header, size_t len)
{
228
    struct timespec now;//标准C库函数,时间格式,包含秒数和纳秒数
229 230
    int ret;

231
    ret = clock_gettime(CLOCK_REALTIME, &now);//获取系统实时时间
232 233 234 235 236
    if (ret != 0) {
        dprintf("In %s line %d,clock_gettime fail", __FUNCTION__, __LINE__);
        return;
    }

237 238 239 240 241
    header->len = len;//写入buffer的内容长度
    header->pid = LOS_GetCurrProcessID();//当前进程ID
    header->taskId = LOS_CurTaskIDGet();	//当前任务ID
    header->sec = now.tv_sec;	//秒级记录
    header->nsec = now.tv_nsec; //纳秒级记录
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
    header->hdrSize = sizeof(struct HiLogEntry);
}

static void HiLogCoverOldLog(size_t bufLen)
{
    int retval;
    struct HiLogEntry header;
    size_t totalSize = bufLen + sizeof(struct HiLogEntry);

    while (totalSize + g_hiLogDev.size >= HILOG_BUFFER) {
        retval = HiLogReadRingBuffer((unsigned char *)&header, sizeof(header));
        if (retval < 0) {
            break;
        }

        HiLogBufferDec(sizeof(header) + header.len);
    }
}
260
//将外部buf写入hilog设备分两步完成
261 262 263 264 265 266 267 268 269
int HiLogWriteInternal(const char *buffer, size_t bufLen)
{
    struct HiLogEntry header;
    int retval;

    (VOID)LOS_MuxAcquire(&g_hiLogDev.mtx);
    HiLogCoverOldLog(bufLen);
    HiLogHeadInit(&header, bufLen);

270
    retval = HiLogWriteRingBuffer((unsigned char *)&header, sizeof(header));//1.先写入头部内容
271 272 273 274
    if (retval) {
        retval = -ENODATA;
        goto out;
    }
275
    HiLogBufferInc(sizeof(header));//
276

277
    retval = HiLogWriteRingBuffer((unsigned char *)(buffer), header.len);//2.再写入实际buf内容
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
    if (retval) {
        retval = -ENODATA;
        goto out;
    }

    HiLogBufferInc(header.len);

    retval = header.len;

out:
    (VOID)LOS_MuxRelease(&g_hiLogDev.mtx);
    if (retval > 0) {
        wake_up_interruptible(&g_hiLogDev.wq);
    }
    if (retval < 0) {
        dprintf("write fail retval=%d\n", retval);
    }
    return retval;
}
297
//写hilog,外部以VFS方式写入
298 299 300 301 302 303 304 305 306 307
static ssize_t HiLogWrite(FAR struct file *filep, const char *buffer, size_t bufLen)
{
    (void)filep;
    if (bufLen + sizeof(struct HiLogEntry) > HILOG_BUFFER) {
        dprintf("input too large\n");
        return -ENOMEM;
    }

    return HiLogWriteInternal(buffer, bufLen);
}
308
//初始化全局变量g_hiLogDev
309 310
static void HiLogDeviceInit(void)
{
311
    g_hiLogDev.buffer = LOS_MemAlloc((VOID *)OS_SYS_MEM_ADDR, HILOG_BUFFER);//分配内核空间
312 313 314
    if (g_hiLogDev.buffer == NULL) {
        dprintf("In %s line %d,LOS_MemAlloc fail", __FUNCTION__, __LINE__);
    }
315 316 317
	//初始化waitqueue头,请确保输入参数wait有效,否则系统将崩溃。
    init_waitqueue_head(&g_hiLogDev.wq);//见于..\third_party\FreeBSD\sys\compat\linuxkpi\common\src\linux_semaphore.c
    LOS_MuxInit(&g_hiLogDev.mtx, NULL);//初始化hilog互斥量
318

319
    g_hiLogDev.writeOffset = 0;//写g_hiLogDev.buffer偏移地址
320
    g_hiLogDev.headOffset = 0;
321
    g_hiLogDev.size = 0;	//
322 323
    g_hiLogDev.count = 0;
}
324
//初始化hilog驱动
325 326
int HiLogDriverInit(VOID)
{
327 328
    HiLogDeviceInit();//初始化全局变量g_hiLogDev
    return register_driver(HILOG_DRIVER, &g_hilogFops, DRIVER_MODE, NULL);//注册字符设备驱动程序,生成inode节点
329 330
}