一:题目介绍
修改或返回指定进程的优先级(nice值和prio值)(详见教材P328)
提示:可能参考的内核函数:set_user_nice()
二:思路分析
图1:系统调用总流程
描述:本实验主要实现了系统调用的添加,其过程书上已经详细给出,先在系统调用表中添加系统调用号,再申明添加的系统调用,最后开始编写内核函数。至此添加系统调用已经完成,之后为了使用它,将内核编译和安装。重启之后使用内核并编写测试文件来调用系统调用。
图2:内核函数流程
描述:在该内核函数中,先根据输入的pid值指定进程,并返回进程控制块,借此来获得该进程的nice和prio值。之后再根据输入的flag标志来判断是否要更改指定进程的nice和prio值。若flag=0,则不更改,通过copy_to_user()函数将其写入用户空间以便使用,若flag=1,则通过set_user_nice()函数进行更改,之后再利用copy_to_user()函数将其写入用户空间以便使用。该代码中主要使用了五个信号量。其中四个为功能实现中使用者需要输入的值:pid(指定进程),nice(需要输出进程的值),flag(判断是否要更改的值),nicevalue(更改后的进程的nice值)。还有一个需要输出的进程的prio值,但由于prio根据nice值的更改而更改,所以该值不要使用者输入,自动变化。
三:遇到问题及解决方法
问题:gcc版本太高出解决方法:gcc9版本太高有些不兼容,之后下载gcc8解决。
问题:一开始将问题想的太简单,对内核函数传参传入nice时,想在内核函数中直接将nice值修改,但是运行后失败
解决方法:查询后是发现内核空间和用户空间不能直接互访,所以必须使用copy_to_user ()函数来在内核函数内改变nice值。
问题:No rule to make target 'debian/certs/benh@debian.org.cert.pem', needed by 'certs/x509_certificate_list'. Stop.
解决方法:进入.Config将CONFIG_SYSTEM_TRUSTED_KEYS设为空
问题:虚拟机内存较小,导致编译内核以及安装之后无法打开
解决方法:重新建立一个虚拟机将内存设置为60G,内核设置4个
问题:虚拟机重启之后无法转换到指定的内核
解决方法:修改grub文件将GRUB_TIMEOUT_STYLE注释掉,并将GRUB_TIMEOUT改为10
四:代码及注释
内核函数及注释:
SYSCALL_DEFINE5(setorlook,pid_t,pid,int,flag,int,nicevalue,void __user*,prio,void __user*,nice)
{
int n;
int p;
struct pid * kpid;
struct task_struct * task;
kpid = find_get_pid(pid);/*得到pid */
task = pid_task(kpid, PIDTYPE_PID);/* 返回task_struct */
n = task_nice(task);/* 返回进程当前nice值 */
p = task_prio(task);/*返回进程当前prio值*/
if(flag == 1)
{
set_user_nice(task, nicevalue);/* 修改进程nice值 */
n = task_nice(task);/*重新取得进程nice值*/
p = task_prio(task);/*重新取得进程prio值*/
copy_to_user(nice,&n,sizeof(n));/*将nice值拷贝到用户空间*/
copy_to_user(prio,&p,sizeof(p));/*将prio值拷贝到用户空间*/
return 0;
}
else if(flag == 0)
{
copy_to_user(nice,&n,sizeof(n));/*将nice值拷贝到用户空间*/
copy_to_user(prio,&p,sizeof(p));/*将prio值拷贝到用户空间*/
return 0;
}
return EFAULT;
}
测试代码:
#define _GNU_SOURCE
#include<unistd.h>
#include<sys/syscall.h>
#include<stdio.h>
#include<stdlib.h>
int main()
{
pid_t pid;
int nicevalue;
int flag;
int n=0;
int p=0;
int *prio;
int *nice;
prio = &p;
nice = &n;
printf("请输入你所指定的pid: \n");
scanf("%d",&pid);
printf("指定的pid输入成功\n");
printf("请输入flag (flag为1时修改信息,为0时查看信息):\n");
scanf("%d",&flag);
if(flag==1){
printf("请输入nice值:\n");
scanf("%d",&nicevalue);
printf("nice输入成功\n");
}
else{
nicevalue=0;
}
syscall(335,pid,flag,nicevalue,prio,nice);
printf("pid为%d的进程目前的nice为%d,prio为%d\n",pid,n,p);
return 0;
}
五:实验结果
图三:包含更改和查看进程的实验结果