31、实时 Linux 内核补丁与调试全解析

实时 Linux 内核补丁与调试全解析

1. 实时内核补丁概述

支持硬实时功能的代码并未包含在 mainline kernel.org 源码树中。若要启用硬实时功能,就必须应用补丁。实时内核补丁是一系列旨在降低 Linux 内核延迟的举措的累积成果,众多开发者参与了该补丁的开发,目前由 Ingo Molnar 负责维护,可从 http://people.redhat.com/~mingo/realtime-preempt 获取。

自 Linux 2.6 早期版本发布以来,其软实时性能有了显著提升。最初发布 2.6 版本时,2.4 版本在软实时性能方面更胜一筹。但从 Linux 2.6.12 左右开始,在性能较好的 x86 处理器上,实现个位数毫秒级的软实时性能已变得轻而易举。若要获得更可重复的性能,则需要应用实时补丁。

实时补丁为 Linux 内核增添了几个重要特性,其中包括新增了一种名为 PREEMPT_RT(Preempt Real Time)的抢占模式。内核共有四种抢占模式,具体如下:
| 抢占模式 | 描述 | 适用场景 |
| — | — | — |
| PREEMPT_NONE | 无强制抢占,平均延迟表现良好,但偶尔会出现较长延迟 | 以整体吞吐量为首要设计标准的应用 |
| PREEMPT_VOLUNTARY | 降低延迟的第一阶段,在内核关键位置添加额外的显式抢占点以减少延迟,会牺牲一定的整体吞吐量来换取更低的延迟 | 需要一定延迟优化的场景 |
| PREEMPT_DESKTOP | 除关键部分处理时,内核其他部分均可抢占,适用于音频和多媒体等软实时应用,通过牺牲整体吞吐量进一步降低延迟 | 软实时应用,如音频、多媒体 |
| PREEMPT_RT | 添加实时补丁的特性,包括将自旋锁替换为可抢占的互斥锁,除了由 preempt_disable() 保护的区域外,内核各处均可进行非自愿抢占,能显著平滑延迟变化(抖动),为对时间要求严格的实时应用提供低且可预测的延迟 | 对延迟要求极高的实时应用 |

若在内核配置中启用了内核抢占,可在启动时通过在 kernel 命令行添加 preempt=0 参数来禁用它。

2. 实时特性

2.1 自旋锁转换为互斥锁

实时补丁将系统中的大部分自旋锁转换为互斥锁,这样做虽然会使整体吞吐量略有降低,但能有效减少延迟。自旋锁转换为互斥锁的好处在于,互斥锁可以被抢占。例如,当进程 A 持有锁,而优先级更高的进程 B 也需要该锁时,如果持有的是互斥锁,进程 A 就可以被进程 B 抢占。

2.2 ISR 作为内核任务

当选择 CONFIG_PREEMPT_HARDIRQ 时,中断服务例程(ISR,也称为 HARDIRQs)将在进程上下文中运行。这使得开发者能够控制 ISR 的优先级,因为它们成为了可调度的实体,同时也变得可被抢占,从而确保更高优先级的硬件中断能够优先得到处理。

有些硬件架构并不强制规定中断优先级,即便有规定,也可能与你指定的实时设计目标不一致。使用 CONFIG_PREEMPT_HARDIRQ,你可以自由定义每个 IRQ 的运行优先级。

ISR 转换为线程的功能可以在运行时通过 /proc 文件系统禁用,也可以在启动时通过在 kernel 命令行输入参数来禁用。若在配置中启用了该功能,除非另行指定,否则 ISR 线程默认处于启用状态。
- 运行时禁用 ISR 线程:

# echo '0' >/proc/sys/kernel/hardirq_preemption
  • 验证设置:
# cat /proc/sys/kernel/hardirq_preemption
  • 启动时禁用 ISR 线程,在 kernel 命令行添加参数:
hardirq-preempt=0

2.3 可抢占的软中断

CONFIG_PREEMPT_SOFTIRQ 通过在 kernel 的软中断守护进程(ksoftirqd)上下文中运行软中断来减少延迟。ksoftirqd 是一个标准的 Linux 任务(进程),因此可以与其他任务一起进行优先级设置和调度。若内核配置为实时模式,且启用了 CONFIG_PREEMPT_SOFTIRQ,ksoftirqd 内核任务将被提升为实时优先级,以处理软中断。以下是相关代码示例:

static int ksoftirqd(void * __bind_cpu)
{
      struct sched_param param = { .sched_priority = 24 };
      printk("ksoftirqd started up.\n");
#ifdef CONFIG_PREEMPT_SOFTIRQS
       printk("softirq RT prio: %d.\n", param.sched_priority);
       sys_sched_setscheduler(current->pid, SCHED_FIFO, &param);
#else
       set_user_nice(current, -10);
#endif
...

软中断线程可以在运行时通过 /proc 文件系统或在启动时通过 kernel 命令行禁用。若在配置中启用了该功能,除非另行指定,否则软中断线程默认处于启用状态。
- 运行时禁用软中断线程:

# echo '0' >/proc/sys/kernel/softirq_preemption
  • 验证设置:
# cat /proc/sys/kernel/softirq_preemption
  • 启动时禁用软中断线程,在 kernel 命令行添加参数:
softirq-preempt=0

2.4 可抢占的 RCU

RCU(Read-Copy-Update)是 Linux 内核中一种特殊的同步原语,专为频繁读取但很少更新的数据而设计,可将其视为一种优化的读锁。实时补丁添加了 CONFIG_PREEMPT_RCU,通过使某些 RCU 部分可抢占来改善延迟。

3. O(1) 调度器

O(1) 调度器自 Linux 2.5 时代就已存在,它是实时解决方案的关键组件。相较于之前的 Linux 调度器,O(1) 调度器有了显著改进,对于拥有大量进程的系统,它的扩展性更好,有助于降低整体延迟。

O(1) 是一阶系统的数学表示,在此情境下,意味着做出调度决策所需的时间不依赖于给定运行队列中的进程数量。而旧的 Linux 调度器不具备这一特性,其性能会随进程数量的增加而下降。

4. 创建实时进程

可以通过设置进程属性,让调度器将其纳入调度算法,从而将进程指定为实时进程。以下是创建实时进程的通用方法示例:

#include <sched.h>
#define MY_RT_PRIORITY MAX_USER_RT_PRIO /* Highest possible */
int main(int argc, char **argv)
{
      ...
      int rc, old_scheduler_policy;
      struct sched_param my_params;
      ...
      /* Passing zero specifies caller's (our) policy */
      old_scheduler_policy = sched_getscheduler(0);
      my_params.sched_priority = MY_RT_PRIORITY;
      /* Passing zero specifies callers (our) pid */
      rc = sched_setscheduler(0, SCHED_RR, &my_params);
      if ( rc == -1 )
           handle_error();
      ...
}

上述代码片段在调用 sched_setscheduler() 时做了两件事:将调度策略更改为 SCHED_RR,并将进程优先级提升到系统允许的最高值。Linux 支持三种调度策略:
- SCHED_OTHER:普通 Linux 进程,采用公平调度。
- SCHED_RR:具有时间片的实时进程,即如果不阻塞,进程将在调度器确定的给定时间段内运行。
- SCHED_FIFO:实时进程,一直运行直到阻塞、显式让出处理器,或者有更高优先级的 SCHED_FIFO 进程变为可运行状态。

sched_setscheduler 的手册页提供了关于这三种不同调度策略的更多详细信息。

5. 关键部分管理

在编写内核代码(如自定义设备驱动程序)时,会遇到需要保护的数据结构,以防止并发访问。保护关键数据的最简单方法是在关键部分周围禁用抢占,并尽可能缩短关键路径,以确保系统的最大延迟保持在较低水平。以下是一个示例:

...
/*
 * Declare and initialize a global lock for your
 * critical data
 */
DEFINE_SPINLOCK(my_lock);
...
int operate_on_critical_data()
{
    ...
    spin_lock(&my_lock);
    ...
    /* Update critical/shared data */
    ...
    spin_unlock(&my_lock);
    ...
}

当任务成功获取自旋锁时,抢占将被禁用,获取自旋锁的任务可以进入关键部分,直到执行 spin_unlock 操作后才会发生任务切换。 spin_lock() 函数实际上是一个宏,根据内核配置有多种形式,它们在 …/include/linux/spinlock.h 中进行了顶层(与架构无关)定义。当内核应用了实时补丁后,这些自旋锁会被提升为互斥锁,以便在持有自旋锁时允许更高优先级的进程进行抢占。

由于实时补丁对设备驱动程序和内核开发者来说基本是透明的,因此可以使用熟悉的结构来保护关键部分,这是实时补丁在实时应用中的一大优势,它保留了广为人知的锁定和中断服务例程语义。使用 DEFINE_SPINLOCK 宏还能确保未来的兼容性,这些宏在 …/include/linux/spinlock_types.h 中定义。

以下是一个简化的流程图,展示了关键部分管理的基本流程:

graph TD;
    A[开始] --> B[获取自旋锁];
    B --> C[进入关键部分];
    C --> D[更新关键数据];
    D --> E[释放自旋锁];
    E --> F[结束];

6. 调试实时内核

6.1 软锁定检测

在 kernel 配置中启用 CONFIG_DETECT_SOFTLOCKUP 可开启软锁定检测功能。该功能可检测长时间在内核模式下运行而无上下文切换的情况,虽然非实时内核中也存在此功能,但对于检测高延迟路径或软死锁状况非常有用。使用时,只需启用该功能,然后留意控制台或系统日志中的相关报告,报告格式类似 BUG: soft lockup detected on CPU0 ,通常还会附带回溯信息、进程名和 PID 等内容,可参考 …/kernel/softlockup.c 获取详细信息,这些信息有助于追踪锁定问题的根源。

6.2 抢占调试

启用 CONFIG_DEBUG_PREEMPT 可进行抢占调试,该调试功能能检测抢占语义的不安全使用情况,如抢占计数下溢以及在无效上下文中尝试睡眠等问题。使用时,启用该功能并关注控制台或系统日志中的报告,以下是启用抢占调试时可能出现的部分报告示例:
- BUG: <me> <mypid>, possible wake_up race on <proc> <pid>
- BUG: lock recursion deadlock detected! <more info>
- BUG: nonzero lock count <n> at exit time?

这些报告有助于在使用实时内核特性时避免死锁及其他错误或危险的编程语义。若想了解更多报告信息及触发条件,可浏览 Linux 内核源文件 …/kernel/rt-debug.c。

6.3 调试唤醒时间

在 kernel 配置中启用 CONFIG_WAKEUP_TIMING 可开启唤醒时间测量功能,该调试选项可测量唤醒高优先级进程到其在 CPU 上调度的时间。配置完成后,测量功能默认禁用,若要启用测量,以 root 身份执行以下命令:

# echo '0' >/proc/sys/kernel/preempt_max_latency

当该 /proc 文件设置为 0 时,每次新的最大唤醒时间结果都会写入该文件。若要读取当前最大值,可执行:

# cat /proc/sys/kernel/preempt_max_latency

只要在内核配置中启用了任何延迟测量模式, preempt_max_latency 就会始终更新为最大延迟值,且无法禁用。向该 /proc 变量写入 0 只是将最大值重置为 0,以重新开始累积测量。

6.4 唤醒延迟历史

在启用 CONFIG_WAKEUP_TIMING 的同时启用 CONFIG_WAKEUP_LATENCY_HIST,可开启唤醒延迟历史记录功能。该选项会将 CONFIG_WAKEUP_TIMING 启用的所有唤醒时间测量结果保存到文件中,以便后续分析。CRITICAL_PREEMPT_TIMING 用于测量禁用抢占时在关键部分所花费的时间,PREEMPT_OFF_HIST 与 WAKEUP_LATENCY_HIST 类似,用于收集禁用抢占的时间测量结果,以便后续分析。

6.5 中断关闭时间测量

在 kernel 配置中启用 CRITICAL_IRQSOFF_TIMING 可开启最大中断关闭时间测量功能,该选项用于测量禁用中断时在关键部分所花费的时间,其工作方式与唤醒延迟时间测量相同。若要启用测量,以 root 身份执行以下命令:

# echo '0' >/proc/sys/kernel/preempt_max_latency

当该 /proc 文件设置为 0 时,每次新的最大中断关闭时间结果都会写入该文件。若要读取当前最大值,可执行:

# cat /proc/sys/kernel/preempt_max_latency

需要注意的是,唤醒延迟和中断关闭延迟的测量都使用同一个 /proc 文件进行启用和显示,这意味着一次只能配置一项测量,否则结果可能无效。而且这些测量会增加显著的运行时开销,因此不建议同时启用所有测量功能。

6.6 中断关闭历史

启用 INTERRUPT_OFF_HIST 可提供与 WAKEUP_LATENCY_HIST 类似的功能,该选项会将中断关闭时间测量结果收集到文件中,以便后续分析。数据以直方图形式呈现,区间从 0 微秒到略超过 10,000 微秒。例如,某次测量的最大延迟为 97 微秒,那么直方图形式的延迟数据在 97 微秒之后的区间将不会包含有用信息。

通过读取特殊的 /proc 文件可获取历史数据,并将输出重定向到常规文件进行分析或绘图,示例如下:

# cat /proc/latency_hist/interrupt_off_latency/CPU0 > hist_data.txt

以下是中断关闭延迟历史数据的前 10 行示例:

#Minimum latency: 0 microseconds.
#Average latency: 1 microseconds.
#Maximum latency: 97 microseconds.
#Total samples: 60097595
#There are 0 samples greater or equal than 10240 microseconds
#usecs           samples
    0           13475417
    1           38914907
    2            2714349
    3             442308

从上述示例中可以看到最小值、最大值、所有值的平均值以及总样本数。在这个例子中,总共积累了超过 6000 万个样本。直方图数据跟在摘要后面,最多包含约 10,000 个区间,可使用 gnuplot 轻松绘制这些数据。

6.7 延迟追踪

启用 LATENCY_TRACE 配置选项可生成与最后一次最大延迟测量相关的内核跟踪数据,这些数据可通过 /proc 文件系统获取。延迟跟踪有助于找出延迟最长的代码路径,每次进行新的最大延迟测量时,都会生成相关跟踪,便于追踪与最大延迟相关的代码路径。

以下是一个 78 微秒最大延迟的跟踪示例:

$ cat /proc/latency_trace
preemption latency trace v1.1.5 on 2.6.14-rt-intoff-tim_trace
-------------------------------------------------------------
 latency: 78 us, #50/50, CPU#0 | (M:rt VP:0, KP:0, SP:1 HP:1)
    -----------------
    | task: softirq-timer/0-3 (uid:0 nice:0 policy:1 rt_prio:1)
    -----------------
                 _------=> CPU#
                / _-----=> irqs-off
               | / _----=> need-resched
               || / _---=> hardirq/softirq
               ||| / _--=> preempt-depth
               |||| /
               |||||     delay
  cmd      pid ||||| time  |   caller
     \    /    |||||    \  |   /
    cat-6637   0D...   1us : common_interrupt ((0))
    cat-6637   0D.h.   2us : do_IRQ (c013d91c 0 0)
    cat-6637   0D.h1   3us+: mask_and_ack_8259A (__do_IRQ)
    cat-6637  0D.h1   10us : redirect_hardirq (__do_IRQ)
    cat-6637  0D.h.   12us : handle_IRQ_event (__do_IRQ)
    cat-6637  0D.h.   13us : timer_interrupt (handle_IRQ_event)
    cat-6637  0D.h.   15us : handle_tick_update (timer_interrupt)
    cat-6637  0D.h1   16us : do_timer (handle_tick_update)
    ...   <we're in the timer interrupt function>
    cat-6637  0D.h.   22us : run_local_timers (update_process_times)
    cat-6637  0D.h.   22us : raise_softirq (run_local_timers)
    cat-6637  0D.h.   23us : wakeup_softirqd (raise_softirq)
    ...   <softirq work pending - need to preempt is signaled>
    cat-6637  0Dnh.   34us : wake_up_process (wakeup_softirqd)
    cat-6637  0Dnh.   35us+: rcu_pending (update_process_times)
    cat-6637  0Dnh.   39us : scheduler_tick (update_process_times)
    cat-6637  0Dnh.   39us : sched_clock (scheduler_tick)
    cat-6637  0Dnh1   41us : task_timeslice (scheduler_tick)
    cat-6637  0Dnh.   42us+: preempt_schedule (scheduler_tick)
    cat-6637  0Dnh1   45us : note_interrupt (__do_IRQ)
    cat-6637  0Dnh1   45us : enable_8259A_irq (__do_IRQ)
    cat-6637  0Dnh1   47us : preempt_schedule (enable_8259A_irq)
    cat-6637  0Dnh.   48us : preempt_schedule (__do_IRQ)
    cat-6637  0Dnh.   48us : irq_exit (do_IRQ)
    cat-6637  0Dn..   49us : preempt_schedule_irq (need_resched)
    cat-6637  0Dn..   50us : __schedule (preempt_schedule_irq)
    ...   <here is the context switch to softirqd-timer thread>
  <...>-3     0D..2   74us+: __switch_to (__schedule)
  <...>-3     0D..2   76us : __schedule <cat-6637> (74 62)
  <...>-3     0D..2   77us : __schedule (schedule)
  <...>-3     0D..2   78us : trace_irqs_on (__schedule)
    ...   <output truncated here for brevity>

该跟踪由定时器中断触发。在硬中断线程中,除了在软中断上下文中为后续工作排队外,几乎没有其他操作,这可从 23 微秒处的 wakeup_softirqd() 函数看出,这是中断处理的典型方式。这会触发 need_resched 标志,跟踪中第二字段第三列的 n 即表示该标志。在 49 微秒时,经过定时器软中断的一些处理后,调度器被调用来进行抢占。在 74 微秒时,控制权传递给了在该特定内核中作为 PID 3 运行的实际 softirqd-timer/0 线程。

大部分字段的含义都很明确, irqs-off 字段在中断关闭的代码段显示 D ,由于这是一个中断关闭跟踪,因此整个跟踪中都会有此指示。 need_resched 字段反映了内核的 need_resched 标志状态, n 表示应尽快运行调度器, . 表示该标志未激活。 hardirq/softirq 字段用 h 表示硬中断上下文的执行线程,用 s 表示软中断上下文。 preempt-depth 字段表示内核的 preempt_count 变量的值,该变量指示内核中锁的嵌套级别,只有当该变量为 0 时才会发生抢占。

6.8 调试死锁状况

启用 DEBUG_DEADLOCKS 内核配置选项可检测和报告内核中与信号量和自旋锁相关的死锁状况。启用后,潜在的死锁状况会以类似以下的方式报告:

==========================================
   [ BUG: lock recursion deadlock detected! |
   ------------------------------------------
   ...

宣布检测到死锁的横幅行之后会显示大量信息,包括锁描述符、锁名称(若可用)、锁文件和名称(若可用)、锁所有者以及当前持有锁的进程等。借助此调试工具,可立即确定引发问题的进程,但解决问题可能并非易事。

6.9 运行时锁定模式控制

DEBUG_RT_LOCKING_MODE 选项允许在运行时将实时互斥锁切换回不可抢占模式,实际上是将实时(自旋锁作为互斥锁)内核的行为改回基于自旋锁的内核。与前面介绍的其他配置选项一样,该工具应仅作为开发辅助工具,用于开发环境。

不建议同时启用所有这些调试模式,因为大多数调试模式会增加内核的大小和显著的处理开销,它们旨在作为开发辅助工具使用,在生产代码中应禁用。

7. 实时内核补丁与调试的综合运用与注意事项

7.1 综合运用场景

在实际的开发过程中,实时内核补丁的各个特性以及调试功能往往需要综合运用。例如,在开发一个对延迟要求极高的工业自动化控制系统时,我们可能会同时使用实时内核补丁的多种特性和调试功能。

首先,为了确保系统能够及时响应硬件中断,我们会选择 PREEMPT_RT 抢占模式,将自旋锁转换为互斥锁,使 ISR 作为内核任务运行,并且启用可抢占的软中断和可抢占的 RCU,以减少系统的整体延迟。同时,使用 O(1) 调度器来保证系统在多进程环境下的高效调度。

在创建实时进程时,将关键的控制进程设置为实时进程,采用 SCHED_RR 或 SCHED_FIFO 调度策略,以确保这些进程能够在需要时及时获得处理器资源。

在调试方面,我们会启用软锁定检测、抢占调试、唤醒时间测量、中断关闭时间测量等多种调试功能,以便及时发现和解决系统中可能出现的延迟问题、死锁问题等。

7.2 注意事项

  • 调试模式的选择 :如前文所述,不建议同时启用所有的调试模式。因为大多数调试模式会增加内核的大小和显著的处理开销,可能会影响系统的正常运行。在开发过程中,应根据具体的问题和需求,有针对性地选择调试模式。例如,当怀疑系统存在死锁问题时,启用 DEBUG_DEADLOCKS 选项;当需要测量唤醒时间时,启用 CONFIG_WAKEUP_TIMING 选项。
  • 内核配置的稳定性 :在应用实时内核补丁和进行内核配置时,要确保配置的稳定性。频繁地更改内核配置可能会导致系统出现不稳定的情况,甚至无法正常启动。在进行重要的配置更改之前,最好先在测试环境中进行充分的测试。
  • 兼容性问题 :实时内核补丁可能会与某些旧的设备驱动程序或应用程序存在兼容性问题。在应用补丁之前,需要对系统中的设备驱动程序和应用程序进行评估,确保它们能够与实时内核补丁兼容。如果发现兼容性问题,可能需要更新设备驱动程序或调整应用程序的代码。

7.3 实际案例分析

假设我们正在开发一个实时音频处理系统,该系统需要对音频数据进行实时采集、处理和播放,对延迟的要求非常高。

7.3.1 内核配置
  • 抢占模式 :选择 PREEMPT_RT 抢占模式,以确保系统能够及时响应音频设备的中断请求,减少音频处理的延迟。
  • 实时特性
    • 将自旋锁转换为互斥锁,避免高优先级的音频处理进程被低优先级进程长时间阻塞。
    • 启用 CONFIG_PREEMPT_HARDIRQ,使音频设备的 ISR 作为内核任务运行,方便控制其优先级,确保音频中断能够优先得到处理。
    • 启用 CONFIG_PREEMPT_SOFTIRQ,将软中断的处理提升到实时优先级,减少音频数据处理过程中的延迟。
    • 启用 CONFIG_PREEMPT_RCU,提高数据读取和更新的效率,减少音频数据处理的延迟。
  • 调度器 :使用 O(1) 调度器,确保系统在多进程环境下能够高效地调度音频处理进程。
7.3.2 实时进程创建

将音频采集、处理和播放进程设置为实时进程,采用 SCHED_RR 调度策略,确保这些进程能够在需要时及时获得处理器资源。以下是创建实时音频处理进程的示例代码:

#include <sched.h>
#define MY_RT_PRIORITY MAX_USER_RT_PRIO /* Highest possible */
int main(int argc, char **argv)
{
      int rc, old_scheduler_policy;
      struct sched_param my_params;
      old_scheduler_policy = sched_getscheduler(0);
      my_params.sched_priority = MY_RT_PRIORITY;
      rc = sched_setscheduler(0, SCHED_RR, &my_params);
      if ( rc == -1 )
           handle_error();
      // 音频处理代码
      ...
      return 0;
}
7.3.3 调试过程
  • 软锁定检测 :启用 CONFIG_DETECT_SOFTLOCKUP,检测系统中是否存在长时间运行而无上下文切换的情况,确保音频处理进程不会被锁定。
  • 抢占调试 :启用 CONFIG_DEBUG_PREEMPT,检测抢占语义的不安全使用情况,避免死锁和其他错误的编程语义。
  • 唤醒时间测量 :启用 CONFIG_WAKEUP_TIMING,测量唤醒音频处理进程到其在 CPU 上调度的时间,确保音频处理的实时性。
  • 中断关闭时间测量 :启用 CRITICAL_IRQSOFF_TIMING,测量音频设备中断关闭的时间,避免中断关闭时间过长影响音频处理的实时性。

通过以上的配置和调试,我们可以确保实时音频处理系统的稳定性和实时性,满足系统对延迟的严格要求。

7.4 总结

实时内核补丁为 Linux 系统提供了强大的实时性能支持,通过多种特性的组合使用,可以显著降低系统的延迟,满足各种实时应用的需求。同时,丰富的调试功能可以帮助开发者及时发现和解决系统中出现的问题,确保系统的稳定性和可靠性。

在实际的开发过程中,我们需要根据具体的应用场景和需求,合理选择实时内核补丁的特性和调试功能,并且注意调试模式的选择、内核配置的稳定性和兼容性问题。通过综合运用这些技术,我们可以开发出高质量的实时应用系统。

以下是一个总结实时内核补丁特性和调试功能的表格:
| 特性/功能 | 描述 | 适用场景 |
| — | — | — |
| PREEMPT_RT 抢占模式 | 除特定区域外,内核各处均可非自愿抢占,平滑延迟变化 | 对延迟要求极高的实时应用 |
| 自旋锁转换为互斥锁 | 减少延迟,允许高优先级进程抢占 | 多进程实时系统 |
| ISR 作为内核任务 | 可控制 ISR 优先级,优先处理高优先级中断 | 对硬件中断响应要求高的系统 |
| 可抢占的软中断 | 减少软中断处理延迟 | 实时数据处理系统 |
| 可抢占的 RCU | 改善频繁读取数据的延迟 | 数据读取频繁的实时系统 |
| O(1) 调度器 | 多进程系统扩展性好,降低整体延迟 | 多进程实时系统 |
| 软锁定检测 | 检测长时间无上下文切换情况 | 排查系统锁定问题 |
| 抢占调试 | 检测抢占语义不安全使用情况 | 避免死锁和错误编程语义 |
| 唤醒时间测量 | 测量唤醒高优先级进程到调度的时间 | 确保进程实时调度 |
| 中断关闭时间测量 | 测量中断关闭时间 | 避免中断关闭影响实时性 |
| 中断关闭历史 | 收集中断关闭时间数据用于分析 | 优化中断处理 |
| 延迟追踪 | 找出延迟最长的代码路径 | 优化代码性能 |
| 调试死锁状况 | 检测和报告死锁问题 | 解决系统死锁问题 |
| 运行时锁定模式控制 | 切换实时互斥锁模式 | 开发环境调试 |

下面是一个实时内核开发流程的 mermaid 流程图:

graph LR;
    A[需求分析] --> B[内核配置选择];
    B --> C[实时进程创建];
    C --> D[代码开发];
    D --> E[调试阶段];
    E --> F{是否满足需求};
    F -- 是 --> G[部署上线];
    F -- 否 --> B;

通过以上的介绍,希望能够帮助开发者更好地理解和运用实时内核补丁和调试功能,开发出高质量的实时应用系统。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值