/
MaestroN
/
Eltex_Homework
Обзор
Документация
Войти
/
MaestroN
/
Eltex_Homework
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
Task_14/task_monitor1.c
197 строк
6 KB
maestronnn
Changed Task 14
13 фев 2025, 09:49
13 фев 2025, 09:49
2a4c4a8
Код
Авторство
О чём код?
/* * task_monitor1.c - Модуль ядра для мониторинга активных задач с использованием RCU и спинлоков. * * Цель: * - Сбор информации о задачах (PID, имя, состояние) с использованием RCU для чтения. * - Защита обновления данных спинлоком. * - Экспорт функции get_task_list для взаимодействия с другими модулями. * - Вывод информации через /proc/task_monitor. */ #include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/sched.h> // Для task_struct и доступа к полям #include <linux/sched/signal.h> // for_each_process #include <linux/kthread.h> #include <linux/delay.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/rcupdate.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/string.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("MaestroN"); MODULE_DESCRIPTION("Модуль мониторинга задач с использованием RCU и спинлоков"); /* Предварительная декларация экспортируемой функции */ struct list_head *get_task_list(void); /* Структура для хранения информации о задаче */ struct task_info { pid_t pid; char comm[TASK_COMM_LEN]; long state; struct list_head list; }; /* Глобальный указатель на список задач (RCU-защищённый) */ static struct list_head *g_task_list = NULL; /* Спинлок для защиты обновления списка */ static spinlock_t task_list_lock; /* Поток для периодического обновления списка задач */ static struct task_struct *monitor_thread; /* Узел /proc для вывода информации */ static struct proc_dir_entry *proc_entry; /* Экспортируемая функция для получения текущего списка задач. * Чтение должно выполняться под rcu_read_lock(). */ struct list_head *get_task_list(void) { return rcu_dereference(g_task_list); } EXPORT_SYMBOL(get_task_list); /* Поток, который каждые 5 секунд обновляет список задач */ static int task_monitor_thread_fn(void *data) { while (!kthread_should_stop()) { struct list_head *new_list; struct list_head *old_list; struct task_struct *p; new_list = kmalloc(sizeof(struct list_head), GFP_KERNEL); if (!new_list) { schedule_timeout_interruptible(5 * HZ); continue; } INIT_LIST_HEAD(new_list); for_each_process(p) { struct task_info *ti = kmalloc(sizeof(*ti), GFP_KERNEL); if (!ti) continue; ti->pid = p->pid; strncpy(ti->comm, p->comm, TASK_COMM_LEN); ti->comm[TASK_COMM_LEN - 1] = '\0'; /* Используем p->__state, так как поле 'state' недоступно */ ti->state = p->__state; list_add_tail(&ti->list, new_list); } spin_lock(&task_list_lock); old_list = g_task_list; rcu_assign_pointer(g_task_list, new_list); spin_unlock(&task_list_lock); synchronize_rcu(); if (old_list) { struct task_info *ti, *tmp; list_for_each_entry_safe(ti, tmp, old_list, list) { list_del(&ti->list); kfree(ti); } kfree(old_list); } schedule_timeout_interruptible(5 * HZ); } return 0; } /* Функция вывода данных в /proc через seq_file */ static int proc_show(struct seq_file *m, void *v) { struct list_head *list_ptr; struct task_info *ti; rcu_read_lock(); list_ptr = rcu_dereference(g_task_list); if (list_ptr) { list_for_each_entry_rcu(ti, list_ptr, list) { seq_printf(m, "PID: %d, Comm: %s, State: %ld\n", ti->pid, ti->comm, ti->state); } } rcu_read_unlock(); return 0; } static int proc_open_func(struct inode *inode, struct file *file) { return single_open(file, proc_show, NULL); } /* Определяем структуру proc_ops для файла /proc */ static const struct proc_ops proc_file_ops = { .proc_open = proc_open_func, .proc_read = seq_read, .proc_lseek = seq_lseek, .proc_release = single_release, }; /* Инициализация модуля */ static int __init task_monitor_init(void) { int ret; spin_lock_init(&task_list_lock); /* Выделяем начальный (пустой) список задач */ g_task_list = kmalloc(sizeof(struct list_head), GFP_KERNEL); if (!g_task_list) return -ENOMEM; INIT_LIST_HEAD(g_task_list); /* Запускаем поток для обновления списка задач */ monitor_thread = kthread_run(task_monitor_thread_fn, NULL, "task_monitor_thread"); if (IS_ERR(monitor_thread)) { ret = PTR_ERR(monitor_thread); kfree(g_task_list); return ret; } /* Создаём запись в /proc */ proc_entry = proc_create("task_monitor", 0444, NULL, &proc_file_ops); if (!proc_entry) { kthread_stop(monitor_thread); kfree(g_task_list); return -ENOMEM; } pr_info("task_monitor: Module loaded successfully\n"); return 0; } /* Выгрузка модуля */ static void __exit task_monitor_exit(void) { struct list_head *old_list; struct task_info *ti, *tmp; if (monitor_thread) kthread_stop(monitor_thread); remove_proc_entry("task_monitor", NULL); spin_lock(&task_list_lock); old_list = g_task_list; g_task_list = NULL; spin_unlock(&task_list_lock); synchronize_rcu(); if (old_list) { list_for_each_entry_safe(ti, tmp, old_list, list) { list_del(&ti->list); kfree(ti); } kfree(old_list); } pr_info("task_monitor: Module unloaded successfully\n"); } module_init(task_monitor_init); module_exit(task_monitor_exit);