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

以下是分析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日

相关文章

  • Linux上安装和卸载rpm软件包的方法

    在Linux上安装和卸载rpm软件包的方法可以分为以下步骤: 安装rpm软件包 下载rpm软件包,以CentOS官方镜像站点为例:http://mirror.centos.org/centos/7/os/x86_64/Packages/,选择需要安装的软件包进行下载。 打开终端或命令行界面,使用root用户或具有sudo权限的用户登录。 运行以下命令安装rp…

    Linux 2023年5月14日
    00
  • linux搭建gfs系统 iscsi+GFS 实现网络存储

    首先需要了解以下概念:- GFS(Global File System):全局文件系统,可以实现多台服务器共享同一块磁盘数据的读写。- iSCSI(Internet Small Computer System Interface):一种用于在IP网络上发送SCSI命令的协议,可以通过网络传输SCSI命令,来控制远程的SCSI设备。 下面我将详细讲解如何在Li…

    Linux 2023年5月24日
    00
  • linux简单命令6—挂载

       

    Linux 2023年4月12日
    00
  • MongoDB数据库的安装步骤

    下面是MongoDB数据库的安装步骤完整攻略: 步骤一:下载安装包 在MongoDB官网上找到对应版本的MongoDB,然后进行下载。根据操作系统的不同,选择对应的安装包。例如,如果你使用的是Windows 64位操作系统,那就下载Windows 64 Bit安装包。 步骤二:安装MongoDB 下载完成后,运行安装包,按照提示进行安装。具体来说,可以按照下…

    Linux 2023年5月14日
    00
  • Linux系统–初识shell

    访问命令行(command line interface,CLI) Linux控制台 1)Linux系统启动时,会自动创建多个虚拟控制台。虚拟控制台是运行在Linux系统内存中的终端会话。多数Linux发行版会启动5~6个 2)通常必须按下Ctrl+Alt组合键,然后再按一个功能键(F1~F7)来进入你要使用的虚拟控制台。功能键F2键会生成虚拟控制台2,F3…

    Linux 2023年4月18日
    00
  • CentOS 7.2安装Nginx 1.10.2的详细教程

    下面是详细的CentOS7.2安装Nginx1.10.2的完整攻略,分为以下几步: 步骤一:安装必要的依赖包 在安装Nginx之前,需要先安装一些必要的依赖包。通过以下命令,可以安装所需的依赖包: sudo yum install gcc pcre-devel openssl-devel zlib-devel 步骤二:下载Nginx 从官方网站下载最新版本的…

    Linux 2023年5月14日
    00
  • Linux下升级安装python3.8并配置pip及yum的教程

    好的!下面是“Linux下升级安装python3.8并配置pip及yum的教程”的完整攻略。 介绍 Python 3.8 是最新的Python版本,它拥有更好的性能,更多的语言特性和更好的库支持。本攻略将向您介绍如何在Linux下升级安装Python 3.8并配置pip及yum。 步骤 1. 确定操作系统 在开始之前,您需要确认您的Linux发行版和版本。不…

    Linux 2023年5月14日
    00
  • Linux certutil命令

    Linux certutil 命令的作用与使用方法 Linux certutil 命令用于管理证书和密钥库。它可以帮助用户创建、导入、导出和删除证书和密钥库。 命令语法 certutil 命令的基本语法如下: certutil [选项] [文件名] 命令选项 certutil 命令支持以下选项: -A:将证书添加到证书库中。 -d:指定证书库的路径。 -D:…

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