📂
build a OS
  • Learn OS with me
  • OS Interfaces
    • OS interfaces
    • I/O and File descriptors
    • Process and Memory
    • Pipes
    • File
  • OS Organization
    • OS Organization
    • Challenge yourself
  • Memory Management
    • XV6 Virtual Memory
    • Page Table
      • Part 1: How to translate address
      • Part 2: Create an Address Space
      • Part 3: How Page Table is used
      • Part 4: Page Fault and Swap
      • Part 5: How to operate on page tables
    • xv6 buddy allocator
      • How to display physical memory
    • Memory Management Walk Through
  • Traps and Interrupts
    • Trap Home Page
      • 系统调用的核心原理
    • What is trapframe
    • What is trampoline
    • Traps from kernel space
    • How fork() works
    • How system calls get into/out of the kernel
    • How exec() works
  • Scheduling
    • XV6 CPU Scheduling
    • How unix pipes work?
    • How does wait(), exit(), kill() work?
  • File System
    • Overview and Disk Layout
    • Buffer Cache
    • Design Inode Layer
    • Inode Content
    • Block Allocator
    • Design a log system for crash recovery
    • Directory Layer
    • Path names
    • File Descriptor Layer
    • FS System Calls
    • XV6 VS Real World
    • Make Xv6 File disk management system
    • Write FS simulator in python
    • How Redirect Shell command works
  • Concurrency
    • Spinlock
    • How linux select work
    • Hardware Support Locking
    • Exercise: Implement atomic counter
    • Locking in Xv6
    • Concurrency in Xv6
    • Exercise: Socket Programming with Event loop
  • Labs
    • Lab 1 Xv6 and Unix utilities
    • Lab 2 Shell
    • Lab 3 Buddy Allocator
    • Lab 4 Lazy
    • Lab 5 Copy-on-Write Fork for xv6
    • Lab 6 RISC-V assembly
    • Lab 6 Uthread: switching between threads
    • Lab 6 Alarm
    • Lab 7 Lock
    • Lab 8 File System: Large Files
    • Lab 8 File System: Symbolic links
    • Lab 9 mmap
    • Lab 10 Networking Part 1
    • Lab 10 Networking Part 2
  • Hardware, Device, Assembly
    • RISC-V assembly
    • Assembly: Access and Store information in Memory
    • Start xv6 and the first process
    • Why first user process loads another program?
    • What does kernel.ld do in XV6?
    • XV6 Device Driver
Powered by GitBook
On this page
  • Introduction
  • Task
  • Hints
  • Solution
  • Add 2 system calls
  • Add alarm infos in Process state
  • Handler alarm in trap handler
  • Implement system calls
  • 心得

Was this helpful?

  1. Labs

Lab 6 Alarm

Implement a primitive form of user-level interrupt/fault handlers.

PreviousLab 6 Uthread: switching between threadsNextLab 7 Lock

Last updated 5 years ago

Was this helpful?

Introduction

In this exercise you'll add a feature to xv6 that periodically alerts a process as it uses CPU time. This might be useful for compute-bound processes that want to limit how much CPU time they chew up, or for processes that want to compute but also want to take some periodic action. More generally, you’ll be implementing a primitive form of user-level interrupt/fault handlers; you could use something similar to handle page faults in the application, for example.

Task

Add a new sigalarm(interval, handler) system call. If an application calls sigalarm(n, fn), then after every n “ticks” of CPU time that the program consumes, the kernel should cause application function fn to be called. When fn returns, the application should resume where it left off. A tick is a fairly arbitrary unit of time in xv6, determined by how often a hardware timer generates interrupts.

Hints

Test code calls sigalarm to set up alarm so that call function periodic after 2 ticks. periodic is the handler code after alarm is fired.

It calls sigreturn at the end to reset process state to before the alarm fired.

Test code
void
periodic()
{
  count = count + 1;
  printf("alarm!\n");
  sigreturn();
}

// tests whether the kernel calls
// the alarm handler even a single time.
void
test0()
{
  int i;
  printf("test0 start\n");
  count = 0;
  sigalarm(2, periodic);
  for(i = 0; i < 1000*500000; i++){
    if((i % 1000000) == 0)
      write(2, ".", 1);
    if(count > 0)
      break;
  }
  sigalarm(0, 0);
  if(count > 0){
    printf("test0 passed\n");
  } else {
    printf("\ntest0 failed: the kernel never called the alarm handler\n");
  }
}

Solution

Add 2 system calls

int sigalarm(int ticks, void (*handler)());
int sigreturn(void);

Add alarm infos in Process state

  uint64 handler;
  int ticks;
  int cur_ticks;
  struct trapframe *alarm_tf; // cache the trapframe when timer fires
  int alarm_on;

Initialize cur_ticks in allocproc (process allocation method). p->cur_ticks = 0;

Handler alarm in trap handler

Save trapframe snapshot in process new field alarm_tf Increment ticks. If ticks is reaching max, set epc program counter to the handler, so handler is called once trap is returned to user space.

if((which_dev = devintr()) != 0){
    // lab 6 alarm
    if (which_dev == 2 && p->alarm_on == 0) {
      // Save trapframe
      p->alarm_on = 1;
      struct trapframe *tf = kalloc();
      memmove(tf, p->tf, PGSIZE);
      p->alarm_tf = tf;

      p->cur_ticks++;
        if (p->cur_ticks >= p->ticks)
        p->tf->epc = p->handler;
    }

Implement system calls

sigalarm saves function handler and max ticks to process state.

uint64 sys_sigalarm(void)
{
  uint64 addr;
  int ticks;

  if(argint(0, &ticks) < 0)
    return -1;
  if(argaddr(1, &addr) < 0)
    return -1;

  myproc()->ticks = ticks;
  myproc()->handler = addr;

  return 0;
}

sigreturn is called after alarm is fired, alarm handler is called, and handled by user space. It restores trapframe page from alarm_tf. Clean up ticks info.

uint64 sys_sigreturn(void)
{
  struct proc *p = myproc();
  memmove(p->tf, p->alarm_tf, PGSIZE);

  kfree(p->alarm_tf);
  p->alarm_tf = 0;
  p->alarm_on = 0;
  p->cur_ticks = 0;
  return 0;
}

心得

在内核的帮助下,用户端也可以实现‘中断’。用system call来启动, 设置好中断后要做的操作,当tick到了设定好的时长,执行记录的操作,操作结束调回用户程序中断前的snapshot. 这样可以再用户端实现分配器,分配用户程序的时长。

Lab: user-level threads and alarm