I have some problem with my code. In my code i solve the reader writers problem using RCU, when i load the module (insmod) everything works ok, and it works as i expected, but when i unload module (rmmod) my program freezes and I have to restart Ubuntu. In this program i have to use call_rcu() to delete previous version of the shared resource and i think that problem is here, because if i have not if I do not use this function and simply delete via kmalloc () then the program works as it should
#include<linux/module.h>#include<linux/kthread.h>#include<linux/wait.h>#include<linux/slab.h>#include<linux/rcupdate.h>enum thread_index {WAKING_THREAD, WRITER_THREAD, FIRST_READER_THREAD, SECOND_READER_THREAD};static struct thread_structure{ struct task_struct *thread[4];} threads;struct st{ int number; struct rcu_head rcu;};static wait_queue_head_t wait_queue;static bool condition;static struct st *number_pointer = NULL; static const int first_reader_number = 1, second_thread_number = 2;static int reader_thread(void *data){ struct st *local_number_pointer = NULL; for(;;) { rcu_read_lock(); local_number_pointer = rcu_dereference(number_pointer); if(local_number_pointer) pr_info("[reader_number: %d] Value of \"number\" variable: %d\n", *(int *)data,local_number_pointer->number); rcu_read_unlock(); if(kthread_should_stop()) return 0; set_current_state(TASK_INTERRUPTIBLE); if(schedule_timeout(HZ>>2)) pr_info("Signal received!\n"); }}static void remove(struct rcu_head *x){ struct st *pntr = container_of(x, struct st, rcu); kfree(pntr);}static int writer_thread(void *data){ struct st *local_number_pointer = NULL; int number = 0; DEFINE_WAIT(wait); for(;;) { struct st *old_pointer = NULL; local_number_pointer = kmalloc(sizeof(*local_number_pointer),GFP_KERNEL); if(IS_ERR(local_number_pointer)) { pr_alert("Error allocating memory: %ld\n",PTR_ERR(local_number_pointer)); return 0; } local_number_pointer->number = number++; old_pointer = number_pointer; rcu_assign_pointer(number_pointer,local_number_pointer); synchronize_rcu(); if(old_pointer) call_rcu(&old_pointer->rcu, remove); add_wait_queue(&wait_queue,&wait); while(!condition) { prepare_to_wait(&wait_queue,&wait,TASK_INTERRUPTIBLE); if(kthread_should_stop()) return 0; pr_info("[writer_thread]: awake\n"); schedule(); } condition=false; finish_wait(&wait_queue,&wait); }}static int waking_thread(void *data){ for(;;) { if(kthread_should_stop()) return 0; set_current_state(TASK_INTERRUPTIBLE); if(schedule_timeout(HZ)) pr_info("Signal received!\n"); condition=true; wake_up(&wait_queue); }}static int __init threads_init(void){ init_waitqueue_head(&wait_queue); threads.thread[WRITER_THREAD] = kthread_run(writer_thread,NULL,"writer_thread"); threads.thread[WAKING_THREAD] = kthread_run(waking_thread,NULL,"waking_thread"); threads.thread[FIRST_READER_THREAD] = kthread_run(reader_thread,(void *)&first_reader_number,"first_reader_thread"); threads.thread[SECOND_READER_THREAD] = kthread_run(reader_thread,(void *)&second_thread_number,"second_reader_thread"); return 0;}static void __exit threads_exit(void){ kthread_stop(threads.thread[WAKING_THREAD]); kthread_stop(threads.thread[WRITER_THREAD]); kthread_stop(threads.thread[FIRST_READER_THREAD]); kthread_stop(threads.thread[SECOND_READER_THREAD]);}module_init(threads_init);module_exit(threads_exit);MODULE_LICENSE("GPL");MODULE_DESCRIPTION("An example of using the kernel linux threads and an RCU mechanism.");MODULE_AUTHOR("Arkadiusz Chrobot <a.chrobot@tu.kielce.pl>");