Linux 多核实时任务软死机

Linux soft lockup in multi-core with realtime task

不确定是不是Linux内核bug,查了很多文档也没找到提示。 我问这个问题是为了检查是否有人遇到过类似的问题以及如何解决这个问题。

Environment: 
Linux Kernel: 2.6.34.10 
CPU: MIPS 64 (total 8 cores)
application running in user space`

应用程序有严格的响应时间要求,所以应用程序线程设置在SCHED_FIFO,一些关键线程与专用CPU核心相关,在这种情况下一切都很好。后来有人发现 CPU 峰值有时会在某些 CPU 核心中发生(例如短峰值时为 60%-80%)。为了解决这个问题,为 Linux 本机应用程序保留 CPU 0 和 CPU 7,并通过在引导行中添加 "isolcpus=1-6" 为我们的应用程序隔离 CPU 1-6 , CPU peak的问题解决了,同时又导致了下面的问题。

在 运行 一段时间和系统挂起后,以下消息将在控制台中打印,并非总是如此,但偶尔会出现。 (它可能发生在多个 CPU 核中)

BUG: soft lockup - CPU#4 stuck for 61s! [swapper:0]
Modules linked in: hdml softdog cmt cmm pio clock linux_kernel_bde  linux_uk_proxy linux_bcm_core mpt2sas
Cpu 4
$ 0   : 0000000000000000 ffffffffc3600020 ffffffffc1000b00 c0000001006f0010
$ 4   : 0000000000000001 0000000000000001 000000005410f8e0 ffffffffbfff00fe
$ 8   : 000000000000001e ffffffffc15b3c80 0000000000000002 0d0d0d0d0d0d0d0d
   : 0000000000000000 000000004000f800 0000000000000000 c000000100768000
   : ffffffffc36108e0 0000000000000010 ffffffffc35f0000 0000000000000000
   : 0000000000000000 0000000000000000 0000000000000000 0000000000000000
   : 0000000000000007 ffffffffc103b3a0                                  
   : c0000001006f0000 c0000001006f3e38 0000000000000000 ffffffffc103d774
Hi    : 0000000000000000
Lo    : 003d0980b38a5000
epc   : ffffffffc1000b20 r4k_wait+0x20/0x40
    Not tainted
ra    : ffffffffc103d774 cpu_idle+0xbc/0xc8
Status: 5410f8e3    KX SX UX KERNEL EXL IE 
Cause : 40808000

查看回调跟踪,线程始终等待条件变量等待,伪wait/signal函数如下

int xxx_ipc_wait(int target)    
{
struct timespec to;

.... /* other code */
clock_gettime(CLOCK_MONOTONIC, &to);
timespec_add_ns(&to, 1000000);
pthread_mutex_lock(&ipc_queue_mutex[target]);
ret = pthread_cond_timedwait (&ipc_queue_cond[target], &ipc_queue_mutex[target], &to);
pthread_mutex_unlock(&ipc_queue_mutex[target]);

return ret;
}

void xxx_ipc_signal_atonce(int target)
{
... 
pthread_mutex_lock(&ipc_queue_mutex[target]);
pthread_cond_signal(&ipc_queue_cond[target]);
pthread_mutex_unlock(&ipc_queue_mutex[target]);
}

那些等待无论如何都应该唤醒,因为它是超时条件变量。甚至创建了一个专用的 Linux 线程来及时通知那些条件变量,例如每 5 秒,问题仍然存在。

用"dmesg"检查了内核日志,没有发现任何有价值的日志。启用内核调试并检查内核日志/proc/sched_debug,有如下奇怪的信息。

cpu#1   /* it is a normal CPU core */
  .nr_running                    : 1
  .load                          : 0
  .nr_switches                   : 1892378
  .nr_load_updates               : 167378
  .nr_uninterruptible            : 0
  .next_balance                  : 4295.060682
  .curr->pid                     : 235  /* it point to the runnable tasks */
            task   PID         tree-key  switches  prio     exec-runtime         sum-exec        sum-sleep
----------------------------------------------------------------------------------------------------------
R         aaTask   235         0.000000       157    49                0               0         

cpu#4
  .nr_running                    : 1  /* okay */
  .load                          : 0
  .nr_switches                   : 2120455  /* this value changes from time to time */
  .nr_load_updates               : 185729
  .nr_uninterruptible            : 0
  .next_balance                  : 4295.076207
  .curr->pid                     : 0   /* why this is ZERO since it has runable task */
  .clock                         : 746624.000000
  .cpu_load[0]                   : 0
  .cpu_load[1]                   : 0
  .cpu_load[2]                   : 0
  .cpu_load[3]                   : 0
  .cpu_load[4]                   : 0
cfs_rq[4]:/
  .exec_clock                    : 0.000000
  .MIN_vruntime                  : 0.000001
  .min_vruntime                  : 14.951424
  .max_vruntime                  : 0.000001
  .spread                        : 0.000000
  .spread0                       : -6833.777140
  .nr_running                    : 0
  .load                          : 0
  .nr_spread_over                : 0
  .shares                        : 0
 rt_rq[4]:/
  .rt_nr_running                 : 1
  .rt_throttled                  : 1
  .rt_time                       : 900.000000
  .rt_runtime                    : 897.915785

runnable tasks:
            task   PID         tree-key  switches  prio     exec-runtime         sum-exec        sum-sleep
----------------------------------------------------------------------------------------------------------
       bbbb_appl   299         6.664495   1059441    49               0               0               0.000000               0.000000               0.000000 /

不知道为什么Linux系统会这样,最后我把任务优先级从SCHED_FIFO改成了SCHED_OTHER,之后就没有出现这个问题了个月 运行。由于 CPU 核心是隔离的,所以系统的行为在 SCHED_FIFO 和 SCHED_OTHER 之间是相似的,而且 SCHED_OTHER 被更广泛地使用。

应用程序永远等待 condition/mutex 可能是优先级反转的标志,除非它使用启用优先级继承的同步原语。

在FIFO实时调度模式下线程有CPU直到它主动放弃。这与大多数软件编写的抢占式多任务处理完全不同。

除非您的软件在配置要求中明确具有 REALTIME_FIFO,否则我不会花时间,而是坚持使用 RR and/or CPU pinning/isolation.