Checkpoint switching to per-process locks, in attempt clarify xv6's
locking plan, which is a difficult to understand because ptable lock protects many invariants. This implementation has a bug: once in a while xv6 unlocks a proc lock that is locked by another core.
This commit is contained in:
		
							parent
							
								
									535ac52efa
								
							
						
					
					
						commit
						67702cf706
					
				
					 12 changed files with 139 additions and 85 deletions
				
			
		| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
#include "param.h"
 | 
					#include "param.h"
 | 
				
			||||||
#include "memlayout.h"
 | 
					#include "memlayout.h"
 | 
				
			||||||
#include "riscv.h"
 | 
					#include "riscv.h"
 | 
				
			||||||
 | 
					#include "spinlock.h"
 | 
				
			||||||
#include "proc.h"
 | 
					#include "proc.h"
 | 
				
			||||||
#include "defs.h"
 | 
					#include "defs.h"
 | 
				
			||||||
#include "elf.h"
 | 
					#include "elf.h"
 | 
				
			||||||
| 
						 | 
					@ -19,7 +20,6 @@ exec(char *path, char **argv)
 | 
				
			||||||
  struct proghdr ph;
 | 
					  struct proghdr ph;
 | 
				
			||||||
  pagetable_t pagetable = 0, oldpagetable;
 | 
					  pagetable_t pagetable = 0, oldpagetable;
 | 
				
			||||||
  struct proc *p = myproc();
 | 
					  struct proc *p = myproc();
 | 
				
			||||||
  uint64 oldsz = p->sz;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  begin_op();
 | 
					  begin_op();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -60,6 +60,9 @@ exec(char *path, char **argv)
 | 
				
			||||||
  end_op();
 | 
					  end_op();
 | 
				
			||||||
  ip = 0;
 | 
					  ip = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  p = myproc();
 | 
				
			||||||
 | 
					  uint64 oldsz = p->sz;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Allocate two pages at the next page boundary.
 | 
					  // Allocate two pages at the next page boundary.
 | 
				
			||||||
  // Use the second as the user stack.
 | 
					  // Use the second as the user stack.
 | 
				
			||||||
  sz = PGROUNDUP(sz);
 | 
					  sz = PGROUNDUP(sz);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,8 +14,8 @@
 | 
				
			||||||
#include "defs.h"
 | 
					#include "defs.h"
 | 
				
			||||||
#include "param.h"
 | 
					#include "param.h"
 | 
				
			||||||
#include "stat.h"
 | 
					#include "stat.h"
 | 
				
			||||||
#include "proc.h"
 | 
					 | 
				
			||||||
#include "spinlock.h"
 | 
					#include "spinlock.h"
 | 
				
			||||||
 | 
					#include "proc.h"
 | 
				
			||||||
#include "sleeplock.h"
 | 
					#include "sleeplock.h"
 | 
				
			||||||
#include "fs.h"
 | 
					#include "fs.h"
 | 
				
			||||||
#include "buf.h"
 | 
					#include "buf.h"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,9 +2,9 @@
 | 
				
			||||||
#include "riscv.h"
 | 
					#include "riscv.h"
 | 
				
			||||||
#include "defs.h"
 | 
					#include "defs.h"
 | 
				
			||||||
#include "param.h"
 | 
					#include "param.h"
 | 
				
			||||||
 | 
					#include "spinlock.h"
 | 
				
			||||||
#include "proc.h"
 | 
					#include "proc.h"
 | 
				
			||||||
#include "fs.h"
 | 
					#include "fs.h"
 | 
				
			||||||
#include "spinlock.h"
 | 
					 | 
				
			||||||
#include "sleeplock.h"
 | 
					#include "sleeplock.h"
 | 
				
			||||||
#include "file.h"
 | 
					#include "file.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										192
									
								
								kernel/proc.c
									
										
									
									
									
								
							
							
						
						
									
										192
									
								
								kernel/proc.c
									
										
									
									
									
								
							| 
						 | 
					@ -2,8 +2,8 @@
 | 
				
			||||||
#include "param.h"
 | 
					#include "param.h"
 | 
				
			||||||
#include "memlayout.h"
 | 
					#include "memlayout.h"
 | 
				
			||||||
#include "riscv.h"
 | 
					#include "riscv.h"
 | 
				
			||||||
#include "proc.h"
 | 
					 | 
				
			||||||
#include "spinlock.h"
 | 
					#include "spinlock.h"
 | 
				
			||||||
 | 
					#include "proc.h"
 | 
				
			||||||
#include "defs.h"
 | 
					#include "defs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct {
 | 
					struct {
 | 
				
			||||||
| 
						 | 
					@ -21,7 +21,7 @@ extern void forkret(void);
 | 
				
			||||||
// for returning  out of the kernel
 | 
					// for returning  out of the kernel
 | 
				
			||||||
extern void sysexit(void);
 | 
					extern void sysexit(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void wakeup1(void *chan);
 | 
					static void wakeup1(struct proc *chan);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern char trampout[]; // trampoline.S
 | 
					extern char trampout[]; // trampoline.S
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -80,11 +80,13 @@ allocproc(void)
 | 
				
			||||||
  return 0;
 | 
					  return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
found:
 | 
					found:
 | 
				
			||||||
 | 
					  initlock(&p->lock, "proc");
 | 
				
			||||||
 | 
					  acquire(&p->lock);
 | 
				
			||||||
 | 
					  release(&ptable.lock);
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
  p->state = EMBRYO;
 | 
					  p->state = EMBRYO;
 | 
				
			||||||
  p->pid = nextpid++;
 | 
					  p->pid = nextpid++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  release(&ptable.lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Allocate a page for the kernel stack.
 | 
					  // Allocate a page for the kernel stack.
 | 
				
			||||||
  if((p->kstack = kalloc()) == 0){
 | 
					  if((p->kstack = kalloc()) == 0){
 | 
				
			||||||
    p->state = UNUSED;
 | 
					    p->state = UNUSED;
 | 
				
			||||||
| 
						 | 
					@ -177,15 +179,9 @@ userinit(void)
 | 
				
			||||||
  safestrcpy(p->name, "initcode", sizeof(p->name));
 | 
					  safestrcpy(p->name, "initcode", sizeof(p->name));
 | 
				
			||||||
  p->cwd = namei("/");
 | 
					  p->cwd = namei("/");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // this assignment to p->state lets other cores
 | 
					 | 
				
			||||||
  // run this process. the acquire forces the above
 | 
					 | 
				
			||||||
  // writes to be visible, and the lock is also needed
 | 
					 | 
				
			||||||
  // because the assignment might not be atomic.
 | 
					 | 
				
			||||||
  acquire(&ptable.lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  p->state = RUNNABLE;
 | 
					  p->state = RUNNABLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  release(&ptable.lock);
 | 
					  release(&p->lock);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Grow current process's memory by n bytes.
 | 
					// Grow current process's memory by n bytes.
 | 
				
			||||||
| 
						 | 
					@ -196,15 +192,22 @@ growproc(int n)
 | 
				
			||||||
  uint sz;
 | 
					  uint sz;
 | 
				
			||||||
  struct proc *p = myproc();
 | 
					  struct proc *p = myproc();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  acquire(&p->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  sz = p->sz;
 | 
					  sz = p->sz;
 | 
				
			||||||
  if(n > 0){
 | 
					  if(n > 0){
 | 
				
			||||||
    if((sz = uvmalloc(p->pagetable, sz, sz + n)) == 0)
 | 
					    if((sz = uvmalloc(p->pagetable, sz, sz + n)) == 0) {
 | 
				
			||||||
 | 
					      release(&p->lock);
 | 
				
			||||||
      return -1;
 | 
					      return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  } else if(n < 0){
 | 
					  } else if(n < 0){
 | 
				
			||||||
    if((sz = uvmdealloc(p->pagetable, sz, sz + n)) == 0)
 | 
					    if((sz = uvmdealloc(p->pagetable, sz, sz + n)) == 0) {
 | 
				
			||||||
 | 
					      release(&p->lock);
 | 
				
			||||||
      return -1;
 | 
					      return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  p->sz = sz;
 | 
					  p->sz = sz;
 | 
				
			||||||
 | 
					  release(&p->lock);
 | 
				
			||||||
  return 0;
 | 
					  return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -244,11 +247,9 @@ fork(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  pid = np->pid;
 | 
					  pid = np->pid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  acquire(&ptable.lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  np->state = RUNNABLE;
 | 
					  np->state = RUNNABLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  release(&ptable.lock);
 | 
					  release(&np->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return pid;
 | 
					  return pid;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -260,45 +261,65 @@ void
 | 
				
			||||||
exit(void)
 | 
					exit(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  struct proc *p = myproc();
 | 
					  struct proc *p = myproc();
 | 
				
			||||||
  struct proc *pp;
 | 
					 | 
				
			||||||
  int fd;
 | 
					  int fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if(p == initproc)
 | 
					  if(p == initproc)
 | 
				
			||||||
    panic("init exiting");
 | 
					    panic("init exiting");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  acquire(&p->lock);
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
  // Close all open files.
 | 
					  // Close all open files.
 | 
				
			||||||
  for(fd = 0; fd < NOFILE; fd++){
 | 
					  for(fd = 0; fd < NOFILE; fd++){
 | 
				
			||||||
    if(p->ofile[fd]){
 | 
					    if(p->ofile[fd]){
 | 
				
			||||||
      fileclose(p->ofile[fd]);
 | 
					      struct file *f = p->ofile[fd];
 | 
				
			||||||
 | 
					      release(&p->lock);
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      fileclose(f);
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      acquire(&p->lock);
 | 
				
			||||||
      p->ofile[fd] = 0;
 | 
					      p->ofile[fd] = 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  struct inode *cwd = p->cwd;
 | 
				
			||||||
 | 
					  release(&p->lock);
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
  begin_op();
 | 
					  begin_op();
 | 
				
			||||||
  iput(p->cwd);
 | 
					  iput(cwd);
 | 
				
			||||||
  end_op();
 | 
					  end_op();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  acquire(&p->lock);
 | 
				
			||||||
  p->cwd = 0;
 | 
					  p->cwd = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  acquire(&ptable.lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Parent might be sleeping in wait().
 | 
					 | 
				
			||||||
  wakeup1(p->parent);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Pass abandoned children to init.
 | 
					 | 
				
			||||||
  for(pp = ptable.proc; pp < &ptable.proc[NPROC]; pp++){
 | 
					 | 
				
			||||||
    if(pp->parent == p){
 | 
					 | 
				
			||||||
      pp->parent = initproc;
 | 
					 | 
				
			||||||
      if(pp->state == ZOMBIE)
 | 
					 | 
				
			||||||
        wakeup1(initproc);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Jump into the scheduler, never to return.
 | 
					  // Jump into the scheduler, never to return.
 | 
				
			||||||
  p->state = ZOMBIE;
 | 
					  p->state = ZOMBIE;
 | 
				
			||||||
  sched();
 | 
					  sched();
 | 
				
			||||||
  panic("zombie exit");
 | 
					  panic("zombie exit");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void tellparent(struct proc *p, struct proc *parent) {
 | 
				
			||||||
 | 
					  struct proc *pp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  acquire(&parent->lock);
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  // Parent might be sleeping in wait().
 | 
				
			||||||
 | 
					  wakeup1(parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Pass abandoned children to init.
 | 
				
			||||||
 | 
					  for(pp = ptable.proc; pp < &ptable.proc[NPROC]; pp++){
 | 
				
			||||||
 | 
					    if(pp->parent == p){
 | 
				
			||||||
 | 
					      pp->parent = initproc;
 | 
				
			||||||
 | 
					      if(pp->state == ZOMBIE) {
 | 
				
			||||||
 | 
					          acquire(&initproc->lock);
 | 
				
			||||||
 | 
					          wakeup1(initproc);
 | 
				
			||||||
 | 
					          acquire(&initproc->lock);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  release(&parent->lock);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Wait for a child process to exit and return its pid.
 | 
					// Wait for a child process to exit and return its pid.
 | 
				
			||||||
// Return -1 if this process has no children.
 | 
					// Return -1 if this process has no children.
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
| 
						 | 
					@ -308,13 +329,16 @@ wait(void)
 | 
				
			||||||
  int havekids, pid;
 | 
					  int havekids, pid;
 | 
				
			||||||
  struct proc *p = myproc();
 | 
					  struct proc *p = myproc();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  acquire(&ptable.lock);
 | 
					  // should p lock!
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  acquire(&p->lock);
 | 
				
			||||||
  for(;;){
 | 
					  for(;;){
 | 
				
			||||||
    // Scan through table looking for exited children.
 | 
					    // Scan through table looking for exited children.
 | 
				
			||||||
    havekids = 0;
 | 
					    havekids = 0;
 | 
				
			||||||
    for(np = ptable.proc; np < &ptable.proc[NPROC]; np++){
 | 
					    for(np = ptable.proc; np < &ptable.proc[NPROC]; np++){
 | 
				
			||||||
      if(np->parent != p)
 | 
					      if(np->parent != p)
 | 
				
			||||||
        continue;
 | 
					        continue;
 | 
				
			||||||
 | 
					      acquire(&np->lock);
 | 
				
			||||||
      havekids = 1;
 | 
					      havekids = 1;
 | 
				
			||||||
      if(np->state == ZOMBIE){
 | 
					      if(np->state == ZOMBIE){
 | 
				
			||||||
        // Found one.
 | 
					        // Found one.
 | 
				
			||||||
| 
						 | 
					@ -330,19 +354,21 @@ wait(void)
 | 
				
			||||||
        np->name[0] = 0;
 | 
					        np->name[0] = 0;
 | 
				
			||||||
        np->killed = 0;
 | 
					        np->killed = 0;
 | 
				
			||||||
        np->state = UNUSED;
 | 
					        np->state = UNUSED;
 | 
				
			||||||
        release(&ptable.lock);
 | 
					        release(&np->lock);
 | 
				
			||||||
 | 
					        release(&p->lock);
 | 
				
			||||||
        return pid;
 | 
					        return pid;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      release(&np->lock);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // No point waiting if we don't have any children.
 | 
					    // No point waiting if we don't have any children.
 | 
				
			||||||
    if(!havekids || p->killed){
 | 
					    if(!havekids || p->killed){
 | 
				
			||||||
      release(&ptable.lock);
 | 
					      release(&p->lock);
 | 
				
			||||||
      return -1;
 | 
					      return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // Wait for children to exit.  (See wakeup1 call in proc_exit.)
 | 
					    // Wait for children to exit.  (See wakeup1 call in tellparent.)
 | 
				
			||||||
    sleep(p, &ptable.lock);  //DOC: wait-sleep
 | 
					    sleep(p, &p->lock);  //DOC: wait-sleep
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -366,13 +392,16 @@ scheduler(void)
 | 
				
			||||||
    intr_on();
 | 
					    intr_on();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Loop over process table looking for process to run.
 | 
					    // Loop over process table looking for process to run.
 | 
				
			||||||
    acquire(&ptable.lock);
 | 
					    for(p = ptable.proc; p < &ptable.proc[NPROC]; p++) {
 | 
				
			||||||
    for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
 | 
					      acquire(&p->lock);
 | 
				
			||||||
      if(p->state != RUNNABLE)
 | 
					      
 | 
				
			||||||
 | 
					      if(p->state != RUNNABLE) {
 | 
				
			||||||
 | 
					        release(&p->lock);
 | 
				
			||||||
        continue;
 | 
					        continue;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Switch to chosen process.  It is the process's job
 | 
					      // Switch to chosen process.  It is the process's job
 | 
				
			||||||
      // to release ptable.lock and then reacquire it
 | 
					      // to release its lock and then reacquire it
 | 
				
			||||||
      // before jumping back to us.
 | 
					      // before jumping back to us.
 | 
				
			||||||
      c->proc = p;
 | 
					      c->proc = p;
 | 
				
			||||||
      p->state = RUNNING;
 | 
					      p->state = RUNNING;
 | 
				
			||||||
| 
						 | 
					@ -382,12 +411,17 @@ scheduler(void)
 | 
				
			||||||
      // Process is done running for now.
 | 
					      // Process is done running for now.
 | 
				
			||||||
      // It should have changed its p->state before coming back.
 | 
					      // It should have changed its p->state before coming back.
 | 
				
			||||||
      c->proc = 0;
 | 
					      c->proc = 0;
 | 
				
			||||||
 | 
					      release(&p->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if(p->state == ZOMBIE) {
 | 
				
			||||||
 | 
					        tellparent(p, p->parent);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    release(&ptable.lock);
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Enter scheduler.  Must hold only ptable.lock
 | 
					// Enter scheduler.  Must hold only p->lock
 | 
				
			||||||
// and have changed proc->state. Saves and restores
 | 
					// and have changed proc->state. Saves and restores
 | 
				
			||||||
// intena because intena is a property of this
 | 
					// intena because intena is a property of this
 | 
				
			||||||
// kernel thread, not this CPU. It should
 | 
					// kernel thread, not this CPU. It should
 | 
				
			||||||
| 
						 | 
					@ -400,8 +434,8 @@ sched(void)
 | 
				
			||||||
  int intena;
 | 
					  int intena;
 | 
				
			||||||
  struct proc *p = myproc();
 | 
					  struct proc *p = myproc();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if(!holding(&ptable.lock))
 | 
					  if(!holding(&p->lock))
 | 
				
			||||||
    panic("sched ptable.lock");
 | 
					    panic("sched p->lock");
 | 
				
			||||||
  if(mycpu()->noff != 1)
 | 
					  if(mycpu()->noff != 1)
 | 
				
			||||||
    panic("sched locks");
 | 
					    panic("sched locks");
 | 
				
			||||||
  if(p->state == RUNNING)
 | 
					  if(p->state == RUNNING)
 | 
				
			||||||
| 
						 | 
					@ -418,10 +452,10 @@ sched(void)
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
yield(void)
 | 
					yield(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  acquire(&ptable.lock);  //DOC: yieldlock
 | 
					  acquire(&myproc()->lock);  //DOC: yieldlock
 | 
				
			||||||
  myproc()->state = RUNNABLE;
 | 
					  myproc()->state = RUNNABLE;
 | 
				
			||||||
  sched();
 | 
					  sched();
 | 
				
			||||||
  release(&ptable.lock);
 | 
					  release(&myproc()->lock);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// A fork child's very first scheduling by scheduler()
 | 
					// A fork child's very first scheduling by scheduler()
 | 
				
			||||||
| 
						 | 
					@ -431,8 +465,8 @@ forkret(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  static int first = 1;
 | 
					  static int first = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Still holding ptable.lock from scheduler.
 | 
					  // Still holding p->lock from scheduler.
 | 
				
			||||||
  release(&ptable.lock);
 | 
					  release(&myproc()->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (first) {
 | 
					  if (first) {
 | 
				
			||||||
    // Some initialization functions must be run in the context
 | 
					    // Some initialization functions must be run in the context
 | 
				
			||||||
| 
						 | 
					@ -451,60 +485,69 @@ forkret(void)
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
sleep(void *chan, struct spinlock *lk)
 | 
					sleep(void *chan, struct spinlock *lk)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  struct proc *p = myproc();
 | 
					  if(myproc() == 0)
 | 
				
			||||||
  
 | 
					 | 
				
			||||||
  if(p == 0)
 | 
					 | 
				
			||||||
    panic("sleep");
 | 
					    panic("sleep");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if(lk == 0)
 | 
					  if(lk == 0)
 | 
				
			||||||
    panic("sleep without lk");
 | 
					    panic("sleep without lk");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Must acquire ptable.lock in order to
 | 
					  // Must acquire p->lock in order to
 | 
				
			||||||
  // change p->state and then call sched.
 | 
					  // change p->state and then call sched.
 | 
				
			||||||
  // Once we hold ptable.lock, we can be
 | 
					  // Once we hold p->lock, we can be
 | 
				
			||||||
  // guaranteed that we won't miss any wakeup
 | 
					  // guaranteed that we won't miss any wakeup
 | 
				
			||||||
  // (wakeup runs with ptable.lock locked),
 | 
					  // (wakeup runs with p->lock locked),
 | 
				
			||||||
  // so it's okay to release lk.
 | 
					  // so it's okay to release lk.
 | 
				
			||||||
  if(lk != &ptable.lock){  //DOC: sleeplock0
 | 
					  if(lk != &myproc()->lock){  //DOC: sleeplock0
 | 
				
			||||||
    acquire(&ptable.lock);  //DOC: sleeplock1
 | 
					    acquire(&myproc()->lock);  //DOC: sleeplock1
 | 
				
			||||||
    release(lk);
 | 
					    release(lk);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  // Go to sleep.
 | 
					  // Go to sleep.
 | 
				
			||||||
  p->chan = chan;
 | 
					  myproc()->chan = chan;
 | 
				
			||||||
  p->state = SLEEPING;
 | 
					  myproc()->state = SLEEPING;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  sched();
 | 
					  sched();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Tidy up.
 | 
					  // Tidy up.
 | 
				
			||||||
  p->chan = 0;
 | 
					  myproc()->chan = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Reacquire original lock.
 | 
					  // Reacquire original lock.
 | 
				
			||||||
  if(lk != &ptable.lock){  //DOC: sleeplock2
 | 
					  if(lk != &myproc()->lock){  //DOC: sleeplock2
 | 
				
			||||||
    release(&ptable.lock);
 | 
					    release(&myproc()->lock);
 | 
				
			||||||
    acquire(lk);
 | 
					    acquire(lk);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//PAGEBREAK!
 | 
					//PAGEBREAK!
 | 
				
			||||||
// Wake up all processes sleeping on chan.
 | 
					// Wake up all processes sleeping on chan,
 | 
				
			||||||
// The ptable lock must be held.
 | 
					// where chan is a proc.
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
wakeup1(void *chan)
 | 
					wakeup1(struct proc *chan)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  struct proc *p;
 | 
					  struct proc *p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for(p = ptable.proc; p < &ptable.proc[NPROC]; p++)
 | 
					  for(p = ptable.proc; p < &ptable.proc[NPROC]; p++)
 | 
				
			||||||
    if(p->state == SLEEPING && p->chan == chan)
 | 
					    if(p == chan && p->state == SLEEPING && p->chan == chan) {
 | 
				
			||||||
 | 
					      if(p->state != SLEEPING || p->chan != chan)
 | 
				
			||||||
 | 
					        panic("wakeup1");
 | 
				
			||||||
      p->state = RUNNABLE;
 | 
					      p->state = RUNNABLE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Wake up all processes sleeping on chan.
 | 
					// Wake up all processes sleeping on chan. Never
 | 
				
			||||||
 | 
					// called when holding a p->lock
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
wakeup(void *chan)
 | 
					wakeup(void *chan)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  acquire(&ptable.lock);
 | 
					  struct proc *p;
 | 
				
			||||||
  wakeup1(chan);
 | 
					
 | 
				
			||||||
  release(&ptable.lock);
 | 
					  for(p = ptable.proc; p < &ptable.proc[NPROC]; p++)
 | 
				
			||||||
 | 
					    if(p->state == SLEEPING && p->chan == chan) {
 | 
				
			||||||
 | 
					      acquire(&p->lock);
 | 
				
			||||||
 | 
					      if(p->state != SLEEPING || p->chan != chan)
 | 
				
			||||||
 | 
					        panic("wakeup");
 | 
				
			||||||
 | 
					      p->state = RUNNABLE;
 | 
				
			||||||
 | 
					      release(&p->lock);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Kill the process with the given pid.
 | 
					// Kill the process with the given pid.
 | 
				
			||||||
| 
						 | 
					@ -515,18 +558,19 @@ kill(int pid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  struct proc *p;
 | 
					  struct proc *p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  acquire(&ptable.lock);
 | 
					 | 
				
			||||||
  for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
 | 
					  for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
 | 
				
			||||||
    if(p->pid == pid){
 | 
					    if(p->pid == pid){
 | 
				
			||||||
 | 
					      acquire(&p->lock);
 | 
				
			||||||
 | 
					      if(p->pid != pid)
 | 
				
			||||||
 | 
					        panic("kill");
 | 
				
			||||||
      p->killed = 1;
 | 
					      p->killed = 1;
 | 
				
			||||||
      // Wake process from sleep if necessary.
 | 
					      // Wake process from sleep if necessary.
 | 
				
			||||||
      if(p->state == SLEEPING)
 | 
					      if(p->state == SLEEPING)
 | 
				
			||||||
        p->state = RUNNABLE;
 | 
					        p->state = RUNNABLE;
 | 
				
			||||||
      release(&ptable.lock);
 | 
					      release(&p->lock);
 | 
				
			||||||
      return 0;
 | 
					      return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  release(&ptable.lock);
 | 
					 | 
				
			||||||
  return -1;
 | 
					  return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -82,6 +82,7 @@ enum procstate { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Per-process state
 | 
					// Per-process state
 | 
				
			||||||
struct proc {
 | 
					struct proc {
 | 
				
			||||||
 | 
					  struct spinlock lock;
 | 
				
			||||||
  char *kstack;                // Bottom of kernel stack for this process
 | 
					  char *kstack;                // Bottom of kernel stack for this process
 | 
				
			||||||
  uint64 sz;                   // Size of process memory (bytes)
 | 
					  uint64 sz;                   // Size of process memory (bytes)
 | 
				
			||||||
  pagetable_t pagetable;       // Page table
 | 
					  pagetable_t pagetable;       // Page table
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,8 +5,8 @@
 | 
				
			||||||
#include "defs.h"
 | 
					#include "defs.h"
 | 
				
			||||||
#include "param.h"
 | 
					#include "param.h"
 | 
				
			||||||
#include "memlayout.h"
 | 
					#include "memlayout.h"
 | 
				
			||||||
#include "proc.h"
 | 
					 | 
				
			||||||
#include "spinlock.h"
 | 
					#include "spinlock.h"
 | 
				
			||||||
 | 
					#include "proc.h"
 | 
				
			||||||
#include "sleeplock.h"
 | 
					#include "sleeplock.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,7 +20,7 @@ initlock(struct spinlock *lk, char *name)
 | 
				
			||||||
// Loops (spins) until the lock is acquired.
 | 
					// Loops (spins) until the lock is acquired.
 | 
				
			||||||
// Holding a lock for a long time may cause
 | 
					// Holding a lock for a long time may cause
 | 
				
			||||||
// other CPUs to waste time spinning to acquire it.
 | 
					// other CPUs to waste time spinning to acquire it.
 | 
				
			||||||
void
 | 
					void //__attribute__ ((noinline))
 | 
				
			||||||
acquire(struct spinlock *lk)
 | 
					acquire(struct spinlock *lk)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  push_off(); // disable interrupts to avoid deadlock.
 | 
					  push_off(); // disable interrupts to avoid deadlock.
 | 
				
			||||||
| 
						 | 
					@ -44,11 +44,13 @@ acquire(struct spinlock *lk)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Release the lock.
 | 
					// Release the lock.
 | 
				
			||||||
void
 | 
					void //__attribute__ ((noinline))
 | 
				
			||||||
release(struct spinlock *lk)
 | 
					release(struct spinlock *lk)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  if(!holding(lk))
 | 
					  if(!holding(lk)) {
 | 
				
			||||||
 | 
					    printf("%p: !holding %s %p\n", mycpu(), lk->name, lk->cpu);
 | 
				
			||||||
    panic("release");
 | 
					    panic("release");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  lk->cpu = 0;
 | 
					  lk->cpu = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
#include "param.h"
 | 
					#include "param.h"
 | 
				
			||||||
#include "memlayout.h"
 | 
					#include "memlayout.h"
 | 
				
			||||||
#include "riscv.h"
 | 
					#include "riscv.h"
 | 
				
			||||||
 | 
					#include "spinlock.h"
 | 
				
			||||||
#include "proc.h"
 | 
					#include "proc.h"
 | 
				
			||||||
#include "syscall.h"
 | 
					#include "syscall.h"
 | 
				
			||||||
#include "defs.h"
 | 
					#include "defs.h"
 | 
				
			||||||
| 
						 | 
					@ -170,7 +171,9 @@ dosyscall(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  num = p->tf->a7;
 | 
					  num = p->tf->a7;
 | 
				
			||||||
  if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
 | 
					  if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
 | 
				
			||||||
 | 
					    //printf("%d: syscall %d\n", p->pid, num);
 | 
				
			||||||
    p->tf->a0 = syscalls[num]();
 | 
					    p->tf->a0 = syscalls[num]();
 | 
				
			||||||
 | 
					    //printf("%d: syscall %d -> %d\n", p->pid, num, p->tf->a0);
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    printf("%d %s: unknown sys call %d\n",
 | 
					    printf("%d %s: unknown sys call %d\n",
 | 
				
			||||||
            p->pid, p->name, num);
 | 
					            p->pid, p->name, num);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,9 +9,9 @@
 | 
				
			||||||
#include "defs.h"
 | 
					#include "defs.h"
 | 
				
			||||||
#include "param.h"
 | 
					#include "param.h"
 | 
				
			||||||
#include "stat.h"
 | 
					#include "stat.h"
 | 
				
			||||||
 | 
					#include "spinlock.h"
 | 
				
			||||||
#include "proc.h"
 | 
					#include "proc.h"
 | 
				
			||||||
#include "fs.h"
 | 
					#include "fs.h"
 | 
				
			||||||
#include "spinlock.h"
 | 
					 | 
				
			||||||
#include "sleeplock.h"
 | 
					#include "sleeplock.h"
 | 
				
			||||||
#include "file.h"
 | 
					#include "file.h"
 | 
				
			||||||
#include "fcntl.h"
 | 
					#include "fcntl.h"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,6 +4,7 @@
 | 
				
			||||||
#include "date.h"
 | 
					#include "date.h"
 | 
				
			||||||
#include "param.h"
 | 
					#include "param.h"
 | 
				
			||||||
#include "memlayout.h"
 | 
					#include "memlayout.h"
 | 
				
			||||||
 | 
					#include "spinlock.h"
 | 
				
			||||||
#include "proc.h"
 | 
					#include "proc.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,8 +2,8 @@
 | 
				
			||||||
#include "param.h"
 | 
					#include "param.h"
 | 
				
			||||||
#include "memlayout.h"
 | 
					#include "memlayout.h"
 | 
				
			||||||
#include "riscv.h"
 | 
					#include "riscv.h"
 | 
				
			||||||
#include "proc.h"
 | 
					 | 
				
			||||||
#include "spinlock.h"
 | 
					#include "spinlock.h"
 | 
				
			||||||
 | 
					#include "proc.h"
 | 
				
			||||||
#include "defs.h"
 | 
					#include "defs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct spinlock tickslock;
 | 
					struct spinlock tickslock;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,8 +2,8 @@
 | 
				
			||||||
#include "param.h"
 | 
					#include "param.h"
 | 
				
			||||||
#include "memlayout.h"
 | 
					#include "memlayout.h"
 | 
				
			||||||
#include "riscv.h"
 | 
					#include "riscv.h"
 | 
				
			||||||
#include "proc.h"
 | 
					 | 
				
			||||||
#include "spinlock.h"
 | 
					#include "spinlock.h"
 | 
				
			||||||
 | 
					#include "proc.h"
 | 
				
			||||||
#include "defs.h"
 | 
					#include "defs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue