fork,你拿什么证明你的写时拷贝(COW)
前段时间在学习内核的进程管理方面的东西,看了进程创建和进程调度的代码,想写个大而全的东西,即有内核代码分析,又有一些实验在效果上证明内核的代码。 但是这篇文章很难产,感觉自己还是驾驭不了这个宏大的主题。 好久没写文章了,今天就放弃这个想法,写一个简单的东西。
- #include<stdio.h>
- #include<stdlib.h>
- #include<unistd.h>
- #include<sys/types.h>
- #include<sys/wait.h>
- #include<string.h>
- int g_var[102400] = {0};
- int main()
- {
- int l_var[102400] = {0};
- fprintf(stderr,"g_var 's address is %lx\n",(unsigned long)g_var);
- fprintf(stderr,"l_var 's address is %lx\n",(unsigned long)l_var);
- memset(g_var,0,sizeof(g_var));
- memset(l_var,0,sizeof(l_var));
- sleep(15);
- int ret = fork();
- if(ret < 0 )
- {
- fprintf(stderr,"fork failed ,nothing to do now!\n");
- return -1;
- }
- if(ret == 0)
- {
- sleep(10);
- fprintf(stderr, "I begin to write now\n");
- fprintf(stderr,"address at %-10lx value(%-6d) will cause page falut\n",
- (unsigned long)(g_var+2048),g_var[2048]);
- g_var[2048] = 4;
- sleep(6);
- fprintf(stderr,"address at %-10lx value(%-6d) will cause page fault\n",
- (unsigned long)(g_var+10240),g_var[10240]);
- g_var[10240] = 8;
- sleep(4);
- fprintf(stderr,"address at %-10lx value(%-6d) will cause page falut\n",
- (unsigned long)(l_var+2048),l_var[2048]);
- l_var[2048] = 8;
- sleep(4);
- fprintf(stderr,"address at %-10lx value(%-6d) will cause page falut\n",
- (unsigned long)(l_var+10240),l_var[10240]);
- l_var[10240] = 8;
- }
- if(ret >0)
- {
- waitpid(-1,NULL,0);
- fprintf(stderr,"child process exit, now check the value\n");
- fprintf(stderr,"g_var[%-6d] = %-4d\ng_var[%-6d] = %-4d\n",
- 2048,g_var[2048],10240,g_var[10240]);
- fprintf(stderr,"l_var[%-6d] = %-4d\nl_var[%-6d] = %-4d\n",
- 2048,l_var[2048],10240,l_var[10240]);
- return 0;
- }
- }
这里面执行了一个fork系统调用,我们调用下systemtap脚本看下他都调用了kernel/fork.c里面的那些函数:systemtap脚本如下:
- probe kernel.function("*@kernel/fork.c")
- {
- if(pid() == target())
- {
- printf("PID(%d) ,execname(%s) probe point:(%s) \n",pid(),execname(),pp());
- }
- }
- probe timer.s(60)
- {
- exit();
- }
- root@libin:~/program/systemtap/process# stap fork_call.stp -x 7192
- PID(7192) ,execname(fork_cow) probe point:(kernel.function("do_fork@/build/buildd/linux-2.6.32/kernel/fork.c:1364"))
- PID(7192) ,execname(fork_cow) probe point:(kernel.function("copy_process@/build/buildd/linux-2.6.32/kernel/fork.c:978"))
- PID(7192) ,execname(fork_cow) probe point:(kernel.function("dup_task_struct@/build/buildd/linux-2.6.32/kernel/fork.c:221"))
- PID(7192) ,execname(fork_cow) probe point:(kernel.function("account_kernel_stack@/build/buildd/linux-2.6.32/kernel/fork.c:141"))
- PID(7192) ,execname(fork_cow) probe point:(kernel.function("rt_mutex_init_task@/build/buildd/linux-2.6.32/kernel/fork.c:941"))
- PID(7192) ,execname(fork_cow) probe point:(kernel.function("copy_flags@/build/buildd/linux-2.6.32/kernel/fork.c:923"))
- PID(7192) ,execname(fork_cow) probe point:(kernel.function("posix_cpu_timers_init@/build/buildd/linux-2.6.32/kernel/fork.c:960"))
- PID(7192) ,execname(fork_cow) probe point:(kernel.function("copy_files@/build/buildd/linux-2.6.32/kernel/fork.c:747"))
- PID(7192) ,execname(fork_cow) probe point:(kernel.function("copy_fs@/build/buildd/linux-2.6.32/kernel/fork.c:727"))
- PID(7192) ,execname(fork_cow) probe point:(kernel.function("copy_sighand@/build/buildd/linux-2.6.32/kernel/fork.c:799"))
- PID(7192) ,execname(fork_cow) probe point:(kernel.function("copy_signal@/build/buildd/linux-2.6.32/kernel/fork.c:854"))
- PID(7192) ,execname(fork_cow) probe point:(kernel.function("posix_cpu_timers_init_group@/build/buildd/linux-2.6.32/kernel/fork.c:826"))
- PID(7192) ,execname(fork_cow) probe point:(kernel.function("copy_mm@/build/buildd/linux-2.6.32/kernel/fork.c:680"))
- PID(7192) ,execname(fork_cow) probe point:(kernel.function("dup_mm@/build/buildd/linux-2.6.32/kernel/fork.c:624"))
- PID(7192) ,execname(fork_cow) probe point:(kernel.function("mm_init@/build/buildd/linux-2.6.32/kernel/fork.c:448"))
- PID(7192) ,execname(fork_cow) probe point:(kernel.function("mm_alloc_pgd@/build/buildd/linux-2.6.32/kernel/fork.c:403"))
- PID(7192) ,execname(fork_cow) probe point:(kernel.function("mm_init_aio@/build/buildd/linux-2.6.32/kernel/fork.c:440"))
- PID(7192) ,execname(fork_cow) probe point:(kernel.function("mm_init_owner@/build/buildd/linux-2.6.32/kernel/fork.c:951"))
- PID(7192) ,execname(fork_cow) probe point:(kernel.function("dup_mmap@/build/buildd/linux-2.6.32/kernel/fork.c:278"))
- PID(7192) ,execname(fork_cow) probe point:(kernel.function("copy_io@/build/buildd/linux-2.6.32/kernel/fork.c:774"))
- PID(7192) ,execname(fork_cow) probe point:(kernel.function("__cleanup_sighand@/build/buildd/linux-2.6.32/kernel/fork.c:816"))
- PID(7192) ,execname(fork_cow) probe point:(kernel.function("__cleanup_signal@/build/buildd/linux-2.6.32/kernel/fork.c:916"))
- PID(7192) ,execname(fork_cow) probe point:(kernel.function("mm_release@/build/buildd/linux-2.6.32/kernel/fork.c:570"))
- PID(7192) ,execname(fork_cow) probe point:(kernel.function("mmput@/build/buildd/linux-2.6.32/kernel/fork.c:509"))
fork调用了do_fork这个内核函数,这个函数比较大,主干程序是copy_process,这里有一系列的copy_xxx系列产品,这个系列产品会根据传进来的标志位,来决定那些资源子进程需要copy一份,那些不用拷贝了,直接用父进程的就可以了。 我们关注的copy_mm这个函数,如果用户标志位中的CLONE_VM置了1,得了,和父进程共享一份就成了,不需要费劲在copy一份了:
- if (clone_flags & CLONE_VM) {
- atomic_inc(&oldmm->mm_users);
- mm = oldmm;
- goto good_mm;
- }
这个地方语意很怪,正常应该是CLONE_VM是1,我应该copy一份,但是正好相反,CLONE_XX意味值share_XX,意味着,不需要copy。
- root@libin:~/program/C/process_share# ./pthread_cmp &
- [3] 7787
- root@libin:~/program/C/process_share# thread OUT
- thread IN
- thread OUT
- [2]- Done ./pthread_cmp
- [3]+ Done ./pthread_cmp
- root@libin:~/program/systemtap/process# stap fork_call.stp -x 7787
- PID(7787) ,execname(pthread_cmp) probe point:(kernel.function("do_fork@/build/buildd/linux-2.6.32/kernel/fork.c:1364"))
- PID(7787) ,execname(pthread_cmp) probe point:(kernel.function("copy_process@/build/buildd/linux-2.6.32/kernel/fork.c:978"))
- PID(7787) ,execname(pthread_cmp) probe point:(kernel.function("dup_task_struct@/build/buildd/linux-2.6.32/kernel/fork.c:221"))
- PID(7787) ,execname(pthread_cmp) probe point:(kernel.function("account_kernel_stack@/build/buildd/linux-2.6.32/kernel/fork.c:141"))
- PID(7787) ,execname(pthread_cmp) probe point:(kernel.function("rt_mutex_init_task@/build/buildd/linux-2.6.32/kernel/fork.c:941"))
- PID(7787) ,execname(pthread_cmp) probe point:(kernel.function("copy_flags@/build/buildd/linux-2.6.32/kernel/fork.c:923"))
- PID(7787) ,execname(pthread_cmp) probe point:(kernel.function("posix_cpu_timers_init@/build/buildd/linux-2.6.32/kernel/fork.c:960"))
- PID(7787) ,execname(pthread_cmp) probe point:(kernel.function("copy_files@/build/buildd/linux-2.6.32/kernel/fork.c:747"))
- PID(7787) ,execname(pthread_cmp) probe point:(kernel.function("copy_fs@/build/buildd/linux-2.6.32/kernel/fork.c:727"))
- PID(7787) ,execname(pthread_cmp) probe point:(kernel.function("copy_sighand@/build/buildd/linux-2.6.32/kernel/fork.c:799"))
- PID(7787) ,execname(pthread_cmp) probe point:(kernel.function("copy_signal@/build/buildd/linux-2.6.32/kernel/fork.c:854"))
- PID(7787) ,execname(pthread_cmp) probe point:(kernel.function("copy_mm@/build/buildd/linux-2.6.32/kernel/fork.c:680"))
- PID(7787) ,execname(pthread_cmp) probe point:(kernel.function("copy_io@/build/buildd/linux-2.6.32/kernel/fork.c:774"))
- PID(7787) ,execname(pthread_cmp) probe point:(kernel.function("mm_release@/build/buildd/linux-2.6.32/kernel/fork.c:570"))
- PID(7787) ,execname(pthread_cmp) probe point:(kernel.function("mmput@/build/buildd/linux-2.6.32/kernel/fork.c:509"))
- PID(7787) ,execname(pthread_cmp) probe point:(kernel.function("__cleanup_sighand@/build/buildd/linux-2.6.32/kernel/fork.c:816"))
- PID(7787) ,execname(pthread_cmp) probe point:(kernel.function("mm_release@/build/buildd/linux-2.6.32/kernel/fork.c:570"))
- PID(7787) ,execname(pthread_cmp) probe point:(kernel.function("mmput@/build/buildd/linux-2.6.32/kernel/fork.c:509"))
dup_mm这里面有两个分支指的注意
- #! /usr/bin/env stap
- global fault_entry_time, fault_address, fault_access
- global time_offset
- probe begin { time_offset = gettimeofday_us() }
- probe vm.pagefault {
- if(pid() == target() || ppid() == target())
- {
- t = gettimeofday_us()
- p = pid()
- fault_entry_time[p] = t
- fault_address[p] = address
- fault_access[p] = write_access ? "w" : "r"
- }
- }
- probe vm.pagefault.return {
- if(pid() == target() || ppid() == target())
- {
- t=gettimeofday_us()
- p = pid()
- if (!(p in fault_entry_time)) next
- e = t - fault_entry_time[p]
- if (vm_fault_contains(fault_type,VM_FAULT_MINOR)) {
- ftype="minor"
- } else if (vm_fault_contains(fault_type,VM_FAULT_MAJOR)) {
- ftype="major"
- } else {
- next #only want to deal with minor and major page faults
- }
- printf("%d:%d:%p:%s:%s:%d\n",
- t - time_offset, p, fault_address[p], fault_access[p], ftype, e)
- #free up memory
- delete fault_entry_time[p]
- delete fault_address[p]
- delete fault_access[p]
- }
- }
- probe timer.s(100){
- exit();
- }
下面看现象:
- root@libin:~/program/C/process_share# g_var 's address is 804a060
- l_var 's address is bf8edf0c
- I begin to write now
- address at 804c060 value(0 ) will cause page falut
- address at 8054060 value(0 ) will cause page fault
- address at bf8eff0c value(0 ) will cause page falut
- address at bf8f7f0c value(0 ) will cause page falut
- .....
- root@libin:~/program/systemtap#
- root@libin:~/program/systemtap#
- root@libin:~/program/systemtap# stap pfaults.stp -x 9081
- 4767196:9081:0xb77ec72c:w:minor:35
- 4767230:9092:0xb77ec728:w:minor:23
- 4767239:9081:0xbf8edea8:w:minor:29
- .....
- 14768229:9092:0x0804c060:w:minor:13
- 20768379:9092:0x08054060:w:minor:37
- 24768564:9092:0xbf8eff0c:w:minor:39
- 28768745:9092:0xbf8f7f0c:w:minor:39
- ...
fork,你拿什么证明你的写时拷贝(COW)相关推荐
- Linux | fork()、僵死进程、写时拷贝
目录 1. 获取进程id的方法 2. 父进程的父进程~bash 3. fork()示例 之 打印了多少个A? (1)打印3个A (2)打印6个A (3)fork()试题总结 4. 进程的结束.僵死进程 ...
- 【Linux进程、线程、任务调度】二 fork/vfork与写时拷贝 线程的本质 托孤 进程睡眠和等待队列
学习交流加(可免费帮忙下载CSDN资源): 个人微信: liu1126137994 学习交流资源分享qq群1(已满): 962535112 学习交流资源分享qq群2(已满): 780902027 学习 ...
- 写时复制,写时拷贝,写时分裂,Copy on write
2019独角兽企业重金招聘Python工程师标准>>> 写时复制,写时拷贝,写时分裂 (Copy-on-write,简称COW)是计算机资源管理方面的一种优化技术,有着广泛的应用,比 ...
- linux进程--写时拷贝技术copy-on-write(七)
COW技术初窥: 在Linux程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑,linux中引入了"写时复制"技术,也就是只 ...
- Linux写时拷贝技术(copy-on-write)
COW技术初窥: 在Linux程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑,linux中引入了"写时复制"技术,也就是只 ...
- 【转】Linux写时拷贝技术(copy-on-write)
http://www.cnblogs.com/biyeymyhjob/archive/2012/07/20/2601655.html 源于网上资料 COW技术初窥: 在Linux程序中,fork()会 ...
- Linux系统编程15:进程控制之如何创建进程和写时拷贝技术
文章目录 (1)fork函数回顾 (2)写时拷贝 (1)fork函数回顾 在下面这篇文章我们演示了fork函数以及相关细节 点击跳转 还是借助上文中的程序和效果图片 #include <stdi ...
- linux 进程0 写时复制,linux 写时复制 COW 过程梳理
最后一次谈到缺页,是在一年多以前,http://blog..net/chenyu105/article/details/7061845 那时结个了草率的尾,定格在了handle_pte_fault,留 ...
- Linux 10分钟让你掌握虚拟地址--写时拷贝技术
程序地址空间 地址:对内存单元的编号 程序是不占用内存的,运行起来的程序才会被加载到内存,才会占用空间.所以程序地址空间也叫做进程地址空间 我们先来看一下代码: zone.c #include < ...
- 写时拷贝技术(COW)
文章目录 写时拷贝技术 写时拷贝技术原理 举个例子 写时拷贝技术 写时拷贝技术实际上是一种拖延战术,是为了提高效率而产生的技术,这怎么提高效率呢?实际上就是在需要开辟空间时,假装开了空间,实际上用 ...
最新文章
- linux如何登陆oracle?如何停止、启动oracle和其监听?
- 硬计算、软计算与混合计算
- 搜狐2012.9.15校园招聘会笔试题
- URAL-1982 Electrification Plan 最小生成树
- 盘点那些世间顶级直男hhhhhh | 今日最佳
- 【转载保存】匿名内部类中this的使用
- 作者:杜圣东(1981-),男,西南交通大学信息科学与技术学院讲师,中国计算机学会(CCF)和国际计算机学会(ACM)会员。...
- 关于产品与数据该如何结合的一点想法(一)
- hashset如何检查重复_如何使用 C# 中的 HashSet
- ubuntu安装ulipad
- 百度网盘使用Motrix下载资源
- 鼠标不受控制一直向右移动的解决办法
- Hadoop生态圈之即席查询工具Presto
- WeWork中国实现全面本土化运营;巴黎欧莱雅沙龙专属全球首家旗舰沙龙开业 | 美通企业日报...
- sklearn 随机森林代码示例
- “FCoE全解系列”之网络融合交换机类型
- 单月营业额一个亿,任泉李冰冰黄晓明追着投钱!这家企业是谁?
- 门萨--高智商者的集中营
- RTL概念与常用RTL建模
- 西工大PAMI论文:发布大规模人群计数/定位基准平台
热门文章
- C++的C4305和C4800的编译警告
- 关联查询objectid_SAP 删除的BOM如何查询呢?
- plsql能连mysql吗_每日囧图连世界首富都秃顶,你还觉脱发是能用钱解决的事吗?...
- Python爬虫从入门到放弃(二十四)之 Scrapy登录知乎
- MySql中in和exists效率
- C++ 从零单排(2)-基础知识二
- [转]winform控件webbrowser和js脚本互调
- cmd启动某个server卡住解决办法
- spring框架包含的模块
- WEB前端 盒子模型稳定性