J'ai essayé d'ajouter des appels système et des planificateurs à Linux

J'ai essayé d'ajouter des appels système et des planificateurs à Linux

Introduction (responsabilité critique: Nada)

Dans cet article

Vers Linux

--Appel système --Planificateur

Expliquez avec le plus de détails possible (afin que le lecteur puisse le reproduire).

Environnement PC

Construction de l'environnement (écrit par Kikuoka)

Quoi qu'il en soit, nous commencerons par construire l'environnement. Cette fois, je vais jouer avec le code source Linux, mais à la fin, j'ai besoin d'un environnement pour exécuter le code source falsifié. Même si votre ordinateur est Mac ou Windows, bien sûr, même s'il s'agit de Linux, vous ne pouvez pas remarquer si le code source du corps principal est changé arbitrairement et que l'opération devient étrange, alors exécutez Linux sur une machine virtuelle À.

Préparation

Tout d'abord, installez VirtualBox et Vagrant en prévision de l'exécution de la machine virtuelle. Dans l'ensemble, j'ai fait référence à ce site sauf indication contraire. Il y a quelques changements, mais si vous suivez cette procédure, il n'y a pas de problème. Finalement, nous allons créer deux machines, l'une qui s'exécute en reflétant le code source modifié (ci-après dénommé debuggee) et l'autre qui débogue le debuggee (ci-après dénommé débogueur). Cela sera expliqué en détail ci-dessous.

Installation de VirtualBox

Pour cette partie, je me réfère à ce site. C'est un site en anglais, mais vous pouvez jeter un œil à la partie Méthode 3, ou si c'est un problème, voir l'explication ci-dessous.

Tout d'abord, ajoutez la clé publique de VirtualBox avec la commande suivante.

~$ wget -q https://www.virtualbox.org/download/oracle_vbox_2016.asc -O- | sudo apt-key add -

Ensuite, utilisez la commande suivante pour vous connecter au référentiel VirtualBox.

~$ sudo add-apt-repository "deb [arch=amd64] http://download.virtualbox.org/virtualbox/debian $(lsb_release -cs) contrib"

Vous pouvez réellement installer VirtualBox avec la commande suivante.

~$ sudo apt update && sudo apt install virtualbox-6.0

Installez Vagrant

Tout d'abord, téléchargez le fichier de package avec la commande suivante. À ce stade, notez que la commande diffère selon l'environnement dont vous disposez. Puisque tous les membres de l'équipe utilisaient des machines x86, les commandes ci-dessous sont adaptées en conséquence.

~$ wget https://releases.hashicorp.com/vagrant/2.2.6/vagrant_2.2.6_x86_64.deb

Installez Vagrant à partir du fichier de package que vous avez téléchargé précédemment avec la commande suivante.

~$ sudo dpkg -i vagrant_2.2.6_x86_64.deb

Comme vous pouvez le voir dans la commande, la version à installer cette fois-ci est 6.0 pour VirtualBox et 2.2.6 pour Vagrant, mais si l'une est trop récente, l'autre ne la prend pas en charge et c'est normal. Il y a des cas où cela ne fonctionne pas, donc à moins que vous n'ayez une raison spécifique, nous vous recommandons d'utiliser cette version.

Créer une machine virtuelle

Enfin, créez une machine virtuelle. Pour ce faire, utilisez la commande suivante pour créer un répertoire de travail et entrez-le.

~$ mkdir -p ~/Vagrant/ubuntu18
~$ cd Vagrant/ubuntu18

Initialisez Vagrant. À ce moment, un fichier de paramètres Vagrant appelé Vagrantfile est généré.


~/Vagrant/ubuntu18$ vagrant init ubuntu/bionic64

Modifiez ce fichier, mais avant de le faire, installez les plugins nécessaires pour augmenter la capacité de votre machine virtuelle.

~$ vagrant plugin install vagrant-disksize

Cela permet d'augmenter la capacité en écrivant une description appropriée dans le Vagrantfile. Si vous ne le faites pas, vous pouvez obtenir une erreur due à une capacité insuffisante après le démarrage de la machine virtuelle, alors soyez prudent.

Ouvrez le Vagrantfile généré et modifiez-le comme suit.


Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/bionic64"
  config.vm.define "debugger" do |c|
    c.vm.provider "virtualbox" do |vb|
      vb.customize ["modifyvm", :id, "--uart2", "0x2F8", "3"]
      vb.customize ["modifyvm", :id, "--uartmode2", "server", "/tmp/vagrant-ttyS1"]
      vb.memory = "8192"
    end
  end
  config.vm.define "debuggee" do |c|
    c.vm.provider "virtualbox" do |vb|
      vb.customize ["modifyvm", :id, "--uart2", "0x2F8", "3"]
      vb.customize ["modifyvm", :id, "--uartmode2", "client", "/tmp/vagrant-ttyS1"]
    end
  end
  config.disksize.size = '100GB'
end

Enfin, démarrez la machine virtuelle. Démarrez la machine virtuelle avec la commande suivante.

~/Vagrant/ubuntu18$ vagrant up

Si le débogueur et le débogueur démarrent sans problème, entrez la commande suivante pour ouvrir le débogueur dans le terminal.

~/Vagrant/ubuntu18$ vagrant ssh debuggee

Ajoutez les paramètres de débogage avec la commande suivante.

debuggee:~$ sudo systemctl enable [email protected]

Redémarrez la machine virtuelle avec la commande suivante.

~/Vagrant/ubuntu18$ vagrant reload 

Ouvrez maintenant le débogueur et voyez si la communication série est possible.

debugger:~$ sudo screen /dev/ttyS1
<Appuyez sur ENTRY>
Ubuntu 18.04.3 LTS ubuntu-bionic ttyS1

ubuntu-bionic login:

paramètres kgdb

Jusqu'à ce point, vous pouvez démarrer la machine virtuelle, mais il est difficile de déboguer tel quel, donc reconstruisez le noyau pour le rendre compatible avec kgdb.

Créez un environnement de développement de noyau sur le débogueur avec la commande suivante.

debugger:~$ sudo apt-get install git build-essential kernel-package fakeroot libncurses5-dev libssl-dev ccache bison flex gdb

Ensuite, téléchargez le code source du noyau dans le répertoire personnel du débogueur. Cette fois, nous viserons la version 5.3.9.

debugger:~$ wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.3.9.tar.xz

Décompressez le fichier téléchargé.

debugger:~$ tar Jxfv ./linux-5.3.9.tar.xz

Entrez le répertoire généré et définissez le fichier config.

debugger:~$ cd linux-5.3.9
debugger:~/linux-5.3.9$ cp /boot/config-`uname -r` .config
debugger:~/linux-5.3.9$ yes '' | make oldconfig
debugger:~/linux-5.3.9$ make menuconfig

Depuis que l'écran des paramètres de configuration s'ouvre, recherchez les éléments suivants, cochez les cinq premiers et décochez le dernier.

Kernel hacking -> [*]KGDB: kernel debugger
Kernel hacking -> KGDB: kernel debugger -> [*]KGDB: use kgdb over the serial console
Kernel hacking -> KGDB: kernel debugger -> [*]KGDB: internal test suite
Kernel hacking -> KGDB: kernel debugger -> [*]KGDB: Allow debugging with traps in notifiers
Kernel hacking -> KGDB: kernel debugger ->  [*]KGDB_KDB: include kdb frontend for kgdb
Processor type and features -> [ ]Randomize the address of the kernel image (KASLR)

Construisez le code source du noyau. Cela dépend de l'ordinateur que vous utilisez, mais cela prendra plusieurs heures, alors faites une pause et laissez l'ordinateur faire de votre mieux.

debugger:~/linux-5.3.9$ make clean
debugger:~/linux-5.3.9$ make -j `getconf _NPROCESSORS_ONLN` deb-pkg

Partagez le package généré par la construction avec le débogueur. Utilisez le fait que le répertoire spécifié par le chemin de / vagrant est défini comme un dossier partagé et déplacez-y le package une fois.

debugger:~/linux-5.3.9$ mv ../linux-headers-5.3.9_5.3.9-1_amd64.deb /vagrant
debugger:~/linux-5.3.9$ mv ../linux-libc-dev_5.3.9-1_amd64.deb /vagrant
debugger:~/linux-5.3.9$ mv ../linux-image-5.3.9_5.3.9-1_amd64.deb /vagrant
debugger:~/linux-5.3.9$ mv ../linux-image-5.3.9-dbg_5.3.9-1_amd64.deb /vagrant

Ouvrez debuggee et installez le package que vous avez partagé précédemment.

debuggee:~$ sudo dpkg -i /vagrant/linux-headers-5.3.9_5.3.9-1_amd64.deb
debuggee:~$ sudo dpkg -i /vagrant/linux-libc-dev_5.3.9-1_amd64.deb
debuggee:~$ sudo dpkg -i /vagrant/linux-image-5.3.9_5.3.9-1_amd64.deb
debuggee:~$ sudo dpkg -i /vagrant/linux-image-5.3.9-dbg_5.3.9-1_amd64.deb

Vous pouvez maintenant déboguer avec kdgb. Il est recommandé de redémarrer la machine virtuelle une fois qu'un nouveau package est installé. Cela est dû au fait que kdgb peut ne pas fonctionner correctement ou que des problèmes peuvent survenir dans le fonctionnement du noyau lui-même.

De plus, si vous installez l'extension Remote-SSH de VSCode, vous pouvez modifier les fichiers de la machine virtuelle avec VSCode, donc si vous êtes familier avec VSCode ou ne pouvez pas utiliser vim pour des raisons religieuses, essayez-le. Tu devrais voir ça.

À ce stade, l'environnement permettant d'apporter des modifications au code source Linux et de l'exécuter réellement est prêt. Maintenant, jouons réellement avec le code source d'ici.

Faisons un nouvel appel système (responsabilité critique: Kikuoka)

Comme vous pouvez le voir dans l'en-tête, l'objectif est d'ajouter un nouvel appel système et de l'appeler pour vérifier son fonctionnement. Un appel système est une fonction utilisée pour appeler une fonction du système d'exploitation (le noyau) dans un programme. L'entrée / sortie de fichier et la communication basée sur le réseau sont implémentées en tant qu'appels système, mais cette fois nous allons ajouter deux arguments entiers et les additionner. Lors de la mise en œuvre de [ce site](https://pr0gr4m.tistory.com/entry/Linux-Kernel-5-system-call-%EC%B6%94%EA%B0%80%ED%95% 98% EA% B8% B0? Category = 714120) est coréen, mais cela a été très utile. La procédure sera décrite ci-dessous.

Ajouter un appel système

Tout d'abord, recherchez le fichier spécifié par * arch / x86 / entry / syscalls / syscall_64.tbl * dans le code source Linux. Je pense que les appels système implémentés dans la version actuelle sont alignés dans un format de liste.

Screenshot from 2020-11-02 14-38-45.png

Tout ce que vous avez à faire est d'ajouter ici les appels système que vous souhaitez ajouter aux numéros gratuits. Si vous copiez la manière d'écrire d'autres appels système qui ont déjà été écrits, cela ressemblera à ceci.

Screenshot from 2020-11-02 14-45-41.png

548     64      mycall                  __x64_sys_mycall

L'appel système mycall au numéro 548 est l'appel système que nous ajoutons. Bien sûr, si rien n'est fait, cela ne fonctionnera pas car il n'y a pas de substance sur la table.

Ensuite, allons au fichier spécifié par include / linux / syscalls.h. Il y aura une déclaration du type d'appel système implémenté.

Screenshot from 2020-11-02 14-59-46.png

Le nom de la fonction correspond ici à la partie sous x64 dans la quatrième colonne ajoutée à la liste ci-dessus. Par conséquent, vous pouvez déclarer le type de sys_mycall à une position appropriée.

Screenshot from 2020-11-02 15-06-33.png

asmlinkage long sys_mycall(int a,int b, int *to_user);

a et b sont deux variables qui effectuent l'addition, et l'argument to_user contient les informations de l'appelant de l'appel système, qui sont nécessaires pour transmettre le résultat du calcul effectué par le noyau.

Après avoir fait la déclaration, il est enfin temps de définir l'entité. Créez un fichier appelé mycall.c (quel que soit son nom) dans un répertoire appelé kernel et définissez-y la fonction. Screenshot from 2020-11-02 15-45-52.png

Screenshot from 2020-11-02 15-28-19.png

#include <linux/kernel.h>
#include <linux/syscalls.h>
#include <asm/processor.h>
#include <asm/uaccess.h>

SYSCALL_DEFINE3(mycall, int, a, int, b, int *, to_user)
{
        int sum = 0;
        printk("[Kernel Message] a = %d, b = %d\n", a, b);
        sum = a + b;
        put_user(sum, to_user);
        return 21;
}

SYSCALL_DEFINE est une macro utilisée lors de la définition d'un appel système, et est utilisée en ajoutant le nombre d'arguments au moment de la déclaration. Puisqu'il y avait trois arguments cette fois, il devient SYSCALL_DEFINE3. L'argument réel est un de plus que ce nombre car le numéro d'appel système est spécifié comme premier argument. De plus, lors de l'appel d'un appel système, il sera appelé avec le nom d'appel système mycall au lieu d'une macro. Dans le cas de l'argument 0, la liaison asm est utilisée comme dans le cas de la déclaration.

C'est la fin de la définition de l'entité, et si vous compilez correctement le noyau, vous devriez pouvoir utiliser mycall.

Utilisons-le réellement

Vérifiez le fonctionnement de mycall. Pour cela, il est nécessaire de reconstruire le noyau, mais comme mycall.c ne peut pas être reflété au moment de la construction tel quel, ajoutez un peu au Makefile.

Screenshot from 2020-11-02 15-45-52.png

obj-y     = fork.o exec_domain.o panic.o \
.................................................
            mycall.o

Puis compilez-le à nouveau, installez le package avec debuggee, redémarrez-le et vous pourrez utiliser les nouveaux appels système.

Exécutons le code de test à titre d'essai. Screenshot from 2020-11-02 15-54-48.png

Lorsque ce code est compilé et exécuté, la sortie est la suivante.

Screenshot from 2020-11-02 15-57-28.png

Le résultat de calcul correct est sorti en tant que valeur de somme, et 21 qui est la valeur de retour de mycall est sorti en tant que valeur de ret, et on peut voir que l'appel système est appelé correctement.

Essayez également d'appeler le message du noyau avec la commande dmesg.

Screenshot from 2020-11-02 16-04-00.png

Les valeurs de a et b sont sorties sous forme de messages du noyau à la fin, indiquant que les valeurs peuvent être transmises correctement au noyau.

Faisons un cours d'ordonnancement (responsabilité critique: Choi Jae-hyun)

Implémentation d'algorithme

Qu'est-ce que la planification aléatoire?

La planification aléatoire montre comment sélectionner au hasard parmi les tâches en attente lors de la sélection de la tâche suivante à partir de la CPU.

Implémentation de file d'attente d'exécution aléatoire

struct random_rq{
	struct list_head task_list;
	unsigned int random_nr_running;
	int random_queued;
	int random_throttled;
	u64 random_time;
	u64 random_runtime;
};
Description de list_head

list_head est une implémentation de la structure de données de liste concaténée dans le code source Linux, qui se trouve dans (répertoire du code source linux) /tools/include/linux/types.h.

struct list_head {
	struct list_head *next, *prev;
};

Généralement, lors de l'utilisation d'une liste concaténée, le pointeur de la structure est utilisé pour indiquer next et prev dans la structure des données. (Voir code ci-dessous)

struct linked_list{
	int data; //Les données
	struct linked_list *next, *prev; //Pointeur de structure
}

Cependant, list_head implémente une liste concaténée en ajoutant la variable list_head à la structure de données. (Voir code ci-dessous)

struct linked_list{
	int data; //Les données
	struct list_head list; //Liste concaténée
}

Maintenant, en regardant comment list_head connecte les éléments (nœuds), il utilise la fonction suivante. ((Il est écrit dans (répertoire du code source linux) /include/linux/list.h)

INIT_LIST_HEAD initialise list_head en faisant siennes le suivant et le précédent de list_head.

static inline void INIT_LIST_HEAD(struct list_head *list)
{
	WRITE_ONCE(list->next, list);
	list->prev = list;
}

En regardant la figure, cela ressemble à ceci, et une liste circulaire bidirectionnelle est créée. figure_list_01.png

list_add et list_add_tail sont des fonctions qui ajoutent des éléments à la liste concaténée, et reçoivent le pointeur de la tête qui est la tête de la liste et le pointeur de l'élément que vous voulez ajouter comme arguments.

static inline void __list_add(struct list_head *new,
			      struct list_head *prev,
			      struct list_head *next)
{
	if (!__list_add_valid(new, prev, next))
		return;

	next->prev = new;
	new->next = next;
	new->prev = prev;
	WRITE_ONCE(prev->next, new);
}

static inline void list_add(struct list_head *new, struct list_head *head)
{
	__list_add(new, head, head->next);
}

static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
	__list_add(new, head->prev, head);
}

La fonction principale de list_add et list_add_tail est __list_add, qui met new à l'intérieur de prev et next. La différence entre list_add et list_add_tail est de savoir s'il faut mettre new dans head-> next, qui est l'élément suivant de head et head, ou de mettre new dans head-> prev, qui est l'élément avant head et head. Est. Après tout, list_add place l'élément au début de la liste, et list_add_tail place l'élément à la fin de la liste.

figure_list_02.png figure_list_03.png

list_del et list_del_init sont des fonctions utilisées pour supprimer des éléments de la liste concaténée.

static inline void __list_del(struct list_head * prev, struct list_head * next)
{
	next->prev = prev;
	WRITE_ONCE(prev->next, next);
}

static inline void __list_del_entry(struct list_head *entry)
{
	if (!__list_del_entry_valid(entry))
		return;

	__list_del(entry->prev, entry->next);
}

static inline void list_del(struct list_head *entry)
{
	__list_del_entry(entry);
	entry->next = LIST_POISON1;
	entry->prev = LIST_POISON2;
}

static inline void list_del_init(struct list_head *entry)
{
	__list_del_entry(entry);
	INIT_LIST_HEAD(entry);
}

La différence entre list_del et list_del_init réside dans ce qu'il faut faire avec les variables next et prev des éléments à supprimer. list_del fait des données un pointeur dénué de sens, mais list_del_init le fait lui-même. (Description de LIST_POISON: https://lists.kernelnewbies.org/pipermail/kernelnewbies/2016-March/015879.html)

Dans random_rq, il était nécessaire d'utiliser list_head pour implémenter une liste de tâches à gérer par ordonnancement aléatoire, et pour sélectionner un nombre aléatoire arbitraire n (entier plus petit que la tâche à traiter) e tâche. Par conséquent, j'ai utilisé list_for_each, qui est une macro qui fait le tour de la liste.

#define list_for_each(pos, head) \
	for (pos = (head)->next; pos != (head); pos = pos->next)

Il commence simplement par l'élément suivant au début et se répète jusqu'à ce qu'il atteigne le début.

Jusqu'à présent, j'ai implémenté toutes les parties de la liste concaténée, mais comme la liste concaténée (list_head) n'a pas réellement de données, même si je demande le nième élément avec list_for_each, les données du nième élément sont Je ne sais pas. Pour trouver ces données, Linux utilise une macro appelée list_entry. (Écrit dans /include/linux/list.h)

#define list_entry(ptr, type, member) \
	container_of(ptr, type, member)

La macro container_of ressemble à ceci: (Écrit dans /include/linux/kernel.h)

#define container_of(ptr, type, member) ({				\
	void *__mptr = (void *)(ptr);					\
	BUILD_BUG_ON_MSG(!__same_type(*(ptr), ((type *)0)->member) &&	\
			 !__same_type(*(ptr), void),			\
			 "pointer type mismatch in container_of()");	\
	((type *)(__mptr - offsetof(type, member))); })

La macro offsetof ressemble à ceci:

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

L'explication détaillée est écrite sur https://stackoverflow.com/questions/5550404/list-entry-in-linux, mais brièvement, le pointeur ptr de list_head, le type de structure avec les données que vous voulez trouver, type (ci-dessus) Selon l'exemple, struct linked_list), prenez le nom de variable membre de list_head (list selon l'exemple ci-dessus) comme argument dans la structure avec les données souhaitées, et calculez le nombre d'octets depuis le début de la structure souhaitée jusqu'à list_head ( Rôle de offsetof) Trouvez le pointeur de la structure qui contient les données que vous voulez trouver en le tirant du pointeur de list_head. La figure est la suivante.

figure_list_04.png

Implémentation de chaque fonction

La partie réellement implémentée dans la fonction requise pour l'ordonnanceur est la suivante. (Référence: https://trepo.tuni.fi/bitstream/handle/10024/96864/GRADU-1428493916.pdf, p.27 ~ p.28)

enqueue_task

static void enqueue_task_random(struct rq *rq, struct task_struct *p, int flags){
	enqueue_list(&rq->rd_rq,p,flags);
	add_nr_running(rq,1);
	rq->rd_rq.random_nr_running++;
}

Ici, la liste_enqueue ressemble à ceci:

void enqueue_list(struct random_rq *rd_rq,struct task_struct *p, int flags){
	INIT_LIST_HEAD(&p->rd_list);
	list_add_tail(&p->rd_list,&rd_rq->task_list);
}

dequeue_task

static void dequeue_task_random(struct rq *rq, struct task_struct *p, int flags){
	dequeue_list(&rq->rd_rq,p,flags);
	sub_nr_running(rq,1);
	rq->rd_rq.random_nr_running--;
}

Ici, la liste de file d'attente ressemble à ceci:

void dequeue_list(struct random_rq *rd_rq,struct task_struct *p, int flags){
	list_del_init(&p->rd_list);
}

yield_task

static void yield_task_random(struct rq *rq){
	struct task_struct *p = rq->curr; //TODO
	dequeue_list(&rq->rd_rq,p,0);
	enqueue_list(&rq->rd_rq,p,0);
}

La fonction yield_task peut être implémentée en prenant la tâche courante et en la déplaçant à la fin de la liste, donc prenez la tâche courante p de dequeue_list et remettez-la dans la liste depuis enqueue_list.

pick_next_task

static struct task_struct * pick_next_task_random(struct rq *rq, struct task_struct *prev, struct rq_flags *rf){
	put_prev_task(rq,prev);
	struct task_struct *p;
	struct random_rq *rd_rq= &rq->rd_rq;
	p = pick_random_entity(rd_rq);
	return p;
}

L'implémentation de la fonction pick_random_entity est la suivante.

static struct task_struct* pick_random_entity(struct random_rq *random_rq){ //Pick one task randomly -> return p
	struct task_struct *p;
	unsigned long random_val;
	unsigned long cnt;
	struct list_head *ptr;
	if(random_rq->random_nr_running){
		random_val = 0UL;
		get_random_bytes(&random_val,sizeof(unsigned long));
		random_val = random_val%(random_rq->random_nr_running);
		cnt = 0UL;
		list_for_each(ptr,&random_rq->task_list){
			if(cnt==random_val){
				p = list_entry(ptr,struct task_struct,rd_list);
				return p;
			}
			cnt++;
		}
	}
	return NULL;
}

Utilisez la fonction get_random_bytes pour mettre un nombre aléatoire dans random_val et divisez-le par le nombre de tâches dans la file d'attente d'exécution aléatoire pour en laisser trop pour calculer le nombre aléatoire n que vous voulez trouver. Utilisez ensuite list_for_each et list_entry pour trouver la tâche p.

put_prev_task

static void put_prev_task_random(struct rq *rq, struct task_struct *p){
	enqueue_list(&rq->rd_rq,p,0);
}

put_prev_task consiste à placer la tâche qui a fonctionné dans la file d'attente d'exécution à la fin de la liste d'attente d'exécution.

task_tick

static void task_tick_random(struct rq *rq, struct task_struct *p, int queued){
	if(!queued){
		resched_curr(rq);
	}
	return;
}

task_tick est une fonction qui est appelée pour la première fois dans un temps spécifié, et le planificateur aléatoire n'a pas besoin de calculer le temps d'attente et l'heure de fin de la tâche, il n'effectue donc que la replanification.

Laissez le planificateur implémenté être utilisé (responsabilité critique: Nada)

Ensuite, assurez-vous que la classe du planificateur implémentée ci-dessus est effectivement utilisée.

Ici, nous allons principalement jouer avec kernel / sched / core.c (ci-après abrégé en core.c).

Allouer un planificateur à un processus (strictement task_struct)

// kernel/sched/core.c
int sched_fork(...){
    (Omission)
	if (dl_prio(p->prio))
		return -EAGAIN;
	else if (rt_prio(p->prio))
		p->sched_class = &rt_sched_class;
	else
		p->sched_class = &fair_sched_class;
    (Abréviation)
}

static void __setscheduler(struct rq *rq, struct task_struct *p,
			   const struct sched_attr *attr, bool keep_boost)
    (Omission)
    if (dl_prio(p->prio))
		p->sched_class = &dl_sched_class;
	else if (rt_prio(p->prio))
		p->sched_class = &rt_sched_class;
	else
		p->sched_class = &fair_sched_class;
	(Abréviation)
}

Autres classes de planificateur pour savoir comment la classe de planificateur est gérée par le noyau

Si vous recherchez dans GNU global rt_sched_class, fair_sched_class, etc., la partie ci-dessus dans core.c sera frappée.

Peut-être pourrions-nous ajouter ici un traitement à notre ordonnanceur aléatoire.

Après examen, la fonction {nom du planificateur} _prio (rt_prio, dl_prio ...) est définie dans le fichier {nom du planificateur} .h.

En regardant l'implémentation de dl_prio comme un essai, il semble qu'il reçoive la priorité (p-> prio) de task_struct (process) et renvoie 1 s'il est dans la plage de priorité dont l'ordonnanceur est en charge, sinon il retourne 0.

Exemple: implémentation de dl_prio

// include/linux/sched/deadline.h
#define MAX_DL_PRIO		0

static inline int dl_prio(int prio)
{
	if (unlikely(prio < MAX_DL_PRIO))
		return 1;
	return 0;
}

Suite à cela, une fonction appelée rd_prio est implémentée dans le fichier d'en-tête include / linux / sched / random_sched.h du planificateur aléatoire.

// include/linux/sched/random_sched.h
static inline int rd_prio(int prio)
{
	if (121 <= prio && prio <= 139)
		return 1;
	return 0;
}

Ici, 1 est renvoyé pour les processus avec une plage de priorité de 121 à 139.

Utilisez cette fonction pour réécrire core.c comme suit.

// kernel/sched/core.c
int sched_fork(...){
    (Omission)
	if (dl_prio(p->prio))
		return -EAGAIN;
	else if (rt_prio(p->prio))
		p->sched_class = &rt_sched_class;
	else if (rd_prio(p->prio)) // Added this line
		p->sched_class = &random_sched_class;
	else
		p->sched_class = &fair_sched_class;
    (Abréviation)
}

static void __setscheduler(struct rq *rq, struct task_struct *p,
			   const struct sched_attr *attr, bool keep_boost)
    (Omission)
    if (dl_prio(p->prio))
		p->sched_class = &dl_sched_class;
	else if (rt_prio(p->prio))
		p->sched_class = &rt_sched_class;
	else if (rd_prio(p->prio)) // Added this line
		p->sched_class = &random_sched_class;
	else
		p->sched_class = &fair_sched_class;
    (Abréviation)
}

La tâche est maintenant affectée au processus.

Cependant, vous devez inclure le fichier random_sched.h nouvellement créé dans core.c.

Encore une fois, suite à l'implémentation d'autres ordonnanceurs, où les instructions include dans kernel / sched / sched.h sont organisées.

#include <linux/sched/random_sched.h>Était ajouté. coeur.c est le noyau/sched/sched.Puisque h est inclus, c'est le noyau.c au hasard_sched.Vous pouvez maintenant utiliser les fonctions de h.







#### Mise en œuvre de la fonction politique

 En regardant à l'intérieur du fichier d'en-tête général du planificateur kenel / sched / sched.h,

```c
static inline int idle_policy(int policy)
{
	return policy == SCHED_IDLE;
}
static inline int fair_policy(int policy)
{
	return policy == SCHED_NORMAL || policy == SCHED_BATCH;
}

static inline int rt_policy(int policy)
{(Omis)}

static inline int dl_policy(int policy)
{(Omis)}
static inline bool valid_policy(int policy)
{
	return idle_policy(policy) || fair_policy(policy) ||
		rt_policy(policy) || dl_policy(policy);
}

J'ai trouvé que la fonction appelée est définie. Vous pouvez probablement deviner que vous vérifiez si le planificateur est correctement spécifié avec la fonction valid_policy.

Par conséquent, le planificateur aléatoire suit ceci, comme suit

// Added this function
static inline int random_policy(int policy)
{
	return policy == SCHED_RANDOM;
}
static inline bool valid_policy(int policy)
{
	return idle_policy(policy) || fair_policy(policy) ||
		rt_policy(policy) || dl_policy(policy) || random_policy(policy); // Fixed this line
}

J'ai implémenté une fonction appelée random_policy et l'ai mise dans valid_policy.

La valeur constante SCHED_RANDOM qui apparaît ici suit d'autres valeurs constantes telles que SCHED_NORMAL et SCHED_IDLE dans include / uapi / sched.h.

#define SCHED_NORMAL		0
#define SCHED_FIFO		1
#define SCHED_RR		2
#define SCHED_BATCH		3
/* SCHED_ISO: reserved but not implemented yet */
#define SCHED_IDLE		5
#define SCHED_DEADLINE		6
#define SCHED_RANDOM		7

A été défini comme.

Résultat d'exécution et débogage (responsabilité critique: Choi Jae-hyun)

Tout d'abord, suite à la construction de la même manière que l'environnement de construction de https://leavatail.hatenablog.com/entry/2019/11/04/235300, l'erreur suivante s'est produite lors du démarrage de Linux. Dans le dossier vagrant (/ Vagrant / ubuntu18), il y a un journal contenant le message du noyau (imprimé par printk). (ubuntu-bionic-18.04-cloudimg-console.log) J'ai donc pu confirmer la raison pour laquelle Linux ne pouvait pas fonctionner.

Journal des erreurs
[   28.333395] watchdog: BUG: soft lockup - CPU#2 stuck for 22s![kworker/2:1:88]
[   28.333395] Modules linked in:
[   28.333395] CPU: 2 PID: 88 Comm: kworker/2:1 Not tainted 5.3.9+ #1
[   28.333395] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
[   28.333395] Workqueue: events timer_update_keys
[   28.333395] RIP: 0010:smp_call_function_many+0x239/0x270
[   28.333395] Code: 08 89 c7 e8 e9 f7 90 00 3b 05 77 a8 70 01 0f 83 5c fe ff ff 48 63 c8 48 8b 13 48 03 14 cd 00 a9 3d 82 8b 4a 18 83 e1 01 74 0a <f3> 90 8b 4a 18 83 e1 01 75 f6 eb c7 0f 0b e9 0b fe ff ff 48 c7 c2
[   28.333395] RSP: 0018:ffffc9000028bd08 EFLAGS: 00000202 ORIG_RAX: ffffffffffffff13
[   28.333395] RAX: 0000000000000000 RBX: ffff88803eaab500 RCX: 0000000000000001
[   28.333395] RDX: ffff88803ea30fe0 RSI: 0000000000000000 RDI: ffff88803e445a98
[   28.333395] RBP: ffffc9000028bd40 R08: ffff88803eb40000 R09: ffff88803e403c00
[   28.333395] R10: ffff88803e445a98 R11: 0000000000000000 R12: 0000000000000006
[   28.333395] R13: 000000000002b4c0 R14: ffffffff810390a0 R15: 0000000000000000
[   28.333395] FS:  0000000000000000(0000) GS:ffff88803ea80000(0000) knlGS:0000000000000000
[   28.333395] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   28.333395] CR2: 0000000000000000 CR3: 000000000260a000 CR4: 00000000000406e0
[   28.333395] Call Trace:
[   28.333395]  ? poke_int3_handler+0x70/0x70
[   28.333395]  on_each_cpu+0x2d/0x60
[   28.333395]  text_poke_bp_batch+0x8c/0x160
[   28.333395]  arch_jump_label_transform_apply+0x33/0x50
[   28.333395]  __jump_label_update+0x116/0x160
[   28.333395]  jump_label_update+0xb9/0xd0
[   28.333395]  static_key_enable_cpuslocked+0x5a/0x80
[   28.333395]  static_key_enable+0x1a/0x30
[   28.333395]  timers_update_migration+0x30/0x40
[   28.333395]  timer_update_keys+0x1a/0x40
[   28.333395]  process_one_work+0x1fd/0x3f0
[   28.333395]  worker_thread+0x34/0x410
[   28.333395]  kthread+0x121/0x140
[   28.333395]  ? process_one_work+0x3f0/0x3f0
[   28.333395]  ? kthread_park+0xb0/0xb0
[   28.333395]  ret_from_fork+0x35/0x40

En regardant RIP ici, j'ai trouvé qu'une erreur s'est produite dans la fonction smp_call_function_many, et lorsque j'ai recherché ce qu'était SMP, j'ai trouvé que la même mémoire était utilisée par deux ou plusieurs processeurs, et cette partie était implémentée dans la planification aléatoire. Je ne l'ai pas fait, j'ai donc supprimé l'option SMP et reconstruit. (Référence: https://en.wikipedia.org/wiki/Symmetric_multiprocessing)

Lorsque SMP est publié

Quand j'ai annulé SMP, j'ai pu me déplacer avec ==> debuggee: Machine booted and ready!, Mais une erreur s'est produite lorsque ==> debuggee: Checking for guest additions in VM .... Le journal des erreurs ressemble à ceci:

[   31.591660][ T1283] BUG: kernel NULL pointer dereference, address: 0000000000000000
[   31.592313][ T1283] #PF: supervisor read access in kernel mode
[   31.592667][ T1283] #PF: error_code(0x0000) - not-present page
[   31.593014][ T1283] PGD 38cbf067 P4D 38cbf067 PUD 3d23e067 PMD 0 
[   31.593377][ T1283] Oops: 0000 [#1] NOPTI
[   31.593615][ T1283] CPU: 0 PID: 1283 Comm: control Tainted: G           OE     5.3.9+ #20
[   31.594097][ T1283] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
[   31.594640][ T1283] RIP: 0010:rb_erase+0x149/0x380
[   31.594927][ T1283] Code: f6 c2 01 0f 84 c2 01 00 00 48 83 e2 fc 0f 84 ee 00 00 00 48 89 c1 48 89 d0 48 8b 50 08 48 39 ca 0f 85 71 ff ff ff 48 8b 50 10 <f6> 02 01 48 8b 4a 08 75 3a 48 89 c7 48 89 48 10 48 89 42 08 48 83
[   31.596105][ T1283] RSP: 0018:ffffc90001df7988 EFLAGS: 00010046
[   31.596454][ T1283] RAX: ffff88803deb0060 RBX: ffff888037a30000 RCX: 0000000000000000
[   31.596909][ T1283] RDX: 0000000000000000 RSI: ffffffff8245ee90 RDI: ffff888037a30060
[   31.597381][ T1283] RBP: ffffc90001df7988 R08: 0000000000000000 R09: ffffc90000343b88
[   31.597846][ T1283] R10: 00000000faccb043 R11: 0000000078dc05ec R12: ffffffff8245ee40
[   31.598322][ T1283] R13: 0000000000000009 R14: ffff888037a30060 R15: 0000000000000001
[   31.598787][ T1283] FS:  00007fef954dc700(0000) GS:ffffffff82447000(0000) knlGS:0000000000000000
[   31.599314][ T1283] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   31.599694][ T1283] CR2: 0000000000000000 CR3: 000000003de92000 CR4: 00000000000406f0
[   31.600157][ T1283] Call Trace:
[   31.600347][ T1283]  dequeue_task_fair+0x9f/0x2a0
[   31.600687][ T1283]  deactivate_task+0x57/0xf0
[   31.600957][ T1283]  ? update_rq_clock+0x2c/0x80
[   31.601235][ T1283]  __schedule+0x344/0x5d0
[   31.601559][ T1283]  schedule+0x32/0xa0
[   31.601823][ T1283]  rtR0SemEventMultiLnxWait.isra.3+0x33b/0x370 [vboxguest]
[   31.602298][ T1283]  ? wait_woken+0x90/0x90
[   31.602569][ T1283]  VBoxGuest_RTSemEventMultiWaitEx+0xe/0x10 [vboxguest]
[   31.603009][ T1283]  VBoxGuest_RTSemEventMultiWaitNoResume+0x28/0x30 [vboxguest]
[   31.603496][ T1283]  vgdrvHgcmAsyncWaitCallbackWorker+0xda/0x210 [vboxguest]
[   31.603925][ T1283]  vgdrvHgcmAsyncWaitCallbackInterruptible+0x15/0x20 [vboxguest]
[   31.604385][ T1283]  VbglR0HGCMInternalCall+0x3ff/0x1180 [vboxguest]
[   31.604764][ T1283]  ? vgdrvHgcmAsyncWaitCallback+0x20/0x20 [vboxguest]
[   31.605168][ T1283]  ? prep_new_page+0x8e/0x130
[   31.605435][ T1283]  ? get_page_from_freelist+0x6db/0x1160
[   31.605827][ T1283]  ? page_counter_cancel+0x22/0x30
[   31.606122][ T1283]  ? page_counter_uncharge+0x22/0x40
[   31.606426][ T1283]  ? drain_stock.isra.49.constprop.76+0x33/0xb0
[   31.606795][ T1283]  ? try_charge+0x62e/0x760
[   31.607062][ T1283]  ? tomoyo_init_request_info+0x80/0x90
[   31.607407][ T1283]  vgdrvIoCtl_HGCMCallWrapper+0x127/0x2c0 [vboxguest]
[   31.607856][ T1283]  VGDrvCommonIoCtl+0x3ca/0x1a20 [vboxguest]
[   31.608234][ T1283]  ? __check_object_size+0xdd/0x1a0
[   31.609064][ T1283]  ? _copy_from_user+0x3d/0x60
[   31.609829][ T1283]  vgdrvLinuxIOCtl+0x113/0x290 [vboxguest]
[   31.610671][ T1283]  do_vfs_ioctl+0xa9/0x620
[   31.611427][ T1283]  ? tomoyo_file_ioctl+0x19/0x20
[   31.612197][ T1283]  ksys_ioctl+0x75/0x80
[   31.612901][ T1283]  __x64_sys_ioctl+0x1a/0x20
[   31.613633][ T1283]  do_syscall_64+0x59/0x130
[   31.614355][ T1283]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[   31.615173][ T1283] RIP: 0033:0x7fef965f56d7
[   31.615877][ T1283] Code: b3 66 90 48 8b 05 b1 47 2d 00 64 c7 00 26 00 00 00 48 c7 c0 ff ff ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 b8 10 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 81 47 2d 00 f7 d8 64 89 01 48
[   31.618044][ T1283] RSP: 002b:00007fef954dba18 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[   31.619237][ T1283] RAX: ffffffffffffffda RBX: 00007fef954dba60 RCX: 00007fef965f56d7
[   31.620163][ T1283] RDX: 00007fef954dba60 RSI: 00000000c0485607 RDI: 0000000000000003
[   31.621066][ T1283] RBP: 00007fef954dba20 R08: 0000000000000079 R09: 0000000000000000
[   31.621966][ T1283] R10: 00007fef900008d0 R11: 0000000000000246 R12: 0000000000693410
[   31.622844][ T1283] R13: 00007fef954dbdbc R14: 00007fef954dbdac R15: 00007fef954dcdac
[   31.623731][ T1283] Modules linked in: nls_utf8 isofs snd_intel8x0 snd_ac97_codec ac97_bus input_leds snd_pcm snd_timer serio_raw snd soundcore vboxguest(OE) mac_hid sch_fq_codel ib_iser rdma_cm iw_cm ib_cm ib_core iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi ip_tables x_tables autofs4 btrfs zstd_compress raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor raid6_pq libcrc32c raid1 raid0 multipath linear crct10dif_pclmul crc32_pclmul ghash_clmulni_intel aesni_intel aes_x86_64 crypto_simd cryptd glue_helper vboxvideo drm_vram_helper ttm drm_kms_helper syscopyarea psmouse sysfillrect sysimgblt mptspi mptscsih mptbase scsi_transport_spi i2c_piix4 fb_sys_fops e1000 drm pata_acpi video
[   31.630278][ T1283] CR2: 0000000000000000
[   31.631004][ T1283] ---[ end trace 7027dee837a160c7 ]---

Cependant, lorsque j'ai démarré directement dans la machine virtuelle Oracle, cela fonctionnait bien et j'y ai essayé le code de test.

Code de test
#include <assert.h>
#include <sched.h>
#include <sys/time.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

/*Le temps commence--Enregistrement de l'exécution sur proc jusqu'à la fin*/
typedef struct {
  double begin;
  double end;
  int proc;
} rec_t;

/*Obtenez l'heure actuelle*/
double cur_time() {
  struct timeval tp[1];
  gettimeofday(tp, 0);
  return tp->tv_sec + tp->tv_usec * 1.0E-6;
}

void die(char * s) {
  perror(s);
  exit(1);
}

/*Continuez à courir pendant T secondes,Enregistrez le fuseau horaire qui semble avoir été attribué au processeur*/
int run(double T, int n) {
  pid_t pid = getpid();
  struct sched_param param;
  double limit = cur_time() + T;
  rec_t * R = (rec_t *)calloc(n, sizeof(rec_t));
  int i = 0;
  R[i].begin = R[i].end = cur_time();
  R[i].proc = sched_getcpu();

  int ret_1 = syscall(145,pid);
  printf("GET_SCHEDULER : %d\n",ret_1);

  param.sched_priority = 139;
  int ret_2 = syscall(144,pid,7,&param);
  if(ret_2==0){
    printf("SET_SCHEDULER TO SCHED_RANDOM SUCCESS\n");
  } else {
    printf("SET_SCHEDULER TO SCHED_RANDOM FAILED\n");
  }

  ret_1 = syscall(145,pid);
  printf("GET_SCHEDULER : %d\n",ret_1);

  while (R[i].end < limit && i < n) {
    double t = cur_time(); /*Obtenez l'heure actuelle*/
    int proc = sched_getcpu();
    if (t - R[i].end < 1.0E-3 && proc == R[i].proc) {
      /*Pas très différent de la dernière fois que je l'ai vu(< 1ms) -> R[i].Augmenter la fin*/
      R[i].end = t;
    } else {
      /*Plus de 1 ms s'est écoulé depuis la dernière fois que je l'ai vu->Entrez dans une nouvelle section*/
      if (i + 1 >= n) break;
      i++;
      R[i].proc = proc;
      R[i].begin = R[i].end = cur_time();
    }
  }
  assert(i < n);
  int j;
  for (j = 0; j <= i; j++) {
    printf("%d %f %f %d %f\n", 
	   pid, R[j].begin, R[j].end, R[j].proc,
	   R[j].end - R[j].begin);
  }
  return 0;
}

int main(int argc, char ** argv) {
  double T = (argc > 1 ? atof(argv[1]) : 10.0);
  int n    = (argc > 2 ? atoi(argv[2]) : 100000);
  run(T, n);
  return 0;
}

Définissez le temps T (secondes) pour que le programme s'exécute à partir des arguments transmis par le terminal et utilisez la fonction sched_set_scheduler pour que le planificateur utilise un planificateur aléatoire. Ici, depuis le terminal, définissez la priorité à l'aide de la commande nice.

vagrant@ubuntu-bionic:~$ nice -15 ./test_2

La commande nice change la valeur nice, et la commande ci-dessus définit la valeur nice sur 15. Autrement dit, la priorité devient 120 + 15 = 135 et entre dans le programmateur aléatoire.

Résultat d'exécution

J'ai pu confirmer que la tâche était dans la file d'attente aléatoire lorsque je l'ai exécutée, mais une erreur s'est produite.

[  107.960596][    C0] BUG: kernel NULL pointer dereference, address: 0000000000000058
[  107.961544][    C0] #PF: supervisor read access in kernel mode
[  107.962053][    C0] #PF: error_code(0x0000) - not-present page
[  107.962552][    C0] PGD 3abb1067 P4D 3abb1067 PUD 3abb0067 PMD 0 
[  107.963078][    C0] Oops: 0000 [#1] NOPTI
[  107.963432][    C0] CPU: 0 PID: 1515 Comm: lsb_release Tainted: G           OE     5.3.9+ #20
[  107.964161][    C0] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
[  107.964929][    C0] RIP: 0010:task_tick_fair+0xcc/0x160
[  107.965382][    C0] Code: 73 8b 0d 93 be 3a 01 48 39 ca 72 29 48 8b 0d 73 b5 3a 01 48 8d 51 e8 48 85 c9 b9 00 00 00 00 48 0f 44 d1 48 8b 8b a0 00 00 00 <48> 2b 4a 58 78 05 48 39 c8 72 12 0f 1f 44 00 00 48 83 c4 08 5b 41
[  107.967048][    C0] RSP: 0000:ffffc90000003e78 EFLAGS: 00010046
[  107.967563][    C0] RAX: 000000002d17f460 RBX: ffff88803abd8000 RCX: 000000076403fcc9
[  107.968239][    C0] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 000b45fd181a81d0
[  107.968913][    C0] RBP: ffffc90000003ea0 R08: 003ffff0b9e49c00 R09: 0000000000000400
[  107.969584][    C0] R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000
[  107.970253][    C0] R13: ffff88803abd8048 R14: ffffffff810f4650 R15: 000000191c91658e
[  107.970926][    C0] FS:  00007fd781841740(0000) GS:ffffffff82447000(0000) knlGS:0000000000000000
[  107.971675][    C0] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  107.972231][    C0] CR2: 0000000000000058 CR3: 000000003bf5e000 CR4: 00000000000406f0
[  107.972914][    C0] Call Trace:
[  107.973188][    C0]  <IRQ>
[  107.973437][    C0]  ? tick_sched_do_timer+0x60/0x60
[  107.973867][    C0]  scheduler_tick+0x44/0x60
[  107.974245][    C0]  update_process_times+0x45/0x60
[  107.974666][    C0]  tick_sched_handle+0x25/0x70
[  107.975069][    C0]  ? tick_sched_do_timer+0x52/0x60
[  107.975505][    C0]  tick_sched_timer+0x3b/0x80
[  107.975909][    C0]  __hrtimer_run_queues.constprop.24+0x10e/0x210
[  107.976443][    C0]  hrtimer_interrupt+0xd9/0x240
[  107.976856][    C0]  ? ksoftirqd_running+0x2f/0x40
[  107.977281][    C0]  smp_apic_timer_interrupt+0x68/0x100
[  107.977743][    C0]  apic_timer_interrupt+0xf/0x20
[  107.978607][    C0]  </IRQ>
[  107.979290][    C0] RIP: 0033:0x56fd37
[  107.980039][    C0] Code: ff 00 00 00 0f 8f 89 02 00 00 4c 8d 3c 07 48 81 fe 40 45 9d 00 0f 85 d3 03 00 00 4c 89 f5 4d 89 e2 4c 21 e5 48 0f be 5c 2a 28 <48> 83 fb ff 0f 84 3f 02 00 00 4c 8d 1c 5b 4f 8d 1c df 49 8b 73 08
[  107.982571][    C0] RSP: 002b:00007fff64ad6810 EFLAGS: 00000202 ORIG_RAX: ffffffffffffff13
[  107.983732][    C0] RAX: 0000000000000080 RBX: 0000000000000040 RCX: 00007fff64ad68b0
[  107.984854][    C0] RDX: 000000000275fac0 RSI: 00000000009d4540 RDI: 000000000275fae8
[  107.985985][    C0] RBP: 0000000000000075 R08: 0000000000000000 R09: 00007fd7817ccd80
[  107.987119][    C0] R10: 9aa0515eaaf52cf5 R11: 00007fd781823130 R12: 9aa0515eaaf52cf5
[  107.988255][    C0] R13: 00007fd7817d0db0 R14: 000000000000007f R15: 000000000275fb68
[  107.989397][    C0] Modules linked in: nls_utf8 isofs snd_intel8x0 snd_ac97_codec ac97_bus input_leds snd_pcm serio_raw vboxguest(OE) snd_timer snd soundcore mac_hid sch_fq_codel ib_iser rdma_cm iw_cm ib_cm ib_core iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi ip_tables x_tables autofs4 btrfs zstd_compress raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor raid6_pq libcrc32c raid1 raid0 multipath linear crct10dif_pclmul crc32_pclmul ghash_clmulni_intel aesni_intel aes_x86_64 crypto_simd cryptd glue_helper vboxvideo drm_vram_helper ttm drm_kms_helper syscopyarea psmouse sysfillrect sysimgblt mptspi mptscsih mptbase scsi_transport_spi i2c_piix4 fb_sys_fops e1000 drm pata_acpi video
[  107.997916][    C0] CR2: 0000000000000058
[  107.998821][    C0] ---[ end trace 717bffdc6fc42d15 ]---

En analysant cette erreur, l'erreur s'est produite car la fonction task_tick_fair a accédé au pointeur NULL. (Déréférence du pointeur NULL du noyau) Étant donné que la fonction task_tick_fair fait partie du planificateur CFS, j'ai pensé qu'une erreur s'est produite en définissant la plage de priorité qui devrait à l'origine entrer dans le planificateur CFS sur la plage du planificateur aléatoire.

en conclusion

Lors de la réécriture de Linux, il est très difficile de comprendre et d'écrire le tout, il est donc recommandé de l'implémenter en utilisant des outils tels que GNU Global le cas échéant. Enfin et surtout Comment était-ce ?

Recommended Posts

J'ai essayé d'ajouter des appels système et des planificateurs à Linux
J'ai essayé de réintroduire Linux
J'ai essayé d'ajouter un post-incrément à CPython. Présentation et résumé
[Linux] J'ai essayé de résumer les commandes de confirmation des ressources
J'ai essayé d'ajouter un post-incrément à l'implémentation CPython
J'ai implémenté DCGAN et essayé de générer des pommes
J'ai essayé d'ajouter VPS à la connexion ConoHa ~ SSH
J'ai essayé d'ajouter un post-incrément à l'édition CPython Extra
J'ai essayé d'utiliser Linux avec Discord Bot
[Introduction au PID] J'ai essayé de contrôler et de jouer ♬
J'ai essayé de déboguer.
J'ai essayé de lire et d'enregistrer automatiquement avec VOICEROID2 2
J'ai essayé d'implémenter et d'apprendre DCGAN avec PyTorch
J'ai essayé de lire et d'enregistrer automatiquement avec VOICEROID2
J'ai essayé d'implémenter Grad-CAM avec keras et tensorflow
J'ai essayé d'installer scrapy sur Anaconda et je n'ai pas pu
Périphérique et système de fichiers Linux
J'ai essayé d'apprendre PredNet
J'ai essayé d'organiser SVM.
J'ai essayé d'implémenter PCANet
J'ai essayé de présenter Pylint
J'ai essayé de résumer SparseMatrix
Pirater les appels système de Linux
jupyter je l'ai touché
J'ai essayé d'implémenter StarGAN (1)
J'ai essayé de prédire et de soumettre les survivants du Titanic avec Kaggle
J'ai essayé de combiner Discord Bot et la reconnaissance faciale-pour LT-
J'ai essayé d'obtenir les informations du Web en utilisant "Requests" et "lxml"
J'ai essayé d'ajouter un post-incrément à CPython. Liste de toutes les modifications
J'ai essayé d'illustrer le temps et le temps du langage C
J'ai essayé d'afficher l'heure et la météo d'aujourd'hui w
[Introduction au modèle de maladie infectieuse] J'ai essayé de m'adapter et de jouer
J'ai essayé d'énumérer les différences entre java et python
J'ai essayé de créer une interface graphique à trois yeux côte à côte avec Python et Tkinter
J'ai essayé d'implémenter Deep VQE
J'ai essayé de créer un environnement de MkDocs sur Amazon Linux
J'ai essayé de créer l'API Quip
J'ai essayé de visualiser les signets volant vers Slack avec Doc2Vec et PCA
J'ai essayé de mettre en place une validation contradictoire
J'ai essayé de laisser Pepper parler des informations sur l'événement et des informations sur les membres
J'ai essayé d'expliquer l'ensemble de données de Pytorch
J'ai essayé l'authentification vocale Watson (Speech to Text)
J'ai essayé de faire un processus d'exécution périodique avec Selenium et Python
J'ai touché l'API de Tesla
J'ai essayé d'afficher l'interface graphique sur Mac avec le système X Window
J'ai essayé de créer des taureaux et des vaches avec un programme shell
J'ai essayé de m'organiser à propos de MCMC.
J'ai essayé de détecter facilement les points de repère du visage avec python et dlib
J'ai essayé d'extraire des noms de joueurs et de compétences d'articles sportifs
J'ai essayé d'implémenter Realness GAN
J'ai essayé de déplacer le ballon
J'ai essayé d'estimer la section.
J'ai essayé de résumer jusqu'à ce que je quitte la banque et devienne ingénieur
J'ai essayé de déplacer l'image vers le dossier spécifié en faisant un clic droit et un clic gauche
J'ai essayé de visualiser la tranche d'âge et la distribution des taux d'Atcoder
J'ai essayé d'exprimer de la tristesse et de la joie face au problème du mariage stable.
[Deep Learning from scratch] J'ai essayé d'implémenter la couche sigmoïde et la couche Relu
J'ai écrit un diagramme de configuration du système avec des diagrammes sur Docker