唤醒 -- try_to_wake_up()

linux多核处理器上的负载均衡原理 <br />看到一篇文章,大概给总结了下,代码就不贴了。<br /> <br />现在很多服务器都是多核服务器了,Linux操作系统会自动把任务分配到不同的处理器上,并尽可能的保持负载均衡。<br />linux多核cpu上负载均衡两个问题:<br /> <br />1. 何时检查并调整负载情况?<br />2. 如何调整负载?<br /> <br />第一个问题,可以定时调整负载,这种方法虽然简单,但不高效。实际上,2.6.20版linux kernel的确使用软中断来定时调整多CPU上的压力(调用函数r 阅读详情
    唤醒操作通过函数wake_up进行,它会唤醒指定的等待队列上的所有进程。它调用函数try_to_wake_up,该函数负责将进程设置为 TASK_RUNNING状态,调用activate_task将此进程放入可执行队列,如果被唤醒的进程优先级比当前正在运行的进程的优先级高,还有设 置need_resched标志。 通常哪段代码促使等待条件达成,它就负责随后调用wake_up()函数。
    The try_to_wake_up( ) function awakes a sleeping or stopped process by setting its state to TASK_RUNNING and inserting it into the runqueue of the local CPU.
    The function receives as its parameters:
1. The descriptor pointer (p) of the process to be awakened
2. A mask of the process states (state) that can be awakened(要唤醒的进程状态集)
3. A flag (sync) that forbids the awakened process to preempt the process currently running on the local CPU
(如果sync为1则表示禁止唤醒进程p抢占当前进程)

static int try_to_wake_up(task_t * p, unsigned int state, int sync)
{
    int cpu, this_cpu, success = 0;
    unsigned long flags;
    long old_state;
    runqueue_t *rq;
#ifdef CONFIG_SMP
    unsigned long load, this_load;
    struct sched_domain *sd;
    int new_cpu;
#endif

1. 关闭本地中断并给本地可执行队列rq加锁
Invokes the task_rq_lock( ) function to disable local interrupts and to acquire the lock of the runqueue rq owned by the CPU that was last executing the process (it could be different from the local CPU). The logical number of that CPU is stored in the p->thread_info->cpu field.
|----------------------------------|
|   rq = task_rq_lock(p, &flags);  |
|----------------------------------|

2. 如果当前进程状态p->state不在要唤醒的进程状态集中,则不能唤醒该进程
Checks if the state of the process p->state belongs to the mask of states state passed as argument to the function; if this is not the case, it jumps to step 9 to terminate the function.
|----------------------------------|
|   old_state = p->state;          |
|   if (!(old_state & state))      |
|       goto out;                  |
|----------------------------------|

3. 如果当前进程本身就在可执行队列中,则无需唤醒本进程
If the p->array field is not NULL, the process already belongs to a runqueue; therefore, it jumps to step 8.
|----------------------------------|
|   if (p->array)                  |
|       goto out_running;          |
|----------------------------------|

task_cpu(p)返回当前进程p所使用的CPU编号(p所归属的runqueue所在的CPU编号)
|----------------------------------|
|   cpu = task_cpu(p);             |
|   this_cpu = smp_processor_id(); |
|----------------------------------|

4. 多处理器系统:

#ifdef CONFIG_SMP
    if (unlikely(task_running(rq, p)))
        goto out_activate;
#ifdef CONFIG_SCHEDSTATS
    schedstat_inc(rq, ttwu_cnt);
    if (cpu == this_cpu) {
        schedstat_inc(rq, ttwu_local);
    } else {
        for_each_domain(this_cpu, sd) {
            if (cpu_isset(cpu, sd->span)) {
                schedstat_inc(sd, ttwu_wake_remote);
                break;
            }
        }
    }
#endif

    new_cpu = cpu;
    if (cpu == this_cpu || unlikely(!cpu_isset(this_cpu, p->cpus_allowed)))
        goto out_set_cpu;

    load = source_load(cpu);
    this_load = target_load(this_cpu);

    if (sync)
        this_load -= SCHED_LOAD_SCALE;

    if (load < SCHED_LOAD_SCALE/2 && this_load > SCHED_LOAD_SCALE/2)
        goto out_set_cpu;

    new_cpu = this_cpu;

    for_each_domain(this_cpu, sd) {
        unsigned int imbalance;
        imbalance = sd->imbalance_pct + (sd->imbalance_pct - 100) / 2;

        if ((sd->flags & SD_WAKE_AFFINE) &&
                !task_hot(p, rq->timestamp_last_tick, sd)) {
            if (cpu_isset(cpu, sd->span)) {
                schedstat_inc(sd, ttwu_move_affine);
                goto out_set_cpu;
            }
        } else if ((sd->flags & SD_WAKE_BALANCE) &&
                imbalance*this_load <= 100*load) {
             if (cpu_isset(cpu, sd->span)) {
                schedstat_inc(sd, ttwu_move_balance);
                goto out_set_cpu;
            }
        }
    }

    new_cpu = cpu;
out_set_cpu:
    new_cpu = wake_idle(new_cpu, p);
    if (new_cpu != cpu) {
        set_task_cpu(p, new_cpu);
        task_rq_unlock(rq, &flags);
        rq = task_rq_lock(p, &flags);
        old_state = p->state;
        if (!(old_state & state))
            goto out;
        if (p->array)
            goto out_running;

        this_cpu = smp_processor_id();
        cpu = task_cpu(p);
    }

out_activate:
#endif


5.If the process is in the TASK_UNINTERRUPTIBLE state, it decreases the nr_uninterruptible field of the target runqueue, and sets the p->activated field of the process descriptor to -1.
|----------------------------------------------|
|   if (old_state == TASK_UNINTERRUPTIBLE) {   |
|       rq->nr_uninterruptible--;              |
|       p->activated = -1;                     |
|   }                                          |
|----------------------------------------------|

6. 更新唤醒进程p的平均睡眠时间sleep_avg和动态优先级prio;记录该进程唤醒前的睡眠状态;将该进程插入活跃优先级数组
|----------------------------------------------|
|   activate_task(p, rq, cpu == this_cpu);     |
|----------------------------------------------|

7. 如果唤醒进程p的动态优先级prio比当前进程current的动态优先级高则当前进程的 TIF_NEED_RESCHED就需要设置
If either the target CPU is not the local CPU or if the sync flag is not set, it checks whether the new runnable process has a dynamic priority higher than that of the current process of the rq runqueue (p->prio < rq->curr->prio); if so, invokes resched_task( ) to preempt rq->curr.
|----------------------------------------------|
|   if (!sync || cpu != this_cpu) {            |
|       if (TASK_PREEMPTS_CURR(p, rq))         |
|           resched_task(rq->curr);            |
|   }                                          |
|   success = 1;                               |
|----------------------------------------------|

8. Sets the p->state field of the process to TASK_RUNNING.
|---------------------------------|
|out_running:                     |
|    p->state = TASK_RUNNING;     |
|---------------------------------|

9. Invokes task_rq_unlock( ) to unlock the rq runqueue and reenable the local interrupts.
|---------------------------------|
|out:                             |
|    task_rq_unlock(rq, &flags);  |
|---------------------------------|
    return success;
}







 
Linux 6.12 源码深度剖析: try_to_wake_up try_to_wake_up是Linux调度器核心函数,负责将睡眠任务唤醒并加入运行队列。它通过p->pi_lock与内存屏障保障多核下状态一致性,结合select_task_rq实现智能CPU分配与负载均衡,并在SMP架构中利用IPI和唤醒列表提升并行性。该函数深度协同同步、中断、内存与CPU管理模块,是任务唤醒与调度的关键枢纽。高并发场景下易引发“惊群效应”,导致锁竞争、频繁迁移与上下文切换,需通过EPOLLEXCLUSIVE、线程池优化及perf/ftrace分析调优。 阅读详情

相关推荐

sched_waking事件及try_to_wake_up函数解析

抓取到的sched_waking事件的一个问题及try_to_wake_up函数解析,try_to_wake_up,on_rq,on_cpu,ttwu_runnable,TTWU_QUEUE,ttwu_queue_wakelist,smp_cond_load_acquire

zhaoxin1989的博客 3658

try_to_wake_up函数

try_to_wake_up函数通过把进程状态设置为TASK_RUNNING,并把该进程插入本地CPU运行队列rq来达到唤醒睡眠和停止的进程的目的。例如:调用该函数唤醒等待队列中的进程,或恢复执行等待信号的进程。该函数接受的参数有:- 被唤醒进程的描述符指针(p)- 可以被唤醒的进程状态掩码(state)- 一个标志(sync),用来禁止被唤醒的进程抢占本地CPU上正在运行的进程

云(存储),松(耦合) 7469

手把手教你用GNU Radio和PlutoSDR搭建FM收音机(附完整流程图)

本文提供了一份详细的实践指南,教你如何使用GNU Radio和PlutoSDR搭建一个功能完整的FM收音机。从软硬件环境准备、核心流程图构建,到运行调试与效果优化,手把手带你完成从射频信号接收、下变频、FM解调到音频输出的全过程,是入门软件定义无线电(SDR)的绝佳实践项目。

weixin_29189377的博客 749

Linux 调度器之抢占式调度

Linux 调度器之抢占式调度简介

小立仔 4153

Python爬虫实战:逆向解析央视频加密参数(附完整代码)

本文详细解析了央视频加密体系的技术实现,通过Python逆向工程实战演示如何解密动态密钥、AES加密和自定义哈希算法等核心组件。文章提供完整代码示例,涵盖GUID生成、参数构造和异步请求处理,帮助开发者掌握现代视频平台的反爬机制破解方法。

weixin_42532473的博客 1130

openEuler 快速入门

openEuler 是一个专注于企业领域的 Linux 发行版,广泛应用于服务器、云计算和边缘计算场景。最初由华为开发,现在由 Open Atom Foundation 进行开发和管理。Open Atom Foundation 是中国第一个开源软件基金会,得到了华为、阿里巴巴、腾讯、百度等知名企业的支持,并且中国信息通信部也是该基金会的一部分。可以将 openEuler 看作是 Red Hat 或 SUSE Linux 的等价物,但它与 SUSE Linux 更为相似。

HuaweiLab_Peach的博客 2054

try_to_wake_up 上面时候会被执行

这个函数是内核调度器的一部分,用于唤醒处于睡眠状态的进程或线程,使其进入就绪状态,以便被调度执行。接下来,我需要列举出所有可能调用这个函数的场景,包括用户空间和内核空间的触发条件。此外,用户可能想知道这些触发条件在内核中的具体实现路径,比如哪些函数会最终调用。还需要考虑内核版本的影响,不同版本的内核可能在实现细节上有所不同,但主要触发条件应该是相似的。接下来,我需要为每个场景提供具体的例子和代码路径,说明在什么情况下会触发。最后,总结这些触发场景,帮助用户全面理解。的调用情况,以便分析具体的唤醒原因。

weixin_45705773的博客 921

Doris + Iceberg 实现高效数据湖分层:架构解析与最佳实践

本文深入解析了如何利用Doris与Iceberg构建高效的数据湖冷热分层架构。通过将高频访问的热数据存储在Doris中以实现毫秒级查询,同时将历史冷数据归档至低成本的Iceberg存储,该方案在保障查询性能的同时显著降低了总体拥有成本。文章详细阐述了从架构设计、自动化迁移到统一查询的最佳实践,为应对海量数据下的成本与性能平衡提供了实战指南。

weixin_29207533的博客 135

try_to_wake_up()、default_wake_function()、autoremove_wake_function()函数详解

先介绍一个非常基础的函数: try_to_wake_up()此函数的作用是:从等待队列中唤醒一个进程,让后将其放到就绪队列中。static int try_to_wake_up(struct task_struct *p, int state, int wake_flags)参数的含义:p : 表示的是将要...

weixin_33877885的博客 616

汽车标定技术(七)--英飞凌TC3xx_Overlay实现页切换

今天说要开个专栏讲讲XCP标定,但在将标定之前,先把英飞凌专门为标定功能设计overlay功能讲解清楚。

认真搞搞汽车MCU 4015

[Dify实战] 解决 Dify 导入 DSL 文件时报 “DSL 版本差异” 的兼容性问题

摘要:本文针对Dify开发者在导入.dsl文件时遇到的版本警告提示问题,分析其根源在于DSL文件与当前系统版本不一致。解决方案是通过导出当前Dify应用的DSL文件查看版本号,手动修改待导入文件的version字段以匹配。文章详细说明了操作步骤,并给出使用专业编辑器、避免修改其他字段等实用建议,帮助开发者规避版本不兼容问题,提升多模态AI应用开发效率。

技术小甜甜:传播可落地技术,帮助个人和企业降低解决真实场景问题的成本 961

Linux内核进程唤醒机制:wake_up与wake_up_process详解

进程唤醒是操作系统调度的核心机制,直接影响系统响应速度和吞吐量。Linux内核通过wait_queue实现高效的进程休眠/唤醒管理,其中wake_up()和wake_up_process()是最关键的唤醒接口。wake_up_process实现精准的单进程唤醒,适合实时任务调度;而wake_up则采用广播模式唤醒整个等待队列,常见于IO完成处理。理解其底层通过try_to_wake_up()的通用路径(包含内存屏障、自旋锁和调度类回调)对开发高性能驱动和系统程序至关重要。在数据库连接池等实际场景中,合理选择

weixin_30340617的博客 396

机器学习势能(MLPs) 第一章 基础理论与核心概念 第二章 数据生成与训练集构建

密度泛函理论(DFT)作为现代计算材料科学的基石,通过求解Kohn-Sham方程在电子结构层面提供可靠的势能面信息。然而,其计算复杂度随体系电子数呈O(N3) 至O(N4) 增长,对于包含数百个原子的体系,单点计算往往需消耗数小时至数天的计算资源。这一瓶颈严重限制了分子动力学模拟的时间尺度,传统DFT-MD通常仅能覆盖皮秒量级,远不足以观测扩散、相变等慢动力学过程。经验力场通过解析函数形式描述原子间相互作用,实现了经典力学的计算效率,但其参数化过程高度依赖物理直觉与经验调参。

VectorShift的博客 182

唤醒 -- try_to_wake_up() http://blog.youkuaiyun.com/linux__kernel/article/details/1476795

唤醒 -- try_to_wake_up() 分类: Process Scheduling2007-01-08 09:57 4706人阅读 评论(1) 收藏 举报 updescriptorfunctiondomainparameterseach     唤醒操作通过函数wake_up进行,它会唤醒指定的等待队列上的所有进程。它调用函数try_to_wake_up,该函数负责将

诺尔曼 2465

基于PChmi.dll的PLC报警显示和记录(C#)

本文介绍了如何使用C#编写基于PChmi.dll的程序,实现PLC报警的显示和记录功能。通过订阅PLC的报警事件,我们可以实时显示报警信息,并通过日志文件记录报警历史。PLC(可编程逻辑控制器)在工业自动化领域中扮演着重要的角色,而报警显示和记录是PLC应用中常见的需求。本文将介绍如何使用C#编写基于PChmi.dll的程序,实现PLC报警的显示和记录功能。当然,这只是实现报警显示和记录的基本框架,具体的实现方式可能因不同的PLC和HMI库而有所差异。你需要根据你所使用的具体库和设备进行相应的调整和修改。

ByteLegend的博客 1673

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

scheduler 与 power mangement 的关系 --- linux kernel 实现之美

scheduler 与 power mangement 的关系 --- linux kernel 实现之美。

500 225

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

linux 配置 内核抢占,Linux内核抢占实现机制分析

另外一种可抢占内核实现方案是在内核代码段中插入抢占点(preemption point)的方案。在这一方案中,首先要找出内核中产生长延迟的代码段,然后在这一内核代码段的适当位置插入抢占点,使得系统不必等到这段代码执行完就可重新调度。这样对于需要快速响应的事件,系统就可以尽快地将服务进程调度到CPU运行。抢占点实际上是对进程调度函数的调用,代码如下:if(current->need_resch...

weixin_34419561的博客 431

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

搞懂 Linux 进程调度核心:一睡眠与唤醒的底层逻辑

作为一名 Linux 开发领域的博主,发现进程阻塞和资源等待问题简直是大家的 “心头大患”。就拿网络 I/O 操作来说,当我们的程序发起网络请求后,数据传输需要时间,这期间进程若一直占用 CPU 资源空转,无疑是巨大的浪费。又比如在多进程同步场景下,进程可能需要等待共享资源的解锁,盲目等待只会拖慢整个系统的运行效率。而进程的睡眠与唤醒机制,是 Linux 内核实现高效 CPU 资源调度的核心。它能让进程在等待资源时主动进入睡眠状态,让出 CPU 给其他更需要的进程,等资源就绪后再被唤醒继续执行。

m0_60259116的博客 433

Linux内核任务调度时机总结

直接调用schedule():主动让出CPU设置TIF_NEED_RESCHED标志:延迟调度,在合适的时机检查该标志并调用schedule()核心调度函数(位于/**/调度类型触发机制调用路径配置依赖主动调度schedule()直接调用阻塞、等待、yield无条件调度内核长循环中非抢占内核用户抢占返回用户空间无内核抢占中断返回抢占中断返回内核态时钟中断调度无唤醒调度无优先级变更无返回用户空间时: 系统调用返回、异常返回、中断返回用户态preempt_enable()时。

tugouxp的专栏 713

【内核调度】【休眠进程的唤醒】【wake_up_process】

wake_up_process 一般当队列里面为空的时候,核心调度器(是否是核心调度器还需要后续去confirm)会在已经睡眠的task中通过调用wake_up_process函数将其唤醒,然后选择合适的cpu来运行 /** * wake_up_process - Wake up a specific process * @p: The process to be woken up. * * Attempt to wake up the nominated process and move i

勿于浮沙筑高台 4750

Linux内核进程唤醒机制:wake_up与wake_up_process对比

进程调度是操作系统核心功能,其中唤醒机制直接影响系统响应速度。wake_up()和wake_up_process()作为Linux内核关键函数,前者适用于批量唤醒等待队列中的进程,后者则针对特定任务进行精确唤醒。在实时系统和驱动开发中,两者的选择尤为关键:wake_up()可能导致额外锁开销,而wake_up_process()能降低延迟并提升RT任务性能。通过分析内核源码可见,wake_up_process()通过直接操作task_struct实现原子唤醒,相比遍历队列的wake_up()减少约40%的C

weixin_34038293的博客 403

从阻塞到唤醒:Linux内核wake_up_process深度剖析

你是否曾经好奇,当你在Linux系统中运行一个程序,它等待某个事件(比如键盘输入或文件数据)时,内核是如何让它从休眠状态重新活跃起来的?本文将深入剖析Linux内核中的wake_up_process函数,带你了解进程从阻塞到唤醒的全过程。读完本文,你将能够: - 理解进程阻塞与唤醒的基本概念 - 掌握wake_up_process函数的工作原理 - 了解wake_up_process在Linux...

gitblog_00314的博客 785

linux内核线程使用,linux内核线程唤醒函数wake_up_process()

int wake_up_process(struct task_struct *p)这个函数用于唤醒一个task。其使用的例程如下:static void cmtp_reset_ctr(struct capi_ctr *ctrl){struct cmtp_session *session = ctrl->driverdata;BT_DBG("ctrl %p", ctrl);capi_ctr_...

weixin_26800111的博客 1094

【linux kernel】linux内核如何唤醒线程

linux内核如何唤醒线程 //本文代码片段出自linux内核版本:4.1.15 linux内核唤醒线程主要使用wake_up_process()。 一、wake_up_process()分析 在linux内核中,唤醒线程由wake_up_process()函数实现。其定义在(/kernel/sched/core.c): int wake_up_process(struct task_struct *p) { WARN_ON(task_is_stopped_or_traced(p)); return t

iriczhao的博客 4034
上一篇: 更新时间片 -- scheduler_tick()
下一篇: 睡眠 -- sleeping
linux__kernel
博客等级 码龄20年 20粉丝 64原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值