This article is part IV of the article "reading thin"linux core design and implementation ", which focuses on the following issues: concepts and implementation principles of interrupt and interrupt handlers, the lower half of Linux, and the kernel synchronization method.
0x00 Interrupt and Interrupt handler I interrupt
Interrupt is a special electrical signal, from the hardware to the processor, when the processor receives an interrupt, the box will be immediately reflected in the operating system, processed by the OS. Interrupts can be generated at any time, so the kernel can be interrupted at any time due to a new outage.
Different devices have different interrupts, each with a unique digital ID, often referred to as interrupt request (IRQ) lines.
II Interrupt Handling Program
The interrupt handler becomes an interrupt processing routine (ISR), which is a function that the kernel executes when the response is interrupted.
One interrupt handler corresponds to one interrupt, and one device may emit multiple interrupts
For external devices, the interrupt handler is part of the device driver
In Linux, interrupt handlers and C functions differ little, but have their own specifications, primarily the runtime needs to be in the context of the interrupt
0x01 Interrupt handling mechanism I register interrupt handler
A driver can request_irq()
register an interrupt handler (linux/interrupt.h) through a function
int request_irq(unsignedint irq, irqhandler_t handler, long falgs, constchar *name, void *dev)
typedef irqhandler_t(*irq_handler_t)(intvoid*);
II Release Interrupt Handler
When uninstalling the driver, you need to unregister the response interrupt handler and release the break.
void free_irq(unsignedintvoid *dev);
If the specified interrupt line is not shared, the function deletes the handler while the interrupt line is disabled, and the interrupt line is shared, and only the dev corresponding handler is deleted, and the interrupt line itself is disabled only when the last handler is deleted.
III prohibition and activation of interrupts
local_irq_disable();local_irq_enable();
IV Upper half and lower part
and want to interrupt the processing program to run fast, and want to interrupt the process to complete a lot of work, these two purposes are obviously inconsistent, so the interruption processing is divided into two parts:
The interrupt handler is the top half, receives an interrupt, it starts execution immediately, but only works with strict deadlines, such as some work that can only be done if the interrupt is disabled
Work that can be allowed to be done later will be postponed from 2 to the lower half, after which, at the right time, the lower part will be interrupted.
Q1: Why do you want to split the top half and the lower half? {% ENDCQ%}
- The interrupt program executes asynchronously, possibly interrupting the execution of important operations, as soon as possible.
- The interrupt handler masks other sibling interrupts, so the faster the execution the better
- Interrupt handlers often require hardware operations, often with a high time-frame requirement
- The interrupt handler does not run in the context of the process, so it cannot block
Q2: How to separate the top and bottom halves? {% ENDCQ%}
- If a task is sensitive to time, put it in the top half;
- If a task is related to hardware, put it in the top half;
- If a task is guaranteed not to be interrupted by another interrupt, place it in the top half;
- All other tasks are considered to be placed on the lower half.
0x02 the lower half of the
The second part of the task is to perform work that is closely related to terminal processing but the interrupt handler itself does not perform. We expect the interrupt handler to put as much work as possible into the lower half of the execution to quickly return from the interrupt.
I lower half realization mechanism a. Soft interrupt
The soft interrupts here are different from the int 80H used by the system call and are supported by the operating system, statically allocated during compilation
Implementation of soft interrupts
- Defined
linux/interrupt.h
in:
struct softirq_action{ void (*action)(struct//待执行的函数 void//传递的参数}
- A maximum of 32 soft interrupts, defined in
kernel/softirq.c
staticstruct softirq_action softirq_vec[NR_SOFTIRQS];
Soft interrupt handlers
void softirq_handler(struct//传递整个结构体
Perform soft interrupts
A registered soft interrupt must be marked before the following is performed, and the pending soft interrupt is checked and executed:
- In the KSOFTIRQD kernel thread
- In code that explicitly checks and executes the soft interrupt to be processed (such as the network subsystem)
Soft interrupts are performed regardless of the timing of the execution do_softirq
Using soft interrupts
Allocation index: linux/interrupt.h
A new soft interrupt is declared by one of the enumeration types in
Registration handler: Registers a soft interrupt handler at run time by calling, open_softirq()
with two parameters, soft interrupt and handler function
Trigger Soft Interrupt: The raise_softirq()
function can set a soft interrupt to suspend, allowing it to run the next time the do_softirq()
function is called
B.tasklet
Soft interrupt-based implementation, but its interface is simpler and lock protection is less demanding
The realization of Tasklet
- Tasklet Structural Body (linux/interrupt.h)
struct tasklet_struct{ struct tasklet_struct *next; //链表 unsignedlong state; //tasklet 状态 //引用计数器 void (*funx)(unsignedlong); //taklet 处理函数 unsignedlong//给处理器函数传递的参数}
Dispatch Tasklet
The soft interrupts that are triggered are stored in 2 data structures:, both tasklet_vec
task_hi_vec
of these data structures are composed task_struct
of linked lists, tasklet_schedule()
and are dispatched by, and the task_hi_schedule()
scheduling steps are as follows:
(1) Check the Tasklet status and TASK_STATE_SCHED
return if
(2) Call _tasklet_schedule()
(3) Save interrupt State, prohibit local interrupt
(4) Add the Tasklet to or from the list to be dispatched tasklet_vec
tasklet_hi_vec
(5) TASKLET_SOFTIRQ
invoke or HI_SOFTIRQ
soft interrupt, the next call do_softirq()
will execute the Tasklet
(6) Resume interrupt
- Soft Interrupt Handler:
tasklet_action()
or task_hi_action()
[core of Tasklet processing ]:
- (1) No interruption
- (2) Set the list header on the current processor to NULL
- (3) Allow interrupts
- (4) Cyclic traversal of tasklet to be processed on the linked list
- (5) If it is multiple processors, check
TASKLET_STATE_RUN
to see if the Tasklet is running on the other processor, and if so, jump to laugh a tasklet
- (6) If no, set
TASKLET_STATE_RUN
- (7) Check if Count is 0, make sure Tasklet is not forbidden, if forbidden, skip to next Tasklet
- (8) Execution of Tasklet processing procedures
- (9) After execution, clear
TASKLET_STATE_RUN
- (10) Repeated execution of the next Tasklet
Use Tasklet to declare your own Tasklet:
- Static: 2 macros in Linux/interrupt.h:
DECLARE_TASKLET(name,func,data);DECLARE_TASKLET_DIASBLED(name,func,data);
- Dynamic: A pointer is assigned to a dynamically created Tasklet_struct:
tasklet_init(t, takslet_handler, dev);
Write your own Tasklet handler
void tasklet_handler(unsignedlong data)
Note: You can no longer use semaphores or other blocking functions in Tasklet
Dispatch your own tasklet.
tasklet_schedule(&my_tasklet);tasklet_enable(&my_tasklet);tasklet_disable(&my_tasklet);
Ksoftirqd
KSOFTIRQD is a kernel thread, each processor has one that handles soft interrupts in the idle processor
for(;;){ if(!softirq_pending(cpu)) schedule(); set_current_state(TASK_RUNNING); while(softirq_pending(cpu)){ do_softirq(); if(need_resched()) schedule(); } set_current_sdtate(TASK_INTERRUPTIBLE);}
As long as the soft interrupt remains to be processed, the thread will process
C. Work queue
The work queue mechanism gives the next half function to the kernel county to execute, the thread context, can sleep
Implementation of the Task Force column
- Provides an interface to create worker threads
- Provides default worker threading to work in the lower half of the queue
- Provide the interface to the queue for tasks that need to be pushed out.
Processing mechanism
- The thread sleeps itself and adds to the wait queue (task_interruptible)
- If the work list is empty, thread calls
schedule()
, hibernate
- If not empty, set yourself as
TASK_RUNNING
- Call
run_workqueue()
to perform deferred work
This function loops through each of the pending work on the list:
- When the list is not empty, select the next Node object
- Get the functions and arguments to execute
- Pending the node from the linked list, zeroing the position
- Calling functions
- Repeated execution
Use of Task Force columns
Static:
void(*func)(voidvoid *data);
Dynamic:
INIT_WORK(structvoid(*func)(voidvoid *data);
- Work Queue processing functions
void work_handler(void *data)
schedule_work(&work);schedule_delayed_work(&work, delay);
void flush_scheduled_work(void);
comparison of 3 lower half mechanisms
mechanism |
Context |
Sequential Execution Assurance |
Soft interrupt |
Interrupt |
No |
Tasklet |
Interrupt |
Same type cannot be executed concurrently |
Work queue |
Process |
Not (as the process context is dispatched) |
Q: What kind of mechanism do we choose? {% ENDCQ%}
If you have hibernation requirements, select the work queue; otherwise, it is best to use tasklet; If you have to focus on performance improvements, select soft interrupts
II lock between the lower half
If the process context and a lower half share data, you need to suppress the processing of the lower half and get the lock right before accessing the data.
If the interrupt context and a lower half share the data, you need to disable the interrupt and get the lock right before accessing the data
0x03 Core Sync I critical section
A critical section is a code snippet that accesses and operates shared resources, and must be guaranteed to be executed atomically to ensure security.
II Plus Lock
Ensure that there is only one in the county where the critical section is executed
III Causes of concurrency
Interrupt
Soft interrupts and Tasklet
Kernel preemption
Synchronization of sleep and user space
Symmetric multi-processing
IV Deadlock Generation conditions
To have one or more execution threads and one or more resources
Each thread waits for one of the resources
All the resources are occupied
All the counties are waiting for each other, but they will never release the resources they already possess.
V Kernel Synchronous Method Atomic operation
- Atomic integer Manipulation (asm/atomic.h)
atomic_dec_and_test(atmoic_t, *v)
- Atomic bit operation (ASM/BITOPS.H)
set_bit(0, &word)
Spin lock
Spin locks can only be held by an executable process
The process is busy (rotated) if a occupied lock is contended
Spin lock can not be used for a long time, otherwise the efficiency is low
This article's copyright belongs to the author Luo voyage All, uses Attribution-noncommercial 3.0 License. Any person may reproduce, share, but not be used without permission for commercial purposes; reprint please specify the source. Thanks for cooperating!
Read thin "Linux kernel design and Implementation" (4)-Interrupts and synchronization