2023-2024-1 20232802 “Linux Kernel Principles and Analysis” Sixth Week Assignment

Experiment 5 Analysis system_call interrupt processing process

How to add time and time-asm commands to MenuOS:

1. Update the menu code to the latest version

rm menu -rf //Force deletion of menu, rm -rf means forced deletion.
git clone URL //Clone a new menu, which will update the menu code to the latest version

2. Add MenuConfig in the main() function

3. Add the corresponding Time function and TimeAsm function (the functions here should be replaced by functions written by ourselves using system calls, such as mkdir and mkdirAsm)

4. make rootfs (helps us automatically compile and generate the root file system, and also automatically helps us start Menuos. At this time, we find that the menu supports more commands than before)

Use gdb to trace the system call kernel function sys_time

Edit the text.c file in menu and write the fork and fork_asm written in last week’s homework in menuos:

Make rootf opens the menu image, enter help and you can see that two new commands have been added to the MenuOS menu:

Next start debugging with gdb:

cd LinuxKernel
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S
Split Horizontally
gdb
file linux-3.18.6/vmlinux //Load the kernel
target remote:1234 //Link to menu os
b start_kernel //Set a breakpoint at start_kernel
c //Continue execution

Next, set a breakpoint, start MenuOs, enter mkdir, and see the gdb debugging results:

list //View the startkernel code
b sys_mkdir //Set a breakpoint at the system call to be analyzed
c //Continue execution
c
c

b sys_time A breakpoint, press c to continue executing the time command, and find that after entering the system call, it will stop at the sys_time function

The process from system_call to iret

The flow chart from saving the scene to restoring the scene is roughly as follows:

Which also uses chatGPT

Textbook Chapter 9 and 10 Study

1. Each node in the linked list represents a request. The thread holds the lock, and the lock protects the data. The difference between various lock mechanisms is mainly that when the lock is already held by other threads and is not available, some locks will perform waiting, and others will cause the current task to sleep until the lock is available. In the mutex mutex, 0 means unlocked and 1 means locked.

2. Pseudo-concurrent execution refers to multiple single-threaded processes sharing files, or processing signals within a program, which may also produce race conditions, but the two do not actually occur at the same time. They intersect with each other; true concurrency refers to On a machine that supports symmetric multiprocessors, two processes are actually executed simultaneously in the critical section. The reasons for concurrent execution in the kernel come from interrupts, softirqs and tasklets, kernel preemption, sleep and synchronization with user space, and symmetric multiprocessing.

3. Why should it be locked? It is because it is afraid that other execution threads can access these data and prevent other things from seeing it. If it is local data, it is only accessed by itself. They exist independently in the stack of the execution thread. It is not surprising. These local variables need to be locked.

4. If there are one or more execution threads and one or more resources, each thread is waiting for one of the resources, but all resources are occupied, all threads are waiting for each other, and they will never be released. occupied resources, this is a deadlock. There are many examples of deadlocks, such as self-deadlock, ABBA deadlock, etc. To avoid deadlock, it is necessary to add locks in order (use multiple locks nested), prevent starvation, do not request the same lock repeatedly, and design applications. Keep it simple. Proper locking must be deadlock-free, scalable, and clear and concise. The essence of locking is to strive for simplicity.

5. Among the kernel synchronization methods, 11 kernel synchronization methods are mainly introduced. The purpose of synchronization is to ensure the security of data. In fact, it is to ensure the security of resources shared between various threads. Among them, the Big Kernel Lock (BLK) is the original chaotic period of the kernel and has few applications, so we mainly study the other ten kernel synchronization methods.

10.1 Atomic operations

Atomic operations are guaranteed by the compiler and are used when the critical section has only one variable, only one integer, to ensure that one thread’s execution of data will not be interrupted by other threads. There are two types of atomic operations:

1. Atomic integer operations, including 32-bit and 64-bit, the header files are <asm/atomic.h> and <asm/atomic64.h> respectively

2. Atomic bit operations, header file <asm/bitops.h>

10.2 Spin lock

Spin lock is the most common lock in Linux. It can only be held by at most one executable thread. If an execution thread tries to acquire a spin lock that is already held, the thread will always perform a busy loop – spin – Wait for the lock to become available again. Since the thread in the waiting state spins while waiting for the lock to be available again, which wastes CPU time, the spin lock should not be held by a thread for a long time. Its header file is

Warning:

1. Spin locks are not recursive, otherwise recursive requests for the same spin lock will lock themselves.

2. Before the thread acquires the spin lock, local interrupts must be disabled, otherwise the interrupt handler will interrupt the kernel code holding the lock and may compete with the thread acquiring the lock for the spin lock.

Spin lock and lower half:

1. When the lower half processing and the process context share data, since the lower half processing can preempt the code of the process context, the process context must prohibit the execution of the lower half before locking the shared data, and then allow the lower half when unlocking. execution of the department.

2. When the interrupt handler (upper half) and the lower half process shared data, since the interrupt handler (upper half) can preempt the execution of the lower half, the lower half must disable interrupt processing before locking the shared data. (upper half), interrupt execution is allowed again when unlocked.

3. The same tasklet cannot run at the same time, so shared data in similar tasklets does not need to be protected.

4. For soft interrupts, regardless of the same type, if data is shared by soft interrupts, it must be protected by a lock. However, one soft interrupt on the same processor will not preempt another soft interrupt, so there is no need to disable the lower half. .

10.3 Read-write spin lock

As for reading and writing spin locks, we have already mentioned in this week’s fourth lesson that reading and reading are not mutually exclusive. The rest of reading and writing, and writing and writing are all mutually exclusive.

10.4 Semaphore

The semaphore is also a kind of sleep lock. Different from the spin lock, when the thread cannot obtain the semaphore, it will not cycle to try to obtain the lock like the spin lock, but will go to sleep until the semaphore is released. When, the sleeping thread will be awakened and enter the critical section for execution, so the semaphore is suitable for critical sections with long waiting times. There are two types of semaphores: binary semaphores and counting semaphores, among which binary semaphores are more commonly used.
A binary semaphore means that the semaphore has only two values: when the semaphore is 1, it means that the critical section is available; when the semaphore is 0, it means that the critical section is inaccessible.

10.5 Read-write semaphores

Both read and write semaphores are binary semaphores (mutually exclusive semaphores), that is, the maximum count value is 1. When a reader is added, the counter does not change. When a writer is added, the counter decreases by one. That is to say, the read and write semaphores are protected. A critical section has at most one writer, but can have multiple readers.

10.6 Mutex

The only locks in the kernel that allow sleep are semaphores. The data structure mutex corresponding to mutex in the kernel behaves similarly to a semaphore with a usage count of 1, but the operation interface is simpler, the implementation is more efficient, and the usage restrictions are stronger, so mutex is preferred unless its constraints cannot be met.

10.7 Completion variables
Completion variables are a simple way to synchronize two tasks. The mechanism of completion variables is similar to a semaphore. If one thread wants to perform work, the other thread will wait on the completion variable; when the thread completes the work, use the completion variable to wake up the waiting tasks.
Header file for completion variables:

10.9 Sequential locks

Usually referred to as seq lock, unlike spin locks and read-write semaphores, sequential locks are used to read and write shared data.

10.10 Preemption prohibited

Although spin locks can prevent kernel preemption, sometimes you only need to disable kernel preemption. You don’t need to block interrupts like spin locks. In this case, you can use the method of disabling kernel preemption. The header file that disables preemption is

10.11 Sequences and Barriers

For a piece of code, the compiler or processor may perform some optimizations on the execution order when compiling and executing it, making the execution order of the code somewhat different from the code we wrote. Under concurrent conditions, the obtained values may be inconsistent with expectations. Therefore, in order to ensure the execution order of the code, a series of barrier methods are introduced to prevent the optimization of the compiler and processor.

Reference website: “Linux Kernel Design and Implementation” Reading Notes (10) – Kernel Synchronization Method – wang_yb – Blog Park