MyTetra Share
Делитесь знаниями!
14. Планирование задач
Время создания: 20.09.2022 09:55
Текстовые метки: linux, ядро, модуль, программирование, язык, C, Си, пособие, документация
Раздел: Компьютер - Linux - Ядро - Пособие по программированию модулей ядра Linux
Запись: xintrea/mytetra_syncro/master/base/16636569150smwuiundy/text.html на raw.github.com

14. Планирование задач

Есть два основных способа выполнения задач: тасклеты и очереди заданий. Тасклеты – это быстрый и простой способ планирования выполнения одной функции, например, при ее активации прерыванием. А вот очереди заданий хоть и более сложны, но зато лучше подходят для выполнения последовательностей задач.

▍ 14.1 Тасклеты

Ниже показан пример модуля тасклета. Функция tasklet_fn выполняется несколько секунд. При этом выполнение функции example_tasklet_init может продолжаться до точки выхода, что будет зависеть от того, была ли она прервана softirq.

example_tasklet.c


/*

* example_tasklet.c

*/

#include <linux/delay.h>

#include <linux/interrupt.h>

#include <linux/kernel.h>

#include <linux/module.h>

/* Макрос DECLARE_TASKLET_OLD присутствует для совместимости.

* См. https://lwn.net/Articles/830964/.

*/

#ifndef DECLARE_TASKLET_OLD

#define DECLARE_TASKLET_OLD(arg1, arg2) DECLARE_TASKLET(arg1, arg2, 0L)

#endif

static void tasklet_fn(unsigned long data)

{

pr_info("Example tasklet starts\n");

mdelay(5000);

pr_info("Example tasklet ends\n");

}

static DECLARE_TASKLET_OLD(mytask, tasklet_fn);

static int example_tasklet_init(void)

{

pr_info("tasklet example init\n");

tasklet_schedule(&mytask);

mdelay(200);

pr_info("Example tasklet init continues...\n");

return 0;

}

static void example_tasklet_exit(void)

{

pr_info("tasklet example exit\n");

tasklet_kill(&mytask);

}

module_init(example_tasklet_init);

module_exit(example_tasklet_exit);

MODULE_DESCRIPTION("Tasklet example");

MODULE_LICENSE("GPL");

После загрузки этого примера dmesg должна отобразить следующее:

tasklet example init

Example tasklet starts

Example tasklet init continues...

Example tasklet ends

И хотя использовать тасклеты легко, они имеют несколько недостатков, и в среде разработчиков обсуждается их возможное исключение из ядра. Обратный вызов тасклета выполняется в атомарном контексте внутри программного прерывания, то есть он не может входить в режим ожидания или получать доступ к данным пользовательского пространства, в результате чего в обработчике тасклетов не получится выполнить всю работу. Кроме того, ядро разрешает одновременно выполнять только один экземпляр любого конкретного тасклета. При этом несколько разных могут выполняться параллельно.

В последних версиях ядра появилась возможность заменить тасклеты очередями заданий, таймерами или прерываниями, выносимыми в отдельные потоки (threaded interrupts). Пока удаление тасклетов продолжает оставаться долгосрочной целью, в своем текущем виде ядро содержит более сотни случаев их использования. Сейчас разработчики продолжают вносить изменения в API, и для совместимости существует макрос DECLARE_TASKLET_OLD. Подробнее читайте на странице https://lwn.net/Articles/830964/.

▍ 14.2 Очереди заданий

Добавлять задачи в планировщик можно через очередь заданий. Для выполнения прописанных в этой очереди задач ядро использует Completely Fair Scheduler (CFS).

sched.c


/*

* sched.c

*/

#include <linux/init.h>

#include <linux/module.h>

#include <linux/workqueue.h>

static struct workqueue_struct *queue = NULL;

static struct work_struct work;

static void work_handler(struct work_struct *data)

{

pr_info("work handler function.\n");

}

static int __init sched_init(void)

{

queue = alloc_workqueue("HELLOWORLD", WQ_UNBOUND, 1);

INIT_WORK(&work, work_handler);

schedule_work(&work);

return 0;

}

static void __exit sched_exit(void)

{

destroy_workqueue(queue);

}

module_init(sched_init);

module_exit(sched_exit);

MODULE_LICENSE("GPL");

MODULE_DESCRIPTION("Workqueue example");



 
MyTetra Share v.0.65
Яндекс индекс цитирования