Autore Topic: SuperKernel !  (Letto 13568 volte)

Offline Z80Fan

  • Administrator
  • Guru
  • *****
  • Post: 1671
  • Karma: +13/-2
    • Mostra profilo
    • http://z80fan.altervista.org
Re: SuperKernel !
« Risposta #15 il: 26 Novembre 2011, 19:15:37 »
Citazione da: "cdimauro"
Delphi o FreePascal.
E sono dei linguaggi talmente usati nello sviluppo di driver da obbligare a complicare l'interfaccia per poterli supportare?
Oppure solo una minoranza di driver è programmata così, e si potrebbe usare un wrapper, qualcosa come questo ?

Poi è da vedere dove il driver deve essere eseguito. Se il modulo sta in user mode, uno può usare il linguaggio che vuole perchè ci saranno le apposite API, che penso saranno quasi sicuramente in stile C.

Attualmente sto implementando dei "driver" che stanno in kernel mode, quindi è plausibile che siano scritti nello stesso linguaggio del kernel.
« Ultima modifica: 01 Gennaio 1970, 02:00:00 da Guest »

Offline cdimauro

  • Human Debugger
  • *****
  • Post: 4291
  • Karma: +7/-95
    • Mostra profilo
Re: SuperKernel !
« Risposta #16 il: 26 Novembre 2011, 19:32:11 »
Citazione da: "Z80Fan"
Citazione da: "cdimauro"
Delphi o FreePascal.
E sono dei linguaggi talmente usati nello sviluppo di driver da obbligare a complicare l'interfaccia per poterli supportare?
Oppure solo una minoranza di driver è programmata così, e si potrebbe usare un wrapper, qualcosa come questo ?
Non vedo perché ci si dovrebbe abbassare a usare dei wrapper: è una gran rottura di scatole!

Il punto è un altro: perché un s.o. dovrebbe essere C++ centrico?

Un s.o. dovrebbe essere agnostico dal punto di vista dell'ABI utilizzata per i vari linguaggi, ed è per questo che si fornisce un "minimo comune denominatore" che è rappresentato da un'interfaccia C o Pascal (ebbene sì: si usa anche questa; buona parte delle API di Windows usano questo modello, e la usavano pure le API del vecchio MacOS).
Citazione
Poi è da vedere dove il driver deve essere eseguito. Se il modulo sta in user mode, uno può usare il linguaggio che vuole perchè ci saranno le apposite API, che penso saranno quasi sicuramente in stile C.

Attualmente sto implementando dei "driver" che stanno in kernel mode, quindi è plausibile che siano scritti nello stesso linguaggio del kernel.
Chiaro, questa è una scelta che hai fatto tu. Comunque se ti limitassi all'ereditarietà singola, probabilmente potresti abbracciare buona parte dei linguaggi che supportano il paradigma OOP.

Offline Z80Fan

  • Administrator
  • Guru
  • *****
  • Post: 1671
  • Karma: +13/-2
    • Mostra profilo
    • http://z80fan.altervista.org
Re: SuperKernel !
« Risposta #17 il: 21 Gennaio 2012, 19:11:07 »
Ho aggiornato il codice nel repository principale; la nuova versione 0.06 (che nel repo git corrisponde al branch cpp_conv) si può scaricare da Sourceforge al link:
https://sourceforge.net/projects/superkernel/

Principalmente questa versione porta il nuovo sistema OOP per le periferiche (classe Device) e gli interrupt (classe GenericISR), più qualche "pulitura" di diversi file.
Non è detto che l'implementazione corrente di questi due sistemi sia definitiva.

Prima di poter eseguire il merge tra cpp_conv e il branch principale, devo pulire ancora diversi file, ad esempio mettendo i namespace giusti, commenti etc...

Manca ancora da fare la gestione della memoria in OOP (principalmente la classe "vspace" per gestire ogni singolo spazio virtuale che andrà a ospitare un singolo processo), e successivamente (o anche contemporaneamente) fare una gestione dei processi, anche una cosa semplice come il round-robin giusto per iniziare.
« Ultima modifica: 01 Gennaio 1970, 02:00:00 da Guest »

Offline cdimauro

  • Human Debugger
  • *****
  • Post: 4291
  • Karma: +7/-95
    • Mostra profilo
Re: SuperKernel !
« Risposta #18 il: 21 Gennaio 2012, 19:42:40 »
Cerca di dare una sistemata anche ai commenti appena puoi: un misto di italiano e inglese non è proprio il massimo. :oops:

Offline Z80Fan

  • Administrator
  • Guru
  • *****
  • Post: 1671
  • Karma: +13/-2
    • Mostra profilo
    • http://z80fan.altervista.org
Re: SuperKernel !
« Risposta #19 il: 21 Gennaio 2012, 20:14:03 »
Citazione da: "cdimauro"
Cerca di dare una sistemata anche ai commenti appena puoi: un misto di italiano e inglese non è proprio il massimo. :oops:
Infatti; la sistemazione comprende anche quello...
« Ultima modifica: 01 Gennaio 1970, 02:00:00 da Guest »

Offline Allanon

  • Administrator
  • Synthetic Voodoo
  • *****
  • Post: 3498
  • Karma: +17/-4
    • Mostra profilo
    • http://www.a-mc.biz
Re: SuperKernel !
« Risposta #20 il: 30 Gennaio 2012, 00:00:45 »
Citazione da: "cdimauro"
Cerca di dare una sistemata anche ai commenti appena puoi: un misto di italiano e inglese non è proprio il massimo. :oops:

...questa cosa mi perseguita inesorabilmente... quando programmo spesso in una sessione metto commenti in italiano e la volta dopo li metto in inglese... :roll:
« Ultima modifica: 01 Gennaio 1970, 02:00:00 da Guest »

Offline cdimauro

  • Human Debugger
  • *****
  • Post: 4291
  • Karma: +7/-95
    • Mostra profilo
Re: SuperKernel !
« Risposta #21 il: 30 Gennaio 2012, 09:10:00 »
Per questo è meglio partire direttamente coi commenti in inglese :D

Comunque non seguo fedelmente questo schema. Ad esempio se sviluppo un'applicazione per il mercato locale (e sono anche sicuro che rimarrà tale), utilizzo commenti e identificatori in italiano per tutta la parte che è strettamente di business-logic (ad esempio Clienti, Fornitori, CodiceFiscale, ecc.) mentre per tutto quello che potrebbe essere riciclato in un'altra applicazione e/o finire poi in una libreria uso solo l'inglese.

Ormai dopo tanti anni sono abituato a lavorare così, ma in ogni caso l'inglese domina sicuramente.

Offline Z80Fan

  • Administrator
  • Guru
  • *****
  • Post: 1671
  • Karma: +13/-2
    • Mostra profilo
    • http://z80fan.altervista.org
Re:SuperKernel !
« Risposta #22 il: 06 ſettembre 2013, 03:22:41 »
Beh, tutti i messaggi più nuovi si son persi, vabbè...

Ho pensato di riprendere lo sviluppo (che magari lo uso anche come tesi di laurea, se non hanno niente in contrario), però devo farvi un RFC:

Ricapitolando la situazione attuale, ho lasciato perdere la "conversione" C++ che stavo facendo dai vecchi sorgenti, e ho ricominciato da capo. Ho ben diviso i compiti di kernel/architettura/piattaforma in modo che sia facilmente portabile, e in generale ho fatto le cose più "object oriented".
Ho riportato tutte le cose essenziali per avviare il sistema, praticamente quello che manca per tornare alle "feature" del vecchio kernel sono i driver delle periferiche (tastiera, video etc).

In questa versione però, mi serve avere un sistema prima di implementare i driver, ed è un sistema di message passing.
Praticamente ho deciso che il message passing sarà una funzione fondamentale in questo kernel, su cui fare praticamente un po' tutto, incluse la maggioranza di API user->kernel (o syscall come vengono chiamate). Su questo poi si costruisce un sistema di RPC etc.

Ovviamente la prima cosa che viene in mente, sono le prestazioni; certamente dover scendere a messaggi per quasi tutto sarà più pesante di non fare delle syscall con interrupt direttamente, però ne viene di flessibilità (si possono aggiungere funzioni successivamente senza infastidire le applicazioni esistenti), e una generale ortogonalità (un programma chiama servizi del kernel allo stesso modo con cui chiama servizi di altri processi o driver).
Una cosa bella è che, in stile Wayland, un protocollo si può definire in XML, e da questo avere un tool che genera l'interfaccia adatta per un particolare linguaggio, così ogni linguaggio può avere l'API fatta in suo stile, ma sempre compatibile col sistema (perchè tanto poi passa tutto per i messaggi) (questo risolve anche quel dibattito che ho avuto con cdimauro sul fatto che uno vorrebbe poter scrivere i driver nel linguaggio che preferisce).
In più, OS ben testati come QNX (un microkernel hard realtime), usano abbondantemente il message passing per implementare RPC, e con uno scheduling intelligente ottengono anche buone prestazioni e latenze.

Ma quindi cosa dovrebbe fare sto sistema? Come ho detto, viene usato sia per user->kernel, sia per kernel->kernel (nel senso di kernel<-> driver in kernel mode), sia user->user. Quando un processo vuole mandare un messaggio a un altro processo, lo costruisce e informa il kernel (con una syscall tipica, probabilmente una delle poche che serviranno ancora, oppure tramite una libreria standard che poi può segnalare il kernel nel modo che preferiamo); quest'ultimo ha l'infrastruttura per direzionare il messaggio e portarlo nella memoria del destinatario, il quale viene avvisato dell'arrivo (in modo indiretto, tramite una variabile nel suo spazio che il processo può testare in un ciclo di eventi, oppure deviando il flusso del processo su una sua funzione di gestione che il processo può registrare).

Ci sono 2 modalità di passaggio che bisogna implementare: il trasferimento semplice, dove un messaggio da un processo viene copiato nel mailbox di un altro processo, e il processo mittente è libero di continuare (messaggi unidirezionali o RPC asincrono), e il trasferimento con attesa, dove il processo mittente viene bloccato finchè il destinatario non risponde con un altro messaggio o finchè non scade un timeout.

Poi, c'è da pensare a come rappresentare i dati nel messaggio: il modo più semplice è considerarlo solo un'area di dati binari con un header, e lasciare che le applicazioni decidano cosa metterci dentro; il modo più avanzato è "formattare" i dati che ci vanno dentro in triplette nome-tipo-valore, ed eseguire marshalling/unmarshalling nel mittente/destinatario.
Il primo ha il vantaggio di essere molto semplice e veloce, mentre il secondo è più complesso però permette di fare cose carine tipo poter mandare i messaggi, attraverso lo stesso sistema, a un'altra macchina (magari collegata in rete), per fare simpatici sistemi cluster.
Sinceramente, poichè il secondo sistema si può costruire sopra il primo, conviene tenere le cose semplici ed avere solo un header con i campi fondamentali per il routing del messaggio (inclusa la sua dimensione), e lasciare la zona dati come area binaria arbitraria.

Infine, bisogna fare un modo per far "scoprire" alle applicazioni i servizi del sistema, ma quello non è un problemone perchè si può sempre avere un processo server sempre attivo, con un'API definita, a cui si può parlare sempre usando i messaggi, e da lui le app possono trovare i servizi disponibili nel sistema.


Date queste specifiche, non è difficile implementare un tale sistema, però c'è da fare un'attenta progettazione per non cadere in dei pitfall; ad esempio, bisogna pensare come vengono rappresentati e gestiti gli indirizzi dei destinatari.

Un modo banale è usare il PID del processo come suo identificatore nel sistema di messaggi, magari con il valore 0 assegnato al kernel; però è facile trovare subito dei problemi: già di progettazione, si limita una singola mailbox (i.e. un posto dove i messaggi possono essere bufferizzati) per processo, quando un sistema complesso potrebbe volerne diverse per diversi thread, senza aver bisogno di un ciclo principale che raccoglie messaggi dalla mailbox centrale e li ricopia in buffer privati di ogni thread. Poi, se un server crasha e viene riavviato con un altro PID, non possiamo avere applicazioni che hanno ancora il vecchio PID e mandano messaggi con informazioni potenzialmente sensibili a processi casuali (neanche il fatto di non riciclare i PID subito è una soluzione).

Allora ogni thread che volesse fornire un punto di ingresso per i messaggi dovrebbe richiedere un ID, che viene usato come mittente/destinatario, però: il problema dei PID sopra si ripete, perchè se un server cade e si riavvia, potenzialmente richiederà un nuovo ID, a meno che non ci sia un modo di riaverlo...
Si potrebbe fare in questo modo: un server che vuole registrarsi come potenziale server richiede al kernel un ID, passandogli una stringa identificativa che vuole lui; la stringa (documentata) la useranno anche i mittenti per recuperare l'ID del server (una sorta di DNS); nel caso il server cada (per crash o per volontario riavvio), quando riparte e chiede un ID con la stessa stringa, il kernel fornirà lo stesso ID di prima (si tiene la lista delle associazioni per un po' anche quando il processo termina). Qua però nasce un problema di sicurezza, ovvero un programma maligno potrebbe far crashare il server (o attendere che termini per i fatti suoi) e poi immediatamente richiedere la stringa del server, e farsi dirottare le richieste (stile man-in-the-middle).
Una possibile soluzione è richiedere che richieste consecutive derivino dallo stesso identico eseguibile della richiesta precedente; ciò rompe quando uno vuole fare un aggiornamento a un altro server equivalente, ma non vuol dire che dobbiamo tenere l'associazione per sempre, solo per un certo time-out dove il precedente eseguibile ha ancora l'esclusiva dell'ID (come avviene già per le porte di rete, dove sono assegnate per un certo periodo anche se il server cade, proprio in modo da evitare che altri dispositivi continuino a inviare dati a un server diverso avviato dopo).

Probabilmente quest'ultima soluzione è la migliore in generale. Sopra questo ora però bisogna pensare a come due processi che vogliono comunicare in modo totalmente privato possano gestire questa opzione; ad esempio si potrebbe voler che un driver in kernel mode possa parlare solo con il relativo server in user-mode, senza che nessun altro si possa connettere, però a questo livello penso sia da lasciare alle singole applicazioni gestirsi, anche perchè, come fa uno a sapere che il client che ti si connette è effettivamente quello che vuoi tu o qualcun altro? Se tutta sta segretezza è richiesta, sarà un problema delle applicazioni validarsi e criptare le comunicazioni... (soluzioni a questo problema sono però ben accette).



Ci saranno sicuramente altre cose a cui ho pensato ma che in questo momento non mi tornano in mente, perciò mi fermo qui. Ho scritto tanto ma ho buttato giù tutto a quello che avevo già pensato, quindi è una specie di riassunto del mio pensiero. È anche abbastanza raw come output, quindi è probabile che ci siano errori o punti non chiari. ;D

Suggerimenti/domande/insulti son tutti ben accetti, perchè essendo questo forse il componente più importante di questo OS deve essere fatto bene già dell'inizio, altrimenti rischiamo di fare tanto lavoro per poi doverlo buttare via e rifarlo.

Offline cdimauro

  • Human Debugger
  • *****
  • Post: 4291
  • Karma: +7/-95
    • Mostra profilo
Re:SuperKernel !
« Risposta #23 il: 06 ſettembre 2013, 21:38:06 »
Per il momento il problema degli ID delle mailbox rimandalo. Assumi che a ogni eseguibile / applicazione sia associato un ID univoco, e sei a posto per ora.

Riguardo al message passing, non lo userei sempre. Francamente mi affiderei ai registri della CPU, riservandone un po' alla scopo quando c'è da effettuare una syscall. Messaggi più complessi useranno il classico paradigma ID messaggio + lunghezza + dati. In pratica l'ID del messaggio ti indica se è semplice o complesso; ad esempio usando il bit più significativo.

Offline Z80Fan

  • Administrator
  • Guru
  • *****
  • Post: 1671
  • Karma: +13/-2
    • Mostra profilo
    • http://z80fan.altervista.org
Re:SuperKernel !
« Risposta #24 il: 07 ſettembre 2013, 00:51:37 »
Per il momento il problema degli ID delle mailbox rimandalo. Assumi che a ogni eseguibile / applicazione sia associato un ID univoco, e sei a posto per ora.
Si, come hack per continuare lo sviluppo si può fare, ma volevo avere un'immagine completa del sistema prima di partire.

Riguardo al message passing, non lo userei sempre. Francamente mi affiderei ai registri della CPU, riservandone un po' alla scopo quando c'è da effettuare una syscall. Messaggi più complessi useranno il classico paradigma ID messaggio + lunghezza + dati. In pratica l'ID del messaggio ti indica se è semplice o complesso; ad esempio usando il bit più significativo.
Non sono d'accordo nel "non usare sempre il message passing", anche se qui potremmo scontrarci sulla definizione di "message passing", con cui non intendo per forza riempire un'area di memoria e copiarla nello spazio di un altro processo; una syscall lo considero un messaggio, anche se poi decidiamo di farlo passare per i registri della cpu.

Le applicazioni (e i driver) parleranno sempre con una libreria (che risiede sempre nel loro spazio di indirizzamento), libreria che l'OS stesso fornisce, e serve per disaccoppiare l'implementazione sottostante con l'API standard del sistema.
In questa libreria possiamo attuare tutte le ottimizzazioni che vogliamo: un esempio a cui ho già pensato è un buffer di messaggi da inviare, se questi messaggi non richiedono una risposta sincrona (i.e. chiamano servizi asincroni). Quando il processo finisce il suo timeslice, rilascia volontariamente la cpu (magari in attesa di un semaforo), o invia un messaggio che richiede una risposta sincrona, il kernel viene richiamato e, già che deve fare un context switch, sposta i messaggi dal buffer ai relativi destinatari. Ciò ci risparmia di dover andare avanti e indietro dal kernel per ogni messaggio la cui consegna magari non è immediatamente importante.

In secondo luogo, non so quanto più veloce sia il passaggio di messaggi via registri, per il seguente motivo: quando l'esecuzione passa al kernel, quest'ultimo deve lo stesso salvare i valori dei registri in una qualche struttura di stato del thread interrotto, perchè anche se fosse lui il destinatario dell'azione, è probabile che debba eseguire molto codice per soddisfare la richiesta, e anche un sottoinsieme di registri lasciato libero per gli usi del kernel non è sufficiente oltre ai primissimi istanti di entrata in kernel mode.
Diverso invece è se ammettiamo che il controllo possa tornare al thread utente con i registri dati sporcati (non necessariamente tutti, anche solo un sottoinsieme): in questo caso il kernel può usare i valori direttamente e lavorarci sopra, senza necessità di salvare e ripristinare i registri.

Con il fatto che il programma utente lavora sempre attraverso la libreria base, è però possibilissimo implementare "dietro le quinte" il sistema doppio registri-memoria come dici te, dove la libreria può scegliere se passare il messaggio via registri oppure via memoria, non solo in base alla dimensione ma in generale la miglior soluzione per quel momento (es. se il messaggio è asincrono, anche se è corto lo vorremo mettere nel buffer di messaggi, sulla base che un accesso in memoria è più veloce che entrare nel kernel e fare il trasferimento subito con i dati nei registri). In un'architettura con pochi registri (come x86), magari il trasferimento a registri non verrà nemmeno preso in considerazione.
Quindi possiamo fare in questo modo: la libreria fornisce un singolo modo di trasferimento di messaggi all'utente (nel senso, un solo formato, poi ovviamente ci sono tutti i modi sincrono/asincrono etc.), e poi sceglierà internamente il modo migliore di inviarlo.

La libreria, oltre alle funzioni di trasferimento di messaggi, espone i servizi del kernel attraverso funzioni facili da usare (es. open(), read() etc.); qui possiamo imbrogliare spudoratamente e creare delle syscall "scorciatoia" che bypassa il sistema di messaggi e attiva direttamente la funzionalità (chiamate sincrone) oppure inserisce un job per i thread kernel di background (chiamate asincrone) direttamente nelle strutture dati del kernel invece che fare il doppio salto parsing messaggio->inserimento nella queue del thread background.

questa soluzione e' usata con successo anche dal vecchio VxWorks v5 che ho sulla 2x68060 board di Eltec.

Il passaggio tramite registri dici?

Offline cdimauro

  • Human Debugger
  • *****
  • Post: 4291
  • Karma: +7/-95
    • Mostra profilo
Re:SuperKernel !
« Risposta #25 il: 07 ſettembre 2013, 07:26:00 »
   E' chiaro che per i servizi asincroni serve un buffer di memoria dove depositare il messaggio.
La mia soluzione riguarda soltanto quelli sincroni (non so se legacy intendesse anche questo; suppongo di sì), dove è fondamentale ridurre al minimo la latenza. Il kernel alla fine può decidere di farci quello che vuole coi registri, anche parcheggiarli in uno spazio temporaneo se gliene serve qualcuno (non è che deve per forza memorizzarli tutti; anche qui, si ottimizza al massimo: si conservano solo quelli che servono).

Per quelli asincroni ho pensato a una soluzione a doppio buffer per i risultati. Il processo / thread utente si smazza un buffer (coda) tutto in user-space, senza interferenze da parte del kernel; si tratta di una lista di messaggi che ha già caricato il kernel tempo fa, e che il processo può smazzarsi direttamente senza usare lock, semafori, ecc. Nel frattempo il kernel riempie il secondo buffer con le nuove richieste, in maniera del tutto indipendente. Quando il processo finisce tutti i messaggi del primo buffer, invoca una syscall; a questo punto il kernel scambia i due buffer (scambia i puntatori alle due aree) e restituisce al processo il puntatore al nuovo buffer che deve processare. E così via.

Qualcosa di simile si potrebbe realizzare anche per le chiamate asincrone, dove il processo le deposita in un buffer, e quando questo si riempie invoca una syscall per dare in pasto al kernel l'intero bundle da processare. La syscall provvede, al solito, a scambiare i due buffer e restituire al processo il puntatore al nuovo buffer da riempire.

Si può pensare a diversi buffer allocati in base alla diverse priorità / esigenze. E magari ad API che devono essere processate con urgenza, e non passano da nessun meccanismo di buffering.

Offline Z80Fan

  • Administrator
  • Guru
  • *****
  • Post: 1671
  • Karma: +13/-2
    • Mostra profilo
    • http://z80fan.altervista.org
Re:SuperKernel !
« Risposta #26 il: 07 ſettembre 2013, 15:33:24 »
Per quelli asincroni ho pensato a una soluzione a doppio buffer per i risultati. Il processo / thread utente si smazza un buffer (coda) tutto in user-space, senza interferenze da parte del kernel; si tratta di una lista di messaggi che ha già caricato il kernel tempo fa, e che il processo può smazzarsi direttamente senza usare lock, semafori, ecc. Nel frattempo il kernel riempie il secondo buffer con le nuove richieste, in maniera del tutto indipendente. Quando il processo finisce tutti i messaggi del primo buffer, invoca una syscall; a questo punto il kernel scambia i due buffer (scambia i puntatori alle due aree) e restituisce al processo il puntatore al nuovo buffer che deve processare. E così via.

È senz'altro un'ottima soluzione, semplice ed elegante; la mia iniziale idea era un semplice buffer circolare pre-allocato (o almeno, pre-riservato anche senza memoria fisica assegnata) e di dimensione fissa; una tale struttura dati è molto semplice da fare e molto veloce in applicazioni di tipo produttore/consumatore, dove un thread (il kernel) inserisce e basta e un thread (il processo) legge e basta.
Tipicamente, se il produttore non può inserire il messaggio si blocca, ma il kernel potrebbe scartare il messaggio e inviare al mittente un messaggio di "casella piena". Anche gli aggiornamenti dei puntatori sono molto veloci, sfruttando le operazioni atomiche.

Il buffer multiplo però sembra molto più simpatico, dato che non si è limitati a una dimensione fissa (anche se una dimensione massima permessa c'è sempre), e c'è una più flessibilità nell'allocazione, quindi probabilmente andrò con questa strada.

Citazione
Qualcosa di simile si potrebbe realizzare anche per le chiamate asincrone, dove il processo le deposita in un buffer, e quando questo si riempie invoca una syscall per dare in pasto al kernel l'intero bundle da processare. La syscall provvede, al solito, a scambiare i due buffer e restituire al processo il puntatore al nuovo buffer da riempire.

Si, quello che avevo pensato io era di svuotare la coda messaggi ogni volta che tocca fare un context-switch, già che ci siamo, ma si può tranquillamente fare lo svuotamento a richiesta (anzi, qualcosa di simile era necessario anche nell'altro caso, per quando un processo si mette in attesa di un messaggio sincrono).

Citazione
Si può pensare a diversi buffer allocati in base alla diverse priorità / esigenze. E magari ad API che devono essere processate con urgenza, e non passano da nessun meccanismo di buffering.

E questo favorisce sicuramente l'approccio multi-buffer. Io organizzerei la priorità mettendo per prime le chiamate sincrone, visto che sono urgenti per il proseguimento del processo (e vengono anche favorite dallo scheduler, come fa QNX, avviando immediatamente il processo destinatario), e successivamente vari buffer di priorità decrescente.

Bisogna però decidere a chi si riferiscono le priorità: se le priorità sono solo del processo mittente, allora lui può mettere un messaggio di priorità alta in un buffer e uno di priorità bassa in un altro, ma non è detto che la priorità maggiore venga soddisfatta prima, perchè il server del messaggio prioritario potrebbe essere occupato mentre il server del messaggio di priorità inferiore è libero.
Far decidere al mittente la priorità del messaggio al lato destinatario non è una soluzione facile, perchè se fatta semplicemente incorre in una serie di possibili attacchi DoS da processi malevoli e starvation dei messaggi "genuini", se fatta bene diventa complessa quanto la gestione dello scheduling (si possono trovare paragoni tra i due sistemi).

La miglior soluzione a cui ho pensato è: diciamo che si hanno 5 livelli di priorità di messaggi; un server può scegliere di avere da 1 a 5 buffer diversi, ognuno che contiene messaggi di uno o più livelli di priorità. Il mittente può scegliere la priorità del messaggio, ma sarà il server poi che attua una sua politica di gestione; un esempio potrebbe essere un server che usa 5 thread diversi (magari a priorità di CPU diverse), ognuno che legge messaggi da una coda diversa, oppure un singolo thread che prende in sequenza da ciascuna coda, in modo da ridurre il tempo medio di attesa di ciscun messaggio nella coda.

In più, si possono implementare policy a livello di OS, dove certi livelli di priorità (magari quella massima) possono essere scelti solo da determinati processi scelti e fidati (come processi di sistema, driver etc), in modo da rispondere con la massima tempestività alle richieste genuinamente importanti (perchè non possiamo fidarci che qualsiasi programma sceglierà sempre la priorità corretta, per il discorso malware). Il kernel, quando smista i messaggi, si preoccuperà di abbassare il livello di un messaggio se questo viene da un processo non privilegiato, anche senza dare errore, in modo che un processo possa comunque usare le priorità per gestire il suo invio di messaggi (il kernel garantisce di gestire/recapitare i messaggi che il mittente ritiene più prioritari), anche se poi vengono abbassati al livello massimo consentito (es. si potrebbe voler far girare un processo al minimo di priorità, quindi impostando opportunamente una policy, i suoi messaggi a livello "normale" vengono automaticamente e trasparentemente convertiti a "basso").

Offline cdimauro

  • Human Debugger
  • *****
  • Post: 4291
  • Karma: +7/-95
    • Mostra profilo
Re:SuperKernel !
« Risposta #27 il: 07 ſettembre 2013, 16:12:07 »
@Z80Fan: va bene.

Ricorda, comunque, che col doppio buffer non devi azzerare alcunché: basta spostare il puntatore indietro, all'inizio del buffer, per ricominciare a scrivere messaggi man mano.

L'unico dubbio è su ciò che bisogna fare se un buffer si riempie. Ma c'è tempo per pensarci.

Offline cdimauro

  • Human Debugger
  • *****
  • Post: 4291
  • Karma: +7/-95
    • Mostra profilo
Re:SuperKernel !
« Risposta #28 il: 07 ſettembre 2013, 16:37:20 »
Lasciamoglielo scrivere prima. :P

Offline Z80Fan

  • Administrator
  • Guru
  • *****
  • Post: 1671
  • Karma: +13/-2
    • Mostra profilo
    • http://z80fan.altervista.org
Re:SuperKernel !
« Risposta #29 il: 07 ſettembre 2013, 16:55:44 »
Ricorda, comunque, che col doppio buffer non devi azzerare alcunché: basta spostare il puntatore indietro, all'inizio del buffer, per ricominciare a scrivere messaggi man mano.
Uhm, non mi pare di averlo pensato a azzeramenti, ma ho scritto quello che mi veniva in mente quindi è possibile che ci siano delle incongruenze. :D

Questo kernel possiamo anche anche provarlo sulla 68060 board con 8Mbyte di ram, o sulla Atlas MIPSR32-r2 con 128Mbyte di ram,
Non mi ricordo, alla fine avevi trovato il compilatore C++ per 68k? Quella patch di LLVM non son riuscito per niente e inserirla, neanche sulla versione 2.9 che dovrebbe essere quella su cui era basata; mi fa credere che quella patch non abbia mai funzionato...  :-\

Citazione
oppure con a una versione mignon (in puro C) sulla 68HC11, uno schedino che volendo potrei produrre con almeno 40Kbyte di ram.
Niente C, come avevo già detto punto tutto su C++, e probabilmente in generale avrebbe prestazioni scadenti su piccoli micro a 8 bit.
Non dico che in C++ non si può fare un sistema prestante per sistemi embedded molto piccoli, è solo che o non si hanno i compilatori o sono veramente poco ottimizzati.

Per quel tipo di applicazioni c'è già Contiki, che è progettato appositamente per quello scopo.

Tags: