v74.01 Hongmeng kernel source code analysis (console article) | a concept that makes many people vague | 100 blogs analyze OpenHarmony source code

Posted by dotty on Mon, 13 Dec 2021 05:17:31 +0100

Analysis of 100 blogs This article is: (console article) | a concept that makes many people vague

Relevant articles of the file system are:

This article tries to explain the console implementation and how Shell depends on the console Only the key codes are listed in the source code section Go to > > Chinese annotation for detailed code to view Hongmeng kernel source code

Shell | console model

The following figure is the model diagram after reading Hongmeng kernel Shell and console source code

Model description

  • The model involves four tasks, two in user space and two in kernel space The of user space has been described in detail in the Shell part of the series. Please go to check it
  • SystemInit task is a system initialization task created in the kernel OsMain, which initializes the root file system, serial port, console and other kernel modules
  • Create the SendToSer task in the console module, which is responsible for outputting the console results to the terminal
  • Structure CONSOLE_CB,CirBufSendCB carries the implementation process of the console

code implementation

Each module has a core structure, and the console is

Structure | CONSOLE_CB

/**
 * @brief Console control block (descriptor)
 */
typedef struct {
    UINT32 consoleID;	///< console ID, for example: 1 | serial port, 2 | remote login
    UINT32 consoleType;	///< console type
    UINT32 consoleSem;	///< console semaphore
    UINT32 consoleMask;	///< console mask
    struct Vnode *devVnode;	///< inode
    CHAR *name;	///< name example: / dev/console1 
    INT32 fd;	///< system file handle, allocated by the kernel
    UINT32 refCount;	///< reference times, used to judge whether the console is occupied
    UINT32 shellEntryId; ///< it is responsible for accepting the "ShellEntry" task from the terminal information. This value may be changed during operation. It always points to the currently running shell client
    INT32 pgrpId;	///< process group ID
    BOOL isNonBlock; ///< no lock mode		
#ifdef LOSCFG_SHELL
    VOID *shellHandle;	///< shell handle, essentially shell control block ShellCB
#endif
    UINT32 sendTaskID;	///< create a task to receive data through events. See OsConsoleBufInit
    /*--The following is a family start---------*/
    CirBufSendCB *cirBufSendCB;	///< circular buffer transmission control block
    UINT8 fifo[CONSOLE_FIFO_SIZE]; ///< console buffer size 1K
    UINT32 fifoOut;	///< flag for fifo, output position
    UINT32 fifoIn;	///< mark fifo, enter position
    UINT32 currentLen;	///< current fifo position
    /*---The above is a family------- https://man7.org/linux/man-pages/man3/tcflow.3.html */
    struct termios consoleTermios; ///< operating procedures
} CONSOLE_CB;

analysis

  • The process of creating a console is to give it to console_ The process of CB assignment is as follows:

    STATIC CONSOLE_CB *OsConsoleCreate(UINT32 consoleID, const CHAR *deviceName)
    {
      INT32 ret;
      CONSOLE_CB *consoleCB = OsConsoleCBInit(consoleID);//Initialize console
      ret = (INT32)OsConsoleBufInit(consoleCB);//Console buf initialization, create consoleendtask task
      ret = (INT32)LOS_SemCreate(1, &consoleCB->consoleSem);//Create console semaphore
      ret = OsConsoleDevInit(consoleCB, deviceName);//Console device initialization. Note that this step should be in front of OsConsoleFileInit
      ret = OsConsoleFileInit(consoleCB);	//Allocate fd(3) for / dev/console(n|1:2)
      OsConsoleTermiosInit(consoleCB, deviceName);//Console line discipline initialization
      return consoleCB;
    }
    
  • Shell is a user space process, which is responsible for parsing and executing commands entered by users But the premise is to get the user's input data first No matter whether the data comes in through the serial port or remote login, it must first go through the kernel, and the role of the console is to help you get the data and then hand it to the shell for processing, and the shell will return the processing results to be displayed to the end user through the console. How can the data be transmitted to the shell? Obviously, the user process can only call read(fd,...) through the system To read kernel data, because the perspective of the application is to recognize only fd The common method is to open the file through the file path to get fd

  • Another way is that after the kernel opens the file and obtains fd, the user task obtains fd by binding, and the shell and console are linked together in this way Specifically, bind yourself with the console when creating a ShellEntry task Look at the source code implementation

    ///Enter the shell client task initialization, which is responsible for editing commands and handling the process of command generation, such as how to handle direction keys, backspace keys, enter keys, etc
      LITE_OS_SEC_TEXT_MINOR UINT32 ShellEntryInit(ShellCB *shellCB)
      {
          UINT32 ret;
          CHAR *name = NULL;
          TSK_INIT_PARAM_S initParam = {0};
          if (shellCB->consoleID == CONSOLE_SERIAL) {
              name = SERIAL_ENTRY_TASK_NAME;
          } 
          initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ShellEntry;//Task entry function
          initParam.usTaskPrio   = 9; /* 9:shell task priority */
          initParam.auwArgs[0]   = (UINTPTR)shellCB;
          initParam.uwStackSize  = 0x1000;
          initParam.pcName       = name;	//Task name
          initParam.uwResved     = LOS_TASK_STATUS_DETACHED;
          ret = LOS_TaskCreate(&shellCB->shellEntryHandle, &initParam);//Create shell task
      #ifdef LOSCFG_PLATFORM_CONSOLE
          (VOID)ConsoleTaskReg((INT32)shellCB->consoleID, shellCB->shellEntryHandle);//Bundle shell to console
      #endif
          return ret;
      }
    

    ConsoleTaskReg binds shellCB and consoleCB together, and they can find each other ShellEntry task I prefer to call it a shell client task. It uses an endless loop to read the user's input character by character. Why do you want to read the shell editing chapter of the series with a single character? In short, it is because you have to deal with the control characters (such as delete, enter = =)

    LITE_OS_SEC_TEXT_MINOR UINT32 ShellEntry(UINTPTR param)
    {
        CHAR ch;
        INT32 n = 0;
        ShellCB *shellCB = (ShellCB *)param;
        CONSOLE_CB *consoleCB = OsGetConsoleByID((INT32)shellCB->consoleID);//Gets the bound console for reading data from the console
        (VOID)memset_s(shellCB->shellBuf, SHOW_MAX_LEN, 0, SHOW_MAX_LEN);//Reset shell command buf
        while (1) {
            n = read(consoleCB->fd, &ch, 1);//System call, read a character from the console, and process the characters one by one
            if (n == 1) {//If you can read a character
                ShellCmdLineParse(ch, (pf_OUTPUT)dprintf, shellCB);
            }
        }
    }
    
  • The consolecb - > FD of the read function is a virtual character device file, such as: / dev/console1. The operation on the file is performed by g_consoleDevOps implementation Read will eventually call ConsoleRead and then UART_Read

      /*! console device driver function structure | Console device driver, implementation of unified vfs interface */
      STATIC const struct file_operations_vfs g_consoleDevOps = {
          .open = ConsoleOpen,   /* open */
          .close = ConsoleClose, /* close */
          .read = ConsoleRead,   /* read */
          .write = ConsoleWrite, /* write */
          .seek = NULL,
          .ioctl = ConsoleIoctl,
          .mmap = NULL,
      #ifndef CONFIG_DISABLE_POLL
          .poll = ConsolePoll,
      #endif
      };
    
  • fifo is used for the specification mode of termios (line discipline), and the input data is processed based on the line. Before the user enters a line terminator (carriage return, EOF, etc.), the system call read() cannot read any characters entered by the user. Line terminators (carriage returns, etc.) other than EOF will be read into the buffer fifo by read() just like ordinary characters. In canonical mode, row editing is possible, and a call to read () can only read up to one row of data at a time. If the data bytes requested by read() are less than the bytes that can be read in the current row, read() will only read the requested bytes, and the remaining bytes will be read again next time. For details, see the travel regulations of the series

  • CirBufSendCB is a structure dedicated to SendToSer tasks. Tasks are driven by events. The console notifies SendToSer to send data to the terminal

    /**
     * @brief Send ring buf control block and send through event
     */
    typedef struct {
        CirBuf cirBufCB;        /* Circular buffer CB | Cyclic buffer control block */
        EVENT_CB_S sendEvent;   /* Inform telnet send task | For example, send an event to the SendToSer task*/
    } CirBufSendCB;
    

Task of sending data to terminal 𞓜 consoleendtask

ConsoleSendTask only does one thing, sending data to the serial port or remote login. The task priority is the same as that of the shell, which is 9. It is created by the system initialization task SystemInit. For details, see the kernel startup in the series

///Console cache initialization, create a send task
STATIC UINT32 OsConsoleBufInit(CONSOLE_CB *consoleCB)
{
    UINT32 ret;
    TSK_INIT_PARAM_S initParam = {0};
    consoleCB->cirBufSendCB = ConsoleCirBufCreate();//Create console
    if (consoleCB->cirBufSendCB == NULL) {
        return LOS_NOK;
    }
    initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ConsoleSendTask;//Console send task entry function
    initParam.usTaskPrio   = SHELL_TASK_PRIORITY;	//Priority 9
    initParam.auwArgs[0]   = (UINTPTR)consoleCB;	//Parameters of the entry function
    initParam.uwStackSize  = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;	//16K
    if (consoleCB->consoleID == CONSOLE_SERIAL) {//Two ways of console
        initParam.pcName   = "SendToSer";	//Task name (send data to serial port) 
    } else {
        initParam.pcName   = "SendToTelnet";//Task name (send data to remote login)
    }
    initParam.uwResved     = LOS_TASK_STATUS_DETACHED; //Use task separation mode
    ret = LOS_TaskCreate(&consoleCB->sendTaskID, &initParam);//Create a task and join the ready queue to apply for immediate scheduling
    if (ret != LOS_OK) { //Create failure handling
        ConsoleCirBufDelete(consoleCB->cirBufSendCB);//Release cycle buf
        consoleCB->cirBufSendCB = NULL;//Set NULL
        return LOS_NOK;
    }//Permanently waiting to read CONSOLE_SEND_TASK_RUNNING event, CONSOLE_SEND_TASK_RUNNING is issued by consoleendtask
    (VOID)LOS_EventRead(&consoleCB->cirBufSendCB->sendEvent, CONSOLE_SEND_TASK_RUNNING,
                        LOS_WAITMODE_OR | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER);
	// ...  Read console_ SEND_ TASK_ The running event will be executed downward  
    return LOS_OK;
}

The implementation of the task entry function consoleendtask is also very simple. All of them are posted here and wait for the event to be sent in an endless loop When it comes to the dead loop, say two more words. Don't be intimidated by while (1) and think that the kernel will get stuck and can't play here. That's the perspective of application programmers on the dead loop. In fact, in the kernel, when the waiting event doesn't come, the task will not be executed down, but in the suspended state. When the event comes, it will switch back and continue to go down. How do you know that the event has come? See event control in the series

STATIC UINT32 ConsoleSendTask(UINTPTR param)
{
    CONSOLE_CB *consoleCB = (CONSOLE_CB *)param;
    CirBufSendCB *cirBufSendCB = consoleCB->cirBufSendCB;
    CirBuf *cirBufCB = &cirBufSendCB->cirBufCB;
    UINT32 ret, size;
    UINT32 intSave;
    CHAR *buf = NULL;
    (VOID)LOS_EventWrite(&cirBufSendCB->sendEvent, CONSOLE_SEND_TASK_RUNNING);//Send an event when a console task is running
    while (1) {//Read CONSOLE_CIRBUF_EVENT | CONSOLE_SEND_TASK_EXIT these two events
        ret = LOS_EventRead(&cirBufSendCB->sendEvent, CONSOLE_CIRBUF_EVENT | CONSOLE_SEND_TASK_EXIT,
                            LOS_WAITMODE_OR | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER);//Read events of loop buf or task exit
        if (ret == CONSOLE_CIRBUF_EVENT) {//Console loop buf event occurs
            size =  LOS_CirBufUsedSize(cirBufCB);//Circular buf use size
            if (size == 0) {
                continue;
            }
            buf = (CHAR *)LOS_MemAlloc(m_aucSysMem1, size + 1);//Allocate memory to receive cirbuf
            if (buf == NULL) {
                continue;
            }
            (VOID)memset_s(buf, size + 1, 0, size + 1);//Clear 0
            LOS_CirBufLock(cirBufCB, &intSave);
            (VOID)LOS_CirBufRead(cirBufCB, buf, size);//Read cycle cirBufCB to buf
            LOS_CirBufUnlock(cirBufCB, intSave);

            (VOID)WriteToTerminal(consoleCB, buf, size);//Write buf data to console terminal equipment
            (VOID)LOS_MemFree(m_aucSysMem1, buf);//Clear buf
        } else if (ret == CONSOLE_SEND_TASK_EXIT) {//After receiving the task exit event, OsConsoleBufDeinit sends the event
            break;//Exit loop
        }
    }
    ConsoleCirBufDelete(cirBufSendCB);//Delete the loop buf and return the memory
    return LOS_OK;
}

The console and terminal mentioned above are often confused and become more and more blurred. Please explain them briefly

Traditional console and terminal

What is the difference between a console and a terminal? Look at this old picture This is not strange. Although it is rarely seen in the realization, it appears in movies

It is said to be NASA space shuttle console, full of sense of science and technology This is the console The early console was actually for system managers Because the machine is very large and expensive, it is impossible for everyone to have a computer that really belongs to them physically, but only one person can use it. What about others? If the efficiency is too low, a multi-user and multi task computer appears. Multiple people log in and use one computer at the same time. Put a simple device (only keyboard and screen) in front of everyone and connect it to the host, as shown in the figure This is called a terminal. Don't look so big. It looks like an all-in-one machine, but in fact it's just a display This is for ordinary users with limited permissions. The core function permissions are still in the hands of the system administrator of the operation console

To sum up, use a chart to list the early differences between the two

difference terminal Console
Device properties Plug in additional equipment Self contained basic equipment
quantity Multiple One
Host trust low high
Output content Information processed by the host Host core / self information
operator Ordinary users administrators

Current console and terminal

Due to the development of the times, the hardware of computer is getting cheaper and cheaper. Now one person monopolizes one computer (personal computer), and the traditional hardware terminal is no longer needed. Now the terminal and console have evolved from the concept of hardware to the concept of software. The boundary between the terminal and the console has gradually blurred and become more complex. Even the console has become a terminal. Now how to understand them? I recommend an article. Please go and search it yourself<< Thoroughly understand various terminal types and concepts of Linux > >

The content of this article is related to the / dev/console part in the upper right corner of the figure From the perspective of Hongmeng kernel, there are still great differences between console and terminal

Analysis of 100 blogs Deep excavation core foundation

  • In the process of annotating Hongmeng kernel source code, we sorted out the following articles. The content is based on the source code, often using life scenes as an analogy. Put the kernel knowledge points into a certain scene as much as possible, which has a sense of picture and is easy to understand and remember. It's important to say what others can understand! A hundred blogs are by no means Baidu's dogmatic talking about a bunch of awkward concepts. It's meaningless. I hope to make the kernel more lifelike and friendly It is indeed difficult and overestimated, but it is impossible to turn back after starting.   😛
  • Just as there are bugs in the code that need to be debug ged continuously, there will be many errors and omissions in the content of articles and comments. Please forgive me, but they will be corrected repeatedly and updated continuously, V * XX represents the article serial number and the number of modifications. It is carefully crafted, concise and comprehensive, and strives to create high-quality content.

By function module:

antecedents and consequences Basic tools Load run Process management
General catalogue Scheduling story Memory master slave Source code comments Source code structure Static site Comments Docs Bidirectional linked list Bitmap management Stack mode timer Atomic operation time management ELF format ELF parsing Static link Relocation Process Image Process management Process concept Fork Special process Process recycling Signal production Signal consumption Shell editing Shell parsing
Compile build Process communication memory management task management
Compiling environment Compilation process Environment script Build tools gn application ninja Ninja Spin lock mutex Process communication Semaphore Event control Message queue memory allocation memory management Memory assembly Memory mapping Memory Rules physical memory Clock task task scheduling task management Scheduling queue Scheduling mechanism Thread concept Concurrent parallel CPU system call Task switching
file system Hardware architecture
Document concept file system Index node Mount directory Root file system Character device VFS File handle Pipeline file Console Compilation basis Assembly parameters Working mode register Abnormal takeover Compilation summary Interrupt switching Interrupt concept Interrupt management

Annotation of millions of Chinese characters Intensive reading kernel source code

Chinese Notes on the four code warehouses Regularly synchronize official codes

weharmonyos | knock a little every day. It's not easy to be original. Welcome to reprint. Please indicate the source. It would be better if you can support and praise. Thank you for your support.

Topics: gitee entry harmonyos liteos