Comment créer un nouveau planificateur de kernel Linux

En parcourant le code source du planificateur (2.6.34, kernel / sched.c), je peux voir comment les ordonnanceurs “enfichables” sont utilisés, et je crois comprendre l’interface à implémenter. Ce que je ne comprends pas encore, c’est comment intégrer mon code au kernel. À tout le moins, des indications sur d’autres sites seraient appréciées.

En ce moment, je suis en train de bricoler SCHED_FIFO, SCHED_RR et SCHED_NORMAL dans l’arborescence des sources du kernel, donc je cherche vraiment un moyen plus perspicace de le regarder 🙂

EDIT: Comme arrière-plan, je suis très familier avec le planificateur FreeBSD (et le kernel FreeBSD en général), donc je ne cherche pas de pointeurs sur la façon de planifier les processus / niveaux de threads. Je cherche un moyen d’append mon propre planificateur avec les ordonnanceurs linux normaux (similaires à SCHED_FIFO).

EDIT # 2: Le pointeur BFS ci-dessous est un bon début, mais il extrait toujours le CFS du kernel. sched.c ressemble maintenant à:

#ifdef CONFIG_SCHED_BFS #include "sched_bfs.c" #else // original sched.c #endif // CONFIG_SCHED_BFS 

J’adorerais voir une réponse ou un indicateur sur la façon de le faire un peu mieux (c.-à-d. Garder CFS, du moins pour le moment).

EDIT # 3: J’ai répondu à ma propre question ci-dessous, car je pense que je l’ai compris.

J’ai trouvé la réponse à ma question, alors j’ai pensé que je l’appendais ici. Vous trouverez ci-dessous le correctif qui appenda un nouveau planificateur au kernel vanilla 2.6.34. Pour l’instant, je n’ai compilé que le kernel. Je m’attends à ce que l’exécution d’un système avec ce correctif EXACT entraîne son blocage – utilisez-le à vos risques et périls 🙂

 diff --git a/include/linux/sched.hb/include/linux/sched.h index 2b7b81d..a2a2b21 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -37,6 +37,7 @@ #define SCHED_RR 2 #define SCHED_BATCH 3 /* SCHED_ISO: reserved but not implemented yet */ +#define SCHED_NEW 4 /* Stealing from SCHED_ISO */ #define SCHED_IDLE 5 /* Can be ORed in to make sure the process is reverted back to SCHED_NORMAL on fork */ #define SCHED_RESET_ON_FORK 0x40000000 diff --git a/init/Kconfig b/init/Kconfig index eb77e8c..0055d26 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -23,6 +23,11 @@ config CONSTRUCTORS menu "General setup" +config SCHED_NEW + bool "NEW cpu scheduler" + ---help--- + Brand new scheduler + config EXPERIMENTAL bool "Prompt for development and/or incomplete code/drivers" ---help--- diff --git a/kernel/sched.cb/kernel/sched.c index 3c2a54f..588960d 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1931,6 +1931,7 @@ static void deactivate_task(struct rq *rq, struct task_struct *p, int sleep) #include "sched_idletask.c" #include "sched_fair.c" +#include "sched_new.c" #include "sched_rt.c" #ifdef CONFIG_SCHED_DEBUG # include "sched_debug.c" diff --git a/kernel/sched_new.cb/kernel/sched_new.c new file mode 100644 index 0000000..c2e269e --- /dev/null +++ b/kernel/sched_new.c @@ -0,0 +1,140 @@ +#ifdef CONFIG_SCHED_NEW + +/* + * Starting with a simple, 1 runq per cpu scheduler. Don't care + * about fairness for right now. Just get it up and running to + * verify that we have the interface correct + */ + +static void +enqueue_task_new(struct rq *rq, struct task_struct *p, int wakeup, bool head) +{ +} + +static void dequeue_task_new(struct rq *rq, struct task_struct *p, int sleep) +{ +} + +static void yield_task_new(struct rq *rq) +{ +} + +static void check_preempt_curr_new(struct rq *rq, struct task_struct *p, int flags) +{ +} + +static struct task_struct *pick_next_task_new(struct rq *rq) +{ +} + +static void put_prev_task_new(struct rq *rq, struct task_struct *p) +{ +} + +#ifdef CONFIG_SMP +static int select_task_rq_new(struct task_struct *p, int sd_flag, int flags) +{ +} +static void pre_schedule_new(struct rq *rq, struct task_struct *prev) +{ +} + +static void post_schedule_new(struct rq *rq) +{ +} + +static void task_woken_new(struct rq *rq, struct task_struct *p) +{ +} + +static void task_waking_new(struct rq *this_rq, struct task_struct *task) +{ +} +static void set_cpus_allowed_new(struct task_struct *p, + const struct cpumask *new_mask) +{ +} +/* Assumes rq->lock is held */ +static void rq_online_new(struct rq *rq) +{ +} + +/* Assumes rq->lock is held */ +static void rq_offline_new(struct rq *rq) +{ +} +#endif /* COMFIG_SMP */ + +static void set_curr_task_new(struct rq *rq) +{ +} + + +static void task_tick_new(struct rq *rq, struct task_struct *p, int queued) +{ +} + +static void task_fork_new(struct task_struct *p) +{ +} +static void switched_from_new(struct rq *rq, struct task_struct *p, + int running) +{ +} +static void switched_to_new(struct rq *this_rq, struct task_struct *task, + int running) +{ +} +static void prio_changed_new(struct rq *rq, struct task_struct *p, + int oldprio, int running) +{ +} +static unsigned int get_rr_interval_new(struct rq *rq, struct task_struct *task) +{ +} + + + +static const struct sched_class new_sched_class = { + .next = &fair_sched_class, + .enqueue_task = enqueue_task_new, + .dequeue_task = dequeue_task_new, + .yield_task = yield_task_new, + + .check_preempt_curr = check_preempt_curr_new, + + .pick_next_task = pick_next_task_new, + .put_prev_task = put_prev_task_new, + +#ifdef CONFIG_SMP + .select_task_rq = select_task_rq_new, + + .pre_schedule = pre_schedule_new, + .post_schedule = post_schedule_new, + + .task_waking = task_waking_new, + .task_woken = task_woken_new, + + .set_cpus_allowed = set_cpus_allowed_new, + + .rq_online = rq_online_new, + .rq_offline = rq_offline_new, +#endif + + .set_curr_task = set_curr_task_new, + .task_tick = task_tick_new, + .task_fork = task_fork_new, + + .switched_from = switched_from_new, + .switched_to = switched_to_new, + + .prio_changed = prio_changed_new, + + .get_rr_interval = get_rr_interval_new, +#ifdef CONFIG_FAIR_GROUP_SCHED + .moved_group = NULL +#endif +}; + +#endif /* CONFIG_SCHED_NEW */ diff --git a/kernel/sched_rt.cb/kernel/sched_rt.c index b5b920a..aaf4beb 100644 --- a/kernel/sched_rt.c +++ b/kernel/sched_rt.c @@ -1731,7 +1731,11 @@ static unsigned int get_rr_interval_rt(struct rq *rq, struct task_struct *task) } static const struct sched_class rt_sched_class = { +#ifdef CONFIG_SCHED_NEW + .next = &new_sched_class, +#else .next = &fair_sched_class, +#endif /* CONFIG_SCHED_NEW */ .enqueue_task = enqueue_task_rt, .dequeue_task = dequeue_task_rt, .yield_task = yield_task_rt, 

Embedded.com a une entrée en 3 parties qui traverse l’implémentation d’un planificateur en temps réel simple:

  • partie 1
  • partie 2
  • partie 3

Contrairement aux autres réponses, celle-ci est créée comme un tutoriel:

[…] dans la littérature, nous n’avons pas trouvé de documents expliquant comment mettre en œuvre une nouvelle politique de planification pour Linux.

[…]

Dans ce document, nous avons présenté dans une description détaillée toutes les étapes nécessaires pour mettre en œuvre une nouvelle politique de planification.

[…]

Ceci est une implémentation simple de cet algorithme de planification. Cependant, certains problèmes avancés, tels que les interruptions, les timers et les systèmes multiprocesseurs, pour ne citer que quelques exemples, sont hors de scope de cet article.

Con Kolivas Brainfuck Scheduler . Je viens de trouver ça par Google. Ce peut être un exemple pour commencer.