文章目录
-
- 专栏博客链接
- 相关查阅链接
- 前引
- 实验注意与提醒
- 预处理(正式开始实验)
-
- 实验前预先准备
- 实验册预浏览
- 实验中须知知识
- 开始编写文件
-
- 提前读Log文件
- 写入Log文件部分
-
- 向系统添加fprintk函数
- 写入Log文件函数fprintk分析
- 寻找状态切换点
-
- 'N' 'J' 'R' 'W' 'E' 符号含义
- 向log写入添加代码 copy_process.c
- 向log写入添加代码 sche.c
- 向log写入添加代码 exit.c
- 运行虚拟机质检process.log
- 编写process.c
- 运行./stat_log.py 得到结果
- 结束实验(含我的process.log 和 部分stat.py 运行结果)
- 完结撒花
专栏博客链接
哈工大操作系统原理与实践 Lab全实验博客链接
相关查阅链接
操作系统中进程的实现 PCB结构(Task_struct) 讲解
task_struct结构体成员详解
UNIX系统中struct tms 分析《转载》
Linux多任务编程(六)—编写多进程程序及其代码
linux中fork()函数详解(原创!!实例讲解)
Linux中wait()函数
详解C语言中volatile关键字
MOOC哈工大操作系统实验3:进程运行轨迹的跟踪与统计 博主:Zhao tianhao
前引
我觉得整个Lab做下来其实还是挺不容易的
因为其实实验册中还是有很多东西没有说
但是需要我们自己去做去补充
而且还需要我们对很多函数有一定的理解
整个Lab在做什么 整个Lab的实验流程是怎么样的
这个Lab3还与Lab1 和 Lab2其中的一部分有关
Lab1 和 Lab2有些地方没弄懂或者没做的
这个Lab有的地方也会卡住
话不多说 直接进入这个Lab吧
待会我还要去上体育课 麻了还要体测
实验注意与提醒
如果是用实验楼 蓝桥云课的hxd的话
其实我这边是建议冲一个月会员的
反正可以去网上找优惠码30
但是可以随时保存环境
前几个Lab因为 忘记保存或者做到晚上
还差一点没有完成 就导致我很多程序没有存下来
并且会清空
这几个Lab的话 一个月之内肯定是可以完成的
所以我这边还是推荐整一个会员
第二个就是
还是对于操作系统的一些小细节的问题
比如我们挂载hdc 卸载hdc时 或者启动虚拟机的时候
一定一定要注意 我们当前文件系统一定不要指向 hdc中的目录
不然的话 指向的目录就会被破坏 你之后那个文件就会访问不了 切记
预处理(正式开始实验)
实验前预先准备
一、
我们需要准备预先知识 就是实验准备的
Ubuntu和Linux文件交换的知识
这个我觉得应该做到现在是知道的
我前面的几个Lab也是用到过
二、
这个Lab要结合我们上一个Lab中用到的
我们添加一个调用程序 我们需要修改MakeFile文件
如果上个Lab没有做明白的话 这里会有个地方卡住
实验册预浏览
我们刚开始可以不用 一章一章一页一页的仔细看
先总览的看一下Lab在说什么 我们要达成的目标是什么
process.c,50%
日志文件建立成功,5%
能向日志文件输出信息,5%
5 种状态都能输出,10%(每种 2 %)
调度算法修改,10%
实验报告,20%
看完后 其实我的完成顺序是
日志文件建立->向日志文件输入信息->创建process.c并进行调试->
调试中肯定会发现自己输入信息的有的地方有误修正日志输出->运行./stat_log.py再次调试->结束实验
我的调度算法修改就没有做了 如果感兴趣还想做的
这里我贴一个链接 我觉得这个博客也讲的挺细致的
MOOC哈工大操作系统实验3:进程运行轨迹的跟踪与统计 博主:Zhao tianhao
如果我有的地方卡住了 或者出错调试了半天 我也会借鉴别人的结果
看看自己哪里有问题 不然的话会浪费大量时间
实验中须知知识
fork() 和 wait() 和 waitpid()函数
必须要求有所掌握及能使用
但是这个可以不急 可以等着我们把日志文件创建及输出弄完后再来弄
Linux中wait()函数
linux中fork()函数详解(原创!!实例讲解)
开始编写文件
提前读Log文件
分析过程实验册已经讲的很清楚了
这里就不再重复了
我们先修改代码
move_to_user_mode();setup((void *) &drive_info);/* for visiting log document in prc0 in advance 这是后面加进去的*/(void) open("/dev/tty0",O_RDWR,0);(void) dup(0);(void) dup(0);(void) open("/var/process.log",O_CREAT|O_TRUNC|O_WRONLY,0666);/*这上面部分是需要添加的*/if (!fork()) {
/* we count on this going ok */init();}
写入Log文件部分
向系统添加fprintk函数
这里主要说的是如何向系统添加fprintk函数
这里实验册说 函数就已经给出来了 编写难度太大
然后推荐我们的是放到kernel\printk.c
中
我记得之前我们的Lab2中就让我们添加系统调用
但那个是系统调用 这个fprintk函数其实本质是调用了其他的系统调用
所以我们不需要在系统调用表中修改 调用数 函数名
我们就按照实验册中说的把这个函数添加到 kernel\printk.c
下面是实验册直接给出的在 kernel\printk.c
添加之后的代码
/** linux/kernel/printk.c** (C) 1991 Linus Torvalds*//** When in kernel-mode, we cannot use printf, as fs is liable to* point to 'interesting' things. Make a printf with fs-saving, and* all is well.*/
#include <stdarg.h>
#include <stddef.h>
#include <linux/kernel.h>/*之后添加进去的*/
#include "linux/sched.h"
#include "sys/stat.h"
/*之后添加进去的*/static char buf[1024];/*之后添加进去的*/
static char logbuf[1024];
/*之后添加进去的*/extern int vsprintf(char * buf, const char * fmt, va_list args);int printk(const char *fmt, ...)
{
va_list args;int i;va_start(args, fmt);i=vsprintf(buf,fmt,args);va_end(args);__asm__("push %%fs\n\t""push %%ds\n\t""pop %%fs\n\t""pushl %0\n\t""pushl $buf\n\t""pushl $0\n\t""call tty_write\n\t""addl $8,%%esp\n\t""popl %0\n\t""pop %%fs"::"r" (i):"ax","cx","dx");return i;
}/*之后添加进去的*/
int fprintk(int fd, const char *fmt, ...)
{
va_list args;int count;struct file * file;struct m_inode * inode;va_start(args, fmt);count=vsprintf(logbuf, fmt, args);va_end(args);if (fd < 3){
__asm__("push %%fs\n\t""push %%ds\n\t""pop %%fs\n\t""pushl %0\n\t""pushl $logbuf\n\t""pushl %1\n\t""call sys_write\n\t""addl $8,%%esp\n\t""popl %0\n\t""pop %%fs"::"r" (count),"r" (fd):"ax","cx","dx");}else{
if (!(file=task[0]->filp[fd]))return 0;inode=file->f_inode;__asm__("push %%fs\n\t""push %%ds\n\t""pop %%fs\n\t""pushl %0\n\t""pushl $logbuf\n\t""pushl %1\n\t""pushl %2\n\t""call file_write\n\t""addl $12,%%esp\n\t""popl %0\n\t""pop %%fs"::"r" (count),"r" (file),"r" (inode):"ax","cx","dx");}return count;
}
/*之后添加进去的*/
这里我卡了一会 因为我发现当我make all 编译内核时
这个地方的函数是出错的
我就一直在想 究竟怎么把这个函数给存进去
我就忽然想起来 上一个Lab 实验册说了一句话
里面的函数链接编译都是按照 MakeFile
里面的来链接的
因为我们这里把我们之后添加的头文件也给写进去
所以我们编写的函数就无法找到对应的头文件
所以我们就打开 MakeFile
按照人家的链接方式依葫芦画瓢的
路径 kernel\MakeFile
把我们之后添加的头文件编译进去(应该是需要按照我们添加的顺序的)
printk.s printk.o: printk.c ../include/stdarg.h ../include/stddef.h \../include/linux/kernel.h \/*之后添加的部分*/../include/linux/sched.h \../include/sys/stat.h
/*之后添加的部分*/
之后编译 我还是发现不对 这个时候我随便点了几个头文件
进去看了看 发现是有函数声明的
就类似 sys_open这些函数
这个时候我就想到了 我们添加的函数 还没有在一个头文件中声明
而我们需要声明的函数 应该是在printk函数声明的头文件里
所以我就找到了在 /include/linux/kernel.h
中
于是就加了一句声明 此时编译就发现通过了
写入Log文件函数fprintk分析
下面的实验册部分给出了两个示例
// 向stdout打印正在运行的进程的ID
fprintk(1, "The ID of running process is %ld", current->pid);// 向log文件输出跟踪进程运行轨迹
fprintk(3, "%ld\t%c\t%ld\n", current->pid, 'R', jiffies);
不难看出 最后这个函数
fprintk(3, "%ld\t%c\t%ld\n", current->pid, 'R', jiffies);
这个是我们的核心函数 也是我们最后要经常使用的函数
用法也给出来了 我们直接用即可
这里顺带再介绍一下jiffies 是记录时钟中断数
并且是一个全局变量 一次时钟中断实验册分析出来是10ms 1/100s
寻找状态切换点
‘N’ ‘J’ ‘R’ ‘W’ ‘E’ 符号含义
X 可以是 N、J、R、W 和 E 中的任意一个,分别表示进程新建(N)、进入就绪态(J)、进入运行态?、进入阻塞态(W) 和退出(E);
向log写入添加代码 copy_process.c
实验册中其实写的还是挺清晰的
就是让我们写在kernel\fork.c的
的copy_process中
这里才是我们实际创建的进程
对于这个函数我就简单分析一下
我就贴出来 我修改部分的代码
'N' 位置代码区
p = (struct task_struct *) get_free_page();if (!p) return -EAGAIN;task[nr] = p;*p = *current; /* NOTE! this doesn't copy the supervisor stack */p->state = TASK_UNINTERRUPTIBLE;p->pid = last_pid;//这里应该是创建了新的进程之后//对p进程赋值 拿末尾的进程号赋值给p//我认为 这里就可以说 这里开始创建新进程了 所以我就选择在这里fprintk//并且还设置了state 更说明了这里应该设置fprintk(3,"%ld\t%c\t%ld\n",p->pid,'N',jiffies);p->father = current->pid;p->counter = p->priority;
'J' 位置代码区
set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt));p->state = TASK_RUNNING; /* do this last, just in case */// 修改state状态是很明显的状态转移赋值fprintk(3,"%ld\t%c\t%ld\n",p->pid,'J',jiffies);//return last_pid;
向log写入添加代码 sche.c
因为添加的小部分函数太多
人懒 我就直接把sche.c的代码全复制下来
按照那个实验册的函数 应该是能找到我添加的位置的
温馨提醒 利用 ctrl+f 快速定位fprintk 可以快速找到对应修改函数位置及代码
/** linux/kernel/sched.c** (C) 1991 Linus Torvalds*//** 'sched.c' is the main kernel file. It contains scheduling primitives* (sleep_on, wakeup, schedule etc) as well as a number of simple system* call functions (type getpid(), which just extracts a field from* current-task*/
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/sys.h>
#include <linux/fdreg.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/segment.h>#include <signal.h>#define _S(nr) (1<<((nr)-1))
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))void show_task(int nr,struct task_struct * p)
{
int i,j = 4096-sizeof(struct task_struct);printk("%d: pid=%d, state=%d, ",nr,p->pid,p->state);i=0;while (i<j && !((char *)(p+1))[i])i++;printk("%d (of %d) chars free in kernel stack\n\r",i,j);
}void show_stat(void)
{
int i;for (i=0;i<NR_TASKS;i++)if (task[i])show_task(i,task[i]);
}#define LATCH (1193180/HZ)extern void mem_use(void);extern int timer_interrupt(void);
extern int system_call(void);union task_union {
struct task_struct task;char stack[PAGE_SIZE];
};static union task_union init_task = {
INIT_TASK,};long volatile jiffies=0;
long startup_time=0;
struct task_struct *current = &(init_task.task);
struct task_struct *last_task_used_math = NULL;struct task_struct * task[NR_TASKS] = {
&(init_task.task), };long user_stack [ PAGE_SIZE>>2 ] ;struct {
long * a;short b;} stack_start = {
& user_stack [PAGE_SIZE>>2] , 0x10 };
/** 'math_state_restore()' saves the current math information in the* old math state array, and gets the new ones from the current task*/
void math_state_restore()
{
if (last_task_used_math == current)return;__asm__("fwait");if (last_task_used_math) {
__asm__("fnsave %0"::"m" (last_task_used_math->tss.i387));}last_task_used_math=current;if (current->used_math) {
__asm__("frstor %0"::"m" (current->tss.i387));} else {
__asm__("fninit"::);current->used_math=1;}
}/** 'schedule()' is the scheduler function. This is GOOD CODE! There* probably won't be any reason to change this, as it should work well* in all circumstances (ie gives IO-bound processes good response etc).* The one thing you might take a look at is the signal-handler code here.** NOTE!! Task 0 is the 'idle' task, which gets called when no other* tasks can run. It can not be killed, and it cannot sleep. The 'state'* information in task[0] is never used.*/
void schedule(void)
{
int i,next,c;struct task_struct ** p;/* check alarm, wake up any interruptible tasks that have got a signal */for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)if (*p) {
if ((*p)->alarm && (*p)->alarm < jiffies) {
(*p)->signal |= (1<<(SIGALRM-1));(*p)->alarm = 0;}if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&(*p)->state==TASK_INTERRUPTIBLE){
(*p)->state=TASK_RUNNING;fprintk(3,"%ld\t%c\t%ld\n",(*p)->pid,'J',jiffies);}}/* this is the scheduler proper: */while (1) {
c = -1;next = 0;i = NR_TASKS;p = &task[NR_TASKS];while (--i) {
if (!*--p)continue;if ((*p)->state == TASK_RUNNING && (*p)->counter > c)c = (*p)->counter, next = i;}if (c) break;for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)if (*p)(*p)->counter = ((*p)->counter >> 1) +(*p)->priority;}if(task[next]->pid != current->pid){
if(current->state == TASK_RUNNING)fprintk(3,"%ld\t%c\t%ld\n", current->pid,'J',jiffies); fprintk(3,"%ld\t%c\t%ld\n", task[next]->pid,'R',jiffies); }switch_to(next);
}int sys_pause(void)
{
current->state = TASK_INTERRUPTIBLE;if(current->pid) fprintk(3,"%ld\t%c\t%ld\n",current->pid,'W',jiffies);schedule();return 0;
}void sleep_on(struct task_struct **p)
{
struct task_struct *tmp;if (!p)return;if (current == &(init_task.task))panic("task[0] trying to sleep");tmp = *p;*p = current;current->state = TASK_UNINTERRUPTIBLE;fprintk(3,"%ld\t%c\t%ld\n",current->pid,'W',jiffies);schedule();if (tmp){
tmp->state=0;fprintk(3,"%ld\t%c\t%ld\n",tmp->pid,'J',jiffies);}
}void interruptible_sleep_on(struct task_struct **p)
{
struct task_struct *tmp;if (!p)return;if (current == &(init_task.task))panic("task[0] trying to sleep");tmp=*p;*p=current;
repeat: current->state = TASK_INTERRUPTIBLE;fprintk(3,"%ld\t%c\t%ld\n",current->pid,'W',jiffies);schedule();if (*p && *p != current) {
(**p).state=0;goto repeat;}*p=NULL;if (tmp){
tmp->state=0;fprintk(3,"%ld\t%c\t%ld\n",tmp->pid,'J',jiffies);}
}void wake_up(struct task_struct **p)
{
if (p && *p) {
(**p).state=0;fprintk(3,"%ld\t%c\t%ld\n",(**p).pid,'J',jiffies);*p=NULL;}
}/** OK, here are some floppy things that shouldn't be in the kernel* proper. They are here because the floppy needs a timer, and this* was the easiest way of doing it.*/
static struct task_struct * wait_motor[4] = {
NULL,NULL,NULL,NULL};
static int mon_timer[4]={
0,0,0,0};
static int moff_timer[4]={
0,0,0,0};
unsigned char current_DOR = 0x0C;int ticks_to_floppy_on(unsigned int nr)
{
extern unsigned char selected;unsigned char mask = 0x10 << nr;if (nr>3)panic("floppy_on: nr>3");moff_timer[nr]=10000; /* 100 s = very big :-) */cli(); /* use floppy_off to turn it off */mask |= current_DOR;if (!selected) {
mask &= 0xFC;mask |= nr;}if (mask != current_DOR) {
outb(mask,FD_DOR);if ((mask ^ current_DOR) & 0xf0)mon_timer[nr] = HZ/2;else if (mon_timer[nr] < 2)mon_timer[nr] = 2;current_DOR = mask;}sti();return mon_timer[nr];
}void floppy_on(unsigned int nr)
{
cli();while (ticks_to_floppy_on(nr))sleep_on(nr+wait_motor);sti();
}void floppy_off(unsigned int nr)
{
moff_timer[nr]=3*HZ;
}void do_floppy_timer(void)
{
int i;unsigned char mask = 0x10;for (i=0 ; i<4 ; i++,mask <<= 1) {
if (!(mask & current_DOR))continue;if (mon_timer[i]) {
if (!--mon_timer[i])wake_up(i+wait_motor);} else if (!moff_timer[i]) {
current_DOR &= ~mask;outb(current_DOR,FD_DOR);} elsemoff_timer[i]--;}
}#define TIME_REQUESTS 64static struct timer_list {
long jiffies;void (*fn)();struct timer_list * next;
} timer_list[TIME_REQUESTS], * next_timer = NULL;void add_timer(long jiffies, void (*fn)(void))
{
struct timer_list * p;if (!fn)return;cli();if (jiffies <= 0)(fn)();else {
for (p = timer_list ; p < timer_list + TIME_REQUESTS ; p++)if (!p->fn)break;if (p >= timer_list + TIME_REQUESTS)panic("No more time requests free");p->fn = fn;p->jiffies = jiffies;p->next = next_timer;next_timer = p;while (p->next && p->next->jiffies < p->jiffies) {
p->jiffies -= p->next->jiffies;fn = p->fn;p->fn = p->next->fn;p->next->fn = fn;jiffies = p->jiffies;p->jiffies = p->next->jiffies;p->next->jiffies = jiffies;p = p->next;}}sti();
}void do_timer(long cpl)
{
extern int beepcount;extern void sysbeepstop(void);if (beepcount)if (!--beepcount)sysbeepstop();if (cpl)current->utime++;elsecurrent->stime++;if (next_timer) {
next_timer->jiffies--;while (next_timer && next_timer->jiffies <= 0) {
void (*fn)(void);fn = next_timer->fn;next_timer->fn = NULL;next_timer = next_timer->next;(fn)();}}if (current_DOR & 0xf0)do_floppy_timer();if ((--current->counter)>0) return;current->counter=0;if (!cpl) return;schedule();
}int sys_alarm(long seconds)
{
int old = current->alarm;if (old)old = (old - jiffies) / HZ;current->alarm = (seconds>0)?(jiffies+HZ*seconds):0;return (old);
}int sys_getpid(void)
{
return current->pid;
}int sys_getppid(void)
{
return current->father;
}int sys_getuid(void)
{
return current->uid;
}int sys_geteuid(void)
{
return current->euid;
}int sys_getgid(void)
{
return current->gid;
}int sys_getegid(void)
{
return current->egid;
}int sys_nice(long increment)
{
if (current->priority-increment>0)current->priority -= increment;return 0;
}void sched_init(void)
{
int i;struct desc_struct * p;if (sizeof(struct sigaction) != 16)panic("Struct sigaction MUST be 16 bytes");set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss));set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt));p = gdt+2+FIRST_TSS_ENTRY;for(i=1;i<NR_TASKS;i++) {
task[i] = NULL;p->a=p->b=0;p++;p->a=p->b=0;p++;}
/* Clear NT, so that we won't have troubles with that later on */__asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");ltr(0);lldt(0);outb_p(0x36,0x43); /* binary, mode 3, LSB/MSB, ch 0 */outb_p(LATCH & 0xff , 0x40); /* LSB */outb(LATCH >> 8 , 0x40); /* MSB */set_intr_gate(0x20,&timer_interrupt);outb(inb_p(0x21)&~0x01,0x21);set_system_gate(0x80,&system_call);
}
向log写入添加代码 exit.c
下面这部分是 exit.c 中含有修改添加 fprintk的全代码
ctrl+f 搜索fprintk 可以快速定位
/** linux/kernel/exit.c** (C) 1991 Linus Torvalds*/#include <errno.h>
#include <signal.h>
#include <sys/wait.h>#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/tty.h>
#include <asm/segment.h>int sys_pause(void);
int sys_close(int fd);void release(struct task_struct * p)
{
int i;if (!p)return;for (i=1 ; i<NR_TASKS ; i++)if (task[i]==p) {
task[i]=NULL;free_page((long)p);schedule();return;}panic("trying to release non-existent task");
}static inline int send_sig(long sig,struct task_struct * p,int priv)
{
if (!p || sig<1 || sig>32)return -EINVAL;if (priv || (current->euid==p->euid) || suser())p->signal |= (1<<(sig-1));elsereturn -EPERM;return 0;
}static void kill_session(void)
{
struct task_struct **p = NR_TASKS + task;while (--p > &FIRST_TASK) {
if (*p && (*p)->session == current->session)(*p)->signal |= 1<<(SIGHUP-1);}
}/** XXX need to check permissions needed to send signals to process* groups, etc. etc. kill() permissions semantics are tricky!*/
int sys_kill(int pid,int sig)
{
struct task_struct **p = NR_TASKS + task;int err, retval = 0;if (!pid) while (--p > &FIRST_TASK) {
if (*p && (*p)->pgrp == current->pid) if ((err=send_sig(sig,*p,1)))retval = err;} else if (pid>0) while (--p > &FIRST_TASK) {
if (*p && (*p)->pid == pid) if ((err=send_sig(sig,*p,0)))retval = err;} else if (pid == -1) while (--p > &FIRST_TASK) {
if ((err = send_sig(sig,*p,0)))retval = err;} else while (--p > &FIRST_TASK)if (*p && (*p)->pgrp == -pid)if ((err = send_sig(sig,*p,0)))retval = err;return retval;
}static void tell_father(int pid)
{
int i;if (pid)for (i=0;i<NR_TASKS;i++) {
if (!task[i])continue;if (task[i]->pid != pid)continue;task[i]->signal |= (1<<(SIGCHLD-1));return;}
/* if we don't find any fathers, we just release ourselves */
/* This is not really OK. Must change it to make father 1 */printk("BAD BAD - no father found\n\r");release(current);
}int do_exit(long code)
{
int i;free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));free_page_tables(get_base(current->ldt[2]),get_limit(0x17));for (i=0 ; i<NR_TASKS ; i++)if (task[i] && task[i]->father == current->pid) {
task[i]->father = 1;if (task[i]->state == TASK_ZOMBIE)/* assumption task[1] is always init */(void) send_sig(SIGCHLD, task[1], 1);}for (i=0 ; i<NR_OPEN ; i++)if (current->filp[i])sys_close(i);iput(current->pwd);current->pwd=NULL;iput(current->root);current->root=NULL;iput(current->executable);current->executable=NULL;if (current->leader && current->tty >= 0)tty_table[current->tty].pgrp = 0;if (last_task_used_math == current)last_task_used_math = NULL;if (current->leader)kill_session();current->state = TASK_ZOMBIE;current->exit_code = code;fprintk(3,"%ld\t%c\t%ld\n",current->pid,'E',jiffies);tell_father(current->father);schedule();return (-1); /* just to suppress warnings */
}int sys_exit(int error_code)
{
return do_exit((error_code&0xff)<<8);
}int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
{
int flag, code;struct task_struct ** p;verify_area(stat_addr,4);
repeat:flag=0;for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
if (!*p || *p == current)continue;if ((*p)->father != current->pid)continue;if (pid>0) {
if ((*p)->pid != pid)continue;} else if (!pid) {
if ((*p)->pgrp != current->pgrp)continue;} else if (pid != -1) {
if ((*p)->pgrp != -pid)continue;}switch ((*p)->state) {
case TASK_STOPPED:if (!(options & WUNTRACED))continue;put_fs_long(0x7f,stat_addr);return (*p)->pid;case TASK_ZOMBIE:current->cutime += (*p)->utime;current->cstime += (*p)->stime;flag = (*p)->pid;code = (*p)->exit_code;release(*p);put_fs_long(code,stat_addr);return flag;default:flag=1;continue;}}if (flag) {
if (options & WNOHANG)return 0;current->state=TASK_INTERRUPTIBLE;fprintk(3,"%ld\t%c\t%ld\n",current->pid,'W',jiffies);schedule();if (!(current->signal &= ~(1<<(SIGCHLD-1))))goto repeat;elsereturn -EINTR;}return -ECHILD;
}
运行虚拟机质检process.log
编译内核部分 具体我就不说了
进入 linux-0.11 make all即可
注意:
退出时记得
记住 sync
记住 sync
输入命令sync 即可向磁盘同步输入 防止文件未被写入
如何质检虚拟机process.log呢
其实还是非常简单的 就是我们可以等待一下虚拟机运行一段时间
sync 得到process.log process.log文件在 hdc/var中
之后我们挂载 hdc 进入linux-0.11把文件copy出来
退出时记得
记住 sync
记住 sync
至于怎么进入linux-0.11 交换文件
这个问题应该重新去看看 实验册第一章 详细介绍了
如果不想看的也可以去看一下我写的Lab2的博客
里面也详细介绍了如何挂载 与注意事项
质检部分 如果还没有写process.c
只是先测验一下 ok 我们拿那个log和我们实验册中的 示例log做一个对比
如下
示例log
1 N 48 //进程1新建(init())。此前是进程0建立和运行,但为什么没出现在log文件里?
1 J 49 //新建后进入就绪队列
0 J 49 //进程0从运行->就绪,让出CPU
1 R 49 //进程1运行
2 N 49 //进程1建立进程2。2会运行/etc/rc脚本,然后退出
2 J 49
1 W 49 //进程1开始等待(等待进程2退出)
2 R 49 //进程2运行
3 N 64 //进程2建立进程3。3是/bin/sh建立的运行脚本的子进程
3 J 64
2 E 68 //进程2不等进程3退出,就先走一步了
1 J 68 //进程1此前在等待进程2退出,被阻塞。进程2退出后,重新进入就绪队列
1 R 68
4 N 69 //进程1建立进程4,即shell
4 J 69
1 W 69 //进程1等待shell退出(除非执行exit命令,否则shell不会退出)
3 R 69 //进程3开始运行
3 W 75
4 R 75
5 N 107 //进程5是shell建立的不知道做什么的进程
5 J 108
4 W 108
5 R 108
4 J 110
5 E 111 //进程5很快退出
4 R 111
4 W 116 //shell等待用户输入命令。
0 R 116 //因为无事可做,所以进程0重出江湖
4 J 239 //用户输入命令了,唤醒了shell
4 R 239
4 W 240
0 R 240
……
log如果没问题 或者只是很少部分和这个有误差
那我们可以进入下一步了
编写process.c了
编写process.c
其实思路 需要我们有个大概的轮廓
对于多进程的编写 可以参照我上面给出的链接
linux 多进程编程示例 这里我就不再详细说我怎么编写的了
这里我还对linux-0.11编译有很大的怨气
因为我觉得编译真的很不方便
我不知道为什么有的时候 我命名int都能说
undefined reference to这些信息
这里我浪费了很多时间调试
process.c代码
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <sys/times.h>//需要这些头文件 新添加
#include <sys/wait.h>
#include <sys/types.h>
//新添加#define HZ 100
void cpuio_bound(int last, int cpu_time, int io_time);//主函数改写 新添加
int main(int argc, char * argv[])
{
pid_t child1,child2,childret;child1 = fork();if(child1 == -1){
printf("child1 fork error!");exit(-1);}else if(child1 == 0){
cpuio_bound(10,1,1);exit(0);}else{
child2 = fork();if(child2 == -1){
printf("child2 fork error!");exit(-1);}else if(child2 == 0){
cpuio_bound(10,3,2);exit(0);}childret = waitpid(child1,NULL,0);if(childret == -1) {
printf("child1 fork error!\n");exit(0);}else {
printf("the child1 exit pid is %d\n!",childret);}childret = waitpid(child2,NULL,0);if(childret == -1) {
printf("child2 fork error!\n");exit(0);}else {
printf("the child2 exit pid is %d\n!",childret);}}return 0;
}
//改写主函数void cpuio_bound(int last, int cpu_time, int io_time)
{
struct tms start_time, current_time; clock_t utime, stime;int sleep_time;while (last > 0){
times(&start_time);do{
times(¤t_time);utime = current_time.tms_utime - start_time.tms_utime; stime = current_time.tms_stime - start_time.tms_stime;} while ( ( (utime + stime) / HZ ) < cpu_time );last -= cpu_time;if (last <= 0 )break;sleep_time=0;while (sleep_time < io_time){
sleep(1);sleep_time++;}last -= sleep_time;}
}
运行./stat_log.py 得到结果
这对于我来说就是最后一步了
再简单说一下 我们需要最后把process.c在linux-0.11下编译 运行后
等待我们结束process.c的多线程工作
之后sync 得到process.log 我们把其
复制到ubuntu中
stat_log.py 在home\teacher
中
我们把他复制到 我们的ubuntu process.log旁边
这样就可以用相对路径直接运行了
之后 我们先对脚本命令修改权限 chmod +x stat_log.py
运行命令看下图示例
最后提一嘴 你需要把你运行的进程进程号记下来
这样子 你最后跟踪的进程才是你想要的 在运行stat_log.py时限制统计进程号
防止统计到一些系统调用进程了
结束实验(含我的process.log 和 部分stat.py 运行结果)
这里就贴一下我的process.log 和 stat.py部分运行结果
可做参考
process.log
1 N 48
1 J 48
0 J 48
1 R 48
2 N 49
2 J 49
1 W 49
2 R 49
3 N 63
3 J 64
2 J 64
3 R 64
3 W 68
2 R 68
2 E 74
1 J 74
1 R 74
4 N 74
4 J 74
1 W 74
4 R 74
5 N 106
5 J 107
4 W 107
5 R 107
4 J 109
5 E 110
4 R 110
4 W 115
0 R 115
4 J 698
4 R 698
4 W 698
0 R 698
4 J 718
4 R 718
4 W 718
0 R 718
4 J 742
4 R 742
4 W 742
0 R 742
4 J 765
4 R 766
4 W 766
0 R 766
4 J 810
4 R 810
4 W 810
0 R 810
4 J 836
4 R 836
4 W 836
0 R 836
4 J 871
4 R 871
4 W 872
0 R 872
4 J 889
4 R 889
4 W 889
0 R 889
4 J 924
4 R 924
4 W 924
0 R 924
4 J 929
4 R 929
4 W 929
0 R 929
4 J 977
4 R 977
4 W 977
0 R 977
4 J 992
4 R 992
4 W 992
0 R 992
4 J 1013
4 R 1013
4 W 1013
0 R 1013
4 J 1018
4 R 1018
4 W 1018
0 R 1018
4 J 1106
4 R 1106
4 W 1106
0 R 1106
4 J 1111
4 R 1111
4 W 1111
0 R 1111
4 J 1135
4 R 1135
4 W 1135
0 R 1135
4 J 1156
4 R 1156
4 W 1156
0 R 1156
4 J 1160
4 R 1160
4 W 1160
0 R 1160
4 J 1177
4 R 1177
4 W 1177
0 R 1177
4 J 1188
4 R 1188
4 W 1188
0 R 1188
4 J 1198
4 R 1198
4 W 1198
0 R 1198
4 J 1270
4 R 1270
4 W 1270
0 R 1270
4 J 1291
4 R 1291
4 W 1291
0 R 1291
4 J 1337
4 R 1337
4 W 1337
0 R 1337
4 J 1357
4 R 1357
4 W 1357
0 R 1357
4 J 1380
4 R 1380
4 W 1380
0 R 1380
4 J 1399
4 R 1399
4 W 1399
0 R 1399
4 J 1422
4 R 1422
4 W 1422
0 R 1422
4 J 1449
4 R 1449
4 W 1449
0 R 1449
4 J 1468
4 R 1469
4 W 1469
0 R 1469
4 J 1544
4 R 1544
4 W 1544
0 R 1544
4 J 1577
4 R 1577
4 W 1577
0 R 1577
4 J 1630
4 R 1630
4 W 1630
0 R 1630
4 J 1651
4 R 1651
4 W 1651
0 R 1651
4 J 1806
4 R 1806
4 W 1806
0 R 1806
4 J 1814
4 R 1814
4 W 1814
0 R 1814
4 J 1833
4 R 1833
4 W 1833
0 R 1833
4 J 1858
4 R 1858
4 W 1858
0 R 1858
4 J 1902
4 R 1902
4 W 1902
0 R 1902
4 J 1921
4 R 1921
4 W 1921
0 R 1921
4 J 1988
4 R 1989
4 W 1989
0 R 1989
4 J 2014
4 R 2014
4 W 2014
0 R 2014
4 J 2037
4 R 2037
4 W 2037
0 R 2037
4 J 2052
4 R 2052
4 W 2052
0 R 2052
4 J 2093
4 R 2093
4 W 2093
0 R 2094
4 J 2119
4 R 2119
4 W 2119
0 R 2119
4 J 2149
4 R 2150
4 W 2150
0 R 2150
4 J 2172
4 R 2172
4 W 2172
0 R 2172
4 J 2201
4 R 2201
4 W 2201
0 R 2202
4 J 2229
4 R 2229
4 W 2229
0 R 2229
4 J 2253
4 R 2253
4 W 2253
0 R 2253
4 J 2279
4 R 2279
4 W 2279
0 R 2279
4 J 2386
4 R 2386
4 W 2386
0 R 2386
4 J 2424
4 R 2424
4 W 2424
0 R 2424
4 J 2454
4 R 2454
4 W 2455
0 R 2455
4 J 2474
4 R 2474
4 W 2474
0 R 2474
4 J 2477
4 R 2477
4 W 2477
0 R 2477
4 J 2521
4 R 2521
4 W 2521
0 R 2521
4 J 2526
4 R 2526
4 W 2526
0 R 2526
4 J 2553
4 R 2553
4 W 2553
0 R 2553
4 J 2566
4 R 2566
4 W 2566
0 R 2566
4 J 2581
4 R 2581
4 W 2581
0 R 2581
4 J 2612
4 R 2612
4 W 2612
0 R 2612
4 J 2636
4 R 2636
4 W 2636
0 R 2636
4 J 2679
4 R 2679
4 W 2679
0 R 2679
4 J 2701
4 R 2701
4 W 2701
0 R 2701
4 J 2711
4 R 2711
4 W 2711
0 R 2711
4 J 2740
4 R 2740
4 W 2740
0 R 2740
4 J 2749
4 R 2750
4 W 2750
0 R 2750
4 J 2771
4 R 2771
4 W 2771
0 R 2771
4 J 2848
4 R 2848
4 W 2848
0 R 2848
4 J 2872
4 R 2872
4 W 2872
0 R 2872
4 J 2986
4 R 2986
4 W 2986
0 R 2986
4 J 3008
4 R 3008
4 W 3008
0 R 3008
3 J 3067
3 R 3067
3 W 3067
0 R 3067
4 J 3281
4 R 3281
4 W 3281
0 R 3281
4 J 3307
4 R 3307
4 W 3307
0 R 3307
4 J 3348
4 R 3348
6 N 3350
6 J 3350
4 W 3351
6 R 3351
7 N 3355
7 J 3356
6 W 3356
7 R 3356
7 E 3411
6 J 3411
6 R 3411
8 N 3412
8 J 3413
6 W 3413
8 R 3413
8 E 3517
6 J 3517
6 R 3517
9 N 3518
9 J 3518
6 W 3518
9 R 3518
9 E 3547
6 J 3547
6 R 3547
10 N 3549
10 J 3549
6 W 3549
10 R 3549
10 E 3629
6 J 3629
6 R 3629
6 E 3631
4 J 3631
4 R 3631
11 N 3631
11 J 3632
4 W 3632
11 R 3632
4 J 3634
11 E 3635
4 R 3635
4 W 3635
0 R 3635
4 J 3913
4 R 3913
4 W 3913
0 R 3914
4 J 3931
4 R 3931
4 W 3931
0 R 3931
4 J 3958
4 R 3958
4 W 3958
0 R 3958
4 J 3984
4 R 3984
4 W 3984
0 R 3984
4 J 4019
4 R 4019
4 W 4020
0 R 4020
4 J 4038
4 R 4038
4 W 4038
0 R 4038
4 J 4055
4 R 4055
4 W 4055
0 R 4055
4 J 4098
4 R 4098
4 W 4098
0 R 4098
4 J 4099
4 R 4099
4 W 4099
0 R 4099
4 J 4122
4 R 4122
4 W 4122
0 R 4122
4 J 4152
4 R 4152
4 W 4152
0 R 4152
4 J 4168
4 R 4168
4 W 4168
0 R 4168
4 J 4194
4 R 4194
4 W 4194
0 R 4194
4 J 4218
4 R 4218
4 W 4219
0 R 4219
4 J 4240
4 R 4240
4 W 4240
0 R 4240
4 J 4258
4 R 4258
4 W 4258
0 R 4258
4 J 4271
4 R 4271
4 W 4271
0 R 4271
4 J 4290
4 R 4290
4 W 4290
0 R 4290
4 J 4313
4 R 4313
12 N 4314
12 J 4314
4 W 4315
12 R 4315
13 N 4316
13 J 4317
14 N 4317
14 J 4317
12 W 4317
14 R 4317
14 J 4332
13 R 4332
13 J 4347
14 R 4347
14 J 4362
13 R 4362
13 J 4377
14 R 4377
14 J 4392
13 R 4392
13 J 4407
14 R 4407
14 J 4422
13 R 4422
13 J 4437
14 R 4437
14 J 4452
13 R 4452
13 J 4467
14 R 4467
14 J 4482
13 R 4482
13 J 4497
14 R 4497
14 J 4512
13 R 4512
13 W 4522
14 R 4522
13 J 4627
14 J 4627
13 R 4627
13 J 4656
14 R 4656
14 J 4671
13 R 4671
13 J 4686
14 R 4686
14 J 4701
13 R 4701
13 J 4716
14 R 4716
14 J 4731
13 R 4731
13 J 4746
14 R 4746
14 J 4761
13 R 4761
13 J 4776
14 R 4776
14 J 4791
13 R 4791
13 W 4802
14 R 4802
14 W 4817
0 R 4817
13 J 4903
13 R 4903
14 J 4926
13 J 4926
14 R 4926
14 W 4926
13 R 4926
13 W 5003
0 R 5003
14 J 5027
14 R 5027
13 J 5116
14 J 5116
13 R 5116
13 J 5144
14 R 5144
14 J 5159
13 R 5159
13 J 5174
14 R 5174
14 J 5189
13 R 5189
13 J 5204
14 R 5204
14 J 5219
13 R 5219
13 J 5234
14 R 5234
14 J 5249
13 R 5249
13 J 5264
14 R 5264
14 J 5279
13 R 5279
13 W 5291
14 R 5291
13 J 5396
14 J 5396
13 R 5396
13 J 5425
14 R 5425
14 J 5440
13 R 5440
13 J 5455
14 R 5455
14 J 5470
13 R 5470
13 J 5485
14 R 5485
14 W 5486
13 R 5486
13 W 5527
0 R 5527
14 J 5587
14 R 5587
14 W 5587
0 R 5587
13 J 5628
13 R 5628
13 E 5628
12 J 5628
12 R 5628
12 W 5628
0 R 5629
14 J 5688
14 R 5688
14 E 5688
12 J 5688
12 R 5688
12 E 5689
4 J 5689
4 R 5689
15 N 5689
15 J 5690
4 W 5690
15 R 5690
4 J 5692
15 E 5693
4 R 5693
4 W 5693
0 R 5693
4 J 6014
4 R 6014
4 W 6014
0 R 6014
4 J 6043
4 R 6043
4 W 6043
0 R 6043
4 J 6088
4 R 6088
4 W 6088
0 R 6088
4 J 6108
4 R 6108
4 W 6108
0 R 6108
4 J 6215
4 R 6215
4 W 6215
0 R 6215
4 J 6240
4 R 6240
4 W 6240
0 R 6240
4 J 6282
4 R 6282
4 W 6282
0 R 6282
4 J 6305
4 R 6305
4 W 6305
0 R 6305
4 J 6434
4 R 6434
4 W 6434
0 R 6434
4 J 6467
4 R 6467
4 W 6467
0 R 6467
4 J 6512
4 R 6512
4 W 6512
0 R 6512
4 J 6536
4 R 6536
4 W 6536
0 R 6536
4 J 6858
4 R 6858
16 N 6860
16 J 6860
4 W 6861
16 R 6861
stat_log.py 运行部分 切换进程结果
完结撒花
结束惹 恰饭去了 晚上8:44了