
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]// 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) {
t = malloc(sizeof(thread_t)); // allocation dynamique …
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...
La fin de cet article est réservée aux abonnés. Soutenez le Club Developpez.com en prenant un abonnement pour que nous puissions continuer à vous proposer des publications.