Search code examples
clinuxoperating-systemxv6

Double Acquire a Spinlock in XV6


As we know, xv6 doesn't let a spinlock be acquired twice (even by a process itself).

I am trying to add this feature which lets a process to acquire a lock more than once. In order to reach this, I am adding an attribute called lock_holder_pid to the struct spinlock which is supposed to hold the pid of the process which has acquired this lock.

The only file I have changed is spinlock.c

Here is my new acquire() function:

// Acquire the lock.
// Loops (spins) until the lock is acquired.
// Holding a lock for a long time may cause
// other CPUs to waste time spinning to acquire it.
void
acquire(struct spinlock *lk)
{
  pushcli(); // disable interrupts to avoid deadlock.

  
  uint cur_proc_pid = myproc()->pid; //Added by me
  
  
  if (holding(lk) && lk->lock_holder_pid == cur_proc_pid) //Added by me
  {
      popcli();
      return;
  }

  if(holding(lk) && lk->lock_holder_pid != cur_proc_pid) //Added by me
    panic("acquire");
  

  /* Commented by me
  if(holding(lk)) 
    panic("acquire");
  */


  // The xchg is atomic.
  while(xchg(&lk->locked, 1) != 0)
    ;

  
  lk-> lock_holder_pid = cur_proc_pid; //Added by me
  

  // Tell the C compiler and the processor to not move loads or stores
  // past this point, to ensure that the critical section's memory
  // references happen after the lock is acquired.
  __sync_synchronize();

  // Record info about lock acquisition for debugging.
  lk->cpu = mycpu();
  getcallerpcs(&lk, lk->pcs);
}

I also changed the initlock() function to this:

void
initlock(struct spinlock *lk, char *name)
{
  lk->name = name;
  lk->locked = 0;
  lk->cpu = 0;
  lk->lock_holder_pid = -1; //Added by me
}

The last function I modified is:

void
release(struct spinlock *lk)
{
  if(!holding(lk))
    panic("release");

  lk->pcs[0] = 0;
  lk->cpu = 0;
  lk->lock_holder_pid = -1; //Added by me



...

The problem is that the xv6 terminal get's stuck when booting with the message:

Booting from Hard Disk...

As far as I have understood, the line causing the problem is:

uint cur_proc_pid = myproc()->pid;

When I comment this line and only set lock_holder_pid to a constant number, it boots successfully.

Can anyone please help me with this?

The sections in the code marked with "Added by me" are the parts I have added.


Solution

  • This is simply because you are trying to have access to a field of a null struct (myproc()->pid).

    As you may know, myproc() returns a process running on the current processor. If you look at main.c, you may notice that the bootstrap processor starts running there. Therefore, if we can find a function which calls the acquire() function before setting up the first process, the problem will be solved.

    If you take a close look at the kinit1 function, you can realize that the acquire function is called in it. Consequently, we found a function that uses the acquire function, even before initializing the ptable struct. Therefore, when you try to access the myproc() value, it is not initialized yet.