У меня проблемы с моим кодом. В своем коде я решаю проблему читателей и писателей с помощью RCU, когда я загружаю модуль (insmod), все работает нормально, и работает как я ожидал, но когда я выгружаю модуль (rmmod), моя программа зависает, и я должен перезапустить Ubuntu. В этой программе я должен использовать call_rcu (), чтобы удалить предыдущую версию общего ресурса, и я думаю, что проблема здесь, потому что если у меня нет, если я не использую эту функцию и просто удаляю через kmallo c (), тогда программа работает как надо
#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>");