IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

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

456PARTAGES

10  0 
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

Une erreur dans cette actualité ? Signalez-nous-la !

Avatar de AoCannaille
Expert confirmé 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!
8  0 
Avatar de sergio_is_back
Expert confirmé 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...
7  0 
Avatar de AoCannaille
Expert confirmé https://www.developpez.com
Le 13/04/2018 à 14:57
Citation Envoyé par vayel Voir le message

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.
Toutafé, je suis d'accord pour une utilisation intensive unique, par exemple ton jeux vidéo. Ou un gros IDE.
Mais déjà :
- Dés que tu atteins les 100%, tu swap. Du coup tu divises les perf par 10 et tu uses prématurément une mémoire dont l'espérence de vie se compte en cycle de lecture/écriture (contrairement à la ram on est d'accord)
- Si tu fais tes efforts de dev, et que tu prend 200Mo au lieu de 400Mo, tu te charges toujours à 100%, donc tu laisse plus de place aux voisins et avant d'user la mémoire.

Et encore, là on parle d'optim basique... à l'origine, la RAM à justement pour objectif de swap le cache processeur... En C++ on peut encore faire ce genre d'optim, en java on déborde du cache processeur, de la ram, et des fois même de la swap...
5  0 
Avatar de sergio_is_back
Expert confirmé https://www.developpez.com
Le 13/04/2018 à 15:26
Citation Envoyé par vayel Voir le message

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.
Y'a le pour et le contre.

Si tu n'utilise "qu'une seule" (entre guillemets) application à la limite rien n’empêche de monopoliser le maximum de RAM dispo (charger toutes les bibliothèques et tout ce qui
peut lui être utile d'un seul coup) elle sera d'autant plus réactive

Le problème est que sur les OS multi-utilisateurs/multi taches lorsque l'on passe d'une tache à l'autre ça va entrainer du SWAP et donc fatalement finir par dégrader les performances
5  0 
Avatar de
https://www.developpez.com
Le 13/04/2018 à 15:18
Citation Envoyé par vayel Voir le message

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é.
Tout à fait, et si les applis étaient bien codées, comment on ferait pour saturer la ram, vendre des iphones à un smic obsolètes en deux an et gaspiller les ressources de la planète inutilement ?
4  0 
Avatar de stef-13013
Membre actif 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...
2  0 
Avatar de Aurelien.Regat-Barrel
Expert éminent sénior https://www.developpez.com
Le 15/04/2018 à 20:39
Citation Envoyé par vayel Voir le message
on peut faire un kernel avec quasi n'importe quel langage...
Ca me rappelle cette citation :

Y'a deux types de développeurs kernel : ceux qui disent qu'il y a 36 façons de faire les choses, et ceux qui expliquent pourquoi les 35 autres ne fonctionnent pas.
Citation Envoyé par vayel Voir le message
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
Le mécanisme try...catch de C++ ne fonctionne pas "out of the box" en mode noyau. Pareil pour l'allocation dynamique : tout cela doit être recodé à la main. Et y'a pas d'exit non plus : le kernel étant à la base de tout, il ne peut pas rendre la main à quelqu'un d'autre. Et pour les listes chaînées, c'est sympa oui mais c'est une catastrophe en terme de performance autant à l'allocation / destruction (l'alloc dynamique coute cher!) qu'au parcours car elles ne sont pas "sympathiques" vis à vis du hardware (data prefetching).

Quant à Python ou "n'importe quel langage", faut déjà pouvoir produire un binaire exécutable qui ne soit lié à aucun runtime ! (pour rappel Python s'appuie sur un interpréteur développé en C).

Sinon, à mi-chemin entre le vrai kernel et l'application C++ il y a includeOS, un "unikernel" C++ : https://github.com/hioa-cs/IncludeOS
2  0 
Avatar de hl037
Membre du Club https://www.developpez.com
Le 20/04/2018 à 20:07
...On peut aussi faire du C++ sans allocation dynamique...
Pour ma part, entre C et C++, la question ne se pose pas trop : C++.
D'abord, c'est (à quelques différences sémantiques prêt) presque un superset du C. Ensuite, C++ atteint un niveau de fiabilité côté les compilateurs assez proche du C.
Et puis... On n'est pas non plus obligé d'accepter TOUTES les fonctionnalité de C++, par exemple, on peut interdire l'allocation dynamique, ainsi que certaines syntaxes obscures. Par contre, les templates, ainsi que la possibilité de redéfinir les opérateurs peuvent s'avérer vachement pratique côté lisibilité et facilité / vitesse de développement, et permettent parfois une analyse statique plus fine. ...On a aussi accès à un héritage pris en charge par le langage et éviter ainsi des hack avec les structures du C...
1  0 
Avatar de archqt
Membre émérite 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
0  0 
Avatar de robertledoux
Membre averti 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.
0  0