nohz_full CPU 上的一次时钟中断

背景:用户程序(名称为fa_pmu.test,pid为14368)开始运行在CPU0 上,通过调用sched_setaffinity 调度至CPU2 上,CPU2 是nohz_full,isolated 的,也就是说默认没有任何程序运行,并通过在CPU2 上通过ftrace 查看地切换过程。

问题:根据nohz_full 原理,用户程序(fa_pmu.test)应该不再受到时钟中断的干扰,但从程序表现来看还是有中断,通过/proc/interrupts 的记录应该就是时钟中断。

结论:(在给出具体分析前,先给出结论。)在测试环境(内核Linux5.4.*)中,用户程序的系统调用退出时并不能保证nohz_full 功能使能,需要在下一次时钟中断的时候才使能nohz_full。也就是说安全起见,实时任务需要在系统调用后忙等一段时间,以消除遗留时钟中断影响。除了忙等,经测试,Linux 6.7+以上版本已经解决该问题。

分析步骤如下:

1 运行在idle 状态

CPU2 默认没有任务程序运行,处于idle 状态,

static void do_idle(void)
{
  // …
  while(!need_resched()) {
    //…
    cpuidle_idle_call();
  }
  //..
  tick_nohz_idle_exit();
  //..
  schedle_idle();
  //..
}

程序运行在do_idle()->cpuidle_idle_call()->arch_cpu_idle()->x86_idle() 中
x86_idle 实际调用的是mwait_idle 还是poll_idle 需看配置。

2 退出Idle(tick_nohz_idle_exit())

CPU2 退出 idle while 循环后,首先执行的是tick_nohz_idle_exit,
该函数主要执行:
1)tick_nohz_stop_idle()->update_ts_time_stats() 更新调度统计信息
2)__tick_nohz_idle_restart_tick()->tick_nohz_restart_sched_tick() 重启tick

void tick_nohz_idle_exit(void)
{
  //…
  if (idle_active || tick_stopped)
  now = ktime_get();

  if (idle_active)
    tick_nohz_stop_idle(ts, now);

  if (tick_stopped)
    __tick_nohz_idle_restart_tick(ts, now);
  //…
}

重启tick(tick_nohz_restart_sched_tick()->tick_nohz_restart),取消调度时钟(hrtimer_cancel()),设置下一次tick,注意这里会导致产生下一次tick。

3 切换任务(schedule_idle())

用户程序会在schedule_idle() 中切换运行。

void __sched schedule_idle(void)
{
  WARN_ON_ONCE(current->state);
  do {
    __schedule(false);
  } while (need_resched());
}

schedule_idle()->__sched() 切换过程如下:
__sched()->rcu_note_context_switch() 处理rcu 相关内容
__sched()->pick_next_task() 将选择下一个任务进行处理
__sched()->context_switch() 将完成任务切换,比如切换mm(switch_mm_irqs_off())寄存器和栈(switch_to())
在这之后用户态任务切换至fa_pmu.test,从此之后将从fa_pmu.test 的内核栈开始执行。
__sched()->context_switch()->finish_task_switch() 完成任务切换的善后工作。

4 切换完成后,将从fa_pmu.test 的系统调用(sched_setaffinity)返回

# tracer: function_graph
#
# CPU  DURATION                  FUNCTION CALLS
# |     |   |                     |   |   |   |
  2)   0.469 us    |          __srcu_read_lock();
  2)               |          rcu_irq_enter_irqson() {
  2)               |            rcu_irq_enter() {
  2)   0.149 us    |              rcu_dynticks_eqs_exit();
  2)   0.359 us    |            }
  2)   0.568 us    |          }
  2)               |          /* cpu_idle: state=4294967295 cpu_id=2 */
  2)               |          rcu_irq_exit_irqson() {
  2)   0.106 us    |            rcu_irq_exit();
  2)   0.305 us    |          }
  2)   0.103 us    |          __srcu_read_unlock();
  2) $ 1751875 us  |        } /* mwait_idle */
  2) $ 1751875 us  |      } /* arch_cpu_idle */
  2) $ 1751875 us  |    } /* default_idle_call */
  2)               |    rcu_idle_exit() {
  2)               |      rcu_eqs_exit.constprop.0() {
  2)   0.099 us    |        rcu_dynticks_eqs_exit();
  2)   0.296 us    |      }
  2)   0.522 us    |    }
  2)   0.107 us    |    arch_cpu_idle_exit();
  2)               |    tick_nohz_idle_exit() {
  2)   0.184 us    |      ktime_get();
  2)               |      update_ts_time_stats() {
  2)   0.135 us    |        nr_iowait_cpu();
  2)   0.329 us    |      }
  2)               |      tick_nohz_restart_sched_tick() {
  2)   0.119 us    |        timer_clear_idle();
  2)   0.132 us    |        calc_load_nohz_stop();
  2)               |        hrtimer_cancel() {
  2)               |          hrtimer_try_to_cancel() {
  2)   0.202 us    |            hrtimer_active();
  2)   0.390 us    |          }
  2)   0.576 us    |        }
  2)   0.104 us    |        hrtimer_forward();
  2)               |        hrtimer_start_range_ns() {
  2)               |          lock_hrtimer_base() {
  2)   0.170 us    |            _raw_spin_lock_irqsave();
  2)   0.354 us    |          }
  2)               |          enqueue_hrtimer() {
  2)               |            /* hrtimer_start: hrtimer=00000000b4a6017d function=tick_sched_timer expires=71074629358859 softexpires=71074629358859 mode=0xa */
  2)   0.232 us    |          }
  2)               |          hrtimer_reprogram() {
  2)               |            tick_program_event() {
  2)               |              clockevents_switch_state() {
  2)               |                lapic_timer_set_oneshot() {
  2)   0.231 us    |                  __setup_APIC_LVTT();
  2)   0.421 us    |                }
  2)   0.704 us    |              }
  2)               |              clockevents_program_event() {
  2)   0.114 us    |                ktime_get();
  2)               |                lapic_next_deadline() {
  2)               |                  do_trace_write_msr() {
  2)               |                    /* write_msr: 6e0, value e8c9fcda004c */
  2)   0.194 us    |                  }
  2)   0.444 us    |                }
  2)   0.847 us    |              }
  2)   2.019 us    |            }
  2)   2.206 us    |          }
  2)   0.116 us    |          _raw_spin_unlock_irqrestore();
  2)   3.391 us    |        }
  2)   4.891 us    |      }
  2)   0.178 us    |      tick_nohz_account_idle_ticks.isra.0();
  2)   6.067 us    |    }
  2)   0.098 us    |    sched_ttwu_pending();
  2)               |    schedule_idle() {
  2)               |      rcu_note_context_switch() {
  2)               |        /* rcu_utilization: Start context switch */
  2)   0.099 us    |        rcu_preempt_deferred_qs();
  2)               |        /* rcu_utilization: End context switch */
  2)   0.477 us    |      }
  2)   0.138 us    |      _raw_spin_lock();
  2)   0.098 us    |      put_prev_task_idle();
  2)   0.172 us    |      pick_next_task_stop();
  2)   0.115 us    |      pick_next_task_dl();
  2)               |      pick_next_task_rt() {
  2)               |        update_rt_rq_load_avg() {
  2)   0.097 us    |          __accumulate_pelt_segments();
  2)   0.390 us    |        }
  2)   0.618 us    |      }
  2)               |      /* sched_switch: prev_comm=swapper/2 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=fa_pmu.test next_pid=14368 next_prio=0 */
  2)               |      switch_mm_irqs_off() {
  2)   0.117 us    |        __srcu_read_lock();
  2)               |        rcu_irq_enter_irqson() {
  2)   0.110 us    |          rcu_irq_enter();
  2)   0.310 us    |        }
  2)               |        /* tlb_flush: pages:-1 reason:flush on task switch (0) */
  2)               |        rcu_irq_exit_irqson() {
  2)   0.208 us    |          rcu_irq_exit();
  2)   0.403 us    |        }
  2)   0.108 us    |        __srcu_read_unlock();
  2)   1.738 us    |      }
  2)               |      do_trace_write_msr() {
  2)               |        /* write_msr: c0000100, value 4d8880 */
  2)   0.215 us    |      }
 ------------------------------------------
  2)    <idle>-0    => fa_pmu.-14368 
 ------------------------------------------

  2)               |              finish_task_switch() {
  2)               |                vtime_common_task_switch() {
  2)               |                  vtime_account_idle() {
  2)   0.110 us    |                    get_vtime_delta();
  2)   0.310 us    |                  }
  2)   0.121 us    |                  arch_vtime_task_switch();
  2)   0.775 us    |                }
  2)   0.111 us    |                _raw_spin_unlock_irq();
  2)               |                __mmdrop() {
  2)               |                  pgd_free() {
  2)   0.107 us    |                    _raw_spin_lock();
  2)   0.100 us    |                    _raw_spin_unlock();
  2)               |                    free_pages() {
  2)               |                      free_pages.part.0() {
  2)               |                        __free_pages() {
  2)               |                          free_unref_page() {
  2)               |                            free_pcp_prepare() {
  2)               |                              /* mm_page_free: page=000000009c017469 pfn=3247560 order=0 */
  2)               |                              __memcg_kmem_uncharge() {
  2)               |                                __memcg_kmem_uncharge_memcg() {
  2)               |                                  page_counter_uncharge() {
  2)               |                                    page_counter_cancel() {
  2)   0.095 us    |                                      propagate_protected_usage();
  2)   0.311 us    |                                    }
  2)               |                                    page_counter_cancel() {
  2)   0.099 us    |                                      propagate_protected_usage();
  2)   0.300 us    |                                    }
  2)               |                                    page_counter_cancel() {
  2)   0.096 us    |                                      propagate_protected_usage();
  2)   0.303 us    |                                    }
  2)               |                                    page_counter_cancel() {
  2)   0.107 us    |                                      propagate_protected_usage();
  2)   0.309 us    |                                    }
  2)   1.706 us    |                                  }
  2)               |                                  page_counter_uncharge() {
  2)               |                                    page_counter_cancel() {
  2)   0.116 us    |                                      propagate_protected_usage();
  2)   0.325 us    |                                    }
  2)               |                                    page_counter_cancel() {
  2)   0.117 us    |                                      propagate_protected_usage();
  2)   0.317 us    |                                    }
  2)               |                                    page_counter_cancel() {
  2)   0.116 us    |                                      propagate_protected_usage();
  2)   0.317 us    |                                    }
  2)               |                                    page_counter_cancel() {
  2)   0.128 us    |                                      propagate_protected_usage();
  2)   0.329 us    |                                    }
  2)   1.763 us    |                                  }
  2)   3.772 us    |                                }
  2)   4.062 us    |                              }
  2)   4.347 us    |                            }
  2)   0.109 us    |                            free_unref_page_prepare.part.0();
  2)   0.198 us    |                            free_unref_page_commit.isra.0();
  2)   5.042 us    |                          }
  2)   5.227 us    |                        }
  2)   5.412 us    |                      }
  2)   5.598 us    |                    }
  2)   6.175 us    |                  }
  2)   0.098 us    |                  destroy_context_ldt();
  2)               |                  kmem_cache_free() {
  2)   0.134 us    |                    __slab_free();
  2)               |                    /* kmem_cache_free: call_site=return_to_handler+0x0/0x27 ptr=00000000d1cf1f6d */
  2)   0.501 us    |                  }
  2)   7.206 us    |                }
  2)   0.128 us    |                __tick_nohz_task_switch();
  2)   8.784 us    |              }
  2) + 41.532 us   |            } /* cpu_stop_queue_work */
  2)               |            wait_for_completion() {
  2)   0.124 us    |              _raw_spin_lock_irq();
  2)   0.098 us    |              _raw_spin_unlock_irq();
  2)   0.518 us    |            }
  2) + 42.835 us   |          } /* stop_one_cpu */
  2) + 50.017 us   |        } /* __set_cpus_allowed_ptr */
  2)               |        cpuset_cpus_allowed() {
  2)   0.136 us    |          _raw_spin_lock_irqsave();
  2)   0.144 us    |          __rcu_read_lock();
  2)   0.104 us    |          __rcu_read_unlock();
  2)   0.107 us    |          _raw_spin_unlock_irqrestore();
  2)   1.048 us    |        }
  2) + 54.746 us   |      } /* sched_setaffinity */
  2) + 55.299 us   |    } /* __x64_sys_sched_setaffinity */

Futex 简述

简介:futex 全称为Fast User-space Mutex,是Linux 2.5.7 内核引入的锁原语,不同于其他进程间通信IPC原语(如信号量Semaphore、信号Signal和各种锁pthread_mutex_lock),futex更轻量级、快速,一般应用开发人员可能很少用到,但可基于futex实现各类读写锁、屏障(barriers)和信号机制等。

相关背景

在Linux的早期版本(内核Linux 2.5.7 版本以前),进程间通信(Inter-Process Communication,IPC)沿用的是传统Unix系统和System V 的IPC,如信号量(Semaphores)和Socket 等,这些IPC 均基于系统调用(System Call)。这类方法的缺点是当系统竞争度较低时,每次都进行系统调用,会造成较大系统开销。

原理和做法

用户程序每次调用IPC机制都会产生系统调用,程序发生用户态和内核态的切换,futex 的基本思想是竞争态总是很少发生的,只有在竞争态才需要进入内核,否则在用户态即可完成。futex的两个目标是:1)尽量避免系统调用;2)避免不必要的上下文切换(导致的TLB失效等)。

具体而言,任务获取一个futex 将发起带锁的减指令,并验证数值结果值是否为0(加上了锁),如果成功则可继续执行程序,失败(为已经占用的锁继续加锁)则任务在内核被阻塞。为相同futex 变量的加锁的任务被阻塞后放在同一个队列,解锁任务通过减少变量(只有一个加锁且锁队列为空)或进入内核从锁队列唤醒任务。

注意:futex 在Linux 的内核实现为一个系统调用(SYS_futex),用户程序如果直接调用它肯定会进入内核态,它还需要和其他语句(如原子操作)配合使用,新手在未理解其futex 原理和并发控制机制时极易犯错,这也是为什么不推荐直接使用它的原因。

继续阅读

安装RTAI5.2 基于Ubuntu18.04和4.14.111 内核

本文记录在我笔记本上安装最新版本RTAI(5.2)的过程和中间遇到的问题及解决方法,虽然不能覆盖所有问题,但希望能给后来者一些帮助。

安装的主要步骤:

1、安装操作系统和工具;

2、给内核打补丁并配置;

3、安装打补丁的内核与RTAI。

步骤一:安装操作系统和工具

1.1 安装操作系统

我选择的是Ubuntu18.04,因为这是带Linux 4.**.***内核的最新Ubuntu 版本(Ubuntu19.04 是以Linux5.**内核开始了)。而RTAI5.2 支持的最新内核版本即为4.14.111;

1.2 安装工具

这些工具是内核编译时需要的,下面命令可以保存为脚本执行

sudo apt install libncurses5-dev

sudo apt install libssl-dev

sudo apt install bison

sudo apt install flex

sudo apt install libssl-dev

sudo apt install libelf-dev

sudo apt install make gcc

sudo apt install patch

sudo apt install unzip

sudo apt install autoconf

注意:如果你使用的是不同的Linux 发布版(Redhat或openSUSE),有些包的名称是不同的,比如对于Redhat,libssl的安装包是libssl-devel。

注意:如果你采用的是Ubuntu16.04,那么可能因为包依赖的原因,你无法用apt install 命令安装libssl1.1,而这个包是在编译4.14.111 内核时必须的,所以建议你要么换更高版本OS,要么在Ubuntu 网站( https://packages.debian.org/stretch/amd64/libssl1.1/download )手动安装该包(sudo dpkg -i libssl1.1_1.1.0k-1~deb9u1_amd64.deb)。

1.3 安装已编译的Linux 内核4.14.111 (可选的)

该步骤是可选的,它会给系统安装上Linux4.14.111 的内核,从而获得一个默认的内核配置文件供后面使用,如果你是第一次安装RTAI,建议你执行该步骤。

在内核网站 https://kernel.ubuntu.com/~kernel-ppa/mainline/v4.14.111/ 下载内核安装包:

cd ~/Downloads/

wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v4.14.111/linux-headers-4.14.111-0414111_4.14.111-0414111.201904052241_all.deb

wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v4.14.111/linux-headers-4.14.111-0414111-lowlatency_4.14.111-0414111.201904052241_amd64.deb

wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v4.14.111/linux-image-unsigned-4.14.111-0414111-lowlatency_4.14.111-0414111.201904052241_amd64.deb`

wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v4.14.111/linux-modules-4.14.111-0414111-lowlatency_4.14.111-0414111.201904052241_amd64.deb

然后使用dpkg -i 命令安装

sudo dpkg -i *.deb   #执行该命令是可能会遇到错,再重新执行该命令可以解决;

sudo update-grub

sudo reboot

重启后可以在Grub (长按shift进入Grub)中看到安装后的内核有“Generic” 和“lowlatency” 两种。如果进入Grub 有困难,在Grub 配置文件(/etc/default/grub)中修改配置`GRUB_TIMEOUT_STYLE=hidden` 为`GRUB_TIMEOUT_STYLE=false`并更新Grub 菜单`sudo update-grub`。

步骤二:内核打补丁和编译

2.1 下载内核 (https://cdn.kernel.org/pub/linux/kernel/v4.x/)

内核的名称为 linux-4.1.111.tar.gz,为之后编译和安装方便,将源码解压到`/usr/src` 中,并创建一个软链接到该源码目录。

cd /usr/src

sudo tar xvf linux-4.1.111.tar.gz

sudo ln -sf linux-4.1.111 linux

然后,从`/boot` 中拷贝配置文件:

cd /usr/src/linux

sudo cp /boot/config-4.14.111-0414111-lowlatency .config

如果你已经有了一个配置文件(比如你安装过老版本RTAI,在其Linux 内核中拷贝其配置文件即可)uIf you already have a configuration file (e.g. in your old RTAI patched Linux system), just copy it to the source path(`/usr/src/linux`).

2.2 给内核打补丁(Ubuntu 的补丁和RTAI 的补丁)

Ubuntu 是Linux 的一个发行版本,并对Linux 内核代码做了少量修改,所以在编译内核前应该打上Ubuntu 的补丁(https://kernel.ubuntu.com/~kernel-ppa/mainline/v4.14.111/)。

cd ~/Downloads/

wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v4.14.111/0001-base-packaging.patch

wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v4.14.111/0002-UBUNTU-SAUCE-add-vmlinux.strip-to-BOOT_TARGETS1-on-p.patch

wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v4.14.111/0003-UBUNTU-SAUCE-tools-hv-lsvmbus-add-manual-page.patch

wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v4.14.111/0004-adhoc-from-__future__-import-syncconfig.patch

wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v4.14.111/0005-UBUNTU-SAUCE-no-up-disable-pie-when-gcc-has-it-enabl.patch

wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v4.14.111/0006-debian-changelog.patch

wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v4.14.111/0007-configs-based-on-Ubuntu-4.14.0-11.13.patch

cd /usr/src/linux

sudo patch -p1 < ~/Downloads/0001-base-packaging.patch

sudo patch -p1 < ~/Downloads/0002-UBUNTU-SAUCE-add-vmlinux.strip-to-BOOT_TARGETS1-on-p.patch

sudo patch -p1 < ~/Downloads/0003-UBUNTU-SAUCE-tools-hv-lsvmbus-add-manual-page.patch

sudo patch -p1 < ~/Downloads/0004-adhoc-from-__future__-import-syncconfig.patch

sudo patch -p1 < ~/Downloads/0005-UBUNTU-SAUCE-no-up-disable-pie-when-gcc-has-it-enabl.patch

sudo patch -p1 < ~/Downloads/0006-debian-changelog.patch

sudo patch -p1 < ~/Downloads/0007-configs-based-on-Ubuntu-4.14.0-11.13.patch

下载RTAI5.2 并给内核打上相应的补丁 :

wget https://www.rtai.org/userfiles/downloads/RTAI/rtai-5.2.tar.bz2

sudo cp rtai-5.2.tar.bz2 /usr/src/

sudo tar xvf rtai-5.2.tar.bz2

sudo ln -sf rtai-5.2 rtai

cd /usr/src/linux

sudo patch -p1 < /usr/src/rtai/base/arch/x86/patches/hal-linux-4.14.111-x86-3.patch

同样方便起见,我们也为rtai 的源码创建了一个软链接。

注意:安装RTAI补丁和PREEMPT-RT补丁的过程是类似的,如果你想安装PREEMPT-RT补丁,它的地址在这里。下载xz或gz格式后的补丁,可以用xz工具解压发现,是一个个编了序号的补丁,通过下面命令逐个应用补丁

patch -p1 -i /path/to/004-patch.x.y.z

也可以通过下面命令应用所有补丁

xzcat /path/to/patch.xz | patch -p1

bzcat /path/to/patch.xz | patch -p1

2.3 配置内核

配置内核主要参考下面的资料:

如果你的配置文件是从其他老的内核里拷贝过来的,首先应执行:

cd /usr/src/linux

sudo make oldconfig

否则直接执行:

sudo make menuconfig

下面是配置项中应修改的部分:

[改为 -rtai] General setup -> Local Version

[改为 None] General setup -> Stack Protector buffer overflow detection

[Enable] Processor type and features -> Interrupt pipeline

[Disable] Power management and ACPI options -> CPU Frequency Scaling

[Disable] Power management and ACPI options -> ACPI Support -> Processor

[Disable] Power management and ACPI options -> CPU Idle -> CPU idle PM support

[Disable] Kernel hacking -> Compile-time checks and compiler options -> Compile the kernel with debug info

[Disable] Kernel hacking -> Tracers

[Disable] Device Drivers -> Microsoft Hyper-V guest support

[Disable] Device Drivers -> Staging drivers -> Data acquisition support (comedi)

在 README.CONF_RMRKS 文件中要求disable `AUDITSYSCALL`,但是我们在选项中没有找到这一项。一个可替代的方法是编辑 `/usr/src/linux/init/Kconfig`文件,找到`AUDITSYSCALL` 如下部分:

config AUDITSYSCALL

    def_bool y

    depends on AUDIT && HAVE_ARCH_AUDITSYSCALL

替换为:

config AUDITSYSCALL

    bool “Enable system-call auditing support”

    depends on AUDIT && HAVE_ARCH_AUDITSYSCALL

    default y if SECURITY_SELINUX

    help

      Enable low-overhead system-call auditing infrastructure that

      can be used independently or with another kernel subsystem,

      such as SELinux.

然后,你就可以在‘General Setup’选项下看到`ADUITSYSCALL`,取消即可。

如果你的主机是多CPU 或多核的,那么 `Processor type and features` 下的SMP 选项要使能(enabled),并且最大CPU 个数(`Maximum numbers of CPUs`)不应小于物理核心个数(即不考虑Hyperthreading)。因此,建议你在BIOS 中取消Hyperthreading。

步骤三:编译安装内核和RTAI

3.1 编译和安装Linux 内核

cd /usr/src/linux

sudo touch REPORTING-BUGS

sudo make -j3

sudo make modules

sudo make modules_install

sudo make install

sudo update-initramfs –c -k 4.14.111-rtai [注意修改这里的版本名称]

sudo update-grub [注意修改/etc/default/grub 启动项为自己的内核]

sudo reboot

从Linux 内核网站下载的4.14.111 版本的源码目录下没有`REPORTING-BUGS`这个文件,可能会导致你在编译的时候遇到`recipe for target ‘kernel_headers’ failed` 的错误,所以我们首先创建了这个文件。

如果一切顺利的的话,你重启后将在Grub 上看到你自己编译的内核选项:ubuntu18.04_4.14.111-rtai 。

3.2 安装RTAI5.2

RTAI 需要autotools 生成链接编译工具:

cd /usr/src/rtai

sudo autoconf

sudo ./configure

接着配置RTAI :

sudo cp ../linux/.config .rtai_config

sudo make menuconfig

将CPU 个数(`number of CPUs`)设置为实际的物理核心个数即可。

sudo make

sudo make install

如果在编译时遇到下面的错误:

make:execup: .//config.guess: Permission denied

make:execup: .//config.sub: Permission denied

手动修改权限后再编译:

chmod 764 ./config.guess

chmod 764 ./config.sub

RTAI 默认的安装路径是`/usr/realtime`,其中`modules`目录下是编译后的模块库, `testSuite` 目录下是RTAI 的测试程序,通过手动加载模块和运行测试程序可以验证RTAI是否安装成功。

cd /usr/realtime/modules

sudo insmod rtai_hal.ko

sudo insmod rtai_sched.ko

sudo insmod rtai_fifos.ko

sudo insmod rtai_sem.ko

sudo insmod rtai_shm.ko

sudo insmod rtai_rtdm.ko

一般来说,负责进程调度的 rtai_sched.ko 模块如果加载后无死机,则安装成功。

可能遇到的问题

最后罗列一些可能遇到的问题:

1 编译内核时, `implicit declaration of function ‘ipipe_root_**_syscalls’ did you mean ‘ipipe_handle_syscall’ ……` 错误

原因:在内核配置里,ipipeline 没有使能(Enable);

2 加载`sudo insmod rtai_hal.ko` 和`sudo insmod rtai_` 后,系统冻死,键盘和鼠标均无响应

可能原因:General setup -> Stack Protector buffer overflow detection 选项默认是`Strong`,应设置为`None`或 `Regular`,更多配置项参考 README.CONF_RMRKS 。

3 不能进入编译Linux内核后的系统,提示`Gave up waiting for root file system device. Common problems:  …… ALERT! UUID=8e478c20-25e4-49c0-…… does not exist. Drop to the shell`.

可能原因:系统无法识别存储设备,注意配置内核时关于存储的驱动(SATA/PATA)要使能,因为我是在U盘中安装的系统,因此U盘相关的驱动也得使能。

4  当准备加载 rtai_hal.ko 模块时,提示`ERROR: Could not insert module rtai_hal.ko: Operation not permitted`错误,系统日志Syslog(`/var/log/syslog`) 提示`RTAI[hal] RTAI configured with less than num online CPUs`。

可能原因:RTAI 配置的CPU 个数比实际CPU 核心数要多,切记不要算上超线程(Hyperthreading)。

以上错误远不能包含所有你在安装RTAI 时遇到的问题,但你还可以借助下面的工具来帮助你的调试。

一些有用的命令和工具

  • Dmesg

dmesg

  • Syslog  

sudo cat /var/logsys

  • Systemctl

   Systemctl -failed   # 查看哪些内核没有被正常加载

  • RTAI 官网和邮件列表

www.rtai.org

  • Dpkg

dpkg –list | grep linux-image

  • mkinitramfs

Vim 常见问题(StackOverflow 高票问题)

如何退出Vim 编辑器?

:点击 Esc 键,然后 :q 退出编辑器(或 :q! 不保存退出编辑器,或:q! 退出编辑器不保存,或 :x 等同于:wq 退出编辑器并保存))。

 

如何快速缩进多行?

:利用 > 命令, >5> 或者  5>>  缩进五行, >% 缩进一个block(需要将光标放在括号上)。

 

如何在Vim 中符号替换为换行符,:%s/,/\n/g 将会插入^@ 字符?

:用/r 代替 /n 。在Vim 中,/r 和 /n 分别插入0X00 和0X0A 字符。

 

Vim 如何高亮搜索?

set nohlsearch 关闭高亮, set hlsearch! 打开高亮。

 

如何设置搜索大小写不敏感?

: /letter\c搜索letter 且大小写不敏感,/letter\C 大小写敏感(默认);或:set ignorecase 设置大小写不敏感。

 

如何复制一行?

yy 复制一行,dd 剪切一行,p  粘贴内容在本行下一行,P 粘贴内容在本行上一行。

 

w !sudo tee % 如何实现sudo (root 权限)保存的功能?

% 表示当前文件,tee 将即输出到% 还输出到屏幕。

 

如何设置Tab 为4 个空格,并自动缩进?

:在vimrc 中添加

filetype plugin indent on
" show existing tab with 4 spaces width
set tabstop=4
" when indenting with '>', use 4 spaces width
set shiftwidth=4
" On pressing tab, insert 4 spaces
set expandtab

 

如何移动到一行的最后?

A 移动到本行最后并进入插入模式或 $ 移动到最后(普通模式,normal mode)

 

如何编辑多个文件?

:使用tabs(Vim7 中引入),:tabe <filepath> 在新tab 中打开文件,:tabn 和 :tabp 在文件之间切换。还可以通过:sp <filepath> 进行分屏,ctrl+w 在屏幕之前切换。

 

remap/map/noremap 命令

remap 是使得映射命令能够递归地映射。系统默认是开启的(建议)。map/noremapd 都是映射命令。:map 和 :noremap 是递归映射(recursive)和非递归映射(no-recursive)。

:map j gg
:map Q j
:noremap W j

j 映射为 ggQ 递归地映射为 gg。 W 将不会映射到 gg 而只会映射到 j ,因为它使用非递归映射。考虑到还有普通模式(normal)可视模式(visual),还有对应的映射命令(:nmap 和 :nnoremap)与 (:vmap 和 :vnoremap)。

 

如何关闭粘贴时的自动缩进?

:set paste 进入插入粘贴模式(显示-- INSERT (paste) --),粘贴后取消 -:set nopast。可以将<F3> 键进行映射,从而快速切换模式::set pastetoggle=<F3>

 

如何使用寄存器(registers)?

:Vim 中寄存器可以用于暂时存储文本、宏命令等,以备后面使用。

:reg a b c 打印出  a b c 寄存器中内容;"a 表示寄存器a,"ayy 复制一行到寄存器a,"ap复制到当前位置;"Ayy 将内容增添在寄存器a;"+ 是一个特殊寄存器指向系统剪切板(clipboard),"+p 将系统剪切板中的内容粘贴到当前位置; "0 – "9 是九个数字寄存器,"0 寄存器保存复制(yank)的内容,"1 – "9 按时间分别保存删除(dd)的内容。

 

如何快速注释多行?

<Ctrl>+v 进入可视块(visual block)模式,选择多行,<Shift>+i 进入插入(insert)模式,在行首加入注释符(//,#),<Esc> 键将在选择的多行前都添加注释符。

 

如何用字符显示空格?

:set listchars=eol:¬,tab:>·,trail:~,extends:>,precedes:<,space:␣

:set list (根据我的经验,不要显示空格,或者空格用点符号更美观  space:·

 

什么是记录(Vim recording)?

q<letter> 开始记录,再次按q 结束记录,并通过@<letter> 回放。它可以记录所有你输入的,比如查找,移动,替换等操作。非常有用。

 

如何删除空白行?

:g/^$/d

 

如何实现全文缩进对齐?

gg=G。 gg 跳到文件开头, = 缩进对其,G 到文件末尾。

 

如何粘贴内容到系统剪切板(clipboard),或者从系统剪切板到Vim 中?

:寄存器 "* 和 "+ 是系统剪切板寄存器,"*yy 或者 "+yy 将复制行到系统剪切板,"*p 和 "+P 粘贴到本行下一行或者上一行。(我更习惯用<shift>+<insert> 粘贴)

 

如何将(Win)dos 中文件行结束转化为Linux 行结束?

dos2unix 是专门处理这个的工具。或者使用替换命令 :%s/^M//g ,或 :set ff=unix 。

 

如何 “重做”(redo) “回退”(undo)?

u 回退,<Ctrl>+r 重做。

 

如何移动屏幕,而不需要移动光标?

zz 移动当前行到屏幕中间,zt 移动当前行到屏幕顶部,zb 移动当前行到屏幕底部。

 

如何删除行而不存在寄存器中?

"_d 删除到“黑洞”寄存器

 

查找下一个

n 查找文件的上一个,N 查找文件中上一个

 

如何设置非贪婪正则表达?

:用.\{-} 代替.* 。

 

如何设置内容超过80 列后提醒?

:在 ~/.vimrc 内添加

highlight OverLength ctermbg=red ctermfg=white guibg=#592929
match OverLength /\%81v.\+/

 

如何复制文件中所有行?

gg"*yG 复制内容到"* 寄存器。

 

如何关闭单个打开的文件缓存(e.g. vim a.txt b.txt 打开后如何关闭一个文件缓存)?

:bd 关闭当前缓冲区,:ls 列出当前所有缓冲区,:bd2 关闭第二个缓冲区。

 

^M 是什么?

:Unix 用 0xA 表示新行,Windows 则用 0xD 0xA^M 显示为 0xD 。

 

如何关闭所有选项页(tabs)?

:qa 退出所有选项,:wqa保存所有选项页并退出。

 

自动补全?

:YouCompleteMe

 

Ubuntu14.04 上安装pygame

因为在一台ubuntu 服务器上跑个pygame 的程序,在ubuntu14.04 上安装pygame 了一天,之前在windows 上安装很顺利,换做ubuntu 上就有点傻傻的。总结来说尽量不要手动下源包,通过configure 和 make install 来安装,因为存在很多依赖(32-bit,64-bit 等)的问题。应该采用正确的安装姿势:

sudo apt-get install python-game

我的过程如下:

在pygame 官网下载了最新(2009年的(⊙﹏⊙)b,因为基于的SDL 从1.2换做2.0版本了,无法做兼容了)的pygame 源码,解压, python setup.py install  安装。

安装后的结果是可以在程序中 import pygame 并使用基本的函数(如pygame.draw.line 等),但如果要使用相关其他模块时,如 import pygame.font 则会出现 font module not found的问题. 我尝试采用 http://stackoverflow.com/a/15368766/1424948 中的方法安装相关的模块:

$ sudo apt-get install python-dev libsdl-image1.2-dev libsdl-mixer1.2-dev  
libsdl-ttf2.0-dev   libsdl1.2-dev libsmpeg-dev python-numpy subversion 
libportmidi-dev ffmpeg libswscale-dev libavformat-dev libavcodec-dev

但是还是会存在  font module not found 的问题,我也尝试使用自动安装pygame的方法来解决:

$ sudo apt-get install python-pygame

但这个问题应该是之前的手动安装已经无法覆盖,而手动的安装依赖问题无法解决。最终我的解决方法是:

  1. sudo python setup.py clean
  2. 删除 python/site-packages 下的pygame 包
  3. sudo apt-get install python-pygame

完成这三步后,一切OK。

 

 

哪些情况会导致"Undefined Reference Error"

“Undefined Reference Error” 是在程序链接(link)时经常遇到的错误,字面意思来说就是没有找到已经定义的引用,在编译器无法找到用户所使用的变量或函数:

一、缺失头文件

例如声明变量 uint64_t tmp,但没有在开头包含 #include<stdint.h>

例如使用 memset() 需要包含头文件 string.h 或 memory.h

二、缺失目标文件或者库文件(.a .o .so …)

编译器查找用户函数,首先会在本文件中的函数中找,然后在系统环境变量定义的目标文件/库(.a .o .so …)文件中找,最后在链接的目标文件/库文件(.a .o .so …)中寻找用户函数;如果没有找到则报”Undefined Reference Error”错

四、库(目标)文件链接顺序有误

库文件的链接顺序是:依赖的库A 放后面,被依赖的库B 放前面。如果A 和B 相互依赖,则使用A B A 或者B A B 的。

例如main 文件中引用func 文件中函数,则编译顺序为main.o func.o

五、C 函数和C++函数引用问题

C++ 程序链接时可以链接C 的库文件,但在.cc(.cpp) 中引用头文件时需要通过extern “C”{ #include “func.h”} 的方式引用该头文件,否则会提示”Undefined Reference Error”

C 程序无法链接C++ 库文件,否则会提示”Undefined Reference Error”,找不到引用C++ 函数的引用

参考:http://blog.csdn.net/aiwoziji13/article/details/7330333