II. LINUX section (Printk)
In Linux, complete similar work, process printk in Linux / kernel / printk.c. This process, relatively, is more complicated. The program code is (before the process code, some global variables are omitted, and we need to point out when we point out):
/ *
* Linux / kernel / printk.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* Modified to make sys_syslog () more flexible: added commands to
* Return The Last 4k of kernel Messages, Regardless of Whether
* They've been read or not. Added Option to Suppress Kernel Printk's
* to the console. Added hook for sending the console message
* Elsewhere, in Preparation for a serial line console (someday).
* TED TS'O, 2/11/93.
* Modified for sysctl supports, 1/8/97, chris horn.
* /
Spinlock_t console_lock; / * Structural variable, control station lock * /
001 ASMLINKAGE INT Printk (Const Char * FMT, ...)
002 {
003 VA_List Args;
004 INT I;
005 char * msg, * p, * buf_end;
006 INT line_feed;
007 Static Signed CHAR MSG_LEVEL = -1; / * Log Level of Current Messages * /
008 long flags;
009
010 spin_lock_irqsave (& Console_lock, Flags);
011 VA_START (ARGS, FMT);
012 i = vSprintf (buf 3, fmt, args); / * Hopefully i 013 BUF_END = BUF 3 I; 014 VA_END (ARGS); 015 for (P = BUF 3; P 016 msg = p; 017 IF (MSG_LEVEL <0) { 018 IF 019 p [0]! = '<' || 020 p [1] <'0' || 021 P [1]> '7' || 022 P [2]! = '>' 023) { 024 p - = 3; 025 p [0] = '<'; 026 p [1] = default_message_loglevel '0'; 027 P [2] = '>'; 028} else 029 msg = 3; 030 msg_level = p [1] - '0'; 031} 032 LINE_FEED = 0; 033 for (; p 034 log_buf [(log_start log_size) & (log_buf_len-1)] = * P; 035 IF (log_size 036 LOG_SIZE ; 037 else { 038 LOG_START ; 039 log_start & = log_buf_len-1; 040} 041 Logged_Chars ; 042 if (* p == '/ n') { 043 LINE_FEED = 1; 044 Break; 045} 046} 047 if (msg_level 048 struct console * c = console_drivers; 049 While (c) { 050 IF ((C-> Flags & Con_Nenabled) && C-> Write 051 C-> Write (C, MSG, P - MSG Line_Feed); 052 C = C-> NEXT; 053} 054} 055 if (line_feed) 056 msg_level = -1; 057} 058 Spin_unlock_irqrestore (& Console_lock, Flags); 059 wake_up_interruptible (& log_wait); 060 RETURN I; 061} 062 The design of this process, some knowledge needs to be introduced. First, Printk is the kernel internal message logging function. Call Printk generally emergency, debug or normal information. It is similar to the parameters of the process Printf, which is a format string and add several parameters (including 0) to this string. In Printk, the format string may be started with a " / * In the file spinlock.h * / #define spin_lock_irqsave (LOCK, FLAGS) / DO {save_flags (flags); CLI ();} while (0) This macro definition is interesting, using the Do-While structure to encapsulate the target. This is a trick that avoids the ambiguity of macros. And the role is to get the control status lock and initialize the FLAGS. VA_START and VA_END are also macros, handled with a special type VA_LIST, and store the "..." section in the printk parameter into Args (011 to 014). The global variable gives the following definitions: #define log_buf_len (16384) / * log_buf 's length * / Static Char BUF [1024]; Unsigned long log_size = 0; Struct Console * console_drivers = null; Static char log_buf [log_buf_len]; STATIC UNSIGNED Long Log_Start = 0; Static unsigned long Logged_Chars = 0; And where console is a structure, it is defined as follows: / * In file console.h * / Struct console { Void (* Write) (Struct Console *, Const Char *, Unsigned); } In this way, you can temporarily go back to continue to see this program, with your own power, come to Iraq. For this process of the Linux kernel, let's take a detailed analysis. For the convenience of discussion, we give the following picture as a reference for the narrative: At the end of 014, we have got the control station lock, and the Parameters of Printk "..." section (if any) is loaded into buf [] with the FMT portion. The 012 line vsprintf is the process of the Linux kernel, writing to the format string and returns the length of the written string (excluding the final termination character 0 byte), by the call situation, ignore The first three characters of BUF, the code will know the reason. 015 to 057 Outer FOR cycle, specific processing message string. 016 msg Record the position of BUF 3. 017 Level of the current message log is a static variable and is initialized to -1. So when PRINTK is called for the first time, 017 to 031 will definitely be executed. If you quickly scan, you will find that the chance to change the MSG_level value is only two, one is at 030, last at 056, if the value of line_feed is 1, then the value of MSG_LEVEL is -1.018 to 029 this IF Judgment is very interesting. The first three characters of BUF [] are re-examined here (a substring). As long as it is not " 030 msg_level records the level of the current message log (one of the numbers of 1 to 7)! 032 LINE_FEED is initialized to 0. Line_feed actually records the number of rows currently processed. 033 to 046 is the inner layer for loop. Here more interest here, also highlighting the ability of C language, and the ability of Linux kernel code writers to use language. Note that P and MSG points to P and MSG, the former points to the log level sequence, which points to the message text immediately followed. 034 buffer log_buf [] Is it easy to make people confused? What does it mean about the bit and (&) operation here? Is a quick sample operation (%)! Of course, there is a guarantee that is the value of LOG_BUF_LEN to be 2 power. In this way, log_buf [] is actually a cyclic buffer. It will record the latest internal message. 035 to 040 is a reset of the circulatory buffer access mechanism, so that log_start log_size is moved behind the loop (molded log_buf_len-1). 041 logged_chars is a global static variable, recorded by the number of all characters written by Printk after the machine is started, here from 1. 042 to 045 is another exit of the internal cycle exit. If the content referred to in P is '/ N', it indicates that the message is about to end. Then line_feed is recorded to 1, exit in the inner layer For loop. From here you can look back at the work made by this inner FOR loop. It can be known that every time the inner FOR cycle starts, starting a new printing line. Only, typically Printk is only used to print a row, so the inner FOR loop is usually only executed once. 047 to 054 Print the work of a line of messages. If it is true, if it is true, it indicates that the log level of the current message is higher than the log level defined by the current console, and the console-driven chain table console_drivers can open. Then, traversing the console_drivers to inform Each console driver to print the current line. We do not discuss the details of this process, only reminding you that the second parameter introduced in 051 is MSG instead of P, which is written in the case where there is no log level sequence. If you need a log level, you can access log_buf []. 055 and 056 If line_feed is 1, a line has ended. No matter whether it is present, it can be regarded as a new line, and MSG_LEVEL is also set to -1. Now you can look at the control logic of MSG_LEVEL. As shown in the following figure (is a brief map, only MSG_level): Control Printk, the context will be more clear. These include the execution of the 017 to 031, and now it can now be said to process messages in each new row. 058 Release the control station lock. 059 Wake Wake Waiting for all processes written to the console log. 060 returns I. 061 ends.