2

Despite consulting the documentation, I still can't understand this line:swtch(&c->scheduler, &p->context);.

My question: I know this line is to switch p->context, including save registers and restore registers, but I can't understand the pc change in this process, that is what execution order of this code? After theswtch(&c->scheduler, &p->context); is executed, is it immedidate to execute c->proc = 0;, then the effect of executing c->proc=p; disappears? I am confused now.

code link: https://github.com/mit-pdos/xv6-riscv/blob/riscv/kernel/proc.c line 456


*// Per-CPU process scheduler.*
*// Each CPU calls scheduler() after setting itself up.*
*// Scheduler never returns.  It loops, doing:*
*//  - choose a process to run.*
*//  - swtch to start running that process.*
*//  - eventually that process transfers control*
*//    via swtch back to the scheduler.*
void
scheduler(void)
{
  struct proc *p;
  struct cpu *c = mycpu();

  c->proc = 0;
  for(;;){
    *// Avoid deadlock by ensuring that devices can interrupt.*
    intr_on();
    int found = 0;
    for(p = proc; p < &proc[NPROC]; p++) {
      acquire(&p->lock);
      if(p->state == RUNNABLE) {
        *// Switch to chosen process.  It is the process's job*
        *// to release its lock and then reacquire it*
        *// before jumping back to us.*
        p->state = RUNNING;
        c->proc = p;
        swtch(&c->scheduler, &p->context);

        *// Process is done running for now.*
        *// It should have changed its p->state before coming back.*
        c->proc = 0;
        found = 1;
      }
      release(&p->lock);
    }
    if(found == 0){
      intr_on();
      asm volatile("wfi");
    }
  }
}
RecharBao
  • 371
  • 2
  • 10
  • I think that it is just a bad code and nothing more. – Vlad from Moscow Jun 04 '21 at 11:19
  • Pay attention to swtch.S, I forget to mark it. – RecharBao Jun 04 '21 at 11:22
  • What don't you understand? – 0___________ Jun 04 '21 at 11:22
  • @Rchar show it here, I do not have a time to search for the code you do not understand. – 0___________ Jun 04 '21 at 11:23
  • The change in the value of the pc register during this process. – RecharBao Jun 04 '21 at 11:24
  • In the code shown I do not see any PC register change – 0___________ Jun 04 '21 at 11:24
  • What I mean is, after executing this line of code, is it going to continue to execute the following c->proc = 0;?Should not be – RecharBao Jun 04 '21 at 11:26
  • 2
    This is context switch. The function that it calls is using those parameters to continue running somewhere else, at a different address and with a different set of loaded registers. This is (very) roughly how any operating system changes the currently executing context. – Thomas Jager Jun 04 '21 at 11:28
  • So where will it be executed after the switch is completed? It should not be executed c->proc = 0; right? @ThomasJager – RecharBao Jun 04 '21 at 11:32
  • It depends on how you think about it executing. In this thread of execution, yes. However, globally, to the CPU, no. It'll probably be running in some other unrelated code in a specific thread. The point of a context switch is to keep running somewhere else. – Thomas Jager Jun 04 '21 at 11:37
  • If according to what you said, the processor will run c->proc = 0; at a certain moment; it may be immediately or after a while. In short, c->proc = 0 will be executed by CPU, then the proc[i] occupies the processor the time is only between c->proc = p; to p->proc = 0; the time is so short, – RecharBao Jun 04 '21 at 12:20
  • and however, the xv6 book states: Scheduler runs a simple loop: find a process to run, run it until it yields, yields is a function that can be used to give up the processor. Furthermore, after all of these executions are completed, it will enter the for loop again, resulting in all processes with p->state == RUNNABLE, change into p->state == RUNNING, which is obviously not feasible.@ThomasJager – RecharBao Jun 04 '21 at 12:21
  • I know what you said, the processor does switch between different threads, but it seems that it can't solve the problem here. – RecharBao Jun 04 '21 at 12:35

1 Answers1

1

This is literally the code that was so confusing that its original authors wrote "You are not expected to understand this" in the comments, so don't feel bad for not understanding it.

The key thing you may have missed is that p->context contains an address where swtch is to resume execution of process p. It's set up, for instance, here:

  // Set up new context to start executing at forkret,
  // which returns to user space.
  memset(&p->context, 0, sizeof(p->context));
  p->context.ra = (uint64)forkret;
  p->context.sp = p->kstack + PGSIZE;

So, when the scheduler calls swtch, it is effectively making an indirect function call to whatever p->context.ra points to. That code will execute for some indefinite period, and then eventually (sort of) return to swtch, which returns to the scheduler, which continues with c->proc = 0.

(In the above sentence, the words "sort of" and "effectively" are doing a lot of work. To understand what's hiding behind those words, the next thing you should read up on is coroutines.)

zwol
  • 135,547
  • 38
  • 252
  • 361
  • I got it.swtch saves the ra register, which holds the return address from which swtch was called, then load the ra of the new context. Last, ret, and here ret == jr ra, so now pc points to the somewhere of the new switched process. – RecharBao Jun 04 '21 at 15:57