在 XV6 中双重获取自旋锁
Double Acquire a Spinlock in XV6
众所周知,xv6 不允许自旋锁被获取两次(即使是进程本身)。
我正在尝试添加此功能,它允许进程多次获取锁。
为了达到这个目的,我将一个名为 lock_holder_pid
的属性添加到 struct spinlock
中,该属性应该保存已获取此锁的进程的 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为一个常量时,它启动成功。
谁能帮我解决这个问题?
代码中标有“由我添加”的部分是我添加的部分。
这仅仅是因为您试图访问空结构 (myproc()->pid
) 的字段。
如您所知,myproc()
returns 当前处理器上的进程 运行。如果您查看 main.c
,您可能会注意到 bootstrap 处理器在那里启动 运行。因此,如果我们能在设置第一个进程之前找到一个调用acquire()
函数的函数,问题就迎刃而解了。
仔细看kinit1
函数,可以发现里面调用了acquire
函数。因此,我们发现了一个使用 acquire
函数的函数,甚至在初始化 ptable
结构之前。因此,当您尝试访问 myproc()
值时,它尚未初始化。
众所周知,xv6 不允许自旋锁被获取两次(即使是进程本身)。
我正在尝试添加此功能,它允许进程多次获取锁。
为了达到这个目的,我将一个名为 lock_holder_pid
的属性添加到 struct spinlock
中,该属性应该保存已获取此锁的进程的 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为一个常量时,它启动成功。
谁能帮我解决这个问题?
代码中标有“由我添加”的部分是我添加的部分。
这仅仅是因为您试图访问空结构 (myproc()->pid
) 的字段。
如您所知,myproc()
returns 当前处理器上的进程 运行。如果您查看 main.c
,您可能会注意到 bootstrap 处理器在那里启动 运行。因此,如果我们能在设置第一个进程之前找到一个调用acquire()
函数的函数,问题就迎刃而解了。
仔细看kinit1
函数,可以发现里面调用了acquire
函数。因此,我们发现了一个使用 acquire
函数的函数,甚至在初始化 ptable
结构之前。因此,当您尝试访问 myproc()
值时,它尚未初始化。