Linux0.11 实验四 进程运行轨迹跟踪与统计

实验4 进程运行轨迹跟踪与统计

pid	X	time

其中:- pid是进程的ID

  • X可以是N,J,R,W和E中的任意一个
    • N 进程新建 ,new
    • J 进入就绪态 , J
    • R 进入运行态 , run
    • W 进入阻塞态, wait
    • E 退出 ,exit
  • time表示X发生的时间。这个时间不是物理时间,而是系统的滴答时间(tick)

仔细阅读sched.c文件

本实验主要分析整个的调度流程,主要方法是,当发生状态转换时,进程的state变化时,我们把这个记录记下来。

打印函数

先看看打印函数:

static char logbuf[1024];

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)		/* 如果输出到stdout或stderr,直接调用sys_write即可 */
	{
    
    
		__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 	/* 假定>=3的描述符都与文件关联。事实上,还存在很多其他情况,这里并没有考虑 */
	{
    
    
		if (!(file=task[0]->filp[fd]))		/* 从进程0的文件描述符表中得到文件句柄 */
			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"  //使用file_write,往文件/var/process.log中写入。
			"addl $12, %%esp\n\t"
			"popl %0\n\t"
			"pop %%fs"
			::"r" (count), "r" (file), "r" (inode)
			:"ax", "cx", "dx");
	}
	return count;
}

linux源码中,只有这几种状态:

#define TASK_RUNNING		0  //正在运行或者已就绪
#define TASK_INTERRUPTIBLE	1  //进程处于可中断等待状态
#define TASK_UNINTERRUPTIBLE	2 //程序处于不可中断等待状态,主要用于I/O操作等待。
#define TASK_ZOMBIE		3   //程序处于僵死状态,已经停止运行,但父进程还没发信号。
#define TASK_STOPPED		4 //程序已停止。

N 进程新建 ,new

新进程在fork的时候产生,fork的关键是copy_process

int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,
		long ebx,long ecx,long edx,
		long fs,long es,long ds,
		long eip,long cs,long eflags,long esp,long ss)
{
    
    
	...
	p->start_time = jiffies;

	fprintk(3, "%ld\t%c\t%ld\n", last_pid, 'N', jiffies); //新建
	...
	p->state = TASK_RUNNING;	/* do this last, just in case */
    
	fprintk(3, "%ld\t%c\t%ld\n", last_pid, 'J', jiffies); //完成后,立马进入就绪态。

	return last_pid;
}

W 进入阻塞态, wait

//系统调用waitpid(),挂起当前进程,直到pid指定的子进程退出。
int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
{
    
    
	...
	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;
		else
			return -EINTR;
	}
	return -ECHILD;
}

E 退出 ,exit

int do_exit(long code)
{
    
    
	...
	current->state = TASK_ZOMBIE;
	fprintk(3, "%ld\t%c\t%ld\n", current->pid, 'E', jiffies);
	/* print message end in 3-processTack */
	current->exit_code = code;
	tell_father(current->father);
	schedule();
	return (-1);	/* just to suppress warnings */
}

就绪与运行

void schedule(void)

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));//到点,给信号alarm
					(*p)->alarm = 0;
				}
			if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) && //除去被block掉的信号,还有其他信号,
			(*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;//检查所有任务中,最需要被调度的进程,将这个号码放入next,这个就是下次要调度的进程。
		}
		if (c) break;	/* 找到一个counter不等于0 且是TASK_RUNNING状态中的counter最大的进程;或者当前系统没有一个可以运行的进程,此时c=-1, next=0,进程0得到调度,所以调度算法是不在意进程0的状态是不是TASK_RUNNING,这就意味这进程0可以直接从睡眠切换到运行! */
		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)

/*
 * 系统无事可做的时候,进程0会不停地调用sys_pause(),以激活调度算法。此时它的状态可以是等待态,
 * 等待有其他可运行的进程;也可以是运行态,因为它是唯一一个在CPU上运行的进程,只不过运行的效果是等待。
 */
int sys_pause(void)
{
    
    
	current->state = TASK_INTERRUPTIBLE;
	if (current->pid != 0) //进程0死循环,一直调用这个函数。防止一直打印。
	{
    
    
		fprintk(3, "%ld\t%c\t%ld\n", current->pid, 'W', jiffies);
	} 
	schedule();
	return 0;
}

void sleep_on(struct task_struct **p)

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插入“等待队列”头部,tmp是原来的头部 */
	current->state = TASK_UNINTERRUPTIBLE;
	fprintk(3, "%ld\t%c\t%ld\n", current->pid, 'W', jiffies);
	schedule();
	if (tmp) {
    
    
		fprintk(3, "%ld\t%c\t%ld\n", tmp->pid, 'J', jiffies);
		/* print message end in 3-processTack */
		tmp->state=TASK_RUNNING;	/* 唤醒队列中的上一个(tmp)睡眠进程。0换作TASK_RUNNING更好。在记录进程被唤醒时一定要考虑到这种情况,实验者一定要注意!!! */
	}
}

void interruptible_sleep_on(struct task_struct **p)

/*
 * TASK_UNINTERRUPTIBLE和TASK_INTERRUPTIBLE的区别在于不可中断的睡眠只能由wake_up()显示唤醒,
 * 再由上面的 schedule()语句后面的
 *
 * if (tmp) tmp->state=0;
 *
 * 依次唤醒,所以不可中断的睡眠一定是严格按照从“队列”(一个依靠放在进程内核栈中的指针变量tmp
 * 维护的队列)的首部进行唤醒。而对于可中断的进程,除了用wake_up唤醒以外,也可以用信号(给进程
 * 发送一个信号,实际上就是将进程PCB中维护的一个向量的某一位置位,进程需要在合适的时候处理
 * 这一位。感兴趣的实验者可以阅读有关代码)来唤醒,如在 schedule()中:
 *
 * for(p = &LAST_TASK; p > &FRIST_TASK; --p)
 * 		if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&
 * 			(*p)->state==TASK_INTERRUPTIBLE)
 * 			(*p)->state=TASK_RUNNING;//唤醒
 *
 * 就是当进程是可中断睡眠时,如果遇到一些信号就将其唤醒。这样的唤醒会出现一个问题,那就是可能会
 * 唤醒等待队列中间的某个进程,此时这个链就需要进行适当调整。interruptible_sleep_on和sleep_on
 * 函数的主要区别就在这里。
 */
void interruptible_sleep_on(struct task_struct **p) //将当前任务置为可中断的等待状态,并放入*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; //等待的任务可中断。
	schedule();//只有当进程被唤醒才会回到这里。
	if (*p && *p != current) {
    
    //此current不等于当时的current,说明队列中间有任务被唤醒了。
		(**p).state=TASK_RUNNING;//将队头唤醒。
        fprintk(3, "%ld\t%c\t%ld\n", (*p)->pid, 'J', jiffies);
		goto repeat;//重新调度。
	}
	*p=NULL;
	if (tmp)//从队头开始,逐个释放。
		tmp->state=0;
    	fprintk(3, "%ld\t%c\t%ld\n", (*p)->pid, 'J', jiffies);
}

void wake_up(struct task_struct **p)

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;
	}
}

进程运行log分析

1	N	48	copy_process	//进程1新建(init())。此前是进程0建立和运行,我们是在move_to_user_mode后才新建/var/process.log文件进行进程运行轨迹记录的,所以进程0的新建和运行没有出现在log文件里
1	J	48	copy_process	//新建后进入就绪队列
0	J	48	schedule		/* --- 进程0从运行->就绪,让出CPU。(执行的是pause,调用)
1	R	48	schedule				进程1运行 --- */
2	N	49	copy_process	/* --- 进程1建立进程2。
2	J	49	copy_process			进程2会运行/etc/rc脚本,然后退出 --- */
1	W	49	sys_waitpid		//进程1开始等待(等待进程2退出)
2	R	49	schedule		//进程2运行
3	N	64	copy_process	/* --- 进程2建立进程3
3	J	64	copy_process			进程3是/bin/sh建立的运行脚本的子进程 --- */
2	E	68	do_exit			//进程2不等进程3退出,就先走一步了
1	J	68	schedule		/* --- 进程1此前在等待进程2退出,被阻塞。进程2退出后,重新进入就绪队列
1	R	68	schedule				进程1运行 --- */
4	N	69	copy_process	/* --- 进程1建立进程4,即shell
4	J	69	copy_process			进程4进入就绪队列 --- */
1	W	69	sys_waitpid		//进程1等待shell退出(除非执行exit命令,否则shell不会退出)
3	R	69	schedule		//进程3开始运行
3	W	75	sys_pause		//进程3主动睡觉,让出CPU
4	R	75	schedule		//进程4开始运行
5	N	107	copy_process	/* --- 进程5是shell建立的不知道做什么的进程(可能是ls命令?)
5	J	107	copy_process			进程5新建后进入就绪队列 --- */
4	W	108	sleep_on		//进程4进入不可中断睡眠状态
5	R	108	schedule		//进程5开始运行
4	J	110	wake_up			//进程5唤醒睡觉的进程4,进程4进入就绪队列
5	E	110	do_exit			//进程5很快退出
4	R	110	schedule		//进程4执行
4	W	115	interruptible_sleep_on	//shell等待用户输入命令
0	R	115	schedule		//因为无事可做,所以进程0重出江湖
4	J	902	wake_up			//用户开始输入命令了,唤醒了shell(从等待用户输入到用户开始输入命令总共经历了将近8s)
4	R	902	schedule		//进程4执行
4	W	903	interruptible_sleep_on	//shell等待用户输入命令
0	R	903	schedule		//因为无事可做,进程0再次执行
4	J	953	wake_up			//用户接着输入命令,唤醒shell(shell等待了0.5s)
4	R	953	schedule		//进程4执行
4	W	953	interruptible_sleep_on	//shell等待用户输入命令
0	R	953	schedule		//因为无事可做,进程0再次执行
4	J	1003	wake_up		//用户接着输入命令,唤醒shell(shell等待了0.5s)
4	R	1003	schedule	//shell执行
4	W	1003	interruptible_sleep_on	//shell等待用户输入
0	R	1003	schedule	//因为无事可做,进程0再次执行
4	J	1056	wake_up		//用户接着输入命令,唤醒shell(shell等待了0.53s)
4	R	1056	schedule	//shell执行
4	W	1056	interruptible_sleep_on	//shell等待用户输入
0	R	1056	schedule	//因为无事可做,进程0再次执行
4	J	1182	wake_up		//用户接着输入命令,唤醒shell(shell等待了1.26s),该命令输入完毕(用户输入该命令总共经历了将近1.8s)
4	R	1182	schedule	//shell执行
6	N	1184	copy_process	/* --- 进程6是shell建立的不知道做什么的进程
6	J	1185	copy_process			进程6进入就绪队列 --- */
4	W	1185	sys_waitpid		//shell开始等待(等待进程6退出)
6	R	1185	schedule		//进程6开始执行
6	E	1191	do_exit			//进程6很快退出
4	J	1191	schedule		//shell此前在等待进程6退出,被阻塞。进程6退出后,重新进入就绪队列
4	R	1191	schedule		//shell执行
7	N	1192	copy_process	/* --- 进程7是shell建立的不知道做什么的进程
7	J	1192	copy_process			进程7进入就绪队列 --- */
4	J	1193	schedule		/* --- shell从运行->就绪,让出CPU。
7	R	1193	schedule				进程7开始运行 --- */
7	E	1195	do_exit			//进程7很快退出
4	R	1195	schedule		//shell执行
4	W	1196	interruptible_sleep_on	//shell等待用户输入命令
0	R	1196	schedule		//因为无事可做,进程0再次执行
4	J	1251	wake_up			//用户开始输入命令,唤醒了shell(从等待用户输入命令到用户开始输入命令,总共经历了0.55s)
4	R	1251	schedule		//shell执行
4	W	1251	interruptible_sleep_on	//shell等待用户继续输入命令
0	R	1252	schedule		//因为无事可做,进程0再次执行
4	J	2345	wake_up			//用户接着输入命令,唤醒shell(shell等待了0.93s)
4	R	2345	schedule		//shell执行
4	W	2345	interruptible_sleep_on	//shell等待用户输入
0	R	2345	schedule		//因为无事可做,进程0再次执行
4	J	2386	wake_up			//用户接着输入命令,唤醒shell(shell等待了0.41s)
4	R	2386	schedule		//shell执行
4	W	2386	interruptible_sleep_on	//shell等待用户输入
0	R	2386	schedule		//因为无事可做,进程0再次执行
4	J	2823	wake_up			//用户接着输入命令,唤醒shell(shell等待了4.37s)
4	R	2823	schedule		//shell执行
4	W	2823	interruptible_sleep_on	//shell等待用户输入
0	R	2823	schedule		//因为无事可做,进程0再次执行
4	J	2864	wake_up			//用户接着输入命令,唤醒shell(shell等待了0.41s)
4	R	2864	schedule		//shell执行
4	W	2864	interruptible_sleep_on	//shell等待用户输入
0	R	2864	schedule		//因为无事可做,进程0再次执行
4	J	2898	wake_up			//用户接着输入命令,唤醒shell(shell等待了0.34s)
4	R	2898	schedule		//shell执行
4	W	2898	interruptible_sleep_on	//shell等待用户继续输入
0	R	2898	schedule		//因为无事可做,进程0再次执行
4	J	2936	wake_up			//用户接着输入命令,唤醒shell(shell等待了0.38s)
4	R	2936	schedule		//shell执行
4	W	2936	interruptible_sleep_on	//shell等待用户输入
0	R	2936	schedule		//因为无事可做,进程0再次执行
4	J	3046	wake_up			//用户接着输入命令,唤醒shell(shell等待了1.1s)
4	R	3046	schedule		//shell执行
4	W	3046	interruptible_sleep_on	//shell等待用户输入
0	R	3046	schedule		//因为无事可做,进程0再次执行
3	J	3074	schedule		/* --- 进程3从睡眠->就绪。
3	R	3074	schedule				进程3运行(进程3由于长时间睡觉,其优先级变高,进入就绪队列后立即得到调度执行) --- */
3	W	3074	sys_pause		//进程3主动睡觉,让出CPU
0	R	3074	schedule		//因为无事可做,进程0再次执行
4	J	3099	wake_up			//用户接着输入命令,唤醒shell(shell等待了0.53s)
4	R	3100	schedule		//shell执行
4	W	3100	interruptible_sleep_on	//shell等待用户输入
0	R	3100	schedule		//因为无事可做,进程0再次执行
4	J	3416	wake_up			//用户接着输入命令,唤醒shell(shell等待了3.16s)
4	R	3417	schedule		//shell执行
4	W	3417	interruptible_sleep_on	//shell等待用户输入
0	R	3417	schedule		//因为无事可做,进程0再次执行
4	J	3457	wake_up			//用户接着输入命令,唤醒shell(shell等待了0.4s)
4	R	3457	schedule		//shell执行
4	W	3457	interruptible_sleep_on	//shell等待用户输入
0	R	3457	schedule		//因为无事可做,进程0再次执行
4	J	3623	wake_up			//用户接着输入命令,唤醒shell(shell等待了1.66s)
4	R	3623	schedule		//shell执行
4	W	3623	interruptible_sleep_on	//shell等待用户输入
0	R	3623	schedule		//因为无事可做,进程0再次执行
4	J	3687	wake_up			//用户接着输入命令,唤醒shell(shell等待了0.64s)
4	R	3687	schedule		//shell执行
4	W	3687	interruptible_sleep_on	//shell等待用户输入
0	R	3687	schedule
    
    
    ....
    
    
0	R	7494	schedule				//因为无事可做,进程0再次运行
4	J	7560	wake_up					//用户继续输入命令,唤醒shell(shell等待了0.66s)
4	R	7560	schedule				//shell执行
4	W	7560	interruptible_sleep_on	//shell等待用户输入
0	R	7561	schedule				//因为无事可做,进程0再次执行
4	J	7617	wake_up					//用户继续输入命令,唤醒shell(shell等待了0.56s)
4	R	7617	schedule				//shell执行
4	W	7617	interruptible_sleep_on	//shell等待用户输入
0	R	7617	schedule				//因为无事可做,进程0再次执行
4	J	8090	wake_up					//用户继续输入命令,唤醒shell(shell等待了3.73s),该命令输入完毕(用户输入该命令总共经历了67.39s,一分钟的时间,用户输入不可能这么长!那么这个命令是什么?全部是由用户输入?)
4	R	8090	schedule				//shell执行该命令
8	N	8092	copy_process			/* --- shell新建进程8(估计是gcc编译process.c生成可执行文件process的命令)。
8	J	8093	copy_process					进程8新建后进入就绪队列 --- */
4	W	8093	sys_waitpid				//shell开始等待进程8退出
8	R	8093	schedule				//进程8开始运行
9	N	8098	copy_process			/* --- 进程8新建进程9(估计是gcc用于编译process.c的预处理子进程?)。
9	J	8098	copy_process					进程9新建后进入就绪队列 --- */
8	W	8099	sys_waitpid				//进程8开始等待进程9退出
9	R	8099	schedule				//进程9开始运行
9	E	8159	do_exit					//进程9退出(运行了0.6s)
8	J	8159	schedule				/* --- 进程8此前在等待进程9退出,被阻塞。进程9退出后,重新进入就绪队列。
8	R	8159	schedule						进程8运行 --- */
10	N	8160	copy_process			/* --- 进程8新建进程10(估计是gcc用于编译process.c的编译子进程,生成汇编代码?)。
10	J	8161	copy_process					进程10新建后进入就绪队列 --- */
8	W	8161	sys_waitpid				//进程8开始等待进程10退出
10	R	8161	schedule				//进程10开始运行
10	E	8295	do_exit					//进程10退出(运行了1.34s)
8	J	8295	schedule				/* --- 进程8此前在等待进程10退出,被阻塞。进程10退出后,重新进入就绪队列。
8	R	8295	schedule						进程8继续运行 --- */
11	N	8295	copy_process			/* --- 进程8新建进程11(估计是gcc用于编译process.c的汇编子进程,生成二进制目标文件?)。
11	J	8296	copy_process					进程11新建后进入就绪队列 --- */
8	W	8296	sys_waitpid				//进程8开始等待进程11退出
11	R	8296	schedule				//进程11开始运行
11	E	8341	do_exit					//进程11退出(运行了0.45s)
8	J	8341	schedule				/* --- 进程8此前在等待进程11退出,被阻塞。进程11退出后,重新进入就绪队列。
8	R	8341	schedule						进程8继续运行 --- */
12	N	8343	copy_process			/* --- 进程8新建进程12(估计是gcc用于编译process.c的链接子进程,生成可执行文件process?)。
12	J	8344	copy_process					进程12新建后进入就绪队列 --- */
8	W	8344	sys_waitpid				//进程8开始等待进程12退出
12	R	8344	schedule				//进程12开始运行
12	E	8425	do_exit					//进程12退出(运行了0.81s)
8	J	8425	schedule				/* --- 进程8此前在等待进程12退出,被阻塞。进程12退出后,重新进入就绪队列。
8	R	8425	schedule						进程8继续运行 --- */
8	E	8427	do_exit					//进程8退出(gcc编译process.c生成process可执行文件经历了3.34s)
4	J	8427	schedule				/* --- shell此前在等待进程8退出,被阻塞。进程8退出后,重新进入就绪队列
4	R	8427	schedule						shell运行 --- */
13	N	8427	copy_process			/* --- shell新建进程13(不知道是做什么的进程)。
13	J	8428	copy_process					进程13新建后进入就绪队列 --- */
4	W	8428	sleep_on				//进程4进入不可中断睡眠状态
13	R	8428	schedule				//进程13开始运行
4	J	8430	wake_up					//进程13唤醒睡觉的进程4,进程4进入就绪队列
13	E	8431	do_exit					//进程13很快退出(运行了0.03s)
4	R	8431	schedule				//shell运行
4	W	8432	interruptible_sleep_on	//shell等待用户输入命令
0	R	8432	schedule				//因为无事可做,进程0再次执行
4	J	9737	wake_up					//用户开始输入命令,唤醒了shell(从等待用户输入命令到用户开始输入命令,总共经历了13s!为什么会这么长时间?)
4	R	9737	schedule				//shell运行
4	W	9737	interruptible_sleep_on	//shell等待用户输入命令
0	R	9737	schedule				//因为无事可做,进程0再次执行
4	J	9790	wake_up					//用户接着输入命令,唤醒了shell(shell等待了0.53s)
4	R	9790	schedule				//shell运行
4	W	9790	interruptible_sleep_on	//shell等待用户输入命令
    
    ......
0	R	11136	schedule				//因为无事可做,进程0再次执行
4	J	11195	wake_up					//用户接着输入命令,唤醒了shell(shell等待了0.59s)
4	R	11195	schedule				//shell运行
4	W	11195	interruptible_sleep_on	//shell等待用户输入命令
0	R	11196	schedule				//因为无事可做,进程0再次执行
4	J	12048	wake_up					//用户接着输入命令,唤醒了shell(shell等待了8.52s),该命令输入完毕(用户输入该命令总共经历了231s!输入不可能需要这么长时间!说明计时单位并不是10ms???)
4	R	12048	schedule				//shell执行该命令(即我们自己编写的样本程序process可执行文件)
14	N	12049	copy_process			/* --- shell新建进程14(即process.c的main()函数)。
14	J	12049	copy_process					进程14新建后进入就绪队列 --- */
4	W	12049	sys_waitpid				//shell开始等待进程14(process.c的main()函数)退出
14	R	12050	schedule				//进程14(process.c的main()函数)开始运行
15	N	12051	copy_process			/* --- main()函数新建进程15(N1 node)。
15	J	12051	copy_process					进程15(N1 node)新建后进入就绪队列 --- */
16	N	12052	copy_process			/* --- main()函数新建进程16(N2 node)。
16	J	12052	copy_process					进程16(N2 node)新建后进入就绪队列 --- */
14	W	12053	sys_waitpid				//进程14(现在为process.c的main()函数中的Root)开始等待进程15(N1 node)和进程16(N2 node)退出
16	R	12053	schedule				//进程16(N2 node)开始运行
17	N	12053	copy_process			/* --- 进程16新建进程17(N5 node)。
17	J	12053	copy_process					进程17(N5 node)新建后进入就绪队列 --- */
16	W	12054	sys_pause				//进程16(N2 node)主动睡觉
17	R	12054	schedule				//进程17(N5 node)开始运行
17	J	12069	schedule				/* --- 进程17(n5 node)时间片(15个滴答)耗完,从运行->就绪(运行了0.15s),让出CPU。
15	R	12069	schedule						进程15(N1 node)开始运行 --- */
18	N	12069	copy_process			/* --- 进程15(N1 node)新建进程18(N3 node)。
18	J	12069	copy_process					进程18(N3 node)新建后进入就绪队列 --- */
19	N	12070	copy_process			/* --- 进程15(N1 node)新建进程19(N4 node)。
19	J	12070	copy_process					进程19(N4 node)新建后进入就绪队列 --- */
15	J	12084	schedule				/* --- 进程15(N1 node)时间片耗完,从运行->就绪(运行了0.15s),让出CPU。
19	R	12084	schedule						进程19(N4 node)开始运行 --- */
19	J	12099	schedule				/* --- 进程19(N4 node)时间片耗完,从运行->就绪(运行了0.15s),让出CPU。
18	R	12099	schedule						进程18(N3 node)开始运行 --- */
18	J	12114	schedule				/* --- 进程18(N3 node)时间片耗完,从运行->就绪(运行了0.15s),让出CPU。
19	R	12114	schedule						进程19(N4 node)运行 --- */
19	J	12129	schedule				/* --- 进程19(N4 node)时间片耗完,从运行->就绪(运行了0.15s),让出CPU。 
18	R	12129	schedule						进程18(N3 node)开始运行 --- */ 
18	J	12144	schedule				/* --- 进程18(N3 node)时间片耗完,从运行->就绪(运行了0.15s),让出CPU。 
17	R	12144	schedule						进程17(N5 node)运行 --- */ 
16	J	12159	schedule				/* --- 进程16(N2 node)被唤醒。
17	J	12159	schedule						进程17(N5 node)时间片耗完,从运行->就绪(运行了0.15s),让出CPU。
16	R	12159	schedule						进程16(N2 node)运行 --- */

猜你喜欢

转载自blog.csdn.net/qq_38307618/article/details/124399345