DragonflyBSD:锁管理器(kern_lock.c)代码中可能存在的竞争条件?



最近我一直在阅读lock_manager(kern_lock.c(代码,并遇到了一些我认为会产生竞争条件的情况。

第 1 步:

@undo_shreq(...(:如果有一个升级请求挂起,代码将重置"LKC_UPREQ"标志并执行wakeup((调用;只有在以下情况下才会发生这种情况

(count & (LKC_EXREQ | LKC_UPREQ | LKC_CANCEL)) &&
(count & (LKC_SMASK | LKC_XMASK)) == 0)

第 2 步:

现在,并行地,另一个线程 T2 正在尝试获取独占锁,它达到了微不足道的条件(即(@lockmgr_exclusive(...

if ((count & (LKC_UPREQ | LKC_EXREQ |
LKC_XMASK)) == 0 &&
((count & LKC_SHARED) == 0 ||
(count & LKC_SMASK) == 0))

因此,T2 将计数增加 1 并将自己设置为所有者线程 - 这意味着它获得了独占性。

第 3 步:

一个线程 (T1( 睡在步骤 1 唤醒的LKC_UPREQ标志上;这是睡眠后的代码(....之后,LK_SLEEPFAIL和睡眠错误健全性检查(,@lockmgr_upgrade(...

if ((count & LKC_UPREQ) == 0) {           // reset by step 1
KKASSERT((count & LKC_XMASK) == 1);      // true, by step 2
lkp->lk_lockholder = td;
break;
}

我看到(如果我错了,请纠正我(,在第 3 步中,线程 T1 将lk_lockholder重置为自己——这意味着,它获得了排他性!

它的工作方式是,如果一个线程设置 UPREQ 然后休眠,另一个线程将授予它独占锁并将其唤醒。 授予线程清除 UPREQ 并增加独占计数,但不知道"谁"设置 UPREQ,因此由设置 UPREQ 的线程来设置锁持有人字段。

由于 lockmgr 代码必须处理多独占到单共享饥饿、多共享到单独占饥饿情况和死锁边缘情况,因此它相当复杂。在过去的一两年里已经发现了边缘情况,但这个特殊情况对我来说并不像一个错误。 只是有点令人困惑,因为排他锁是由第二个线程授予的(UPREQ 清除并且排除计数增加(,但第一个线程仍然负责设置 lk_lockholder 字段。

相关内容

  • 没有找到相关文章

最新更新