操作系统实验:Linux内核进程

文章来源:
https://blog.csdn.net/qq_43561345/article/details/110420372
https://www.cnblogs.com/nanfengnan/p/14931891.html

任务一:练习在内核模块中打印linux PCB中的关键信息
任务要求:
(1)遍历系统中的所有task,打印每个task的PID、其父进程PID、进程优先级、进程静态优先级、进程状态信息(十六进制打印),每个task信息占一行,要求打印出的信息清晰美观。
(2)统计系统中当前正在运行的进程数,并打印。
提示:
1、遍历系统中所有进程所使用的接口for_each_process,定义在头文件<linux/sched.h>中。
2、求打印的关键信息和结构体成员的对应关系如下:
task PID(pid)
父进程PID(real_parent->pid)
进程优先级(prio)
进程静态优先级(static_prio)
进程状态(state)
实验步骤
实验内容一
1、编写模块代码(文件名hello.c,随便创建一个文件夹放在里边就好)

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>

// 初始化函数
static int hello_init(void)
{
    int count=0;//记录当前系统中的进程数目
    struct task_struct *p;  //Linux内核的进程控制块是task_struct结构体,所有运行在系统中的进程都以task_struct链表的形式存在内核中
    printk(KERN_ALERT"pid\tparent->pid\tprio\tstatic_prio\tstate\t");
    for_each_process(p)  //for_each_process是一个宏,在sched.h里面定义: 是从init_task开始遍历系统所有进程,init_task是进程结构链表头。
    {
        if(p->mm == NULL){ //对于内核线程,mm为NULL
            printk(KERN_ALERT"%d\t%d\t\t%ld\t%ld\t\t%x\n",p->pid, p->real_parent->pid, p->prio, p->static_prio, p->state);
        }
        if(p->state == 0){
			count++;
		}
    }
    printk("The number of currently running processes:%d\n",count);
    return 0;
}
// 清理函数
static void hello_exit(void)
{
    printk(KERN_ALERT"goodbye!\n");
}

// 函数注册
module_init(hello_init);  
module_exit(hello_exit);  
// 模块许可申明
MODULE_LICENSE("GPL");  

2、编写Makefile(文件名Makefile,下面代码中,$(MAKE)前面的是Tab,不是单纯的空格)这个文件和hello.c写在一个文件夹内

obj-m:=hello.o
PWD:= $(shell pwd)
KERNELDIR:= /lib/modules/$(shell uname -r)/build
EXTRA_CFLAGS= -O0

all:
	make -C $(KERNELDIR)  M=$(PWD) modules
clean:
	make -C $(KERNELDIR) M=$(PWD) clean

obj-m: 编译成可动态加载的module,通过insmod动态重定位装入到内核
obj-y: 静态编译链接进内核,在系统启动过程中进行初始化
在这里插入图片描述
3、编译,添加模块,并输出日志
(1)编译

make

(2)添加模块

insmod hello.ko

(3)输出日志查看效果

dmesg

(4)若要修改hello.c代码,重新添加同名模块前需要先卸载模块,否则会报错。

rmmod hello.ko

在这里插入图片描述
任务二:体会linux用户线程和内核线程
背景知识:Linux 实现线程由两部分组成:内核的线程支持+用户态的库支持(glibc)。Linux 在早期的时候并不支持内核级线程,因此在用户态的 glibc 库中就以用户态线程的方式支持多线程了,每个线程都有一个 id,我们给它叫 utid(或 tid)。后来的 Linux 内核支持多线程了,一个进程中的所有内核线程属于同一组,每个内核线程有唯一的编号,我们给它起名为 ktid(以区别用户态 tid),于是一个线程就有了两个编号,utid 和和 ktid。这里强调的是,用户级线程遵循 POSIX 标准,具有可移植性。可以看到 Linux 中,用户级线程与内核级线程是一对一模型。
任务要求
在用户空间进程中创建一个线程,分别打印主线程、新创建线程两个线程的PID、在用户空间的id、线程在内核空间中的id。
提示
(1)创建用户线程的接口:pthread_create
(2)获取线程用户空间id的接口:pthread_self()
(3)获取线程在内核空间id的方法:gettid(),但此系统调用没有被封装到库中,因此可以先使用:#define gettid() syscall(__NR_gettid),声明之后再使用。

#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/syscall.h>

//定义宏
#define gettid() syscall(__NR_gettid)

//主要加深用户线程和内核级线程对应的模型
pthread_t ntid;

void *printids(void *s)
{
        pid_t pid; //进程号
        pid_t ktid; //内核级线程号
        pthread_t utid; //用户级线程号

        pid = getpid();  //得到当前进程号
        ktid = gettid(); //获得内核级线程线程号
        utid = pthread_self(); //获得用户级线程号

        //s是外部传入进来的参数
        printf("%s pid %u ktid %u utid %u (0x%x)\n",
                (char *)s,(unsigned int)pid,(unsigned int)ktid,
                (unsigned int)utid,(unsigned int)utid);
        pause();
}
int main(void)
{
        //主线程main()调用pthread_create创建一个子线程
        pthread_create(&ntid,NULL,&printids,"new thread:");

        //主线程main()调用printids()打印自己的线程号和所属的进程号
        printids("main thread:");
        sleep(1);

        return 0;
}

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值