C1.
Monitor Delirium {

  float[] birre = new Array(MAX);
  Pair assetati = new Pair(<Condition, Queue(float)>); // init a 0
  Condition chiamato = new Condition();                // magazziniere
  Queue richieste = new Queue(<Int>);

  Delirium() {
    birre = FULL;
    assetati.second = new Queue(float);
  }

  int isempty() {
    if (richieste.isEmpty()) {
      chiamato.wait();
    }
    return richieste.dequeue();
  }

  void pour(int type, float quantity) {
    if (birre[type] < quantity) {
      quantity -= birre[type];
      birre[type] = 0;
      assetati[type].second.enqueue(quantity);
      if (assetati[type].second.length == 1) {
        richieste.enqueue(type);
        chiamato.signal();
      }
      assetati[type].first.wait();
      assetati[type].second.dequeue();
    }
    birre[type] -= quantity;
    if (assetati[type].second.top() <= birre[type])
      assetati[type].first.signal();
    else {
      richieste.enqueue(type);
      chiamato.signal();
    }
  }

  void loaded(int type, float quantity) {
    birre[type] += quantity;
    assetati[type].first.signal();
  }
}

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

C2.

Class Lifobuf {

  Stack valueStack = new Stack(Int); // buffer interno
  // pila dei semafori dove ciascun processo è bloccato
  // semafori e processi sono bloccati uno a uno.
  Stack processStack = new Stack(Semaphore);

  Semaphore valueStackMutex = new Semaphore(1);
  Semaphore processStackMutex = new Semaphore(1);

  void push(int value) {
    // memorizzo il nuovo valore nel buffer interno
    valueStackMutex.P();
    valueStack.push(value);
    valueStackMutex.V();
    // se c'era almeno un processo in attesa sblocco l'ultimo arrivato
    processStackMutex.P();
    if (!processStack.isEmpty())
      processStack.pop().V();
    processStackMutex.V();
  }

  int pop() { // Aspetto che processList non sia vuota
    // se non ci sono valori memorizzati mi blocco
    valueStackMutex.P();
    if (valueStack.isEmpty()) {
      valueStackMutex.V();
      Semaphore s = new Semaphore(0);
      processStackMutex.P();
      processStack.push(s);
      processStackMutex.V();
      s.P();
    } else {
      valueStackMutex.V();
    }
    // prendo l'ultimo valore inserito nel buffer interno
    valueStackMutex.P();
    int tmp = valueStack.pop();
    valueStackMutex.V();
    return tmp;
  }
}

------------------------------------

G1.

Lo scheduler è necessariamente preemptive perché A viene interrotto
per cause indipendenti dalla sua volontà:
  - Non si è interrotto di sua spuntanea volontà perché si è autoterminato,
    siccome lo rincontriamo in istanti successivi
  - Non si è interrotto di sua spuntanea volontà per operazioni di I/O 
    o sistem call bloccante, perché all'istante 5 ha un altro CPU burst
E' possibile che lo scheduler sia round-robin senza priorità con timeSlice di 3,
ma non certo. Per esempio in questa esecuzione particolare tutti i processi potrebbero
aver avuto la stessa priorità.

-------------------------------------------------------------

G2.

a) E' bene non usarla se:
  - La memoria secondaria ha dimensioni analoghe a quelle della memoria primaria
  - Se non abbiamo bisogno di più memoria di quella fisica principale
  - Viene a cadere il principio di località spaziale temporale 
  - Si punta ad un sistema concettualmente minimale

b) Il sistema FAT viene ancora utilizzato per:
  - Implementazione semplice
  - Interoperabilità (portabile) (vecchi sistemi windows)
I restanti vantaggi vengono superclassati da sistemi di file-system ottimizzati 
(ext2,ext3,ext4), e quindi non costituiscono motivi validi per utilizzare ancora FAT.

c) Grazie ai sistemi RAID riusciamo a produrre sistemi con memoria di rindondanza la
quale ci permette il recupero di memoria danneggiata/persa. Inoltre in base alla 
tipologia di RAID utilizzata potremmo avere diversi vantaggi ad esempio in termini
di velocità di lettura. A seconda dell'importanza dei dati memorizzati, potrebbe essere
comunque necessario fare uso di un backup esterno, poiché c'è sempre la possibilità
di un fallimento generalizzato a tutta la batteria.

d) Siano P,Q,R processi. Sia A una classe di risorse, con due istanze a1,a2 sia B una
classe di risorse con una istanza b1. Se a P abbiamo assegnato a1 e P richiede B, se 
a Q abbiamo assegnato b1 e Q richiede A, se a R abbiamo assegnato a2,
allora abbiamo un ciclo, ma non un knot (e infatti è completamente riducibile
facendo terminare prima R, poi Q e infine P) e quindi neanche deadLock.