Progettazione di un modo in cui il processo deve comunicare con il kernel

2

Ho un progetto che è una specie di sistema operativo virtuale.

In questo progetto, la classe Kernel è responsabile della creazione delle classi Process . La classe di processo è composta da% classi% co_de e la classe Thread sarà composta da una classe Thread . La classe CPU è in realtà un emulatore CPU e il CPU è quindi un thread "emulato". Quindi, quando la classe Thread incontra un'istruzione di interrupt, deve essere gestita dal kernel perché di solito è una chiamata di sistema. La classe CPU non può visualizzare direttamente la classe Kernel , è incorporata nella classe CPU , che è incorporata nella classe Thread .

L'approccio che sto utilizzando ora utilizza una classe Process , che gestisce le chiamate di sistema e i breakpoint. Ecco come appare il codice.

class CPU final {
  std::shared_ptr<MemoryBus> memoryBus;
  std::shared_ptr<InterruptHandler> interruptHandler;
  std::uint32_t regs[32];
public:
  void Run(unsigned int steps) {
    for (decltype(steps) i = 0; i < steps; i++)
      RunInst();
  }
protected:
  // This function will call the interrupt
  // handler if it encounters an interrupt instruction.
  void RunInst();
};

class Thread final {
  std::shared_ptr<CPU> cpu;
  std::shared_ptr<InterruptHandler> interruptHandler;
public:
  Thread() : cpu(new CPU) {
  }
  void Run(unsigned int steps) {
    cpu->Run(steps);
  }
};

class Process final {
  std::vector<std::shared_ptr<Threads>> threads;
  std::shared_ptr<MemoryMap> memoryMap;
  std::shared_ptr<InterruptHandler> interruptHandler;
public:
  void Run(unsigned int steps) {
    for (auto &t : threads)
      t->Run(steps);
  }
};

class InterruptHandler {
  std::shared_ptr<FS> fs;
public:
  void HandleInterrupt(CPU &cpu, int interrupt_type);
  void HandleSyscall(CPU &cpu, int syscall_type);
  void HandleWrite(CPU &cpu, int fd, const void *buf, unsigned int len);
  // More system calls follow
};

class Kernel final {
  std::vector<std::shared_ptr<Process>> processes;
  std::vector<InterruptHandler> interruptHandler;
public:
  void Run(unsigned int steps) {
    for (auto &p : processes)
      p->Run(steps);
  }
  void AddProcess(const std::string &path) {
    // opens process, assigns interrupt handler
    processes.emplace_back(process);
  }
};

Il problema qui è che la classe del gestore di interruzioni deve essere passata a quasi tutte le sottoclassi della classe InterruptHandler , inclusa la classe Process . Inoltre, Process sembra che finirà per contenere molti degli stessi dati della classe InterruptClass . Non mi piace perché sento che viola il principio di "non ripeterti".

So che c'è un modo migliore di progettarlo ma non l'ho ancora capito. Il modello di progettazione Proxy è applicabile a questo scenario? Per quanto riguarda l'utilizzo di segnali e slot, simile a Qt e anche descritto qui ?

Ho omesso l'URL di questo progetto, perché non voglio essere promosso da me stesso. Se il codice che ho fornito è troppo incompleto, farò riferimento ai file nel progetto per maggiori informazioni.

    
posta tay10r 27.05.2018 - 00:36
fonte

2 risposte

0

È abbastanza ovvio che quello che sto cercando di fare qui è un errore di progettazione.

Con il grafico delle dipendenze tra il kernel e la classe CPU / interprete, è abbastanza ovvio che non dovrebbero interagire nel modo in cui sto cercando di convincerli a interagire. Ci sono due soluzioni, ho capito, per gestire gli interrupt software dalla CPU.

Soluzione 1:

Rompere la dipendenza tra il kernel e la CPU / Interprete. Avrei potuto dichiarare le classi CPU / Interpreter come la classe più alta del design. La CPU / Interprete emula il sistema e il kernel è scritto nel codice byte che la CPU / interprete emula. Questo è simile al modo in cui i sistemi funzionano normalmente.

Soluzione due:

Invece di usare le istruzioni di interrupt della CPU per implementare le chiamate di sistema (nel modo in cui sono solitamente fatte), potrei usare input / output mappati in memoria. Ho già implementato una classe MemoryMap composta da istanze di classe MemorySection astratte. L'unica implementazione corrente di MemorySection è solo una sezione di memoria piatta. Potrei ricavare la classe MemorySection in un'interfaccia di file system mappata in memoria, un'interfaccia di allocazione della memoria, ecc.

Ho finito con la soluzione due, perché non richiede quasi nessuna riscrittura del progetto.

    
risposta data 07.06.2018 - 02:06
fonte
0

CPU / interpreti non dovrebbero appartenere a thread / processi ma al kernel. Sono risorse che vengono allocate dal kernel alla richiesta di thread.

    
risposta data 07.06.2018 - 12:08
fonte

Leggi altre domande sui tag