The Linux kernel must be compiled using the GNU gcc compiler, and GCC provides a number of C language extensions that provide strong support for optimization, target code layout, and more secure inspections. Therefore, the C syntax used by kernel code does not fully conform to the ANSI C standard, and whenever possible, kernel developers always use the C language extensions provided by GCC.
Calculate maximum and minimum values:
/*
* .. And if you can ' t take the strict
* types, can specify one yourself.
*
* Or not with Min/max/clamp at all, of course.
*/
#define MIN_T (type, x, y) ({ \
type __min1 = (x); \
Type __min2 = (y); \
__min1 < __min2 __min1: __min2;})
#define MAX_T (type, x, y) ({ \
type __MAX1 = (x); \
Type __max2 = (y); \
__max1 > __max2 __max1: __max2;})
0 Length Array
The 0-length array in the structure does not occupy the structure space, meaning that the length of the structure is variable.
Variable parameter macros
Printk
Special Properties __attribute__
GCC can support more than 10 properties, and __attribute__ can support properties that are more commonly used and
__attribute__ (attributes), which attribute is a description of the property
-Noreturn indicates that the function never returns
-Format
-unused indicates that the function or variable may not use the
-section used for functions and variables to be placed only from the cheap area
-aligned for variable, struct, or union, set a specified size alignment format, one byte per unit
-packed is used for variables and types, for variables or struct members to represent the use of the smallest possible pair of them, for enumerations, structs or consortia that represent the type using minimal memory.
Built-in functions
Built-in functions starting with __builtin, __buildin_xxx functions
Features of Linux kernel development
There are a number of different kernel developments in relation to application development in user space, and the most important differences include the following:
1 The kernel can not access the C library when programming.
2 when the kernel is programmed, GNU C must be used.
3 The kernel programming lacks the memory protection mechanism like user space.
4 when kernel programming, floating-point numbers are difficult to use.
5 The kernel has only a small fixed-length stack.
6 because the kernel supports asynchronous interrupts, preemption, and SMP, synchronization and concurrency must always be noted.
7 to consider the importance of portability.
1. No libc Library
Unlike user-space applications, the kernel cannot link to a standard C function library (other libraries are not available). The main reason is speed and size. Although not available, most commonly used C library functions have been implemented in the kernel. For example, the function groups that manipulate strings are located in the Lib/string.c file and can be used as long as they contain <linux/string.h> header files.
The kernel does not implement printf (), but you can use PRINTK (), PRINTK () is responsible for copying the formatted string to the kernel log buffer so that the Syslog program can read the buffer to obtain kernel information. The use of PRINTK () is much like printf () ':
PRINTK ("Hello world! A string:%s and an integer:%d.\n ", a_string, An_integer);
A notable difference between PRINTK () and printf () is that PRINTK () allows you to set a priority by specifying a flag. The syslog determines where the system message is displayed based on this priority flag.
PRINTK (Kern_err "This is a error!\n");
2.GNU C
The Linux kernel is written in C, but it does not fully conform to the ANSI C standard and uses many of the language extensions provided by GCC.
1) inline (inline) function
Inline causes the function to expand at the location it is called, which eliminates the overhead (register storage and recovery) of function calls and returns. Also, because the compiler optimizes the code and functions of the calling function together, there is a possibility of further optimizing the code. However, there is a cost to doing so, and the code will become longer, meaning that it takes up more memory space or consumes more instruction caching. It is generally defined as an inline function for functions that have higher time requirements and are shorter in length.
static inline void Dog (unsinged long tail_size);
In the kernel, inline functions are preferred rather than complex macros for type-safe reasons.
2) inline assembly
The GCC compiler supports embedding assembly directives in C functions. Of course, in the kernel programming, only know the corresponding architecture, to use this function.
3) Branch Statement
For conditional selection statements, GCC built an instruction for optimization, when a condition often occurs, or if the condition is rarely present, the compiler can optimize the conditional branch selection based on this instruction, which encapsulates the instruction into macros such as likely () and unlikely ().
For example, the following is a conditional selection statement:
if (foo) {/* ......
*/
}
If you want to mark this selection as a rarely occurring branch:
* * We think that most of the time will be 0 *
/if (Unlikely (foo)) {/
*
...
Conversely, if we want to mark a branch as usually the true choice
/* We do not think that Foo will normally be 0
/if (likely (foo)) {/
* ...
When you want to optimize a conditional selection statement, it is important to know whether there is such a condition and that it will be true in most cases: if your judgment is correct and you determine that the condition is overwhelming, then performance will improve and if you are mistaken, performance will fall. Unlikely () and likely () are often used when judging some error conditions. As can be guessed, unlikely () is widely used in the kernel because if statements often judge a particular case.
3. No memory protection mechanism
If a user program attempts an illegal memory access, the kernel discovers the error, sends the SIGSEGV, and ends the process. However, if the kernel itself illegally accesses memory, the consequences are difficult to control, and memory errors in the kernel can cause oops, the most common type of error that occurs in the kernel. In the kernel, you should not do access to an illegal memory address, refer to a null pointer or something like that, otherwise it might die, but you never know--in the kernel, the risk is often larger than the outside.
In addition, the memory in the kernel is not paginated, that is, using a byte, the physical memory is reduced by one byte. So, remember this when you want to add new features to the kernel.
4. Do not easily use floating-point numbers in the kernel
In the process of user space, the kernel completes the pattern conversion from integer operations to floating-point operations. What exactly does a floating-point instruction do when it is executed, because the architecture is different, the kernel is chosen differently, but the kernel usually traps and handles the trap accordingly.
Unlike user-space processes, the kernel does not perfectly support floating-point operations because it cannot be caught in itself. When floating point numbers are used in the kernel, there are other trivial things to do, in addition to manually saving and restoring floating-point registers. If you want to answer straight, that is: don't do it, don't use floating-point numbers in the kernel.
5. Small volume and fixed stack
User-space programs can allocate a lot of space from the stack to hold variables, even large structures or arrays that contain many data items. Because the user space of the stack itself is relatively large, but also dynamic growth.
The exact size of the kernel stack changes with the architecture. On the x86, the stack size is configured at compile time and can be 4KB or 8KB. The kernel stack is two pages in size, so the 32-bit kernel stack is 8KB and the 64-bit machine is 16KB, which is fixed. Each processor has its own stack.
6. Synchronization and concurrency
The kernel is prone to competitive conditions, because many of the kernel's features require concurrent access to shared data, which requires synchronization mechanisms to ensure that no competition conditions are present, in particular:
1 Linux is a preemptive multitasking operating system. The process scheduler of the kernel dispatches and dispatches the process in an impromptu procedure. The kernel must synchronize these tasks.
2 The Linux kernel supports multiprocessor systems. Without proper protection, code running on two or more processors is likely to access the same resource that is shared.
3 interrupts are coming asynchronously, regardless of the current code being executed. Without proper protection, it is entirely possible for interrupts to arrive within the code access shared resource so that the interrupt handler is likely to access the same resource.
4 The Linux kernel can preempt, if not properly protected, a section of the kernel is executing code may be preempted by another piece of code, which may cause several pieces of code to access the same resources at the same time.
7. The importance of portability
Linux is a portable operating system in which most C code should be independent of architecture and can be compiled and executed on computers in many different architectures. Therefore, you must share the architecture-related code appropriately from a specific directory in the kernel code tree.
A range of guidelines, such as keeping byte-order, 64-bit alignment, and not assuming word length and page lengths, are helpful for portability.