当前位置:   article > 正文

Linux操作系统实验2——进程描述_山东大学操作系统实验

山东大学操作系统实验

实验要求:

1.查看task_struct的结构,找到其中的pid,state,prio,parent pid字段

2.在task_struct结构中找到vma相关字段,vm_start,vm_end,vm_next

3.打印指定pid的基本信息,包括基本信息及VMA内存区的信息。

4.显示dmesg的查看内核模块的输出信息里的vma地址,和通过cat /proc/pid/maps命令显示内容一致。

 实验原理:

1.linux内核中进程控制块结构,linux内核管理进程的数据结构及其访问方法:

其结构大概如上图,即task_struct。其中定义了子进程、父进程、优先级和进程状态等字段。不同内核版本的字段名可能不一样。

访问方法就是定义一个进程控制块task_struct类型的指针,然后通过指针获取进程号、优先级等字段属性。

2.linux系统中vm结构,linux系统中vm的管理以及vm链表的组织形式:

Linux中,虚存是通过链表的形式管理的,利用vm_next指针可以指向下一个地址块节点。

获取虚存地址时,先定义一个进程控制块指针p,利用p的mm指针找到mm_struct中的mmap指针(指向虚存区域列表),进而找到每块虚存地址的起始地址。

3.内核模块参数传递,加载内核模块时候的参数传递方法:

其实就是函数module_param(pid,int,0644)的使用,第一个参数为参数名,第二个参数为参数类型,第三个参数为指定了在sysfs中相应文件的访问权限。

加载内核模块时,需要在命令后边给参数赋值,比如:

本实验中,pid对应的进程必须存在且正在运行,否则会提示“已杀死”:

参考代码:

 task_struct.c:

  1. # include <linux/kernel.h>
  2. # include <linux/module.h>
  3. # include <linux/sched.h>
  4. # include <linux/init_task.h>
  5. # include <linux/init.h>
  6. # include <linux/fdtable.h>
  7. # include <linux/fs_struct.h>
  8. # include <linux/mm_types.h>
  9. MODULE_LICENSE("GPL");
  10. //内核模块初始化函数
  11. static int __init print_pid(void)
  12. {
  13. struct task_struct *task, *p;
  14. struct list_head *pos;
  15. int count=0;
  16. printk("Printf process'message begin:\n");
  17. task = &init_task;
  18. //遍历进程链表
  19. list_for_each(pos,&task->tasks)
  20. {
  21. p = list_entry(pos,struct task_struct,tasks);
  22. count++;
  23. printk("\n\n");
  24. printk("pid:%d; state:%lx; prio:%d; static_prio:%d; parent'pid:%d; count:%d; umask:%d;", \
  25. p->pid,p->__state,p->prio,p->static_prio,(p->parent)->pid, \
  26. atomic_read((&(p->files)->count)),(p->fs)->umask);
  27. if((p->mm)!=NULL)
  28. printk("total_vm:%ld;",(p->mm)->total_vm);
  29. }
  30. printk("进程的个数:%d\n",count);
  31. return 0;
  32. }
  33. //内核模块退出函数
  34. static void __exit pid_exit(void)
  35. {
  36. printk("exiting...\n");
  37. }
  38. module_init(print_pid);
  39. module_exit(pid_exit);

  task_struct.c对应Makefile文件:

  1. #Makefile文件注意:假如前面的.c文件起名为first.c,那么这里的Makefile文件中的.o文
  2. #件就要起名为first.o 只有root用户才能加载和卸载模块
  3. obj-m:=task_struct.o #产生task_struct模块的目标文件
  4. #目标文件 文件 要与模块名字相同
  5. CURRENT_PATH:=$(shell pwd) #模块所在的当前路径
  6. LINUX_KERNEL:=$(shell uname -r) #linux内核代码的当前版本
  7. LINUX_KERNEL_PATH:=/usr/src/linux-headers-$(LINUX_KERNEL)
  8. all:
  9. make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules #编译模块
  10. #[Tab] 内核的路径 当前目录编译完放哪 表明编译的是内核模块
  11. clean:
  12. make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean #清理模块

mem.c:

  1. #include<linux/module.h>
  2. #include<linux/init.h>
  3. #include<linux/interrupt.h>
  4. #include<linux/sched.h>
  5. static int pid;
  6. module_param(pid,int,0644);
  7. static int __init memtest_init(void){
  8. struct task_struct *p;
  9. //struct task_struct *p1;
  10. struct vm_area_struct *temp;
  11. printk("The virtual memory areas(VMA) are:\n");
  12. p=pid_task(find_vpid(pid),PIDTYPE_PID);//该函数因内核版本而稍有不同
  13. //printk("%p\n",p);
  14. //p1=pid_task(find_get_pid(pid),PIDTYPE_PID);
  15. //printk("%p\n",p1);
  16. temp=p->mm->mmap;
  17. while(temp){
  18. //printk("start:%p\tend:%p\n",(unsigned long*)temp->vm_start,(unsigned long*)temp->vm_end);
  19. //printk("start:%x\tend:%x\n",(unsigned long*)temp->vm_start,(unsigned long*)temp->vm_end);
  20. printk("start:%lx\tend:%lx\n",(unsigned long*)temp->vm_start,(unsigned long*)temp->vm_end);
  21. //printk("start:%pK\tend:%pK\n",(unsigned long*)temp->vm_start,(unsigned long*)temp->vm_end);
  22. temp=temp->vm_next;
  23. }
  24. return 0;
  25. }
  26. static void __exit memtest_exit(void){
  27. printk("Unloading my module.\n");
  28. return;
  29. }
  30. module_init(memtest_init);
  31. module_exit(memtest_exit);
  32. MODULE_LICENSE("GPL");

mem.c对应Makefile文件:

  1. #Makefile文件注意:假如前面的.c文件起名为first.c,那么这里的Makefile文件中的.o文
  2. #件就要起名为first.o 只有root用户才能加载和卸载模块
  3. obj-m:=mem.o #产生task_struct模块的目标文件
  4. #目标文件 文件 要与模块名字相同
  5. CURRENT_PATH:=$(shell pwd) #模块所在的当前路径
  6. LINUX_KERNEL:=$(shell uname -r) #linux内核代码的当前版本
  7. LINUX_KERNEL_PATH:=/usr/src/linux-headers-$(LINUX_KERNEL)
  8. all:
  9. make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules #编译模块
  10. #[Tab] 内核的路径 当前目录编译完放哪 表明编译的是内核模块
  11. clean:
  12. make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean #清理模块

 exam.c:

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<unistd.h>
  4. #include<sys/mman.h>
  5. #include<sys/types.h>
  6. #include<sys/stat.h>
  7. #include<fcntl.h>
  8. int main(){
  9. int i,fd;
  10. char * buf;
  11. printf("pid=%d\n",getpid());
  12. sleep(500);
  13. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/577574
推荐阅读
相关标签
  

闽ICP备14008679号