linux RCU 使用实例

2023-12-23 01:38:15

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/rcupdate.h>
#include <linux/delay.h>
#include <linux/kthread.h>?

struct foo {
? ? int a;
? ? struct rcu_head rcu;
};

static struct foo *g_ptr;

static int myrcu_reader_thread(void *data)//读者线程
{
? ? struct foo *p = NULL;
? ??
? ? while(1) {
? ? ? ? //msleep(200);
? ? ? ? mdelay(200); //不可抢占RCU中读者获取锁不允许睡眠
? ? ? ? rcu_read_lock();
? ? ? ? p = rcu_dereference(g_ptr);
? ? ? ? if (p)
? ? ? ? ? ? printk("%s: read a=%d\n", __func__, p->a);
? ? ? ? rcu_read_unlock();
? ? }
? ??
? ? return 0;
}

static void myrcu_del(struct rcu_head *rh)
{
? ? struct foo *p = container_of(rh, struct foo, rcu);
? ? printk("%s: del a=%d\n", __func__, p->a);
? ? kfree(p);
}

static int myrcu_writer_thread(void *p) //写者线程
{
? ? struct foo *old;
? ? struct foo *new_ptr;
? ? int value = (unsigned long)p;
? ??
? ? while (1) {
? ? ? ? msleep(400);
? ? ? ? new_ptr = kmalloc(sizeof(struct foo), GFP_KERNEL);
? ? ? ? old = g_ptr;
? ? ? ? printk("%s: write to new %d\n", __func__, value);
? ? ? ? *new_ptr = *old;
? ? ? ? new_ptr->a = value;
? ? ? ? rcu_assign_pointer(g_ptr, new_ptr);
? ? ? ? call_rcu(&old->rcu, myrcu_del);
? ? ? ? value++;
? ? }
? ??
? ? return 0;
}

static int __init my_test_init(void)
{
? ? struct task_struct *reader_thread;
? ? struct task_struct *writer_thread;
? ??
? ? int value = 5;
? ? printk("figo: my module init");
? ? g_ptr = kzalloc(sizeof(struct foo), GFP_KERNEL);
? ??
? ? reader_thread = kthread_run(myrcu_reader_thread,NULL,"rcu_reader");
? ? writer_thread = kthread_run(myrcu_writer_thread,(void *)(unsigned long)value,"rcu_writer");
? ? return 0;
}
static void __exit my_test_exit(void)
{
? ? printk("goodbye\n");
? ? if (g_ptr)
? ? ? ? kfree(g_ptr);
}
MODULE_LICENSE("GPL");
module_init(my_test_init);
module_exit(my_test_exit);

对于读者线程myrcu_reader_thread:
1)?? ?通过rcu_read_lock()和rcu_read_unlock()来构建一个读者的临界区。
2)?? ?通过调用rcu_dereference()获取被保护数据g_ptr指针的一个副本,即指针p,这时p和g_ptr都指向旧的被保护数据。
3)?? ?读者线程每隔200毫秒读取一次被保护数据。

对于写者线程myrcu_writer_thread:
1)?? ?分配一个新的保护数据new_ptr,并修改相应的数据。
2)?? ?rcu_assign_pointer()让g_ptr指向新数据。
3)?? ?call_rcu()注册一个回调函数,确保所有对旧数据的引用都执行完成之后,才调用回调函数来删除旧数据old_data.
4)?? ?写者线程每隔400毫秒修改被保护数据。

输出:
[162809.226469] figo: my module init
[162809.441385] myrcu_reader_thread: read a=0
[162809.644025] myrcu_writer_thread: write to new 5
[162809.648888] myrcu_reader_thread: read a=5
[162809.660006] myrcu_del: del a=0
[162809.846702] myrcu_reader_thread: read a=5
[162810.049708] myrcu_writer_thread: write to new 6
[162810.053969] myrcu_reader_thread: read a=6
[162810.080608] myrcu_del: del a=5
[162810.270821] myrcu_reader_thread: read a=6
[162810.454659] myrcu_writer_thread: write to new 7
[162810.486279] myrcu_del: del a=6
[162810.488527] myrcu_reader_thread: read a=7
[162810.692156] myrcu_reader_thread: read a=7
[162810.865196] myrcu_writer_thread: write to new 8
[162810.881099] myrcu_del: del a=7
?

文章来源:https://blog.csdn.net/liu1250836704/article/details/135159687
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。