Fuchsia OS : C++ est-il plus avantageux que C pour le développement d'un microkernel ?
Le choix de Google divise

Le , par Patrick Ruiz, Chroniqueur Actualités
Les nouvelles de l’existence d’un mystérieux système d’exploitation en développement du côté de la firme de Mountain View ont commencé à filtrer sur cette plateforme il y a bientôt deux ans. Depuis, pas d’annonce officielle de la part de Google, mais une communication par dépôts interposés.

Ce qui serait le premier de tous est apparu sur GitHub. À date, ce dernier semble ne plus être disponible sur la plateforme d’hébergement et de gestion de développement des logiciels (ou a tout simplement été renommé). Il a toutefois laissé filtrer un certain nombre d’informations importantes à propos de cet OS, notamment, sur les supputations relatives au possible lien de filiation avec Linux. On sait depuis lors que Fuchsia est basé sur Magenta, un microkernel qui tire ses fondations du projet Little Kernel – affectueusement baptisé LK par les férus de programmation – et donc, ne dérive pas du noyau Linux.

Google l’a réitéré dans la nouvelle documentation accessible sur sa propre plateforme Git en déclarant que « Fuchsia n’est pas Linux. » Magenta, devenu Zircon par le truchement d’un changement de dénomination, adopte bien l’approche microkernel tandis que Linux est un noyau monolithique. Sur la question des usages réservés à Fuchsia, le lien de filiation donne des pistes.

« LK (Little Kernel) est un infime système d’exploitation qui vise des applications au sein de petits appareils embarqués, des chargeurs d’amorce et autres environnements au sein desquels des primitives comme les threads, les mutexes et les timers sont requis, tout en gardant à l’esprit de conserver une empreinte mémoire légère », lit-on sur le dépôt du projet dont Fuchsia tire ses sources. Fuchsia est donc conçu pour s’adapter à différents types de systèmes de toutes tailles et formes (systèmes embarqués, ordiphones, ordinateurs…).

Voilà de façon brossée ce que cache le mystérieux OS de Google. Des détails supplémentaires feront surface dans les jours à venir puisque certaines sections de la documentation demeurent grisées. Toutefois, un aspect déjà bien visible dans la doc actuelle divise énormément la communauté : Google a fait le choix du langage C++ au détriment du C pour coder le microkernel qui anime le système d’exploitation.


Les discussions sur les fils reddit battent leur plein à ce sujet. Google a implémenté l’allocation dynamique de mémoire et la gestion des exceptions au sein du microkernel, toutes choses qui justifient le choix du langage C++. Illustration avec cette portion du code source de l’interface de gestion de threads.

Code cpp : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
// Copyright 2016 The Fuchsia Authors 
	// Copyright (c) 2008-2015 Travis Geiselbrecht 
	// 
	// Use of this source code is governed by a MIT-style 
	// license that can be found in the LICENSE file or at 
	// https://opensource.org/licenses/MIT 
  
	/** 
         * @file 
         * @brief  Kernel threading 
         * 
         * This file is the core kernel threading interface. 
         * 
         * @defgroup thread Threads 
         * @{ 
         */ 
	#include <kernel/thread.h> 
  
	#include <arch/exception.h> 
	#include <assert.h> 
	#include <debug.h> 
	#include <err.h> 
	#include <inttypes.h> 
  
	#include <kernel/atomic.h> 
	#include <kernel/dpc.h> 
	#include <kernel/mp.h> 
	#include <kernel/percpu.h> 
	#include <kernel/sched.h> 
	#include <kernel/stats.h> 
	#include <kernel/thread.h> 
	#include <kernel/timer.h> 
  
	#include <lib/counters.h> 
	#include <lib/heap.h> 
	#include <lib/ktrace.h> 
  
	#include <list.h> 
	#include <malloc.h> 
	#include <object/c_user_thread.h> 
	#include <platform.h> 
	#include <printf.h> 
	#include <string.h> 
	#include <target.h> 
	#include <vm/vm.h> 
	#include <zircon/types.h> 
  
	// kernel counters. TODO(cpu): remove LK-era counters 
	// The counters below never decrease. 
	// 
	// counts the number of thread_t succesfully created. 
	KCOUNTER(thread_create_count, "kernel.thread.create"); 
	// counts the number of thread_t joined. Never decreases. 
	KCOUNTER(thread_join_count, "kernel.thread.join"); 
	// counts the number of calls to suspend() that succeeded. 
	KCOUNTER(thread_suspend_count, "kernel.thread.suspend"); 
	// counts the number of calls to resume() that succeeded. 
	KCOUNTER(thread_resume_count, "kernel.thread.resume"); 
  
	/* global thread list */ 
	static struct list_node thread_list = LIST_INITIAL_VALUE(thread_list); 
  
	/* master thread spinlock */ 
	spin_lock_t thread_lock = SPIN_LOCK_INITIAL_VALUE; 
  
	/* local routines */ 
	static void thread_exit_locked(thread_t* current_thread, int retcode) __NO_RETURN; 
	static void thread_do_suspend(void); 
  
	static void init_thread_struct(thread_t* t, const char* name) { 
	    memset(t, 0, sizeof(thread_t)); 
	    t->magic = THREAD_MAGIC; 
	    strlcpy(t->name, name, sizeof(t->name)); 
	    wait_queue_init(&t->retcode_wait_queue); 
	} 
  
	static void initial_thread_func(void) TA_REQ(thread_lock) __NO_RETURN; 
	static void initial_thread_func(void) { 
	    int ret; 
  
	    /* release the thread lock that was implicitly held across the reschedule */ 
	    spin_unlock(&thread_lock); 
	    arch_enable_ints(); 
  
	    thread_t* ct = get_current_thread(); 
	    ret = ct->entry(ct->arg); 
  
	    thread_exit(ret); 
	} 
  
  
	/** 
         * @brief  Create a new thread 
         * 
         * This function creates a new thread.  The thread is initially suspended, so you 
         * need to call thread_resume() to execute it. 
         * 
         * @param  name            Name of thread 
         * @param  entry           Entry point of thread 
         * @param  arg             Arbitrary argument passed to entry() 
         * @param  priority        Execution priority for the thread. 
         * @param  stack_size      Stack size for the thread. 
         * @param  alt_trampoline  If not NULL, an alternate trampoline for the thread 
         *                         to start on. 
         * 
         * Thread priority is an integer from 0 (lowest) to 31 (highest).  Some standard 
         * prioritys are defined in <kernel/thread.h>: 
         * 
         *  HIGHEST_PRIORITY 
         *  DPC_PRIORITY 
         *  HIGH_PRIORITY 
         *  DEFAULT_PRIORITY 
         *  LOW_PRIORITY 
         *  IDLE_PRIORITY 
         *  LOWEST_PRIORITY 
         * 
         * Stack size is typically set to DEFAULT_STACK_SIZE 
         * 
         * @return  Pointer to thread object, or NULL on failure. 
         */ 
	thread_t* thread_create_etc( 
	    thread_t* t, 
	    const char* name, 
	    thread_start_routine entry, void* arg, 
	    int priority, 
	    void* stack, void* unsafe_stack, size_t stack_size, 
	    thread_trampoline_routine alt_trampoline) { 
	    unsigned int flags = 0; 
  
	    if (!t) { 
	        <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">t = malloc(sizeof(thread_t));  // allocation dynamique …</span>	        
                    if (!t) 
	            return NULL; 
	        flags |= THREAD_FLAG_FREE_STRUCT; 
	    } 
  
	    init_thread_struct(t, name); 
  
	    t->entry = entry; 
	    t->arg = arg; 
	    t->state = THREAD_INITIAL; 
	    t->signals = 0; 
	    t->blocking_wait_queue = NULL; 
	    t->blocked_status = ZX_OK; 
	    t->interruptable = false; 
	    t->curr_cpu = INVALID_CPU; 
	    t->last_cpu = INVALID_CPU; 
	    t->cpu_affinity = CPU_MASK_ALL; 
  
	    t->retcode = 0; 
	    wait_queue_init(&t->retcode_wait_queue); 
  
	    sched_init_thread(t, priority); 
  
	    /* create the stack */ 
	    if (!stack) { 
	        if (THREAD_STACK_BOUNDS_CHECK) { 
	            stack_size += THREAD_STACK_PADDING_SIZE; 
	            flags |= THREAD_FLAG_DEBUG_STACK_BOUNDS_CHECK; 
	        } 
	        t->stack = malloc(stack_size); 
	        if (!t->stack) { 
	            if (flags & THREAD_FLAG_FREE_STRUCT) 
	                free(t); 
	            return NULL; 
	        } 
	        flags |= THREAD_FLAG_FREE_STACK; 
	        if (THREAD_STACK_BOUNDS_CHECK) { 
	            memset(t->stack, STACK_DEBUG_BYTE, THREAD_STACK_PADDING_SIZE); 
	        } 
	    } else { 
	        t->stack = stack; 
	    } 
  
	#if __has_feature(safe_stack) 
	    if (!unsafe_stack) { 
	        DEBUG_ASSERT(!stack); 
	        DEBUG_ASSERT(flags & THREAD_FLAG_FREE_STACK); 
	        t->unsafe_stack = malloc(stack_size); 
	        if (!t->unsafe_stack) { 
	            free(t->stack); 
	            if (flags & THREAD_FLAG_FREE_STRUCT) 
	                free(t); 
	            return NULL; 
	        } 
	        if (THREAD_STACK_BOUNDS_CHECK) { 
	            memset(t->unsafe_stack, STACK_DEBUG_BYTE, THREAD_STACK_PADDING_SIZE); 
	        } 
	    } else { 
	        DEBUG_ASSERT(stack); 
	        t->unsafe_stack = unsafe_stack; 
	    } 
	#else 
	    DEBUG_ASSERT(!unsafe_stack); 
	#endif 
  
	    t->stack_size = stack_size; 
  
	    /* save whether or not we need to free the thread struct and/or stack */ 
	    t->flags = flags; 
  
	    if (likely(alt_trampoline == NULL)) { 
	        alt_trampoline = initial_thread_func; 
	    } 
  
	    /* set up the initial stack frame */ 
	    arch_thread_initialize(t, (vaddr_t)alt_trampoline); 
  
	    /* add it to the global thread list */ 
	    THREAD_LOCK(state); 
	    list_add_head(&thread_list, &t->thread_list_node); 
	    THREAD_UNLOCK(state); 
  
	    kcounter_add(thread_create_count, 1u); 
	    return t; 
	}


Pour les uns, ces décisions ne se justifient pas pour plusieurs raisons. Primo, elles ne respectent pas les canons de développement de ce type de noyau. « Je me serais attendu à ce qu’ils respectent les propriétés des microkernel connues depuis les années ’90 : pas d’allocation dynamique de mémoire au sein du noyau – toute la mémoire requise est allouée au démarrage », lit-on. Secundo, l’allocation dynamique de mémoire est susceptible de rendre le noyau du système d’exploitation perméable à des attaques par déni de service. Enfin, l’implémentation des exceptions est susceptible de le rendre plus lent et gourmand en ressource mémoire.

L’allocation dynamique de mémoire est cependant susceptible d’avoir des avantages dans le contexte du développement d’un microkernel pour une autre tranche d’intervenants reddit. « Il faut de la mémoire pour contenir les métadonnées relatives à un processus. Il en faut pour gérer les ressources liées aux autres services. Le passage de données entre ces services requiert également de la mémoire », lit-on en guise de réponse à la question sur l’utilité d’un gestionnaire de mémoire au sein d’un microkernel. Ce groupe d’intervenants reddit est également d’avis que Google a opté pour C++ en raison de la disponibilité de bibliothèques de type, ainsi que pour son typage plus poussé que le C, toutes choses qui peuvent également permettre une gestion efficiente des exceptions.

Sources

Google Git

Reddit

Et vous ?

Quelles raisons selon vous devraient motiver un développeur à choisir le langage C++ plutôt que le C dans le cadre du développement d’un noyau de système d’exploitation ?

Quel commentaire faites-vous de la décision de Google de faire usage du langage C++ au détriment du C pour coder le noyau de ce système d’exploitation ?

L’implémentation de l’allocation dynamique de mémoire et des exceptions a-t-elle sa place au sein d’un microkernel ? Si oui, quelle serait la façon la plus efficiente de la mettre en œuvre ?

Avez-vous déjà eu à choisir entre les langages C et C++ dans le cadre du développement d'un noyau ? Partagez votre expérience

Voir aussi

Fuchsia : le nouvel OS mystérieux de Google se concrétise en images, il serait destiné aux téléphones et aux ordinateurs personnels modernes


Vous avez aimé cette actualité ? Alors partagez-la avec vos amis en cliquant sur les boutons ci-dessous :


 Poster une réponse Signaler un problème

Avatar de vayel vayel - Inactif https://www.developpez.com
le 13/04/2018 à 9:23
on peut faire un kernel avec quasi n'importe quel langage...
Il y'a forcément la partie boot de coder en assembleur (x86,arm,sparc...) mais le reste peut être fait en C,C++,Python...

Je m’étais amuser a faire un noyaux en python en partant de la base Pépin et en virant le maximum de code c par du python

un excellent tutoriel pour créer son propre OS, c'est même potentiellement le seul qui soit aussi accessible (n'importe quel débutant en herbe peut créer son OS avec)
http://a.michelizza.free.fr/pmwiki.p...=TutoOS.TutoOS
et en plus il est français sans faute d'orthographe, que demander de plus

Le choix entre C/C++ est un faux débat, le plus intéressant c'est allocation statique ou dynamique.

Pour ma part j'opterais pour du tous dynamique, j'aime les structures flexible comme les listes doublement chainé par exemple plus pratique qu'un tableau statique.
L’avantage je dirais c'est moins de bug donc moins "d'écrans bleu", surtout si il font des try catch pass qui est préférable si on cherche la stabilité à un exit 1

Concernant l'aspect consommation mémoire/cpu on est en 2018, même l'embarqué le plus modeste aujourd'hui peut faire tourner du java...
Quand je vois les smartphones sortir avec 8GB de ram, je pense que c'est une problématique du passé
Avatar de stef-13013 stef-13013 - Membre habitué https://www.developpez.com
le 13/04/2018 à 9:24
Bon la, en même temps, si on regarde rapidement juste la portion de code du post, cela ressemble plus à du "C++ as better C"
qu'à du C++ pur et dur (classes, template, STL, ...)

Pourquoi pas...
Avatar de archqt archqt - Membre actif https://www.developpez.com
le 13/04/2018 à 10:02
Bonjour,
le C++ tiend la route en embarqué, je ne vois donc pas le soucis à l'utiliser. Après les exceptions et la gestion mémoire à voir, mais cela sera plus sécurisant au niveau gestion que la même chose en C.
Bonne journée
Avatar de - https://www.developpez.com
le 13/04/2018 à 10:40
Si à partir d'une modélisation, UML ou merise ou ALM ou autres il est possible d'obtenir du code source C et C++ quelques soit la complexité "objet/code.source" de celui, alors je veux bien croire qu'il y aura une égalité voir même au moins une équivalence de code source...

Sachant que le compilateur est souvent le même, au stade d'équivalent, le résultat au linkage devrait donc être le même...
Avatar de robertledoux robertledoux - Membre habitué https://www.developpez.com
le 13/04/2018 à 10:52
Du "void" pour éviter que la fonction ne prenne une infinité d'argument (chose qui n'est pas nécessaire en C++), du "malloc" pour allouer de la mémoire, utilisation de structures, pas de pointeur sur fonction dans les structures, ... bref c'est clairement du C et même pas du C objet. Pas de débat possible la dessus.

Par contre, oui la partie allocation dynamique est intéressante et c'est une approche plutôt sexy de la chose, à voir ce que ça donne sur des systèmes embarqués "anémiques" en terme de puissance.
Avatar de - https://www.developpez.com
le 13/04/2018 à 11:01
Citation Envoyé par Patrick Ruiz Voir le message
[...] ordiphones [...]
Jipété !!!
Avatar de AoCannaille AoCannaille - Membre émérite https://www.developpez.com
le 13/04/2018 à 11:46
Citation Envoyé par vayel Voir le message

Concernant l'aspect consommation mémoire/cpu on est en 2018, même l'embarqué le plus modeste aujourd'hui peut faire tourner du java...
Quand je vois les smartphones sortir avec 8GB de ram, je pense que c'est une problématique du passé
Je suis d'accord avec le reste de ton message. Mais pas avec ça.
Quand on voit ce que consomme Android, qui demande autant que windows 7, en n'en faisant moins que windows XP (et en reprennant tous ses défauts), on voit que beaucoup de dev arrivent à la même conclusion que toi, et que du coup font n'importe quoi. Tout explose sans que ce ne soit nécessaire... Android est l'OS le plus catastrophique de l'histoire des OS à succès...
Un peu de rigueur bon sang!
Avatar de sergio_is_back sergio_is_back - Membre expérimenté https://www.developpez.com
le 13/04/2018 à 12:06
Citation Envoyé par MikeRowSoft Voir le message
Si à partir d'une modélisation, UML ou merise ou ALM ou autres il est possible d'obtenir du code source C et C++ quelques soit la complexité "objet/code.source" de celui, alors je veux bien croire qu'il y aura une égalité voir même au moins une équivalence de code source...

Sachant que le compilateur est souvent le même, au stade d'équivalent, le résultat au linkage devrait donc être le même...
Rappelle-moi de ne pas t'embaucher...
Avatar de sergio_is_back sergio_is_back - Membre expérimenté https://www.developpez.com
le 13/04/2018 à 12:16
Citation Envoyé par AoCannaille Voir le message
Je suis d'accord avec le reste de ton message. Mais pas avec ça.
Quand on voit ce que consomme Android, qui demande autant que windows 7, en n'en faisant moins que windows XP (et en reprennant tous ses défauts), on voit que beaucoup de dev arrivent à la même conclusion que toi, et que du coup font n'importe quoi. Tout explose sans que ce ne soit nécessaire... Android est l'OS le plus catastrophique de l'histoire des OS à succès...
Un peu de rigueur bon sang!
Le problème vient du fait que beaucoup de développeurs actuels on appris leur métier dans un cadre où la capacité mémoire (et capacité disque) n'a que d'importance... Avant les années 1990-2000 la mémoire était limitée et
coutait très cher (je rappelle avoir payé quelques 1000 francs pour une extension mémoire de 1M sur mon 286). Les développeurs faisait attention à n'utiliser que ce qui était nécessaire...

Sur un IBM PC/XT avec un disque de 5Mo, on pouvait vite saturer le disque avec des fichiers temporaires non nettoyés

Combien de softs aujourd'hui génèrent des dizaines de fichiers temp et ne les nettoient pas... pareil pour la mémoire, on alloue des dizaines d'objets, de variables, de streams sans se préoccuper le moins du monde de savoir si
c'est pertinent ou pas... (Voir les derniers déboires de la version 32 bits de Skype for Business)

Cela dit, ça sort un peu de la discussion d'origine...
Avatar de vayel vayel - Inactif https://www.developpez.com
le 13/04/2018 à 13:22
Citation Envoyé par AoCannaille Voir le message
Je suis d'accord avec le reste de ton message. Mais pas avec ça.
Quand on voit ce que consomme Android, qui demande autant que windows 7, en n'en faisant moins que windows XP (et en reprennant tous ses défauts), on voit que beaucoup de dev arrivent à la même conclusion que toi, et que du coup font n'importe quoi. Tout explose sans que ce ne soit nécessaire... Android est l'OS le plus catastrophique de l'histoire des OS à succès...
Un peu de rigueur bon sang!
Oui et non.
Car du temps de windows xp les dev n'avais pas a ce soucier des cpu multicœurs par exemple... sous android on essaye d'exploiter les 8 coeurs cpu. Le multithreading impose de facto de partager des variables en mémoire ce qui augmente la conso mémoire.

Aujourd'hui pour l'embarqué le plus modeste (hors cas très spécifique comme l'aérospatial qui doit résister a des conditions extrême donc matos spécial) c'est désormais des cpu arm multicore à moins de 10$ le cpu.
le compteur linky en est le parfait exemple, un petit cpu arm 4 coeurs.

Et puis je vais dire un truc politiquement pas correcte (c'est pas la 1ere fois sur ce forum ), pourquoi économiser la ram, elle est faite pour être utilisé ! Si j'ai 8GB de ram sur mon smartphone c'est pour les exploiter, je préfère que l'applie se charge à 100% en ram et m'offre une meilleur fluidité.

je préfere que mon JV consomme mes 16GB de ram mais réduit les temps de chargement.
Contacter le responsable de la rubrique Accueil