给 Minix 内核的进程消息计数

the minix book

Minix 是个有别于 Linux 单内核的微内核操作系统,系统各个模块之间采用发消息的方式互相通信。在这本经典操作系统书:Operating Systems Design and Implementation, 3/E 的第219页有个练习题:

44. Add code to the MINIX 3 kernel to keep track of the number of messages sent from process (or task) i to process (or task) j. Print this matrix when the F4 key is hit.

这个练习题要比修改 Minix 内核的进程调度简单多了,只需要:

  1. 为每个进程初始化一个计数器;
  2. 在每次进程发消息的时候计数;
  3. 找到 Minix 在什么地方触发 F4 键,并把每个进程的计数器打印出来就可以了。

代码

在 proc.h 的 proc 进程数据结构里定义一个计数器 p_mess[NR_TASKS + NR_PROCS]:

struct proc {
...
  unsigned long p_mess[NR_TASKS + NR_PROCS];
};

在 main.c 的 main 里初始化计数器:

for (j = 0; j < NR_TASKS + NR_PROCS; j++) rp->p_mess[j] = 0;

在 proc.c 的 sys_call 里计数:

switch(function) {
  case SENDREC:
      /* A flag is set so that notifications cannot interrupt SENDREC. */
      priv(caller_ptr)->s_flags |= SENDREC_BUSY;
      /* fall through */
  case SEND:
      result = mini_send(caller_ptr, src_dst, m_ptr, flags);
      if (function == SEND || result != OK) {
          break;                                /* done, or SEND failed */
      }                                         /* fall through for SENDREC */
      if (result == OK)
          rp->p_mess[NR_TASKS+src_dst]++;
  case RECEIVE:
      if (function == RECEIVE)
          priv(caller_ptr)->s_flags &= ~SENDREC_BUSY;
      result = mini_receive(caller_ptr, src_dst, m_ptr, flags);
      break;
  case NOTIFY:
      result = mini_notify(caller_ptr, src_dst);
      break;
  case ECHO:
      CopyMess(caller_ptr->p_nr, caller_ptr, m_ptr, caller_ptr, m_ptr);
      result = OK;
      break;
  default:
      result = EBADCALL;                        /* illegal system call */
}

最后按 F4 打印出来,修改 dmp_kernel.c 的 privileges_dmp:

  printf("\n---- message track table dump ----\n\n");
  printf("-nr-             ", proc_nr(rp));
  for (rp = oldrp; rp < oldrp+10; rp++) {
        printf("[%2d]  ", proc_nr(rp));
  }
  printf("\n");
  /*for (rp = oldrp; rp < END_PROC_ADDR; rp++) {*/
  for (rp = oldrp; rp < oldrp+10; rp++) {
      if (isemptyp(rp)) continue;
          printf("\n[%2d]  %-7.7s  ", proc_nr(rp), rp->p_name);
          for (i = 0; i < 10; i++) {
              printf(" %4lu ", rp->p_mess[i]);
              rp->p_mess[i] = 0;
        }
  }

编译内核和服务,并重新用新内核启动:

# cd /usr/src/tools
# make clean
# make hdboot; make services
# reboot

注意:如果修改了 proc.h 文件,一定要 make clean 以后再 make hdboot; make services 编译内核和服务以后才能正常启动,如果没有修改 proc.h 只修改了 .c 文件可以只 make hdboot.

评论 (5 Comments)

  1. vpsee,一直不能理解billable的意义,能予以解释一下吗 ?^_^

  2. 1个 billable process 是可以用来记账(bill)的进程,主要是记录 clock ticks,每个进程都有限量的 clock ticks 运行时间,每次 clock tick 都会引发 bill_ptr 指着的那个进程被记账(clock ticks – 1)。书上应该有详细解释。

  3. 正好在做这题,sys_call in proc.c 里面没有define rp,应该用caller_ptr

  4. @Anonymous
    这个是2009年的 Minix,现在的 Minix 版本有了很大变化。

  5. 我用的是 书上 那个 3.1.0 版本 minix,privileges_dmp 那个 部分 一直有错啊, compiler 报错。请问 你知道怎么改么?

发表评论