分析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 基础(6)简单认识 bash

    shell 和 bash 是什么? shell 是一种应用程序,在这个程序里输入文字指令,系统就会做出响应的操作。这个“壳程序”是我们使用系统各种功能的接口,学会了 shell 就是学会操作 linux 系统。检索/etc/shells,可以看到当前系统的 shell 有哪些。而 bash (Bourne Again SHell)是大部分 linux 的默认…

    Linux 2023年4月10日
    00
  • 记录无法安装mysql-Invalid GPG Key from file:/etc/pki/rpm-gpg/RPM-GPG-KEY-mysql的解决办法

    记录无法安装mysql-InvalidGPGKeyfromfile:/etc/pki/rpm-gpg/RPM-GPG-KEY-mysql的解决办法 问题描述 在安装mysql时,可能会遇到以下错误: Error: Failed to download metadata for repo ‘mysql56-community’: Cannot prepare …

    Linux 2023年5月14日
    00
  • Linux bridge桥接两个VirtualBox虚拟网络的方法步骤

    Linux bridge是一种网络设备,它可以将多个物理或虚拟网络接口连接到同一个网络。VirtualBox是一种常见的虚拟机软件,可以在计算机上创建虚拟机环境来运行不同的操作系统。本文将介绍如何使用Linux bridge来桥接两个VirtualBox虚拟网络。 以下是步骤: 1. 确认VirtualBox虚拟网络配置 在VirtualBox中创建两个不同…

    Linux 2023年5月24日
    00
  • Linux chmod命令及权限含义

    sudo chmod -R 777 ./*  给当前文件夹下所有文件或者子文件赋值最高权限 -R 遍历路径内的所有文件   对于一条权限赋值命令:sudo chmod  -R 764 ×××;我们必须了解其含义:(1)各字段含义:sudo chmod  -R(更改文件夹及其子文件夹)                             7(所有者权限)6…

    Linux 2023年4月12日
    00
  • Linux reset命令

    当使用Linux系统时,有时候我们需要重新初始化终端,以便清空所有设置并回到一致的状态。此时,可以使用reset命令。reset命令用于将终端恢复到初始状态,也可用来清楚区域屏幕和缓冲区域。 命令格式 reset [-ns] [-V] 命令参数 -n或–no-init:不要从文件/etc/termcap或$TERMCAP获取初始化字符串。 -s或–soft:…

    Linux 2023年3月28日
    00
  • 干货!超实用的 Linux 初始化脚本

    咸鱼今天给大家分享一个无论是学习还是工作中都很实用的 Linux 系统初始化脚本,其实就是各种命令的集合   完整代码在文章最后哦   定义相关变量       配置 yum 镜像源     获取阿里云 yum 镜像源     判断函数是否执行成功     写入一行配置     修改配置     配置系统时区     配置 dns 服务器     修改最大文…

    Linux 2023年4月10日
    00
  • Linux中zip压缩和unzip解压缩命令详解

    Linux中zip压缩和unzip解压缩命令详解 一、zip压缩命令 zip命令可以在Linux系统中对多个文件或文件夹进行压缩,其基本的用法为: zip 压缩文件名.zip 待压缩文件或文件夹 其中: 压缩文件名.zip表示压缩后的文件名,可以自定义。 待压缩文件或文件夹表示要压缩的文件或文件夹,可以是绝对路径或相对路径。 例如,要将当前目录下所有.txt…

    Linux 2023年5月14日
    00
  • 如何搭建属于自己的服务器(Linux7.6版)

    从0搭建属于自己的服务器 最近小伙伴推荐的华为云活动,购买服务器相当的划算,本人也是耗费巨资购买了一台2核4G HECS云服务器。话不多说,在这里给华为云打一个广子,活动力度还是很不错的。活动详情见链接:https://kuy8.com/xcGtU 1、购买与搭建 一般个人使用,我觉得2核4G的已经绰绰有余啦,所以本文也是基于这个配置来搭建的(看准最便宜的下…

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