【问题标题】:Double Acquire a Spinlock in XV6在 XV6 中双重获得自旋锁
【发布时间】:2021-08-25 16:11:05
【问题描述】:

我们知道,xv6 不允许两次获取自旋锁(即使是进程本身)。

我正在尝试添加此功能,它允许进程多次获取锁。 为了实现这一点,我在struct spinlock 中添加了一个名为lock_holder_pid 的属性,该属性应该保存已获得此锁的进程的pid。

我唯一更改的文件是spinlock.c

这是我的新 acquire() 函数:

// 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);
}

我还将initlock() 函数更改为:

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

我最后修改的函数是:

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



...

问题是xv6终端在启动时卡住了以下消息:

Booting from Hard Disk...

据我了解,导致问题的行是:

uint cur_proc_pid = myproc()->pid;

当我评论这一行并且只将 lock_holder_pid 设置为一个常数时,它会成功启动。

谁能帮我解决这个问题?

代码中标有“我添加”的部分是我添加的部分。

【问题讨论】:

  • 请注意测试持有人和设置持有人之间的竞争。
  • @stark 您能否提供更详细的解释?好吧,我不能在这个获取函数中获取另一个锁。我应该实现某种信号量来避免这种竞争条件吗?
  • 也许允许 CPU 以递归方式获取锁比允许进程以递归方式获取锁更有意义。此外,它需要被引用计数,需要与锁一样多的解锁。
  • @IanAbbott 如何让 CPU 这样做?我应该更改内核的其他文件吗?如果您能提供有关引用计数的更详细说明,我将不胜感激。

标签: c linux operating-system xv6


【解决方案1】:

这仅仅是因为您试图访问空结构 (myproc()->pid) 的字段。

您可能知道,myproc() 返回一个在当前处理器上运行的进程。如果您查看main.c,您可能会注意到引导处理器开始在那里运行。因此,如果我们能在设置第一个进程之前找到一个调用acquire()函数的函数,问题就迎刃而解了。

如果你仔细观察kinit1函数,你会发现acquire函数在其中被调用。因此,我们发现了一个使用acquire 函数的函数,甚至在初始化ptable 结构之前。因此,当您尝试访问myproc() 值时,它还没有被初始化。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多