Linux kernel soft interrupt

Linghu onion Dennis 2021-05-04 14:43:49
linux kernel soft interrupt


1 Overview of softinterrupt

Soft interrupt is a way to realize the lower part of interrupt , And 2.5 The mechanism of the second half of the previous version is different . Soft interrupts can run in different environments at the same time CPU On .

1.1 Soft interrupt representation

Structure is used in the kernel softirq_action Represents a soft interrupt . Softinterrupts are a set of statically defined interfaces , Yes 32 individual . But the kernel (2.6.34) Only... Has been achieved in 10 individual . The number of available softinterrupts NR_SOFTIRQ Express ,NR_SOFTIRQ=10, The type of soft interrupt is represented by an enumeration body . What needs to be noted here is ,32 The bit mask of each soft interrupt is unsigned int type .

static struct softirq_action softirq_vec[NR_SOFTIRQS] ;
enum
{
HI_SOFTIRQ=0,
TIMER_SOFTIRQ,
NET_TX_SOFTIRQ,
NET_RX_SOFTIRQ,
BLOCK_SOFTIRQ,
BLOCK_IOPOLL_SOFTIRQ,
TASKLET_SOFTIRQ,
SCHED_SOFTIRQ,
HRTIMER_SOFTIRQ,
RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */
NR_SOFTIRQS
};
struct softirq_action
{
void (*action)(struct softirq_action *);
};

2 Soft interrupt related data structure

2.1 thread_info Of preempt_count Field

preempt_count It's a 32 Bit int type , Will be divided into 5 A field
 Picture description here
macro in_interrupt Detect soft interrupt counter Hard interrupt counter and NMI Mask , As long as any of the three fields is not 0, Indicates that the process is in the interrupt context .

#define in_irq() (hardirq_count())
#define in_softirq() (softirq_count())
#define in_interrupt() (irq_count())

2.2 pending Bitmask

Every CPU There's a irq_stat structure ,irq_stat Medium __softirq_pending It's a 32 Bit mask , by 1 Indicates that the soft interrupt has been activated , Waiting to be processed . by 0 Indicates that soft interrupt is disabled . stay do_irq Is used in .
The kernel using local_softirq_pending Get the present CPU Bit mask on

#define local_softirq_pending() percpu_read(irq_stat.__softirq_pending)
#define set_softirq_pending(x) percpu_write(irq_stat.__softirq_pending, (x))
#define or_softirq_pending(x) percpu_or(irq_stat.__softirq_pending, (x))
irq_cpustat_t irq_stat[NR_CPUS]
typedef struct {
...
unsigned int __softirq_pending;
...
}irq_cpustat_t;

2.3 Soft interrupt stack

The size of the process's kernel stack depends on the compile time options , It can be 4K perhaps 8K. If it is 8K Stack , interrupt , Exception and soft interrupt (softirq) Share this stack . If you choose 4K Stack , Then the kernel stack Hard interrupt stack Each soft interrupt stack uses one 4K Space . About soft interrupt stack , Later, it will be explained in detail when handling soft interrupt .

#ifdef CONFIG_4KSTACKS
static DEFINE_PER_CPU_PAGE_ALIGNED(union irq_ctx, softirq_stack);
union irq_ctx {
struct thread_info tinfo;
u32 stack[THREAD_SIZE/sizeof(u32)];
} __attribute__((aligned(PAGE_SIZE)));

3 Initialization of soft interrupt

The kernel using open_softirq Initialize a soft interrupt ,nr Is a constant representing the type of soft interrupt ,action Point to a soft interrupt handler

void open_softirq(int nr, void (*action)(struct softirq_action *))
{
softirq_vec[nr].action = action;
}

4 Soft interrupt trigger (raise softirq)

Trigger is to mask bits pending The corresponding bit of Set up 1 The process of . The kernel using raise_softirq Finish triggering soft interrupt ,nr Is the type of soft interrupt to trigger . It's worth noting that , Interrupt trigger In the case of a shutdown hard interrupt .

In the process of triggering soft interrupt , If the process is not in the interrupt context , Indicates that the current process is in the process context , So let's call wakeup_softirqd Dispatch ksoftirqd that will do .

conversely , If you are currently in interrupt context or soft interrupt is disabled , Then you don't have to schedule kernel threads , After interrupt processing irq_exit in , Would call invoke_softirq() Handle soft interrupts .
The actual job is to give or_softirq_pending(1UL << (nr)); Accomplished , This function specifies and... By bit operation pending Add up .

 Picture description here

void raise_softirq(unsigned int nr)
{
unsigned long flags;
local_irq_save(flags);
raise_softirq_irqoff(nr);
local_irq_restore(flags);
}
inline void raise_softirq_irqoff(unsigned int nr)
{
__raise_softirq_irqoff(nr);
/*
* If we're in an interrupt or softirq, we're done
* (this also catches softirq-disabled code). We will
* actually run the softirq once we return from
* the irq or softirq.
*
* Otherwise we wake up ksoftirqd to make sure we
* schedule the softirq soon.
* If not in interrupt context
*/
if (!in_interrupt())
wakeup_softirqd();
}
#define __raise_softirq_irqoff(nr) do { or_softirq_pending(1UL << (nr)); }

5. Soft interrupt processing

5.1 When to deal with soft interrupt

1 stay do_irq At the end of (irq_exit)

If the current process is not in the interrupt context and is local CPU There are also soft interrupts that are not handled on , So call invoke_softirq() Handle soft interrupts .

#ifdef __ARCH_IRQ_EXIT_IRQS_DISABLED
# define invoke_softirq() __do_softirq()
#else
# define invoke_softirq() do_softirq()
#endif
void irq_exit(void)
{
account_system_vtime(current);
trace_hardirq_exit();
sub_preempt_count(IRQ_EXIT_OFFSET);
if (!in_interrupt() && local_softirq_pending())
invoke_softirq();
rcu_irq_exit();
#ifdef CONFIG_NO_HZ
/* Make sure that timer wheel updates are propagated */
if (idle_cpu(smp_processor_id()) && !in_interrupt() && !need_resched())
tick_nohz_stop_sched_tick(0);
#endif
preempt_enable_no_resched();
}
#ifdef __ARCH_IRQ_EXIT_IRQS_DISABLED
# define invoke_softirq() __do_softirq()
#else
# define invoke_softirq() do_softirq()
#endif

Program 5-1 irq_exit

2 When soft interrupts are repeatedly triggered over 10 When the time , The kernel calls wakeup_softirqd() Wake up the kernel thread ksoftirqd To handle soft interrupts .

5.2 Soft interrupt processing

1 do_softirq

According to the kernel stack size , There are two kinds of do_softirq, One is universal do_irq, The other is architecture related do_irq(arch/x86/kernel/irq_32.c).

General purpose do_irq workflow
1 Judge whether it is in the context of hard interrupt or soft interrupt is disabled , If so, go straight back to
2 preservation Eflags Then turn off the local hardware interrupt
3 Access to the local CPU Bit mask for pending If the soft interrupt to be processed is called __do_irq
4 from __do_irq Back to recovery Eflags

asmlinkage void do_softirq(void)
{
// The local variable used to hold the bitmask
__u32 pending;
// preservation Eflags Local variables of registers
unsigned long flags;
// If do_softirq Called in interrupt context or Soft interrupt is forbidden So don't handle soft interrupts
// Go straight back to
if (in_interrupt())
return;
// take Eflags Save to flags in Then turn off the hardware interrupt
local_irq_save(flags);
// Access to the local CPU Bit mask on
pending = local_softirq_pending();
if (pending)
__do_softirq();
// take flags
local_irq_restore(flags);
}

x86_32 Use under architecture 4K Soft interrupt stack do_softirq Processing flow
1 Similar to general do_softirq, If it's in the context of an interrupt or if soft interrupts are disabled, return immediately . Then turn off the external interrupt
2 If the local CPU If there is a soft interrupt to be processed on the stack, the soft interrupt stack will be processed , The key is to make isp Point to the bottom of the soft interrupt stack . Then call... On the soft interrupt stack call_on_stack.call_on_stack It's an inline compilation , Its main purpose is to switch from kernel stack to softinterrupt stack . First the esp Save to ebx in , Use call The command jumps to __do_softirq Subroutines , Subroutines are restored when they return esp.

asmlinkage void do_softirq(void)
{
unsigned long flags;
struct thread_info *curctx;
union irq_ctx *irqctx;
u32 *isp;
if (in_interrupt())
return;
local_irq_save(flags);
if (local_softirq_pending()) {
//curctx Pointing to the current process thread_info structure
curctx = current_thread_info();
//irqctx Contains a soft interrupt heap and thread_info structure
irqctx = __get_cpu_var(softirq_ctx);
// Trigger hard interrupt and soft interrupt are the same process, so threadinfo Of task The pointer is uniform
irqctx->tinfo.task = curctx->task;
// Switch from kernel stack to soft interrupt stack You need to save the stack pointer register contents of the kernel stack
irqctx->tinfo.previous_esp = current_stack_pointer;
/* build the stack frame on the softirq stack */
//isp Point to the bottom of soft interrupt stack
isp = (u32 *) ((char *)irqctx + sizeof(*irqctx));
// Call... On the soft interrupt stack __do_softirq
call_on_stack(__do_softirq, isp);
}
local_irq_restore(flags);
}
static void call_on_stack(void *func, void *stack)
{
//call *%%edi Indirect absolute near call The offset address is stored in edi In the register
// Instruction execution First the eip Push And then edi-->eip
// Exchange first ebx and esp
// And then call __do_softirq
// And then ebx-->esp recovery xchgl Previous esp
// The output constraint will ebx --> stack
asm volatile("xchgl %%ebx,%%esp \n"
"call *%%edi \n"
"movl %%ebx,%%esp \n"
: "=b" (stack)
: "0" (stack),
"D"(func)
: "memory", "cc", "edx", "ecx", "eax");
}

2 __do_softirq

Soft interrupt is actually handled by __do_softirq complete , The whole idea is to traverse pending, If a bit is not empty, it means local CPU Soft interrupts to be processed on , Call soft interrupt processing function .
Before you start processing soft interrupts , The kernel calls __local_bh_disable( By way of preempt_count Soft interrupt counter plus 1) Close the bottom half . As mentioned before , There is more than one time to deal with soft interrupts , The kernel should be local CPU The processing of soft interrupt is serial .
In addition, at the end of the loop that handles soft interrupts , The kernel also needs to detect whether there are repeated soft interrupts . First call local_softirq_pending() Get bitmask pending, And then according to pending Continue processing soft interrupts , But this kind of repetition can't be more than 10 Time (MAX_SOFTIRQ_RESTART), Once you surpass 10 Time , The kernel will wake up ksoftirqd

#define MAX_SOFTIRQ_RESTART 10
asmlinkage void __do_softirq(void)
{
// softirq_action Represents a soft interrupt
struct softirq_action *h;
// local variable pending Save the pending soft interrupt bitmap
__u32 pending;
// The number of soft interrupt restarts
int max_restart = MAX_SOFTIRQ_RESTART;
int cpu;
// Access to the local CPU All pending soft interrupts on the
pending = local_softirq_pending();
account_system_vtime(current);
// Close the bottom half of the interrupt
__local_bh_disable((unsigned long)__builtin_return_address(0));
lockdep_softirq_enter();
cpu = smp_processor_id();
restart:
/* Reset the pending bitmask before enabling irqs */
//pending All the status of soft interrupt has been saved So will pending bitmask clear
set_softirq_pending(0);
// Open the interrupt
local_irq_enable();
//h Point to the first kind of soft interrupt
h = softirq_vec;
do {
// Handle the first kind of soft interrupt first
if (pending & 1) {
int prev_count = preempt_count();
kstat_incr_softirqs_this_cpu(h - softirq_vec);
trace_softirq_entry(h, softirq_vec);
// Call soft interrupt handler
h->action(h);
trace_softirq_exit(h, softirq_vec);
if (unlikely(prev_count != preempt_count())) {
printk(KERN_ERR "huh, entered softirq %td %s %p"
"with preempt_count %08x,"
" exited with %08x?\n", h - softirq_vec,
softirq_to_name[h - softirq_vec],
h->action, prev_count, preempt_count());
preempt_count() = prev_count;
}
rcu_bh_qs(cpu);
}
h++;
pending >>= 1;
} while (pending);
// Shut down the local CPU Hard interrupt on
local_irq_disable();
// Get bitmask
pending = local_softirq_pending();
if (pending && --max_restart)
goto restart;
if (pending)
wakeup_softirqd();
lockdep_softirq_exit();
account_system_vtime(current);
// Add the soft interrupt counter to 1, Activate softinterrupt
_local_bh_enable();
}

6 ksoftirqd Kernel thread

6.1 ksoftirqd

In the kernel processing similar NET_RX_SOFTIRQ Soft interrupt of , If there are a lot of packets waiting to be processed . It's going to keep calling
__raise_softirq_irqoff(NET_RX_SOFTIRQ) Trigger soft interrupt repeatedly NET_RX_SOFTIRQ. Doing so will cause the user process to ” The problem of hunger “ ( Not available for a long time CPU).
To solve this problem, the kernel uses kernel threads ksoftirqd To handle self triggering more than 10 Second soft interrupt .

6.2 ksoftirqd The implementation of the

static int ksoftirqd(void * __bind_cpu)
{
//ksoftirqd Has the lowest priority (nice = 19)
set_user_nice(current, 19);
// take ksoftirqd Set to unfrozen
current->flags |= PF_NOFREEZE;
// Set up ksoftirqd Is interruptible
set_current_state(TASK_INTERRUPTIBLE);
while (!kthread_should_stop()) {
// If there are no pending soft interrupts, then Scheduling other processes
if (!local_softirq_pending())
schedule();
__set_current_state(TASK_RUNNING);
while (local_softirq_pending()) {
/* Preempt disable stops cpu going offline.
If already offline, we'll be on wrong CPU:
don't process */
// Turn off kernel preemption
preempt_disable();
// Handle soft interrupts
do_softirq();
// Turn on kernel preemption
preempt_enable();
//cond_resched() The purpose is to improve the real-time performance of the system , Give up on your own initiative cpu For higher priority tasks
cond_resched();
}
set_current_state(TASK_INTERRUPTIBLE);
}
__set_current_state(TASK_RUNNING);
return 0;
}

Program 6-1 ksoftirqd Main function

out:
local_irq_enable();
return;
softnet_break:
__get_cpu_var(netdev_rx_stat).time_squeeze++;
__raise_softirq_irqoff(NET_RX_SOFTIRQ);
goto out;

Program 6-2 net_rx_action

void wakeup_softirqd(void)
{
/* Interrupts are disabled: no need to stop preemption */
struct task_struct *tsk = __get_cpu_var(ksoftirqd);
if (tsk && tsk->state != TASK_RUNNING)
wake_up_process(tsk);
}

Program 6-3 wakeup_softirqd

Unsolved problems

set_current_state and __set_current_state The difference between
PF_NOFREEZE
cond_resched()
Why is it do_softirq Turn off hardware interrupt when you start processing software interrupt

Reference resources

ULK
http://blog.csdn.net/hardy_2009/article/details/7383729 Description of kernel stack and interrupt stack

版权声明
本文为[Linghu onion Dennis]所创,转载请带上原文链接,感谢
https://javamana.com/2021/05/20210504144300249M.html

  1. ASP调用SDK微信分享好友、朋友圈
  2. ASP calls SDK wechat to share friends and circle of friends
  3. SpringCloud(六)Bus消息总线
  4. 详解JavaScript中的正则表达式
  5. Springcloud (6) bus message bus
  6. Explain regular expressions in JavaScript
  7. Java 响应式关系数据库连接了解一下
  8. Java14它真的来了, 真是尾气都吃不到了
  9. 视频:使用Docker搭建RabbitMQ环境
  10. Java responsive relational database connection
  11. Java14 it's really coming. I can't eat the exhaust
  12. Video: building rabbitmq environment with docker
  13. SpringCloud(六)Bus消息总线
  14. 详解JavaScript中的正则表达式
  15. Springcloud (6) bus message bus
  16. Explain regular expressions in JavaScript
  17. Docker实战:用docker-compose搭建Laravel开发环境
  18. Docker: building laravel development environment with docker compose
  19. 求助,JAVA如何获取系统当前所有进程
  20. 有人用过JMeter或用HttpUnit写过测试吗????
  21. Help, Java how to get all the current processes of the system
  22. Has anyone ever used JMeter or written tests in httpUnit????
  23. Living in a mountain village in late spring
  24. Partridge day, spring of HKUST
  25. JavaScript异步编程4——Promise错误处理
  26. 海康摄像SDK开发笔记(一):海康威视网络摄像头SDK介绍与模块功能
  27. JavaScript asynchronous programming 4 -- promise error handling
  28. Haikang video SDK development notes (1): introduction and module functions of Hikvision webcam SDK
  29. JOP:用于FPGA的嵌入式实时系统中的Java优化处理器内核
  30. Spring Boot源码:使用MongoDB MongoTemplate公开REST在几分钟内实现CRUD功能
  31. Spring Boot应用程序事件教程 - reflectoring
  32. 带有Resilience4j断路器的Spring云网关 - rome
  33. 经验分享:Apache Kafka的缺点与陷阱 - Emil Koutanov
  34. 通过Spring Boot Webflux实现Reactor Kafka
  35. 从Java 8升级到Java 11应该注意的问题
  36. Jop: Java optimized processor core for FPGA embedded real time system
  37. Spring boot source code: use mongodb mongotemplate to open rest to realize crud function in a few minutes
  38. Spring boot application event tutorial - reflecting
  39. Spring cloud gateway with resilience4j circuit breaker - ROM
  40. Experience sharing: shortcomings and pitfalls of Apache Kafka - Emil koutanov
  41. Realization of reactor Kafka through spring boot Webflux
  42. RPC框架设计----Socket与I/0模型
  43. Problems in upgrading from Java 8 to Java 11
  44. RPC framework design -- socket and I / 0 model
  45. RPC框架设计----I/0模型
  46. RPC framework design: I / 0 model
  47. RPC框架设计----NIO编程缓冲区Buffer
  48. RPC框架设计----NIO编程缓冲区Buffer
  49. RPC framework design -- NiO programming buffer
  50. RPC framework design -- NiO programming buffer
  51. Java多线程基础
  52. Java multithreading Foundation
  53. 码农飞升记-00-Java发展历程
  54. Development history of coder-00-java
  55. 码农飞升记-00-Java发展历程
  56. Development history of coder-00-java
  57. Spring and Autumn Moon
  58. Node.js与Spring Boot比较? - Ryan Gleason
  59. Spring WebFlux的明显陷阱 - ŁukaszKyć
  60. Spring创始人Rod大叔对YAML的真实想法