xv6操作系统中增加一个系统调用

简要介绍一下xv6中增加系统调用的方法和步骤。

 

本文情景:xv6系统中,不自带Linux下的ps命令,不能直观查看各个进程的状态。为此,需要新增一个系统调用sys_cps(),通过它查看进程,将进程名,pid和优先级打印出来,为之后的调度算法实现做准备。

 

涉及到的文件有:

syscall.c
syscall.h
usys.S
user.h
sysproc.c
proc.c
proc.h
defs.h

 

准备工作

 

xv6中的进程是不带有优先级的,因此需要在进程结构体struct proc中加入一个表示优先级的成员。(在proc.h中)引入priority表示优先级,最终的proc如下:

// Per-process state
struct proc {
  uint sz;                     // Size of process memory (bytes)
  pde_t* pgdir;                // Page table
  char *kstack;                // Bottom of kernel stack for this process
  enum procstate state;        // Process state
  int pid;                     // Process ID
  struct proc *parent;         // Parent process
  struct trapframe *tf;        // Trap frame for current syscall
  struct context *context;     // swtch() here to run process
  void *chan;                  // If non-zero, sleeping on chan
  int killed;                  // If non-zero, have been killed
  struct file *ofile[NOFILE];  // Open files
  struct inode *cwd;           // Current directory
  char name[16];               // Process name (debugging)
  int priority;		           // (0-20)
};

在创建一个进程的时候,可以默认将其优先级设定为10,在proc.c中的allocproc函数中,found模块下,修改p->priority=10即可。(图中倒数第二行)

开始加入系统调用

 

其他的系统调用,可以参考本文方法,实现不同的函数。

 

1、首先,在proc.c中,实现具体的系统调用函数功能,此时它只是一个普通的函数,还不是一个系统调用。此处,实现的函数cps()功能即为遍历进程池,打印每个进程的信息,具体实现如下:(直接加在proc.c的最后)

int 
cps(void)
{
  struct proc *p;
  sti();	// Enable interrupts
  acquire(&ptable.lock);
  cprintf("name \t pid \t state \t \t priority \n");
  for(p = ptable.proc; p < &ptable.proc[NPROC]; p++)
  {
    if(p->state == SLEEPING)
    cprintf("%s \t %d \t SLEEPING \t %d\n", p->name, p->pid, p->priority);
    else if(p->state == RUNNING)
    cprintf("%s \t %d \t RUNNING \t %d\n", p->name, p->pid, p->priority);
    else if(p->state == RUNNABLE)
    cprintf("%s \t %d \t RUNNABLE \t %d\n", p->name, p->pid, p->priority);
  }
  release(&ptable.lock);
  return 22;
}

最后,cps()的返回值为22。因为cps()最终需要变成一个系统调用,而每个系统调用函数的返回值都是int,代表系统调用号。因此需要制定它的返回编号,在后续操作中,sys_cps的系统调用号即为22。

 

2、在user.h和defs.h中,定义该函数。(在defs.h中,定义在//proc.c那一块下),定义的语句均为:

int cps(void);

3、在usys.S的最后,加上:

SYSCALL(cps);

至此,完成了该函数的原型实现和用户系统调用接口。然而现在它还不是一个系统调用,需要进一步配置将其加入系统调用的范围。

 

4、在sys_call.h的最后,加入系统调用号的定义:(注意,第一步里面的函数名字(cps)和这里的系统调用标识(SYS_cps)不要同名,之后会有函数将其关联起来)

#define SYS_cps    22

5、在sys_call.c中,注册该函数:(一共有两处)

 

第一处:(很多extern的地方,在那一段最后加)

第二处:(在static int (*syscalls[])(void)的大括号中)

在这一步中,将系统调用标识SYS_cps和系统调用函数sys_cps关联起来了。

 

6、最后一步,也是最关键的,那就是如何将系统调用sys_cps和功能函数cps关联起来,也就是说,只有通过这一步,cps才能成为系统调用。

在sysproc.c中,添加对于sys_cps这个系统调用函数的具体实现:(一般而言,系统调用函数用普通功能函数作为返回。)

至此,系统调用sys_cps会调用函数cps,即实现了系统调用的实际功能。

 

总结

 

新增系统调用包括两大部分,一方面,需要在内核中注册它,让系统认为它是一个系统调用(包括系统调用编号、syscalls[]中的注册等),另一方面要实现系统调用的具体功能代码,这一部分和普通函数无差别。

 

其中,syscall.c、syscall.h两个文件定义了该系统调用标识SYS_cps和系统调用函数sys_cps,proc.c中的cps实现了该函数的具体功能,user.h和defs.h则具体定义了功能函数cps,usys.S则实现了用户访问系统调用的接口,而最后的sysproc.c是将用户和系统调用相连的关键部分。

 

最后,当前的系统调用已经添加好了。如何实现输入指令ps,执行本文所实现的系统调用,打印进程信息,请参考我另外一篇博客:https://blog.csdn.net/yyd19981117/article/details/95199634

  • 23
    点赞
  • 80
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值