分析Linux内核调度器源码之初始化

yizhihongxing

以下是分析Linux内核调度器源码之初始化的完整攻略:

一、准备工作

1.1 确认内核版本

在开始分析内核调度器源码之前,先要确认自己使用的内核版本。可以通过以下命令查看:

uname -r

1.2 获取内核源码

从官方网站或者镜像站点下载对应内核版本的源码包,解压后存放在合适的位置。也可以通过以下命令获取内核源码:

git clone https://github.com/torvalds/linux.git

1.3 安装内核调试符号

通过以下命令安装内核调试符号,方便在调试时查看源代码:

sudo apt-get install linux-image-$(uname -r)-dbgsym

二、分析内核调度器源码

内核调度器源码主要位于kernel/sched/目录下,其中init_task.c是调度器初始化的入口文件,我们从这个文件开始分析。

2.1 了解任务结构体

任务结构体task_struct是内核中描述进程/线程的数据结构,定义在include/linux/sched.h文件中,其中包含各种成员变量,比如进程ID、父进程ID、线程状态等等。

struct task_struct {
    ……  // 其它成员
    pid_t pid;  // 进程ID
    pid_t tgid; // 线程组ID
    ……  // 其它成员
};

2.2 了解调度器初始化过程

具体来说,调度器初始化过程包括以下几个部分:

  • 初始化进程0的task_struct结构体。
  • 初始化进程0的thread_info结构体。
  • 初始化内核线程的task_struct结构体和thread_info结构体。
  • 初始化进程1以及swapper线程的task_struct结构体。

其中,swapper线程是内核中专门用来做调度的进程,它的负责空转和协作调度器进行操作系统级别的任务调度。

2.3 分析源码细节

以上是调度器初始化过程的大致概述,接下来分析具体的源代码,请见以下两个示例:

示例1:初始化进程0的task_struct结构体。

进程0是系统中唯一一个运行在内核模式下的进程,它在内核初始化过程中被创建并且不会结束。在init_task中完成它的初始化过程。

// 在arch/x86/kernel/head_64.S中,定义了进程0(swapper)的task_union和其地址
// 进程0的task_struct定义在include/linux/sched.h中
// 我们可以在init_task.c中发现的代码如下:
union thread_union init_thread_union __init_task_data =
  { INIT_THREAD_INFO(init_task) };

struct task_struct init_task = INIT_TASK(init_task);

从代码中可以看出,进程0的task_struct结构体由INIT_TASK(init_task)定义,INIT_TASK宏展开后如下:

/* include/linux/sched.h */
#define INIT_TASK(tsk) {                                              \
        .state          = 0,                                           \
        .stack          = init_thread_union.stack,                      \
        .usage          = ATOMIC_INIT(2),                               \
        .flags          = PF_KTHREAD,                                   \
        .prio           = MAX_PRIO - 20,                                \
        .static_prio    = MAX_PRIO - 20,                                \
        .normal_prio    = MAX_PRIO - 20,                                \
        .rt_priority    = MAX_RT_PRIO - 1,                              \
        .pid            = 0,                                           \
        .tgid           = 0,                                           \
        .stack_canary   = STACK_CANARY_INIT,                            \
        .task_file      = INIT_FILES,                                   \
        .tasks          = LIST_HEAD_INIT(init_task.tasks),              \
        .ptraced        = LIST_HEAD_INIT(init_task.ptraced),            \
        .children       = LIST_HEAD_INIT(init_task.children),           \
        .sibling        = LIST_HEAD_INIT(init_task.sibling),            \
        .group_leader   = &init_task,                                   \
        .se             = {                                              \
                .group_node     = LIST_HEAD_INIT(init_task.se.group_node), \
                .on_rq          = 0,                                   \
                .load           = { { 0, 0 } },                         \
                .runnable_weight= WMULT_CONST(TASK_UNMAPPED_BASE),       \
                .sum_exec_runtime = 0,                                 \
                .prev_sum_exec_runtime = 0,                             \
                .last_wakeup    = 0,                                   \
                .last_wakeup_time = 0,                                 \
                .nr_migrations  = 0,                                   \
                .statistics     = {                                    \
                        [0] = { .max = 0, .sum = 0, .count = 0 },        \
                        [1] = { .max = 0, .sum = 0, .count = 0 },        \
                        [2] = { .max = 0, .sum = 0, .count = 0 },        \
                        [3] = { .max = 0, .sum = 0, .count = 0 },        \
                },                                                      \
                .wakeup_preempt_start = 0,                              \
                .wakeup_preempt_end = 0,                                \
                .wakeup_flags   = 0,                                    \
                .load_avg       = { INIT_AVG, INIT_AVG, INIT_TASK_LOAD }, \
                .se_nr_migrations = 0,                                  \
                .nr_failed_migrations = 0,                              \
                .h_load         = { [0 ... H_LOADIDX_MAX - 1] = WMULT_CONST(TASK_UNMAPPED_BASE), }, \
                .h_nr_running   = 0,                                    \
                .h_nr_scan      = 0,                                    \
        },                                                              \
        .sched          = {                                              \
                .next           = LIST_HEAD_INIT(init_task.sched.next),  \
                .prev           = LIST_HEAD_INIT(init_task.sched.prev),  \
                .group_node     = LIST_HEAD_INIT(init_task.sched.group_node), \
                .on_rq          = 0,                                   \
                .on_lock        = 0,                                   \
                .prio           = MAX_PRIO - 20,                        \
                .static_prio    = MAX_PRIO - 20,                        \
                .normal_prio    = MAX_PRIO - 20,                        \
                .rt_priority    = MAX_RT_PRIO - 1,                      \
                .policy         = SCHED_NORMAL,                         \
                .nr_cpus_allowed= NR_CPUS,                              \
                .cpus_allowed   = CPU_MASK_ALL,                         \
                .cpus_ptr       = &cpu_possible_mask,                    \
                .nr_cpus        = NR_CPUS,                              \
                .load           = { { 0, 0 } },                         \
                .se             = &init_task.se,                         \
                .timestamp      = 0,                                   \
        },                                                              \
        .thread         = {                                              \
                .sp             = init_thread_union.stack + THREAD_SIZE, \
                .tp_value       = 0,                                    \
                .flags          = SP_DEFAULT,                           \
                .pstate         = PSR_MODE_EL0t,                         \
                .addr_limit     = KERNEL_DS,                            \
                .sve_max_vl     = SVE_VL_LEN_MASK,                       \
#ifdef CONFIG_ARM64_SVE                                                      \
                .sve_state      = {},                                   \
#endif                                                                      \
        },                                                              \
        .ptrace         = {                                              \
                .test_thread    = current,                              \
        },                                                              \
        .journal_info   = NULL,                                         \
        .audit_context  = NULL,                                         \
        .pi_lock        = __RAW_SPIN_LOCK_UNLOCKED(init_task.pi_lock),   \
        .pi_waiters     = LIST_HEAD_INIT(init_task.pi_waiters),         \
        .pi_top_task    = &init_task,                                   \
        INIT_CGROUP_SCHED(init_task),                                   \
        INIT_TRACE_IRQFLAGS,                                            \
        INIT_PERF_EVENTS(init_task),                                    \
        INIT_PERF_EVENTS_LIST,                                          \
        INIT_TASK_RCU_PREEMPT(init_task)                                \
}

示例2:初始化进程0的thread_info结构体。

下面是thread_info结构体的定义,定义在include/linux/sched.h文件中,task_struct结构体中包含一个thread_info结构体的指针。

struct thread_info {
    struct task_struct  *task;
    struct exec_domain  *exec_domain;
    __u32           flags;
    __u32           status;
    __u32           cpu;
    int             preempt_count;
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
    struct vtime        vtime;
#endif
#ifdef CONFIG_DEBUG_STACK_USAGE
    unsigned long       *stack_canary;
#endif
};

那么,thread_info结构体如何初始化呢?我们在init_task中找到相应的代码,如下:

#define INIT_THREAD_INFO(var) {                                         \
        .task           = &(var),                                        \
        .exec_domain    = &default_exec_domain,                          \
        .flags          = 0,                                             \
        .status         = 0,                                             \
        .cpu            = 0,                                             \
        .preempt_count  = 0,                                             \
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
        .vtime          = {.state = VTIME_INACTIVE},
#endif
#ifdef CONFIG_DEBUG_STACK_USAGE
        .stack_canary   = &init_thread_union.stack[THREAD_SIZE/sizeof(long)-1],
#endif
}

由此可以看出,thread_info结构体中的各个成员变量都在这里得到了初始化。其中,task指向的是它所属的task_struct结构体,stack_canary用于检测栈溢出。

三、总结

通过以上的分析过程,我们可以清楚地了解到Linux内核调度器的初始化过程和相关的源代码细节,为我们理解进程调度机制提供了帮助。

上述示例只是其中的一部分,实际上Linux内核调度器的源码比较复杂,要想完全掌握它的原理,需要不断去阅读内核代码和了解相关原理。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:分析Linux内核调度器源码之初始化 - Python技术站

(0)
上一篇 2023年5月14日
下一篇 2023年5月14日

相关文章

  • python库lxml在linux和WIN系统下的安装

    下面是Python库lxml在Linux和Windows系统下的安装完整攻略。 安装pip 为了安装Python库lxml,我们需要先确保在系统上有pip,pip是Python上标准的包管理工具,在Linux和Windows系统上安装方法略有不同。 在Linux系统上安装pip 在Ubuntu Linux上,可以使用以下命令安装pip: sudo apt-g…

    Linux 2023年5月14日
    00
  • linux系统AutoFs自动挂载服务安装配置

    本文将从安装AutoFs服务开始,详细讲解Linux系统AutoFs自动挂载服务的安装配置过程。本文主要涉及以下内容: AutoFs服务概述 安装AutoFs服务 配置AutoFs服务 验证AutoFs服务配置 AutoFs服务实例 1. AutoFs服务概述 AutoFs是一种自动挂载服务,它可以在需要时挂载文件系统,而在不需要时则卸载。AutoFs提供了…

    Linux 2023年5月14日
    00
  • Linux下的Java配置与tomcat配置

    下面是关于”Linux下的Java配置与tomcat配置”的完整攻略。 一、Java配置 1. 安装Java 首先我们需要在Linux环境下安装Java,可以通过以下命令进行安装: sudo apt update sudo apt install default-jdk 安装完成后,可以通过java -version命令来检查Java是否成功安装。 2. 配…

    Linux 2023年5月14日
    00
  • linux时间与internet时间同步

    我们首先来了解下面几个知识点: 1. date命令: #date 显示系统时间 2.hwclock命令   (即hardwareclock系统硬件时间) #hwclock 显示硬件时间 #hwclock -w 将系统时间写入到系统硬件当中 3.ntpdate ntpdate 是一个linux时间同步服务软件,具体的详细资料请参考下百度,有很多详细的资料 第二…

    Linux 2023年4月11日
    00
  • Linux下mysql 5.7 部署及远程访问配置

    下面我就来详细讲解“Linux下mysql5.7部署及远程访问配置”的完整攻略。 准备工作 在进行MySQL5.7部署之前,需要先行准备以下工作: 一台已经安装了Linux系统的服务器(本次示例以CentOS 7.0为例) MySQL5.7安装包,可从MySQL官方网站下载 部署MySQL5.7 安装MySQL5.7 使用以下命令安装MySQL5.7: su…

    Linux 2023年5月14日
    00
  • 虚拟机安装linux系统无法上网的解决方法

    下面我将详细讲解一下“虚拟机安装linux系统无法上网的解决方法”的完整攻略。 背景 在虚拟机软件中安装 Linux 系统时,常常会遇到无法上网的情况。这是由于虚拟机默认无法正常获取网络连接导致的,需要我们手动配置才能上网。 解决方法 1. 修改虚拟机网络设置 进入虚拟机软件的虚拟网络编辑器,选择对应的虚拟机网络接口,启用 DHCP 服务器,并勾选 NAT …

    Linux 2023年5月24日
    00
  • rpmbuild时为什么会出现空的debugsourcefiles.list?

    错误: 空 %file 文件 /home/user/rpmbuild/BUILD/xxxx-0.1/debugsourcefiles.list 你看错误的里边有一个%file,这是使用spec文件构建时的一个命令阶段,用于列出文件以生成对应的rpm包。我们查找rpm的宏定义,发现了一行代码%files debugsource -f debugsourcefi…

    Linux 2023年4月10日
    00
  • 【linux系统安装】Anolis OS-龙蜥操作系统实机安装流程整理

    【linux系统安装】Anolis OS-龙蜥操作系统实机安装流程整理 Posted on2023-03-03 16:15 brad1208 阅读(0) 评论(0) 编辑 收藏 举报【安装准备】 1、准备一个U盘,可储存空间不低于20G,U盘内资料移出去,待会儿要格式化做U盘启动盘 2、windows操作系统上下载“Rufus”,官网:http://rufu…

    Linux 2023年4月10日
    00
合作推广
合作推广
分享本页
返回顶部