Экспериментируя с (ядром linux) rwlock API, я получаю поведение (тупик), что не могу понять, почему это происходит.У кого-нибудь есть какое-то объяснение?(Обратите внимание, что этот код предназначен только для экспериментов без какой-либо логики: например, я знаю, что спать с удерживанием спин-блокировки плохая идея, но это никак не влияет на код, который я тестирую).
Код - этои результаты запускаются в тупике.
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("<toto@gmail.com>");
MODULE_DESCRIPTION("test rwlock");
static DEFINE_RWLOCK(rwlock);
// shared variable
static int var;
static struct task_struct *w;
static struct task_struct *r1;
static struct task_struct *r2;
static int w_f(void *unsed)
{
while (1) {
printk("w: try to lock\n");
if (write_trylock(&rwlock)) {
printk("w: locked\n");
} else {
printk("w: unavailable lock, spin\n");
write_lock(&rwlock);
printk("w: out of spin\n");
}
var = 1;
ssleep(4);
write_unlock(&rwlock);
printk("w: write unlock\n");
if (kthread_should_stop()) {
printk("w: should stop now\n");
return 1;
} else {
printk("w: continue...\n");
}
}
return 1;
}
static int r1_f(void *unsed)
{
while (1) {
if (read_trylock(&rwlock)) {
printk("\tr1: locked\n");
ssleep(3);
printk("\tr1: read access\n");
read_unlock(&rwlock);
} else {
printk("\tr1: unavailbe lock, spin\n");
read_lock(&rwlock);
}
if (kthread_should_stop()) {
printk("\tr1: should stop now\n");
return 1;
} else {
printk("\tr1: continue...\n");
}
}
return 0;
}
static int r2_f(void *unsed)
{
while (1) {
if (read_trylock(&rwlock)) {
printk("\tr2: locked\n");
ssleep(1);
printk("\tr2: read access\n");
read_unlock(&rwlock);
} else {
printk("\tr2: unavailbe lock, spin\n");
read_lock(&rwlock);
}
if (kthread_should_stop()) {
printk("\tr2: should stop now\n");
return 1;
} else {
printk("\tr2: continue...\n");
}
}
return 0;
}
static int __init init_thread(void)
{
printk(KERN_ALERT "Thread creating ...\n");
w = kthread_create(w_f, NULL, "writer1");
r1 = kthread_create(r1_f, NULL, "reader1");
r2 = kthread_create(r2_f, NULL, "reader2");
if (w && r1 && r2) {
printk(KERN_ALERT "Thread Created Sucessfully\n");
wake_up_process(w);
wake_up_process(r1);
wake_up_process(r2);
} else {
printk("Thread Creation Failed\n");
}
return 0;
}
static void __exit cleanup_thread(void)
{
int ret, ret1, ret2;
printk(KERN_ALERT "Cleaning up ...\n");
ret = kthread_stop(w);
ret1 = kthread_stop(r2);
ret2 = kthread_stop(r2);
printk("stop threads returned %d,%d,%d\n", ret, ret1, ret2);
}
module_init(init_thread)
module_exit(cleanup_thread)
Я получаю журнал:
[0 291.18289] Thread creating ...
[0 291.18444] Thread Created Sucessfully
[0 291.18450] w: try to lock
[0 291.18453] r1: locked
[0 291.18456] r2: locked
[0 291.18459] w: unavailable lock, spin
[1 292.261093] r2: read access
[1 292.261096] r2: continue...
[1 292.261096] r2: unavailbe lock, spin
[3 294.261151] r1: read access
[3 294.261153] r1: continue...
[3 294.261167] w: out of spin
[3 294.261168] r1: unavailbe lock, spin
[7 298.265307] w: write unlock
[7 298.265308] r1: continue...
[7 298.265308] r2: continue...
[7 298.265309] r1: locked
[7 298.265309] r2: locked
[7 298.265314] w: continue...
[7 298.265314] w: try to lock
[7 298.265315] w: unavailable lock, spin
[8 299.269282] r2: read access
[8 299.269285] r2: continue...
[8 299.269286] r2: unavailbe lock, spin
[10 301.269377] r1: read access
[10 301.269380] r1: continue...
[10 301.269381] r1: unavailbe lock, spin
[33 324.122110] **NMI watchdog: BUG: soft lockup - CPU#2 stuck for 22s! [writer1:3819]**
Я попытался схематизировать среду выполнения:
(----) -> running(ssleep) holding the lock.
(====) -> spinning on the lock
time 0 1 2 3 4 5 6 7 8 9 10 11 12 33
r1 *-----+-----+-----+=====+=====+=====+=====+-----+-----+-----+=====+=====+===== ... +=====+=====
r2 *-----+=====+=====+=====+=====+=====+=====+-----+=====+=====+=====+=====+===== ... +=====+=====
w *=====+=====+=====+-----+-----+-----+-----+=====+=====+=====+=====+=====+===== ... +=====+=====
Непонятное поведение: Мне интересно, почему (w) поток продолжает вращаться со скоростью 10 с , ситуация идентична мгновенной 3 с : r2 вращается, потому что попытался wполучить блокировку записи (w вращается, так как r1 удерживает блокировку), но когда r1 завершится, w должен разблокироваться и начать работать.Это происходит в 3 с, но не в 10 с.