鸿蒙对 /proc 的实现很有意思,/proc被称为伪文件系统,或内存文件系统

    百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
    国内:https://weharmony.21cloudbox.com
    国外:https://weharmony.github.io
上级 c04f7d62
......@@ -78,7 +78,7 @@ typedef unsigned short fmode_t;
#define FMODE_READ ((fmode_t)0x1)
struct ProcFile;
//操作pro file的抽象接口,proc本质是个内存文件系统,
struct ProcFileOperations {
char *name;
ssize_t (*write)(struct ProcFile *pf, const char *buf, size_t count, loff_t *ppos);
......@@ -86,32 +86,32 @@ struct ProcFileOperations {
int (*release)(struct Vnode *vnode, struct ProcFile *pf);
int (*read)(struct SeqBuf *m, void *v);
};
//proc 目录/文件项, @notethinking 直接叫 ProcEntry不香吗 ?
struct ProcDirEntry {
mode_t mode;
int flags;
const struct ProcFileOperations *procFileOps;
struct ProcFile *pf;
struct ProcDirEntry *next, *parent, *subdir;
struct ProcDirEntry *next, *parent, *subdir;//当前目录项的关系项
void *data;
atomic_t count; /* open file count */
spinlock_t pdeUnloadLock;
int nameLen;
struct ProcDirEntry *pdirCurrent;
struct ProcDirEntry *pdirCurrent;//当前目录
char name[NAME_MAX];
enum VnodeType type;
enum VnodeType type; //节点类型
};
//Proc文件结构体,对标 FILE 结构体
struct ProcFile {
fmode_t fMode;
spinlock_t fLock;
atomic_t fCount;
struct SeqBuf *sbuf;
struct ProcDirEntry *pPDE;
unsigned long long fVersion;
loff_t fPos;
char name[NAME_MAX];
fmode_t fMode; //操作文件的模式
spinlock_t fLock; //自旋锁
atomic_t fCount; //原子操作
struct SeqBuf *sbuf;//序列号BUF
struct ProcDirEntry *pPDE;//目录项
unsigned long long fVersion;//版本号
loff_t fPos; //文件操作偏移位
char name[NAME_MAX];//文件名
};
struct ProcStat {
......
......@@ -37,15 +37,15 @@
#include "fs/file.h"
#include "internal.h"
//显示文件系统类型,将被作为回调函数回调
static int ShowType(const char *mountPoint, struct statfs *statBuf, void *arg)
{
struct SeqBuf *seqBuf = (struct SeqBuf *)arg;
char *type = NULL;
char *name = NULL;
switch (statBuf->f_type) {
case PROCFS_MAGIC:
switch (statBuf->f_type) {//目前鸿蒙支持的文件系统
case PROCFS_MAGIC:
type = "proc";
name = "proc";
break;
......@@ -72,12 +72,12 @@ static int ShowType(const char *mountPoint, struct statfs *statBuf, void *arg)
default:
return 0;
}
(void)LosBufPrintf(seqBuf, "%s %s %s\n", name, mountPoint, type);
(void)LosBufPrintf(seqBuf, "%s %s %s\n", name, mountPoint, type);//打印到 seqBuf 中,即 arg中
return 0;
}
// 读取 mount 接口实现
static int MountsProcFill(struct SeqBuf *m, void *v)
{
foreach_mountpoint_t handler = ShowType;
......@@ -85,7 +85,7 @@ static int MountsProcFill(struct SeqBuf *m, void *v)
return 0;
}
//实现 操作proc file 接口,也可理解为驱动程序不同
static const struct ProcFileOperations MOUNTS_PROC_FOPS = {
.read = MountsProcFill,
};
......
......@@ -36,31 +36,31 @@
#include "sys/stat.h"
#include "los_init.h"
#ifdef LOSCFG_FS_PROC
#ifdef LOSCFG_FS_PROC //使能 PROC 模块
//pro file 初始化
void ProcFsInit(void)
{
int ret;
ret = mkdir(PROCFS_MOUNT_POINT, 0);
ret = mkdir(PROCFS_MOUNT_POINT, 0);//创建 "/proc"
if (ret < 0) {
PRINT_ERR("failed to mkdir %s, errno = %d\n", PROCFS_MOUNT_POINT, get_errno());
return;
}
//装载文件系统
ret = mount(NULL, PROCFS_MOUNT_POINT, "procfs", 0, NULL);
if (ret) {
PRINT_ERR("mount procfs err %d\n", ret);
return;
}
ProcMountsInit();
ProcMountsInit();//初始化 /pro/mounts
#if defined(LOSCFG_SHELL_CMD_DEBUG) && defined(LOSCFG_KERNEL_VM)
ProcVmmInit();
ProcVmmInit();//初始化 /pro/vmm
#endif
ProcProcessInit();
ProcUptimeInit();
ProcKernelTraceInit();
ProcProcessInit();//初始化 /pro/process
ProcUptimeInit();//初始化 /pro/uptime
ProcKernelTraceInit();//初始化 /pro/ktrace
}
LOS_MODULE_INIT(ProcFsInit, LOS_INIT_LEVEL_KMOD_EXTENDED);
......
......@@ -33,18 +33,18 @@
#include <sys/mount.h>
#include "proc_fs.h"
#include "los_process_pri.h"
//这个太牛了,直接读 taskinfo,注意 SeqBuf 的第一个参数是 char* buf
static int ProcessProcFill(struct SeqBuf *m, void *v)
{
(void)v;
(void)OsShellCmdTskInfoGet(OS_ALL_TASK_MASK, m, OS_PROCESS_INFO_ALL);
return 0;
}
// 对 /proc/process 各种骚操作,只能读
static const struct ProcFileOperations PROCESS_PROC_FOPS = {
.read = ProcessProcFill,
.read = ProcessProcFill,//读取操作
};
//创建进程相关信息 /proc/process
void ProcProcessInit(void)
{
struct ProcDirEntry *pde = CreateProcEntry("process", 0, NULL);
......
......@@ -40,7 +40,7 @@
#include "los_process_pri.h"
#ifdef LOSCFG_KERNEL_VM
//获取虚拟内存内核相关的信息,用这个方法去窥视内核是个很好的办法,精读本函数的过程是理解虚拟内存实现的过程
STATIC VOID OsVmDumpSeqSpaces(struct SeqBuf *seqBuf)
{
LosVmSpace *space = NULL;
......@@ -89,7 +89,7 @@ STATIC VOID OsVmDumpSeqSpaces(struct SeqBuf *seqBuf)
}
(VOID)LOS_MuxRelease(aspaceListMux);
}
// .read 接口的现实
static int VmmProcFill(struct SeqBuf *m, void *v)
{
(void)v;
......@@ -97,21 +97,21 @@ static int VmmProcFill(struct SeqBuf *m, void *v)
return 0;
}
//实现 操作proc file 接口,也可理解为驱动程序不同
static const struct ProcFileOperations VMM_PROC_FOPS = {
.write = NULL,
.read = VmmProcFill,
};
//初始化 虚拟内存 内容信息
void ProcVmmInit(void)
{
struct ProcDirEntry *pde = CreateProcEntry("vmm", 0, NULL);
struct ProcDirEntry *pde = CreateProcEntry("vmm", 0, NULL);//创建目录
if (pde == NULL) {
PRINT_ERR("create /proc/vmm error!\n");
return;
}
pde->procFileOps = &VMM_PROC_FOPS;
pde->procFileOps = &VMM_PROC_FOPS;//每个目录的驱动程序都不一样
}
#endif
#endif
......@@ -39,25 +39,25 @@
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define PROC_ROOTDIR_NAMELEN 5
#define PROC_INUSE 2
DEFINE_SPINLOCK(procfsLock);
bool procfsInit = false;
//定义自旋锁,说明 procfs不支持多线程访问
DEFINE_SPINLOCK(procfsLock);//定义profs 自旋锁
bool procfsInit = false; //是否初始化了profs
static struct ProcFile g_procPf = {
.fPos = 0,
};
static struct ProcDirEntry g_procRootDirEntry = {
static struct ProcDirEntry g_procRootDirEntry = { //proc 根部 即 /proc
.nameLen = 5,
.mode = S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH,
.mode = S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH,//(04555)
.count = ATOMIC_INIT(1),
.procFileOps = NULL,
.parent = &g_procRootDirEntry,
.name = "/proc",
.subdir = NULL,
.next = NULL,
.pf = &g_procPf,
.type = VNODE_TYPE_DIR,
.procFileOps = NULL,//对根节点无操作需求
.parent = &g_procRootDirEntry,//自己当爹又当儿
.name = "/proc",
.subdir = NULL, //暂无,后续必有子
.next = NULL, //暂无.后续必有续
.pf = &g_procPf, //全局PRO文件
.type = VNODE_TYPE_DIR, //是个目录
};
int ProcMatch(unsigned int len, const char *name, struct ProcDirEntry *pn)
......@@ -360,12 +360,12 @@ static struct ProcDirEntry *ProcCreateFile(struct ProcDirEntry *parent, const ch
return pn;
}
//创建 pro (目录/文件)项
struct ProcDirEntry *CreateProcEntry(const char *name, mode_t mode, struct ProcDirEntry *parent)
{
struct ProcDirEntry *pde = NULL;
if (S_ISDIR(mode)) {
if (S_ISDIR(mode)) {//目录模式 0
pde = ProcCreateDir(parent, name, NULL, mode);
} else {
pde = ProcCreateFile(parent, name, NULL, mode);
......
......@@ -49,7 +49,33 @@
#include "proc_fs.h"
#define WRITEPROC_ARGC 3
/*****************************************************************
鸿蒙内核提供了一种通过 /proc 文件系统,在运行时访问内核内部数据结构、改变内核设置的机制。
proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。它以文件系统的方式为
访问系统内核数据的操作提供接口。
用户和应用程序可以通过proc得到系统的信息,并可以改变内核的某些参数。由于系统的信息,
如进程,是动态改变的,所以用户或应用程序读取proc文件时,proc文件系统是动态从系统内核读出
所需信息并提交的。
proc fs支持传入字符串参数,需要每个文件实现自己的写方法。
命令格式
writeproc <data> >> /proc/<filename>
参数说明
参数 参数说明
data 要输入的字符串,以空格为结束符,如需输入空格,请用""包裹。
filename data要传入的proc文件。
proc文件实现自身的write函数,调用writeproc命令后会将入参传入write函数。
注意:procfs暂不支持多线程访问
OHOS # writeproc test >> /proc/uptime
[INFO]write buf is: test
test >> /proc/uptime
说明: uptime proc文件临时实现write函数,INFO日志为实现的测试函数打印的日志。
*****************************************************************/
int OsShellCmdWriteProc(int argc, char **argv)
{
int i;
......
......@@ -95,7 +95,7 @@ STATIC UINT32 *taskWaterLine = NULL;
#else
#define PROCESS_INFO_SHOW(seqBuf, arg...) PRINTK(arg)
#endif
LITE_OS_SEC_TEXT_MINOR UINT8 *OsShellCmdProcessMode(UINT16 mode)
{
if (mode == OS_KERNEL_MODE) {
......@@ -109,9 +109,9 @@ LITE_OS_SEC_TEXT_MINOR UINT8 *OsShellCmdProcessMode(UINT16 mode)
LITE_OS_SEC_TEXT_MINOR UINT8 *OsShellCmdSchedPolicy(UINT16 policy)
{
if (policy == LOS_SCHED_RR) {
if (policy == LOS_SCHED_RR) {
return (UINT8 *)"RR";
} else if (policy == LOS_SCHED_FIFO) {
} else if (policy == LOS_SCHED_FIFO) {
return (UINT8 *)"FIFO";
} else if (policy == LOS_SCHED_IDLE) {
return (UINT8 *)"IDLE";
......@@ -119,25 +119,25 @@ LITE_OS_SEC_TEXT_MINOR UINT8 *OsShellCmdSchedPolicy(UINT16 policy)
return (UINT8 *)"ERROR";
}
LITE_OS_SEC_TEXT_MINOR UINT8 *OsShellProcessStatus(UINT16 status)
{
status = status & OS_PROCESS_STATUS_MASK;
if (status & OS_PROCESS_STATUS_ZOMBIES) {
if (status & OS_PROCESS_STATUS_ZOMBIES) {
return (UINT8 *)"Zombies";
} else if (status & OS_PROCESS_STATUS_INIT) {
} else if (status & OS_PROCESS_STATUS_INIT) {
return (UINT8 *)"Init";
} else if (status & OS_PROCESS_STATUS_RUNNING) {
} else if (status & OS_PROCESS_STATUS_RUNNING) {
return (UINT8 *)"Running";
} else if (status & OS_PROCESS_STATUS_READY) {
} else if (status & OS_PROCESS_STATUS_READY) {
return (UINT8 *)"Ready";
} else if (status & OS_PROCESS_STATUS_PENDING) {
} else if (status & OS_PROCESS_STATUS_PENDING) {
return (UINT8 *)"Pending";
}
return (UINT8 *)"Invalid";
}
STATIC VOID OsShellCmdProcessTitle(VOID *seqBuf, UINT16 flag)
{
PROCESS_INFO_SHOW(seqBuf, "\r\n PID PPID PGID UID Status ");
......@@ -204,14 +204,14 @@ STATIC VOID OsShellCmdAllProcessInfoShow(const LosProcessCB *pcbArray, const INT
for (pid = 1; pid < g_processMaxNum; ++pid) {
processCB = pcbArray + pid;
if (OsProcessIsUnused(processCB)) {
if (OsProcessIsUnused(processCB)) {
continue;
}
OsShellCmdProcessInfoShow(processCB, group, memArray, seqBuf, flag);
}
}
#ifdef LOSCFG_KERNEL_VM
STATIC VOID OsProcessMemUsageGet(UINT32 *memArray)
{
......@@ -221,7 +221,7 @@ STATIC VOID OsProcessMemUsageGet(UINT32 *memArray)
for (pid = 0; pid < g_processMaxNum; ++pid) {
processCB = g_processCBArray + pid;
if (OsProcessIsUnused(processCB)) {
if (OsProcessIsUnused(processCB)) {
continue;
}
proMemUsage = &memArray[pid * PROCESS_VM_INDEX_MAX];
......@@ -504,7 +504,7 @@ STATIC VOID OsShellCmdAllTaskInfoData(const LosTaskCB *allTaskArray, VOID *seqBu
}
}
}
STATIC VOID OsShellCmdTskInfoData(const LosTaskCB *allTaskArray, VOID *seqBuf, UINT16 flag)
{
OsShellCmdTskInfoTitle(seqBuf, flag);
......@@ -532,7 +532,7 @@ STATIC VOID OsProcessAndTaskInfoGet(LosProcessCB **pcbArray, INT32 **group, LosT
SCHEDULER_UNLOCK(intSave);
}
}
//获取任务相关信息
LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdTskInfoGet(UINT32 taskID, VOID *seqBuf, UINT16 flag)
{
UINT32 size;
......@@ -554,15 +554,15 @@ LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdTskInfoGet(UINT32 taskID, VOID *seqBuf,
}
(VOID)memset_s(pcbArray, size, 0, size);
OsProcessAndTaskInfoGet(&pcbArray, &group, &tcbArray, &memArray, flag);
OsShellCmdProcessInfoData(pcbArray, group, memArray, seqBuf, flag);
OsShellCmdTskInfoData(tcbArray, seqBuf, flag);
OsShellCmdProcessInfoData(pcbArray, group, memArray, seqBuf, flag);
OsShellCmdTskInfoData(tcbArray, seqBuf, flag);
(VOID)LOS_MemFree(m_aucSysMem1, pcbArray);
}
return LOS_OK;
}
LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdDumpTask(INT32 argc, const CHAR **argv)
{
UINT32 flag = 0;
......@@ -601,6 +601,6 @@ TASK_HELP:
}
#ifdef LOSCFG_SHELL
SHELLCMD_ENTRY(task_shellcmd, CMD_TYPE_EX, "task", 1, (CmdCallBackFunc)OsShellCmdDumpTask);
SHELLCMD_ENTRY(task_shellcmd, CMD_TYPE_EX, "task", 1, (CmdCallBackFunc)OsShellCmdDumpTask);
#endif
......@@ -31,8 +31,10 @@
#include "los_seq_buf.h"
#include <stdlib.h>
static int ExpandSeqBuf(struct SeqBuf *seqBuf, size_t oldCount)
/*
Sequential buffer 顺序缓存区 实现
*/
static int ExpandSeqBuf(struct SeqBuf *seqBuf, size_t oldCount)//扩展buf
{
char *newBuf = NULL;
int ret;
......@@ -45,21 +47,21 @@ static int ExpandSeqBuf(struct SeqBuf *seqBuf, size_t oldCount)
goto EXPAND_FAILED;
}
newBuf = (char*)malloc(seqBuf->size <<= 1);
newBuf = (char*)malloc(seqBuf->size <<= 1);//将现有buf扩大一倍
if (newBuf == NULL) {
goto EXPAND_FAILED;
}
(void)memset_s(newBuf + oldCount, seqBuf->size - oldCount, 0, seqBuf->size - oldCount);
ret = memcpy_s(newBuf, seqBuf->size, seqBuf->buf, oldCount);
//memset_s 注意 oldCount 位置,因为 newBuf头部要被旧buf覆盖,所以只set后部分
ret = memcpy_s(newBuf, seqBuf->size, seqBuf->buf, oldCount);//拷贝旧buf数据到新buf,注意 oldCount 位置
if (ret != LOS_OK) {
free(newBuf);
goto EXPAND_FAILED;
}
seqBuf->count = oldCount;
seqBuf->count = oldCount;//目前偏移量,可理解为seek
free(seqBuf->buf);
seqBuf->buf = newBuf;
free(seqBuf->buf);//释放原有的buf
seqBuf->buf = newBuf;//采用新的buf
return LOS_OK;
EXPAND_FAILED:
......@@ -70,7 +72,7 @@ EXPAND_FAILED:
return -LOS_NOK;
}
//创建seq buf
struct SeqBuf *LosBufCreat(void)
{
struct SeqBuf *seqBuf = NULL;
......@@ -84,7 +86,7 @@ struct SeqBuf *LosBufCreat(void)
return seqBuf;
}
//真正写 buf 函数,调整 size/count的值,count可理解为偏移位
int LosBufVprintf(struct SeqBuf *seqBuf, const char *fmt, va_list argList)
{
bool needreprintf = FALSE;
......@@ -109,10 +111,10 @@ int LosBufVprintf(struct SeqBuf *seqBuf, const char *fmt, va_list argList)
seqBuf->size - seqBuf->count - 1, fmt, argList);
if (bufLen >= 0) {
/* succeed write. */
seqBuf->count += bufLen;
seqBuf->count += bufLen;//成功写入,count要增长
return 0;
}
if (seqBuf->buf[seqBuf->count] == '\0') {
if (seqBuf->buf[seqBuf->count] == '\0') {//这里没看懂,为啥要有这个判断, @note_thinking
free(seqBuf->buf);
seqBuf->buf = NULL;
break;
......@@ -127,19 +129,19 @@ int LosBufVprintf(struct SeqBuf *seqBuf, const char *fmt, va_list argList)
return -LOS_NOK;
}
//支持可变参数 写 buf
int LosBufPrintf(struct SeqBuf *seqBuf, const char *fmt, ...)
{
va_list argList;
int ret;
va_start(argList, fmt);
va_start(argList, fmt);//可变参数的实现,有点意思.
ret = LosBufVprintf(seqBuf, fmt, argList);
va_end(argList);
return ret;
}
//释放 seq buf
int LosBufRelease(struct SeqBuf *seqBuf)
{
if (seqBuf == NULL) {
......
......@@ -41,13 +41,13 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
#define SEQBUF_PAGE_SIZE 4096
#define SEQBUF_LIMIT_SIZE (256 * SEQBUF_PAGE_SIZE)
#define SEQBUF_PAGE_SIZE 4096 //4K 一页
#define SEQBUF_LIMIT_SIZE (256 * SEQBUF_PAGE_SIZE) //缓冲区最大空间为1M
//序列化BUF
struct SeqBuf {
char *buf;
size_t size;
size_t count;
char *buf; //内容
size_t size;//buf大小
size_t count;//当前位置
void *private;
};
......
git add -A
git commit -m '理解 进程文件描述符 和 系统文件描述 是理解FD的关键.
git commit -m '鸿蒙对 /proc 的实现很有意思,/proc被称为伪文件系统,或内存文件系统
百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
国内:https://weharmony.gitee.io
国内:https://weharmony.21cloudbox.com
国外:https://weharmony.github.io
'
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册