RCU
Read-Copy-Update
linux内核RCU的演变
下面是一个使用rcu做读写的演示
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/rcupdate.h>
#include "tmain.h"
MODULE_DESCRIPTION("The module is only used for test");
MODULE_VERSION("1.0.0");
MODULE_AUTHOR("David Zhang");
MODULE_LICENSE("GPL");
#define MAX_KTHREAD 10
static unsigned long reader_bitmap;
static void set_reader_number(int reader)
{
WARN_ON((MAX_KTHREAD-reader) != 1);
reader_bitmap=0;
while(reader){
reader_bitmap |= (1 << --reader);
}
}
/*
unsigned int testpar= 0;
module_param(testpar, uint, S_IRUGO | S_IWUSR);
//static DEFINE_SPINLOCK(threads_lock);
static spinlock_t threads_lock;
static void threads_lock_init(void)
{
//spin_lock_init
spin_lock_init(&threads_lock);
}
*/
struct our_data{
int count1;
int count2;
};
static struct our_data my_data;
//to tell reader this pointer is protected by rcu
//linux kernel will check staticly when you use rcu_dereference, and source code is friendly to reader
static struct our_data __rcu *pmy_data=&my_data;
static void reader_do(void)
{
struct our_data *data;
rcu_read_lock();
data = rcu_dereference(pmy_data);
printk("read count1 %d, count2 %d.\n",data->count1,data->count2);
rcu_read_unlock();
}
static void writer_do(void)
{
struct our_data *data, *tmp=pmy_data;
data = kmalloc(sizeof(*data),GFP_KERNEL);
if(!data)
return;
//Read + Copy. */
memcpy(data,pmy_data,sizeof(*data));
data->count1++;
data->count2 +=10;
rcu_assign_pointer(pmy_data,data);
if(tmp != &my_data)
{
synchronize_rcu();
kfree(tmp);
printk("write completed!");
}
//Update
}
static struct task_struct *threads[MAX_KTHREAD];
static int thread_do(void *data)
{
long i=(long)data;
int isReader=reader_bitmap & (1 << i);
printk("run ...%ld %s \n",i,isReader?"reader":"writer");
while(!kthread_should_stop())
{
if(isReader)
reader_do();
else
writer_do();
msleep(10);
}
return 0;
}
static void show_my_data(void)
{
printk("my_data,count1:%d,count2:%d\n",pmy_data->count1,pmy_data->count2);
}
static int create_threads(void)
{
int i;
for(i=0;i<MAX_KTHREAD;i++){
struct task_struct *thread;
thread=kthread_run(thread_do,(void *)(long)i,"thread-%d",i);
if(IS_ERR(thread))
return -1;
threads[i]=thread;
}
return 0;
}
static void cleanup_threads(void)
{
int i;
for(i=0;i<MAX_KTHREAD;i++)
{
if(threads[i]){
kthread_stop(threads[i]);
}
}
}
static __init int minit(void)
{
// printk("testpar= %#x.\n",testpar);
printk("call %s.\n",__FUNCTION__);
// other_function();
set_reader_number(9);
if(create_threads())
{
cleanup_threads();
return -1;
}
return 0;
}
static __exit void mexit(void)
{
printk("call %s.\n",__FUNCTION__);
show_my_data();
}
module_init(minit)
module_exit(mexit)
//
sudo dmesg -c
sudo rmmod rcumain
sudo dmesg -c
sudo insmod rcumain.ko
sudo dmesg -c
[21685.846012] read count1 736, count2 7360.
[21685.846026] read count1 736, count2 7360.
[21685.846048] read count1 736, count2 7360.
[21685.849910] read count1 736, count2 7360.
[21685.849920] read count1 736, count2 7360.
[21685.857896] read count1 736, count2 7360.
[21685.857917] read count1 737, count2 7370.
[21685.861919] read count1 737, count2 7370.
[21685.861930] read count1 737, count2 7370.
[21685.861934] read count1 737, count2 7370.
[21685.861942] read count1 737, count2 7370.
[21685.861950] read count1 737, count2 7370.
[21685.865947] read count1 737, count2 7370.
[21685.865951] read count1 737, count2 7370.
[21685.873999] read count1 737, count2 7370.
[21685.874012] read count1 737, count2 7370.
[21685.878018] read count1 737, count2 7370.
[21685.878042] write completed!
[21685.878042] read count1 737, count2 7370.
[21685.878052] read count1 737, count2 7370.
[21685.878058] read count1 737, count2 7370.
[21685.878071] read count1 737, count2 7370.
[21685.881994] read count1 737, count2 7370.
[21685.882041] read count1 737, count2 7370.
[21685.889995] read count1 737, count2 7370.
[21685.890014] read count1 737, count2 7370.
[21685.894022] read count1 737, count2 7370.
[21685.894030] read count1 737, count2 7370.
[21685.894034] read count1 737, count2 7370.
[21685.894047] read count1 737, count2 7370.
[21685.894071] read count1 738, count2 7380.
[21685.898010] read count1 738, count2 7380.
[21685.898032] read count1 738, count2 7380.
[21685.906007] read count1 738, count2 7380.
[21685.906039] read count1 738, count2 7380.
[21685.910028] read count1 738, count2 7380.
[21685.910033] read count1 738, count2 7380.
[21685.910054] read count1 738, count2 7380.
[21685.910059] read count1 738, count2 7380.
[21685.910087] read count1 738, count2 7380.
[21685.913979] write completed!
[21685.913980] read count1 738, count2 7380.
[21685.913992] read count1 738, count2 7380.
[21685.922028] read count1 738, count2 7380.
[21685.922039] read count1 738, count2 7380.
[21685.926040] read count1 738, count2 7380.
[21685.926056] read count1 738, count2 7380.
[21685.926060] read count1 738, count2 7380.
[21685.926069] read count1 738, count2 7380.
[21685.926081] read count1 739, count2 7390.
[21685.929972] read count1 739, count2 7390.
[21685.929983] read count1 739, count2 7390.
[21685.938034] read count1 739, count2 7390.
[21685.938050] read count1 739, count2 7390.
[21685.942048] read count1 739, count2 7390.
[21685.942056] read count1 739, count2 7390.
[21685.942070] read count1 739, count2 7390.
[21685.942095] read count1 739, count2 7390.
[21685.942106] write completed!
[21685.942107] read count1 739, count2 7390.
[21685.946061] read count1 739, count2 7390.
[21685.946067] read count1 739, count2 7390.
[21685.954022] read count1 739, count2 7390.
[21685.954039] read count1 739, count2 7390.
[21685.958001] read count1 739, count2 7390.
[21685.958010] read count1 739, count2 7390.
[21685.958038] read count1 739, count2 7390.
[21685.958055] read count1 739, count2 7390.
[21685.962051] read count1 739, count2 7390.
[21685.962071] read count1 739, count2 7390.
[21685.962083] read count1 739, count2 7390.
[21685.970068] read count1 740, count2 7400.
[21685.970106] read count1 740, count2 7400.
[21685.974073] read count1 740, count2 7400.
[21685.974108] read count1 740, count2 7400.
[21685.974140] read count1 740, count2 7400.
[21685.974156] read count1 740, count2 7400.
[21685.978060] read count1 740, count2 7400.
[21685.978081] read count1 740, count2 7400.
[21685.978084] read count1 740, count2 7400.
[21685.986083] read count1 740, count2 7400.
[21685.986091] read count1 740, count2 7400.
[21685.989117] write completed!
[21685.990030] read count1 740, count2 7400.
[21685.990039] read count1 740, count2 7400.
[21685.990046] read count1 740, count2 7400.
[21685.990056] read count1 740, count2 7400.
[21685.994081] read count1 740, count2 7400.
[21685.994088] read count1 740, count2 7400.
[21685.994104] read count1 740, count2 7400.
[21686.002038] read count1 740, count2 7400.
[21686.002045] read count1 740, count2 7400.
[21686.006030] read count1 741, count2 7410.
[21686.006050] read count1 741, count2 7410.
[21686.006059] read count1 741, count2 7410.
[21686.006070] read count1 741, count2 7410.
[21686.010040] read count1 741, count2 7410.
[21686.010074] read count1 741, count2 7410.
[21686.010084] read count1 741, count2 7410.
[21686.014687] write completed!
[21686.018046] read count1 741, count2 7410.
[21686.018053] read count1 741, count2 7410.
[21686.022043] read count1 741, count2 7410.
[21686.022059] read count1 741, count2 7410.
[21686.022061] read count1 741, count2 7410.
[21686.022073] read count1 741, count2 7410.
[21686.026037] read count1 741, count2 7410.
[21686.026048] read count1 741, count2 7410.
[21686.026075] read count1 741, count2 7410.
=============
call_rcu vs. synchronize_rcu
static void rcu_free(struct rcu_head *head)
{
struct our_data *data;
data =container_of(head,struct our_data,rhead);
printk("rcu_free is called!");
kfree(data);
}
static void writer_do(void)
{
struct our_data *data, *tmp=pmy_data;
data = kmalloc(sizeof(*data),GFP_KERNEL);
if(!data)
return;
//Read + Copy. */
memcpy(data,pmy_data,sizeof(*data));
data->count1++;
data->count2 +=10;
rcu_assign_pointer(pmy_data,data);
if(tmp != &my_data)
{
call_rcu(&tmp->rhead,rcu_free);
}
//Update
}
[ 140.690494] read count1 49, count2 490.
[ 140.690505] read count1 49, count2 490.
[ 140.690526] read count1 50, count2 500.
[ 140.706419] rcu_free is called!
[ 140.706462] read count1 50, count2 500.
[ 140.706466] read count1 50, count2 500.
[ 140.706471] read count1 50, count2 500.
[ 140.706484] read count1 50, count2 500.
[ 140.706488] read count1 50, count2 500.
[ 140.706497] read count1 50, count2 500.
[ 140.706510] read count1 50, count2 500.
[ 140.706511] read count1 50, count2 500.
[ 140.706515] read count1 50, count2 500.
[ 140.722388] rcu_free is called!
[ 140.722439] read count1 51, count2 510.
[ 140.722444] read count1 51, count2 510.
[ 140.722447] read count1 51, count2 510.
[ 140.722452] read count1 51, count2 510.
[ 140.722465] read count1 51, count2 510.
[ 140.722473] read count1 51, count2 510.
[ 140.722480] read count1 51, count2 510.
[ 140.722487] read count1 52, count2 520.
[ 140.722508] read count1 52, count2 520.
[ 140.738443] rcu_free is called!
[ 140.738478] rcu_free is called!read count1 52, count2 520.
[ 140.738495] read count1 52, count2 520.
[ 140.738521] read count1 52, count2 520.
[ 140.738525] read count1 52, count2 520.
[ 140.738529] read count1 52, count2 520.
[ 140.738536] read count1 52, count2 520.
[ 140.738542] read count1 52, count2 520.
[ 140.738557] read count1 52, count2 520.
[ 140.738560] read count1 52, count2 520.
[ 140.754488] read count1 53, count2 530.
[ 140.754494] read count1 53, count2 530.
[ 140.754513] read count1 53, count2 530.
[ 140.754528] read count1 53, count2 530.
[ 140.754546] read count1 53, count2 530.
[ 140.754558] read count1 53, count2 530.
[ 140.754562] read count1 53, count2 530.
[ 140.754587] read count1 54, count2 540.
[ 140.754590] read count1 54, count2 540.
[ 140.770496] rcu_free is called!
[ 140.770497] read count1 54, count2 540.
[ 140.770510] read count1 54, count2 540.
[ 140.770518] read count1 54, count2 540.
[ 140.770523] read count1 54, count2 540.
[ 140.770529] read count1 54, count2 540.
[ 140.770539] read count1 54, count2 540.
[ 140.770543] read count1 54, count2 540.
[ 140.770556] read count1 54, count2 540.
[ 140.770589] read count1 54, count2 540.
[ 140.786502] rcu_free is called!
[ 140.786503] read count1 55, count2 550.
[ 140.786543] read count1 55, count2 550.
[ 140.786547] read count1 55, count2 550.
[ 140.786557] read count1 55, count2 550.
[ 140.786563] read count1 55, count2 550.
[ 140.786569] read count1 55, count2 550.
[ 140.786574] read count1 55, count2 550.
[ 140.786618] read count1 56, count2 560.
[ 140.786644] read count1 56, count2 560.
[ 140.802465] read count1 56, count2 560.
[ 140.802491] rcu_free is called!
[ 140.802523] read count1 56, count2 560.
[ 140.802526] read count1 56, count2 560.
[ 140.802529] read count1 56, count2 560.
[ 140.802538] read count1 56, count2 560.
[ 140.802544] read count1 56, count2 560.
[ 140.802560] read count1 56, count2 560.
[ 140.802563] read count1 56, count2 560.
[ 140.802573] read count1 56, count2 560.
[ 140.818512] rcu_free is called!
[ 140.818512] read count1 57, count2 570.