鸿蒙内核源码分析(控制台篇) | 一个让很多人模糊的概念

Shell | 控制台模型

下图为看完鸿蒙内核Shell和控制台源码后整理的模型图

模型说明

  • 模型涉及四个任务, 两个在用户空间,两个在内核空间.用户空间的在系列篇Shell部分中已有详细说明,请前往查看.
  • SystemInit任务是在内核OsMain中创建的系统初始化任务,其中初始化了根文件系统,串口,控制台等内核模块
  • 在控制台模块中创建SendToSer任务,这是一个负责将控制台结果输出到终端的任务.
  • 结构体CONSOLE_CB,CirBufSendCB承载了控制台的实现过程.

代码实现

每个模块都有一个核心结构体,控制台则是

结构体 | CONSOLE_CB
/**
 * @brief 控制台控制块(描述符)
 */
typedef struct {
    UINT32 consoleID;	///< 控制台ID    例如 : 1 | 串口 , 2 | 远程登录
    UINT32 consoleType;	///< 控制台类型
    UINT32 consoleSem;	///< 控制台信号量
    UINT32 consoleMask;	///< 控制台掩码
    struct Vnode *devVnode;	///< 索引节点
    CHAR *name;	///< 名称 例如: /dev/console1 
    INT32 fd;	///< 系统文件句柄, 由内核分配
    UINT32 refCount;	///< 引用次数,用于判断控制台是否被占用
    UINT32 shellEntryId; ///<  负责接受来自终端信息的 "ShellEntry"任务,这个值在运行过程中可能会被换掉,它始终指向当前正在运行的shell客户端
    INT32 pgrpId;	///< 进程组ID
    BOOL isNonBlock; ///< 是否无锁方式		
#ifdef LOSCFG_SHELL
    VOID *shellHandle;	///< shell句柄,本质是 shell控制块 ShellCB
#endif
    UINT32 sendTaskID;	///< 创建任务通过事件接收数据, 见于OsConsoleBufInit
    /*--以下为 一家子 start---------*/
    CirBufSendCB *cirBufSendCB;	///< 循环缓冲发送控制块
    UINT8 fifo[CONSOLE_FIFO_SIZE]; ///< 控制台缓冲区大小 1K
    UINT32 fifoOut;	///< 对fifo的标记,输出位置
    UINT32 fifoIn;	///< 对fifo的标记,输入位置
    UINT32 currentLen;	///< 当前fifo位置
    /*---以上为 一家子 end------- https://man7.org/linux/man-pages/man3/tcflow.3.html */
    struct termios consoleTermios; ///< 行规程
} CONSOLE_CB;

解析

  • 创建控制台的过程是给CONSOLE_CB赋值的过程,如下

    STATIC CONSOLE_CB *OsConsoleCreate(UINT32 consoleID, const CHAR *deviceName)
    {
      INT32 ret;
      CONSOLE_CB *consoleCB = OsConsoleCBInit(consoleID);//初始化控制台
      ret = (INT32)OsConsoleBufInit(consoleCB);//控制台buf初始化,创建 ConsoleSendTask 任务
      ret = (INT32)LOS_SemCreate(1, &consoleCB->consoleSem);//创建控制台信号量
      ret = OsConsoleDevInit(consoleCB, deviceName);//控制台设备初始化,注意这步要在 OsConsoleFileInit 的前面.
      ret = OsConsoleFileInit(consoleCB);	//为 /dev/console(n|1:2)分配fd(3)
      OsConsoleTermiosInit(consoleCB, deviceName);//控制台行规程初始化
      return consoleCB;
    }
    
    
  • Shell是用户空间进程, 负责解析和执行用户输入的命令. 但前提是得先拿到用户的输入数据. 不管数据是从串口进来,还是远程登录进来,必须得先经过内核, 而控制台的作用就是帮你拿到数据再交给shell处理, shell再将要显示的处理结果通过控制台返回给终端用户, 那数据怎么传给shell呢? 很显然用户进程只能通过系统调用 read(fd,...)来读取内核数据, 因为应用程序的视角是只认fd.通用的办法是通过文件路径来打开文件来获取fd.

  • 还有一种办法是内核先打开文件,获取fd后,用户任务通过捆绑的方式获取fd,而shellconsole之间正是通过这种方式勾搭在一块的.具体在创建ShellEntry任务时将自己与控制台进行捆绑.看源码实现

    ///进入shell客户端任务初始化,这个任务负责编辑命令,处理命令
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值