操作系统实验一 添加系统调用实现对value值读写及关闭线程

操作系统实验一 添加系统调用实现对value值读写及关闭线程

操作系统:ubuntu

内核版本:kernel5.5.5

一 整体思路

​ 计算机分为用户态和内核态两种状态,用户态是上层应用程序的活动空间,被限制不能直接接触底层。内核态直接控制硬件,对用户态提供运行环境。二者之间有访管控制,不允许直接访问。如果从用户态进入内核态,就需要系统调用。系统调用就是一系列的用户态和内核态的接口函数。

​ 自己添加系统调用,需要三步。

​ 一、在系统调用表里添加系统调用号

​ 二、声明系统调用服务例程原型

​ 三、实现系统调用函数

修改内核代码完成后,编译重启,就可以调用自己的系统调用函数了。

实现的调用函数功能:传入pid,可以读取进程的value和prio值,可以修改value值,可以杀死进程。

二 具体实现

我的内核版本是5.5.5,所以内核根目录在usr/src/linux-5.5.5,进入目录操作

​ 一、在系统调用表里添加系统调用号

​ 系统调用表是./arch/x86/entry/syscalls/syscall64.tbl

​ 在表尾部添加系统调用号

​ 未被占用的调用号 x32/x64/common 系统调用名 服务例程入口

550 common mysetprocess __x64_sys_mysetprocess

​ 二、

​ 服务例程原型声明在 ./include/linux/syscalls.h

asmlinkage int sys_mysetprocess(pid_t pid, int flag, int nicevalue,void __user * prio, void __user * nice);

​ 五个参数:

​ pid:操作线程的pid

​ flag: 操作码,读取value值0,修改value值1,杀死进程2

​ nicevalue:要修改的value值

​ prio,nice:调用copy_to_user()函数把内核态读取到的prio,nice传递给用户

三、实现系统调用函数

	在./kernel/sys.c中实现系统调用函数
SYSCALL_DEFINE5(mysetprocess,pid_t,pid, int, flag, int, nicevalue,void __user *, prio, void __user *, nice){
if(find_get_pid(pid)==NULL){
	printk("input pid error.");
	return EFAULT;
}
struct pid * kpid;
struct task_struct * task;
kpid = find_get_pid(pid);
task = pid_task(kpid,PIDTYPE_PID);
int cur_nice;
int cur_prio;
cur_nice=task_nice(task);
cur_prio=task_prio(task);
if(flag==1){
	//set process's nice
	set_user_nice(task,nicevalue);
	cur_nice=task_nice(task);
	cur_prio=task_prio(task);
	printk("the nice value is changed!\n");
	printk("current nice is %d and piro is %d.\n",cur_nice,cur_prio);
}else if(flag==0){
	//get process's nice
	printk("current nice is %d and piro is %d.\n",cur_nice,cur_prio);
}else if(flag==2){
	//safely kill process by pid
	kill_pid(kpid,SIGTERM,1);
	printk("process is killed safely.\n");
	return 0;
}else{
	printk("operate failed.\n");
	return EFAULT;
}
copy_to_user(prio,&cur_prio,sizeof(cur_prio));
copy_to_user(nice,&cur_nice,sizeof(cur_nice));
return 0;
}

使用的函数简单说明

​ find_get_pid(pid_t nr)

​ 根据进程号nr得到进程描述符struct pid

​ pid_task(struct pid* pid,enum pid_type)

​ PIDTYPE_PID表示进程的进程号这一类型

​ 根据进程描述符返回任务描述符

​ task_nice(const struct task_struct *p ),nice范围-20-19

​ 返回进程nice值

​ task_prio(const struct task_struct *p)

​ 返回进程prio值

​ set_user_nice(struct task_struct *p, long nice)

​ 设置进程的nice值

​ kill_pid(struct pid *pid, int sig, int priv)

​ sig设为SIGTERM程序结束信号,SIGTERM可以被阻塞和处理,要程序正常退出。

​ priv设为1,发送SEND_SIG_PRIV信号,

​ 发送进程描述符,结束信号,杀死进程

​ copy_to_user(void __user *to, const void *from, unsigned long n)

​ 从内核空间拷贝内容到用户空间

​ n表示拷贝空间大小

四、编译内核

​ 编译内核耗时长(单核的话要约两小时),占用空间大(至少准备30G空间),要耐心等待

​ 在linux-5.5.5目录下

​ make menuconfig 选择save后exit

​ make -j4 (推荐使用多核编译,快一倍左右,虚拟机分配核数越多参数可以更大)

​ make modules_install

​ make install

​ 使用uname -r 查看当前内核版本,判断是否编译成功

​ make clean 清理编译文件(一定要用,清理之前编译的占用空间)

​ 重启

​ 如果编译有问题,推荐去看这篇文章添加链接描述,介绍的很详细

五、测试系统调用

​ 编写c程序,测试系统调用是否添加成功

#define _GNU_SOURCE 
#include <unistd.h>
#include <sys/syscall.h>
#include <stdio.h>

int main(){
    int pid,flag,nicevalue,prio,nice;
    char control;
 
    printf("请输入pid:\n");
    scanf("%d",&pid);
    printf("读入:0,修改:1, 杀死: 2 \n");
    scanf("%d",&flag);
    if(flag!=0&&flag!=1&&flag!=2){
        printf("输入错误");
        return 1;
    }

    if(flag==0){
        int res = syscall(550,pid ,flag,0,&prio,&nice);
        if(res!=0){
            printf("进程不存在!\n");
            return 1;
        }
        printf("进程的nice值为%d,prio值为%d\n",nice,prio);
    }else if(flag==1){
        printf("请输入要修改的nice值:\n");
        scanf("%d",&nicevalue);
        int res = syscall(550,pid,flag,nicevalue,&prio,&nice);
        if(res!=0){
            printf("进程不存在!\n");
            return 1;
        }
        printf("修改成功!\n");
        printf("进程的nice值为%d,prio值为%d\n",nice,prio);
    }else if(flag==2){
	int res = syscall(550,pid,flag,0,&prio,&nice);
	if(res!=0){
            printf("进程不存在!\n");
            return 1;
        }
	
	printf("杀死进程成功.\n");
    }
 
 return 0;

}

运行测试:
在这里插入图片描述
dmesg里的日志记录
在这里插入图片描述

成功!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值