转自:https://blog.csdn.net/dog250/article/details/5303442

linux的电源管理发展非常迅速,比如在挂起到内存的时候,系统会冻结住所有的进程,也就是所有的进程都不再运行,它们被冻结之前,最后的状态被保存,等到解冻的时候,所有进程恢复运行,linux对此的实现非常巧妙,它没有用特殊的机制来实现这一点,而是用它的freeze框架加上信号处理来实现的,在freeze所有进程的时候并没有将之挂起或者说使其不再运行,而是在信号处理的开始挂了一个类似于钩子的东西,把挂起进程交给信号处理来做,freeze框架要做的就是设置一些标志位来指示信号处理要冻结它了,然后设置此进程的信号附着位,这样该进程在返回用户空间的时候就乖乖进入到冻结状态了,这一点下面的代码分析会详述。这么做有几个好处,一来从设计上讲这又是一个为了低耦合而将一个框架分离成几个模块让各个模块分别承担一部分职责的做法,这样的话,将来如要升级会非常灵活,这看似复杂,但是一旦你理解了精要,还是觉得蛮好的;二来从效果上说,冻结进程其实是一个很危险的操作,2.6内核有了内核抢占,如果一个任务在内核中正执行或者正在内核中睡眠,那么它很有可能持有一把锁或者在等待一把锁,这个时候如果使其无条件的冻结,那么等待解冻的时候,解冻的顺序就要求很高了,要不然很容易死锁,因此把冻结操作安排在进程返回用户空间的时候,这样可以保证进程将不在内核了,既然已经到了返回用户空间的前夕,那么可以保证它肯定不会和内核的其它进程或中断引起竞态,这么做简直好的没法说。
int freeze_processes(void)
{
         error = try_to_freeze_tasks(true); //低强度冻结
...//错误处理以及信息打印
         error = try_to_freeze_tasks(false); //高强度冻结
...//错误以及善后处理
}
static int try_to_freeze_tasks(bool sig_only)
{
         struct task_struct *g, *p;
         unsigned int todo;
...//这些变量和主要问题无关
         do {
                 todo = 0;
                 read_lock(&tasklist_lock);
                 do_each_thread(g, p) {
                         if (frozen(p) || !freezeable(p))
                                 continue;
                         if (!freeze_task(p, sig_only))  //这个函数本质上造成了进程的冻结,但是在它里面你却找不到任何“冻结”的操作。
                                 continue;
                         if (!task_is_stopped_or_traced(p) && !freezer_should_skip(p))
                                
todo++; 
//如果有个进程我们目前无法设置它的冻结位,也就是对它无可奈何的时候,我们将todo递增,以表示要再进行一轮,直到将之冻结或者超过预定期限或者别的什么更加重要的事情发生。

                 } while_each_thread(g, p);
                 read_unlock(&tasklist_lock);
                
yield();
//刚才在freeze_task中不是可能给要冻结的进程发送信号了吗(其实就是设置了一个信号位小小欺骗一下,并没有发送真正的信号)?那么此时就要给这个进程机会使之运行,然后在信号处理中真正冻结,注意yield并不改变当前操作进程的任何标志,仅仅让出cpu而已,理想情况,等到这一轮的进程p被真正冻结以后,这个当前调用try_to_freeze_tasks的进程将继续运行,以便使下一个进程冻结

                 if (time_after(jiffies, end_time))
                         break;
         } while (todo);
...//这下面的我们不必关心
         }
         return todo ? -EBUSY : 0;
}
bool freeze_task(struct task_struct *p, bool sig_only)
{
         if (!freezing(p)) {
                 rmb();
                 if (frozen(p))
                         return false;
                 if (!sig_only || should_send_signal(p))
                         set_freeze_flag(p);
                 else
                         return false;
         }
         if (should_send_signal(p)) {
                 if (!signal_pending(p))
                        
fake_signal_wake_up(p); 
//对进程p设置上_TIF_SIGPENDING标志,然后唤醒它,这其实是一场欺骗,根本没有什么信号被发往p,这么做是因为在进程被唤醒后,检查是否有_TIF_SIGPENDING置位,如有的话,在执行get_signal_to_deliver的时候有个死亡之神在等着它,就是get_signal_to_deliver中马上调用的try_to_freeze,以便进程p上当受骗。

         } else if (sig_only) {
                 return false;
         } else {
                 wake_up_state(p, TASK_INTERRUPTIBLE);
         }
         return true;
}
在get_signal_to_deliver中会调用try_to_freeze,然后这个函数将进程真正冻结,非常安全,因为信号处理在返回用户空间时执行,此时该进程已经退出了内核的执行路径,不会被搅进内核的管理竞态中,是的,此时的事情十分安全:
static inline int try_to_freeze(void)
{
         if (freezing(current)) {
                 refrigerator();
...//别的处理
}
以下这个refrigerator函数彻底冻结了一个进程,即当前进程,它其实就是让当前进程在当前的状态上定格,等到被唤醒以后马上恢复到当前情况,这个当前进程其实睡眠在TASK_UNINTERRUPTIBLE的状态撒谎能够
void refrigerator(void)
{
         long save;
         task_lock(current);
         if (freezing(current)) {
                 frozen_process(); //freezing已经完成,将该进程设置为frozen
                 task_unlock(current);
...
         save = current->state;
         spin_lock_irq(&current->sighand->siglock);
         recalc_sigpending();  //刚才为了欺骗这个进程才使得人家跑到这里准备被绑,现在绑架任务已经完成,清除掉为了引诱目的而设置的标志位
         spin_unlock_irq(&current->sighand->siglock);
         for (;;) {
                 set_current_state(TASK_UNINTERRUPTIBLE);
                 if (!frozen(current))
                         break;
                 schedule();
         }
         __set_current_state(save);  //被唤醒,继续执行
}
唤醒的过程比这简单多了,就是一个一个的调用wake_up_process而已,这实在太简单了以至于不说了。这里就有了一个问题,在2.6.25以来新内核中,增加了对cgroup的支持,那么某种意义上,linux开始支持只有商用unix上才有“容器”的概念,linux内核陆续增加了cgroup对内存,文件等的控制,用户可以对单个group进行资源限制了,在linux内核上,以资源作为区分相当于运行着好几个虚拟机,每台虚拟机都是资源分配的一个单位,如果联系前面刚说的freeze框架的话就会发现,如果把一个cgroup的进程作为一个组进行冻结的话会很有用,比如这样的话我们可以将全组的进程“热迁移”到别的处理器,其实不是真正的热迁移,毕竟那些进程已经不再运行了,呵呵。其实freeze框架本身就可以对热插拔cpu进行支持,cgroup的freeze框架仅仅使得冻结的粒度可以切割了,不再是要么一下子冻结全部然后唤醒全部,要么就一个也不冻结,这就需要一个内核补丁,在最新的2.6.29内核中已经有了这样的机制,其实就是在冻结的时候加上了一个croup作为参数,然后把这个cgroup的进程应用上面的机制将之冻结,linux总是这样,一开始设计时就很灵活,然后后面修改加补丁的时候才不受罪。

另外在2.6.29内核中还有了文件系统的冻结,其实和上述的进程冻结一样,如果说进程冻结是将进程冻结到内存从而为了cpu而做一点事的话,那么文件系统就是将文件系统冻结到磁盘,然后让备份系统做一点事,以使得备份时是一个稳定又一致的文件系统,其实很简单,所谓冻结就是不让挂载不让写,其实用信号量就可以搞定,冻结一个文件系统的时候要得到其bdev的一个相关的信号量,而且挂载和写这个文件系统的时候也要得到这个信号量,如此就完结了。

版权声明:本文为博主原创,无版权,未经博主允许可以随意转载,无需注明出处,随意修改或保持可作为原创! https://blog.csdn.net/dog250/article/details/5303442

linux新内核的freeze框架以及意义【转】的更多相关文章

  1. linux新内核中关闭硬盘的DMA

    vortex86 SIS550 Minit-5250E瘦客户机,使用CF卡启动,显示不支持DMA. 搜索得新内核已基本不再使用ide=nodma参数了,查到这篇文章:“Debian下关闭CF卡的DMA ...

  2. linux新内核的时钟机制代码

    http://blog.chinaunix.net/uid-22810130-id-384173.html 如果说cfs是linux的一个很有创意的机制的话,那么linux中另一个创意就是nohz,我 ...

  3. Linux新内核:提升系统性能 --Linux运维的博客

    http://blog.csdn.net/linuxnews/article/details/52864182

  4. linux如何编译安装新内核支持NTFS文件系统?(以redhat7.2x64为例)

    内核,是一个操作系统的核心.它负责管理系统的进程.内存.设备驱动程序.文件和网络系统,决定着系统的性能和稳定性.Linux作为一个自由软件,在广大爱好者的支持下,内核版本不断更新.新的内核修订了旧内核 ...

  5. Virtio:针对 Linux 的 I/O 虚拟化框架

    Virtio:针对 Linux 的 I/O 虚拟化框架 --http://www.ibm.com/developerworks/cn/linux/l-virtio/#ibm-pcon 使用 KVM 和 ...

  6. linux设备驱动程序--串行通信驱动框架分析

    linux 串行通信接口驱动框架 在学习linux内核驱动时,不论是看linux相关的书籍,又或者是直接看linux的源码,总是能在linux中看到各种各样的框架,linux内核极其庞杂,linux各 ...

  7. 深入linux kernel内核配置选项

    ============================================================================== 深入linux kernel内核配置选项 ...

  8. (转)linux IO 内核参数调优 之 参数调节和场景分析

    1. pdflush刷新脏数据条件 (linux IO 内核参数调优 之 原理和参数介绍)上一章节讲述了IO内核调优介个重要参数参数. 总结可知cached中的脏数据满足如下几个条件中一个或者多个的时 ...

  9. [转]Linux中文件权限目录权限的意义及权限对文件目录的意义

    转自:http://www.jb51.net/article/77458.htm linux中目录与文件权限的意义 一.文件权限的意义 r:可以读这个文件的具体内容: w:可以编辑这个文件的内容,包括 ...

随机推荐

  1. [luogu2144][bzoj1002][FJOI2007]轮状病毒【高精度+斐波那契数列+基尔霍夫矩阵】

    题目描述 轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的.一个N轮状基由圆环上N个不同的基原子和圆心处一个核原子构成的,2个原子之间的边表示这2个原子之间的信息通道.如下图所示 N轮状病 ...

  2. [poj2528]Mayor's posters

    题目描述 The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campa ...

  3. 洛谷 P2774 方格取数问题 解题报告

    P2774 方格取数问题 题目背景 none! 题目描述 在一个有 \(m*n\) 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大. ...

  4. PendingIntent的使用

    1, 构造intent Intent mIntent = new Intent("android.intent.action.MAIN"); ComponentName comp ...

  5. Linux下的定时器类实现(select定时+线程)

    更好的计时器类实现:LINUX RTC机制实现计时器类(原创) 很多时候需要在LINUX下用到定时器,但像setitimer()和alarm()这样的定时器有时会和sleep()函数发生冲突,这样就给 ...

  6. P4139 上帝与集合的正确用法

    本题是欧拉定理的应用.我这种蒟蒻当然不知道怎么证明啦! 那么我们就不证明了,来直接看结论: ab≡⎧⎩⎨⎪⎪ab%φ(p)abab%φ(p)+φ(p)gcd(a,p)=1gcd(a,p)≠1,b< ...

  7. centos服务重启

    重启openstack的整个服务openstack-service restart 1. 重启dashboardservice httpd restart service memcached rest ...

  8. 百度echart初用总结

    1.先下载echarts.js.我在百度下载的是 echarts-2.2.7 (from Baidu).压缩包里面的build->dist中的echarts.js或者echarts-all.js ...

  9. Hadoop+HBase+Spark+Hive环境搭建

    杨赟快跑 简书作者 2018-09-24 10:24 打开App 摘要:大数据门槛较高,仅仅环境的搭建可能就要耗费我们大量的精力,本文总结了作者是如何搭建大数据环境的(单机版和集群版),希望能帮助学弟 ...

  10. item2乱码问题

    使用的是 mac 环境,本地使用终端打开中文可以正常显示,但是连接远端服务器上发现就编程乱码了,之前一直是好好的,但是突然有一天开始就乱码了,怀疑是我电脑升级后导致系统环境配置发生变化引起的.直接上解 ...