(2) 4.19版本开始支持伤害-等待(Wound-Wait)算法:一个事务申请另一个事务已经获取的锁的时候,如果持有锁的事务年轻,那么申请锁的事务伤害(wound)持有锁的事务,请求它去死亡;如果持有锁的事务年老,那么申请锁的事务等待(wait)。
(1) 获取上下文(acquire context):一个获取上下文表示一个事务,关联一张门票(ticket),门票也称为序列号,门票编号小表示年老,门票编号大表示年轻。获取上下文跟踪调试状态,捕获对伤害/等待互斥锁接口的错误使用。
(2) 伤害/等待类:初始化获取上下文的时候需要指定锁类,锁类会给获取上下文分配门票。锁类也指定算法:等待-死亡(Wait-Die)或伤害-等待(Wound-Wait)。当多个进程竞争同一个锁集合的时候,它们必须使用相同的锁类。
(1) 普通的获取锁函数ww_mutex_lock(),带有获取上下文。
(2) 进程在回滚(即释放所有已经获取的锁)以后,使用慢路径获取锁函数ww_mutex_lock_slow()获取正在竞争的锁。带有“_slow”后缀的函数不是必需的,因为可以调用函数ww_mutex_lock()获取正在竞争的锁。带有“_slow”后缀的函数的优点是接口安全,如下。
(3) 只获取一个伤害/等待互斥锁,和获取普通的互斥锁完全相同。调用函数ww_mutex_lock(),把获取上下文指定为空指针。
(1) 定义一个锁类,锁类在初始化获取上下文的时候需要,锁类也指定算法:等待-死亡(Wait-Die)或伤害-等待(Wound-Wait)。
/* 指定等待-死亡算法 */
static DEFINE_WD_CLASS(my_class);
/* 指定伤害-等待算法 */
static DEFINE_WW_CLASS(my_class);
(2) 初始化一个获取上下文,锁类会给获取上下文分配一张门票。
void ww_acquire_init(struct ww_acquire_ctx *ctx, struct ww_class *ww_class);
int ww_mutex_lock(struct ww_mutex *lock, struct ww_acquire_ctx *ctx);
void ww_acquire_done(struct ww_acquire_ctx *ctx);
void ww_mutex_unlock(struct ww_mutex *lock);
void ww_acquire_fini(struct ww_acquire_ctx *ctx);
/* 第1步:定义锁类,指定伤害-等待算法。*/
static DEFINE_WW_CLASS(ww_class);
struct obj {
struct ww_mutex lock;
/* obj data */
};
struct obj_entry {
struct list_head head;
struct obj *obj;
};
int lock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
{
struct obj *res_obj = NULL;
struct obj_entry *contended_entry = NULL;
struct obj_entry *entry;
int ret;
/* 第2步:初始化获取上下文。*/
ww_acquire_init(ctx, &ww_class);
/* 第3步:获取锁。*/
retry:
list_for_each_entry(entry, list, head) {
if (entry->obj == res_obj) {
res_obj = NULL;
continue;
}
ret = ww_mutex_lock(&entry->obj->lock, ctx);
if (ret < 0) {
contended_entry = entry;
goto err;
}
}
/* 第4步:标记获取阶段结束。*/
ww_acquire_done(ctx);
return 0;
err:
/* 回滚,释放已经获取的锁。*/
list_for_each_entry_continue_reverse(entry, list, head) {
ww_mutex_unlock(&entry->obj->lock);
}
if (res_obj) {
ww_mutex_unlock(&res_obj->lock);
}
if (ret == -EDEADLK) {
/* 使用慢路径获取锁函数获取正在竞争的锁。*/
ww_mutex_lock_slow(&contended_entry->obj->lock, ctx);
res_obj = contended_entry->obj;
/* 获取其它锁。*/
goto retry;
}
ww_acquire_fini(ctx);
return ret;
}
void unlock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
{
struct obj_entry *entry;
/* 第5步:释放锁。*/
list_for_each_entry (entry, list, head) {
ww_mutex_unlock(&entry->obj->lock);
}
/* 第6步:释放获取上下文。*/
ww_acquire_fini(ctx);
}
(1) Wait/wound mutexes,https://lwn.net/Articles/548909/
(2) 内核文档“Documentation/locking/ww-mutex-design.rst”