2

I'm trying to implement the priority round robin scheduling system in xv6 after fixing some lock errors which were causing a panic error but now I keep running into a booting error and my kernel gets stuck before booting up completely.

xv6 kernel is booting

hart 2 starting
hart 1 starting

After this my kernel stops booting and gets stuck.

Sometimes the hart starting order changes from 1 then 2 and sometimes 2 then 1 starts.

My scheduler is defined in proc.c as follows:-

scheduler(void)
{
  struct proc *p;
  struct cpu *c = mycpu();
  struct proc *highp = 0;
  
  c->proc = 0;
  for(;;){
    // Avoid deadlock by ensuring that devices can interrupt.
    intr_on();

    for(p = proc; p < &proc[NPROC]; p++) {
      if (p->state != RUNNABLE)
      continue;
      if (highp == 0 || p->priority > highp->priority)
      highp = p;
      if (highp != 0) {
        continue;
      }
      }

      if (ticks-lastagingtime > 100) {
        struct proc *p;
        for (p = proc ; p < &proc[NPROC]; p++) {
          if (p->state == SLEEPING || p->state == RUNNABLE)
          p->priority++;
        }
        lastagingtime = ticks;

      }
     
    }
  }

My setpriority is defined in proc.c as follows:-

setpriority(int pid, int priority)
{
  struct  proc *p;
  for (p = proc; p < &proc[NPROC]; p++) {
    if (p->pid == pid) {
       p->priority = priority;
    }
  }
    return pid;
}

I acquired a spinlock for looping over process table and then released it in the end then returned the pid value.

Now I keep running into this booting error and my kernel gets stuck.

Any idea how to solve this error or what necessary changes I should make?

I'm a beginner and any inputs would be extremely helpful !

Ayxux
  • 21
  • 3

1 Answers1

1

You still (because I remember the first question version) have issue in for loops:

  • You do not lock spinlock before modifying proc (acquire / release functions)
  • You do not switch to process to run it (swtch function)

I think (I didn't test it, I didn't have installed the needed qemu) that a corrected code should looks like:

scheduler(void)
{
    struct proc *p;
    struct cpu *c = mycpu();
    struct proc *highp = 0;
 
    c->proc = 0;
    for(;;){
        // Avoid deadlock by ensuring that devices can interrupt.
        intr_on();
        
        // try to find the highest priority process and put in in highp
        for(p = proc; p < &proc[NPROC]; p++) {
            acquire(&p->lock);
            if (p->state == RUNNABLE && (highp == 0 || (p->priority > highp->priority))) {
                highp = p;
            }
            release(&p->lock);
        }
        
        // at this point highp is the highest priority process to run
        acquire(&highp->lock);
        highp->state = RUNNING;
        c->proc = highp;
        swtch(&c->context, &highp->context);
        release(&highp->lock);
        
        
        if (ticks-lastagingtime > 100) {
            struct proc *p;
            for (p = proc ; p < &proc[NPROC]; p++) {
                acquire(&p->lock);
                if (p->state == SLEEPING || p->state == RUNNABLE)
                    p->priority++;
                release(&p->lock);
            }
            lastagingtime = ticks;
        }     
    }
}
setpriority(int pid, int priority)
{
    struct  proc *p;
    for (p = proc; p < &proc[NPROC]; p++) {
        acquire(&p->lock);
        if (p->pid == pid) {
            p->priority = priority;
        }
        release(&p->lock);
    }
    return pid;
}

But I don't think that you priority field is used well.

You should have two members:

  • base_priority (set by setpriority syscall)
  • dynamic_priority increased by the second for loop in scheduler())

and the dynamic_priority should be used to determine which process is to be runned (first for loop) and reset to base_priority after the process is runned (after swtch call)


This part of answer was bound to the first question version: acquire/release was placed quite randomly into for loops.

Your problem is in the for loops.

In scheduler and setpriority functions, the pattern is

for (p = proc...) {
    acquire(&p->lock);
    
    // some processing
    
    release(&p->lock);
}

If during some processing you call continue or break, the spinlock (p->lock) acquired won't be released.

Yet calling acquire on a already acquired spinlock leads to a kernel panic (see acquire definition in kernel/spinlock.c file.

Mathieu
  • 8,840
  • 7
  • 32
  • 45
  • Thank you for the clarification I removed the locks and the panic error stopped occurring. But when I'm trying to reboot xv6, it's showing a new problem as follows:- `xv6 kernel is booting hart 1 starting hart 2 starting` After this the kernel stops booting. I'm really confused about what to do. – Ayxux Jun 19 '23 at 08:32
  • 1
    @AyxuxPlease edit your question to post the code that is actually running, please to not post image, and use formatting options, see https://stackoverflow.com/editing-help#code – Mathieu Jun 19 '23 at 11:09