哈工大-操作系统-HitOSlab-李治军-实验3-进程运行的轨迹跟踪与统计

操作系统实验3:进程运行轨迹的跟踪与统计

实验内容请查看实验指导手册

绪论

开始实验之前,需要弄清楚实验具体要做什么:

  • 参考home/teacher目录下的process.c编写一个能够创建多个并行子进程的程序。
  • 在linux0.11系统的内核中,添加和修改程序,使得我们启动linux0.11并且运行process.c后,系统能够打印出一个监视进程运行的process.log文件

一、实验内容

1.编写process.c文件

process.c代码如下:

#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <sys/times.h>
#include <sys/types.h>

#define HZ	100

void cpuio_bound(int last, int cpu_time, int io_time);
/*
1.  所有子进程都并行运行,每个子进程的实际运行时间一般不超过30秒;
2.  父进程向标准输出打印所有子进程的id,并在所有子进程都退出后才退出;
*/
int main(int argc, char * argv[])
{
   
	pid_t n_proc[10]; /*10个子进程 PID*/
	int i;
	for(i=0;i<10;i++)
	{
   
		n_proc[i] = fork();
		/*如果fork 失败*/
		if(n_proc[i] < 0 )
		{
   
			printf("Failed to fork child process %d!\n",i+1);
			return -1;
		}
		else if(n_proc[i] == 0)/*子进程*/
		{
   
			cpuio_bound(20,2*i,20-2*i); /*每个子进程都占用20s*/
			exit(0); /*执行完cpuio_bound 以后,结束该子进程,下一次循环,该子进程不会fork出新的进程*/
		}
		/*一直都是那一个父进程在fork出子进程*/
	}
	/*打印所有子进程PID*/
	for(i=0;i<10;i++)
		printf("Child PID: %d\n",n_proc[i]);
	/*等待所有子进程完成;
	这里不是很完美,由于wait函数的特点,父进程只要有回收了一个子进程,就会结束自己*/
	wait(&i);  /*Linux 0.11 上 gcc要求必须有一个参数, gcc3.4+则不需要*/ 
	return 0;
}
/* cpuio_bound函数无需修改,直接用 */
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(&current_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;
	}
}

process.c的保存路径为~/oslab/hdc/usr/root/
如果你对fork()函数和wait()函数的作用以及工作方式还不是很清楚的话,建议你花点时间,看一下相关文章,这应该会帮助你更好的理解process.c程序的功能作用

2.日志文件

2.1 修改main.c

为了让linux0.11在启动之后,就创建process.log并开始记录,需要将~/oslab/linux-0.11/init/main.c文件做如下修改:

//……
move_to_user_mode();

/***************添加开始***************/
setup((void *) &drive_info);

// 建立文件描述符0和/dev/tty0的关联
(void) open("/dev/tty0",O_RDWR,0);    

//文件描述符1也和/dev/tty0关联
(void) dup(0);        

// 文件描述符2也和/dev/tty0关联
(void) dup(0);        

(void) open("/var/process.log",O_CREAT|O_TRUNC|O_WRONLY,0666);

/***************添加结束***************/

if (!fork()) {
           /* we count on this going ok */
    init();
}
//……
2.2 添加fprintk()函数

在内核状态下,write()功能失效,其原理等同于《系统调用》实验中不能在内核状态调用 printf(),只能调用printk()。编写可在内核调用的 write() 的难度较大,所以这里直接给出源码。它主要参考了 printk()sys_write()而写成的:因为和 printk()

### 哈工大操作系统实验3课程资料解析 #### 实验背景概述 哈工大操作系统实验系列由治军老师设计并提供支持,旨在帮助学生深入了解 Linux 内核的工作机制及其底层实现细节。实验三通常围绕进程管理和调度展开,重点在于让学生熟悉 Linux 进程创建、销毁及相关系统调用的实现过程[^1]。 #### 关键知识点总结 在实验三中,主要涉及以下几个方面的内容: 1. **fork() 系统调用**:用于创建新进程。通过分析 `kernel/fork.c` 文件中的代码,了解父进程如何复制其地址空间给子进程。 2. **execve() 系统调用**:负责加载新的程序到当前进程中执行。此部分需要阅读 `fs/exec.c` 中的相关源码。 3. **exit() 和 wait() 系统调用**:分别处理进程退出和等待子进程结束的功能。这些功能实现在 `kernel/exit.c` 和 `kernel/sched.c` 中。 4. **进程状态转换**:深入探讨进程的状态变化(运行态、就绪态、阻塞态),并通过调试工具观察实际运行情况。 以下是 fork 的核心逻辑示例代码片段: ```c asmlinkage int sys_fork(struct pt_regs regs) { return do_fork(SIGCHLD, regs.esp, &regs, 0); } ``` 上述代码展示了如何利用 `_syscall` 宏定义来简化用户层对内核服务接口的访问方式[^2]。 #### 配套环境搭建建议 由于 Linux 0.11 是早期版本的操作系统内核,在现代开发环境中无法直接编译运行。因此推荐使用 GCC 3.4 编译器配合 Bochs 或 QEMU 虚拟机模拟真实硬件平台完成整个构建流程[^3]。 #### 学习资源扩展 除了官方文档外,还可以参考以下补充材料进一步巩固所学知识: - 视频教程:关注 Bilibili 上关于嵌入式编程方向的内容创作者分享的经验贴; - 推荐书籍《Linux设备驱动程序》第三版作为辅助读物加深理解; - 访问 HIT OS Lab 官方网站获取最新动态更新和技术博客文章。
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值