This repository has been archived on 2021-01-15. You can view files and clone it, but cannot push or open issues or pull requests.
html-scheduler/index.html
2016-05-25 12:56:37 +02:00

709 lines
31 KiB
HTML

<!DOCTYPE HTML>
<html lang="it">
<head>
<meta charset="utf-8">
<title>Scheduler</title>
<meta name="author" content="Claudio Maggioni, Fabio Brambilla, Pamela Dardano, Federico Mainetti"/>
<meta name="description" content="Simulazione di uno scheduler in HTML, Javascript e (purtroppo) CSS."/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
<link href='https://fonts.googleapis.com/css?family=Hammersmith+One' rel='stylesheet' type='text/css'>
<script>
var lunghezzaExec=300 //in millis
var risorse = {
varie: new Array(10),
mem: new Array(100) //vettore contenente 100 cloni di memoria
}
function Memoria(){
this.pid = 0;
this.istanteAllocazione = 0;
this.numeroPagina = -1;
}
var pidNuovo = 1;
function Processo(){
processiDisponibili.push(this);
processi.push(this);
this.pid=pidNuovo;
this.logProcesso="";
this.pagine=new Array(Math.floor(Math.random()*10)+3); //vettore contenente gli indirizzi di tutte le pagine in ordine
for(var i=0; i<this.pagine.length; i++){
this.pagine[i]=-1;
}
this.percorsoAllocazione=new Array(Math.floor(Math.random()*10)+this.pagine.length);
this.risorseVarie=new Array(Math.floor(Math.random()*4));
for(var i=0; i<this.percorsoAllocazione.length; i++){
this.percorsoAllocazione[i]=Math.floor(Math.random()*this.pagine.length);
}
for(var i=0; i<this.pagine.length; i++){
if(this.percorsoAllocazione.indexOf(i)==-1){
this.percorsoAllocazione.push(i);
}
}
for(var i=0; i<this.risorseVarie.length; i++){
var tmp=Math.floor(Math.random()*risorse.varie.length);
for(var j=0; j<this.risorseVarie.length; j++){
if(this.risorseVarie[j]!==undefined && this.risorseVarie[j].numero===tmp) break;
}
if(j<this.risorseVarie.length){
i--;
continue;
}
this.risorseVarie[i] = {};
this.risorseVarie[i].numero = tmp;
this.risorseVarie[i].allocata = false;
}
this.stato="disponibile";
this.contatorePercorso=0;
scriviLog("<span style=\"color: white\">Nuovo processo: pid="+this.pid+" pagine="+
this.pagine.length+" lunghezzaPercorso="+this.percorsoAllocazione.length+"</span>");
pidNuovo++;
}
Processo.prototype.log = function(str){
var tmp = str.replace(/ *\<[^>]*\> */g, " ");
scriviLog("<span style=\"color: lightblue\">Processo "+this.pid+": </span>"+str+"\n");
this.logProcesso+="Processo "+this.pid+": "+tmp+"\n";
};
Processo.prototype.cambiaStato = function (str) {
this.stato=str;
this.log("<span style=\"color: violet\">"+this.stato+"</span>");
};
Processo.prototype.rilasciaRisorsaDaIndice = function(index){
risorse.varie[this.risorseVarie[index].numero]=-1;
aggiornaRisorse(this.risorseVarie[index].numero, "#FF6666");
this.risorseVarie.allocata=false;
this.log("<span style=\"color: violet\">rilasciata</span> risorsa <span style=\"color: orange\">"+this.risorseVarie[index].numero+"</span>");
};
Processo.prototype.rilasciaRisorsaDaNumero = function(index){
for(var tmp=0; i<this.risorseVarie.length; tmp++){
if(this.risorseVarie[tmp].numero==index) break;
}
if(tmp<this.risorseVarie.length){
return this.rilasciaRisorsaDaIndice(tmp);
}
return false;
};
Processo.prototype.ottieniRisorsaDaIndiceOFallisci = function(j){
if(risorse.varie[this.risorseVarie[j].numero]==-1){
risorse.varie[this.risorseVarie[j].numero] = this.pid;
this.risorseVarie[j].allocata = true;
this.log("<span style=\"color: violet\">allocata</span> risorsa <span style=\"color: orange\">"+this.risorseVarie[j].numero+"</span>");
aggiornaRisorse(this.risorseVarie[j].numero, "#CCFF66");
return true;
}
return false;
};
Processo.prototype.termina = function(){
if(this.terminazioneCont===undefined){
this.terminazioneCont=0;
this.cambiaStato("terminazione");
//rilascio risorse
for(var i=0; i<this.risorseVarie.length; i++){
this.rilasciaRisorsaDaIndice(i);
}
}
if(this.pagine[this.terminazioneCont+1]===undefined){
if(this.pagine[this.terminazioneCont]!=-1){
aggiornaMemoria(this.pagine[this.terminazioneCont],"#FF6666");
resettaPagina(this.pagine[this.terminazioneCont]);
this.pagine[this.terminazioneCont]=-1;
}
this.cambiaStato("terminato");
this.terminazioneCont=undefined;
var i = processiPronti.indexOf(this);
processiTerminati.push(processiPronti.splice(i, 1)[0]);
return "TERM";
}
else if(this.pagine[this.terminazioneCont]==-1){
this.terminazioneCont++;
return this.termina();
}
else{
aggiornaMemoria(this.pagine[this.terminazioneCont],"#FF6666");
resettaPagina(this.pagine[this.terminazioneCont]);
this.pagine[this.terminazioneCont]=-1;
this.terminazioneCont++;
return true;
}
};
Processo.prototype.numeroPagineAllocate = function(){
var tmp=0;
for(var i=0; i<this.pagine.length; i++){
if(this.pagine[i]>=0) tmp++;
}
return tmp;
}
Processo.prototype.esecuzioneCicloSingolo = function(){ //false: non terminato, true: terminato
if(this.contatorePercorso>=this.percorsoAllocazione.length){
return this.termina();
}
this.stato="esecuzione";
this.log("<span style=\"color: violet\">esecuzione</span> pagina <span style=\"color: orange\">" +
this.percorsoAllocazione[this.contatorePercorso]+"</span>");
if(paginaDaCaricareGiaAllocata(this)){
this.contatorePercorso++;
this.stato="pronto";
return false;
}
else {
if(allocaSegmento(this)==="DEALLOC") return true;
this.stato="pronto";
return false;
}
};
var processiDisponibili = new Array();
var processiPronti = new Array();
var processiTerminati = new Array();
var processi = new Array();
function assegnaRisorse(){
for(var i=0;i<processiDisponibili.length; i++){
var k=0;
for(var j=0; j<processiDisponibili[i].risorseVarie.length; j++){
processiDisponibili[i].ottieniRisorsaDaIndiceOFallisci(j);
if(processiDisponibili[i].risorseVarie[j].allocata) k++;
}
if(k==processiDisponibili[i].risorseVarie.length){
processiDisponibili[i].cambiaStato("pronto");
processiPronti.push(processiDisponibili.splice(i, 1)[0]);
}
}
if(processiPronti.length<2&&processiDisponibili.length){ //se non ci sono tanti pronti assegna tutte le risorse necessarie al processo più vecchio
for(var i=0; i<processiDisponibili.length; i++){
processiDisponibili[i].log("<span style=\"color: orange\">Forzatura dello stato a pronto</span>");
var j;
for(j=0; j<processiDisponibili[i].risorseVarie.length; j++){
if(risorse.varie[processiDisponibili[i].risorseVarie[j].numero]!=processiDisponibili[0].pid){
if(risorse.varie[processiDisponibili[i].risorseVarie[j].numero]!=-1 &&
trovaProcessoDaPid(risorse.varie[processiDisponibili[i].risorseVarie[j].numero]).stato=="pronto"){
processiDisponibili[i].log("<span style=\"color: red\">La risorsa <span style=\"color: orange\">"+
processiDisponibili[i].risorseVarie[j].numero+"</span> è mantenuta da un processo pronto</span>");
break;
}
if(processi[risorse.varie[processiDisponibili[i].risorseVarie[j].numero]]==processiDisponibili[i])
continue;
if(risorse.varie[processiDisponibili[i].risorseVarie[j].numero]!=-1)
trovaProcessoDaPid(risorse.varie[processiDisponibili[i].risorseVarie[j].numero])
.rilasciaRisorsaDaNumero(processiDisponibili[i].risorseVarie[j].numero);
processiDisponibili[i].ottieniRisorsaDaIndiceOFallisci(j);
}
}
if(j==processiDisponibili[i].risorseVarie.length){
processiDisponibili[i].cambiaStato("pronto");
processiPronti.push(processiDisponibili.splice(i, 1)[0]);
break;
}
}
if(i==processiDisponibili.length){
scriviLog("<span style=\"color: orange\">Tutti i tentativi di forzatura dello stato non sono andati a buon fine.</span>")
}
}
}
function allocaSegmento(proc){
var min=0;
//ricerca memoria libera tramite first-fit
for(var i=0; i<100; i++){
if(risorse.mem[i].pid==0) break;
}
if(i==100){
//allocazione fallita
proc.log("<span style=\"color: orange\">Allocazione fallita. Gestione della memoria piena...</span>");
//si applica least recently used
min=0;
for(i=1; i<100; i++){
if(risorse.mem[min].istanteAllocazione > risorse.mem[i].istanteAllocazione)
min = i;
}
if(!resettaPagina(min)){
proc.log("<span style=\"color: red\">gestione della memoria piena fallita.</span>");
return false;
};
aggiornaMemoria(min, "#FF6666");
return "DEALLOC";
}
risorse.mem[i].pid=proc.pid;
risorse.mem[i].numeroPagina=proc.percorsoAllocazione[proc.contatorePercorso];
risorse.mem[i].istanteAllocazione=Date.now();
proc.pagine[proc.percorsoAllocazione[proc.contatorePercorso]]=i;
proc.log("<span style=\"color: grey\">allocata pagina <span style=\"color: orange\">"+proc.percorsoAllocazione[proc.contatorePercorso]+
"</span> in locazione di memoria <span style=\"color: orange\">"+i+"</span></span>");
proc.contatorePercorso++;
return true;
}
function paginaDaCaricareGiaAllocata(proc){
if(proc.contatorePercorso>=proc.percorsoAllocazione.length) return false;
if(proc.pagine[proc.percorsoAllocazione[proc.contatorePercorso]]!=-1) return true;
return false;
}
function resettaPagina(pagina){
scriviLog("<span style=\"color: grey\">Libero locazione di memoria <span style=\"color: orange\">"+pagina+"</span></span>");
for(var i=0; i<processiPronti.length; i++){
if(processiPronti[i].pid==risorse.mem[pagina].pid){
var a = processiPronti[i].pagine.indexOf(pagina);
if(a<0){
scriviLog("<span style=\"color: red\">Pagina non registrata nel processo.</span>");
return false;
}
processiPronti[i].pagine[a]=-1;
break;
}
}
if(i==processiPronti.length){
scriviLog("<span style=\"color: red\">Pid non trovato. Questa locazione potrebbe essere già libera</span>");
return false;
}
risorse.mem[pagina].pid=0;
risorse.mem[pagina].numeroPagina=-1;
risorse.mem[pagina].istanteAllocazione=-1;
return true;
}
function scriviLog(str){
var $cont = $('.logger');
$cont.append('<p>' + str + '</p>');
$cont[0].scrollTop = $cont[0].scrollHeight;
}
var pidAttuale = 0;
var vuoto=false;
var interrompi=false;
function loopProcessiPronti(){
assegnaRisorse();
aggiornaProcessiNellaScheda();
if(processiPronti.length>0){
if(pidAttuale >= processiPronti.length) pidAttuale=0;
var tmp;
if((tmp = processiPronti[pidAttuale].esecuzioneCicloSingolo())===true) pidAttuale--;
else if(tmp==="TERM"){
window.setTimeout(aggiornaMemoria, lunghezzaExec);
}
else{
aggiornaMemoria(processiPronti[pidAttuale].pagine[processiPronti[pidAttuale]
.percorsoAllocazione[processiPronti[pidAttuale].contatorePercorso-1]],"#CCFF66");
}
pidAttuale++;
vuoto=false;
}
else if(!vuoto){
scriviLog("<span style=\"color: white\">Coda dei processi pronti vuota.<span>");
aggiornaRisorse(11,"");
vuoto=true;
}
if(interrompi){
if(interrompi===true){
scriviLog("<span style=\"color: white\">In pausa.</span>");
interrompi=2;
}
return;
}
window.setTimeout(function(){
loopProcessiPronti();
},lunghezzaExec);
}
function toggleProcessiPronti(){
if(processiPronti.length==0) return;
interrompi= !interrompi;
if(!interrompi) {
scriviLog("<span style=\"color: white\">Continuo...</span>");
loopProcessiPronti();
}
}
function avvio(){
for(var i=0; i<risorse.mem.length; i++){
risorse.mem[i] = new Memoria();
}
for(var i=0; i<risorse.varie.length; i++){
risorse.varie[i]=-1;
}
processi.push({pid: 0, pagine:"https://www.youtube.com/watch?v=PbpjqD-blo4&t=4s"});
for(var j=0; j<10; j++){
new Processo();
}
loopProcessiPronti();
}
function cambiaVel(e,elem){
if(e.keyCode!=13) return;
var tmp = parseInt(elem.value);
if(isNaN(tmp)||tmp<1){
alert("Inserimento non valido.");
return;
}
lunghezzaExec=tmp;
}
function aggiornaMemoria(eseguita, colore){
for(var i=0; i<100; i++){
var cella = document.getElementById("memoria"+Math.floor(i/10)+i%10);
if(eseguita==i) cella.style.background=colore;
else if(processiPronti[pidAttuale]!==undefined&&risorse.mem[i].pid==(processiPronti[pidAttuale].pid))
cella.style.background="lightblue";
else if(risorse.mem[i].pid!=0) cella.style.background="orange";
else cella.style.background="white";
cella.innerHTML= risorse.mem[i].pid!=0 ? risorse.mem[i].pid : "";
}
}
function aggiornaRisorse(eseguita, colore){
for(var i=0; i<10; i++){
var cella = document.getElementById("risorse"+i);
if(eseguita==i) cella.style.background=colore;
else if(i==risorse.varie[eseguita])
cella.style.background="lightblue";
else if(risorse.varie[i]!=-1) cella.style.background="orange";
else cella.style.background="white";
cella.innerHTML= risorse.varie[i]!=-1 ? risorse.varie[i] : "";
}
}
function trovaProcessoDaPid(pid){
if(pid===0) window.open(processi[pid].pagine,"","width=600,height=450");
return $.grep(processi, function(e){ return e.pid == pid; })[0];
}
function comandiDaTastiera(e){
switch(e.keyCode){
case 84:
case 116:
//lettera T: nuovo processo
new Processo();
break;
case 69:
case 101:
//lettera E: pausa/riprendi processi
toggleProcessiPronti();
break;
case 67:
case 99:
//lettera C: avanza di un esecuzioneCicloSingolo se è in pausa
if(interrompi) loopProcessiPronti();
break;
};
}
function aggiornaProcessiNellaScheda(){
var tmp="";
for(var i=0;i<processi.length; i++){
tmp+="<option value=\""+processi[i].pid+"\" ";
if(document.getElementById('#proc-pid')!=undefined && parseInt(document.getElementById('#proc-pid').innerHTML)==processi[i].pid)
tmp+="selected=\"selected\"";
else if(processi[i].pid>0){
tmp+=">Processo "+processi[i].pid
}
else tmp+=">SELEZIONA";
tmp+="</option>";
}
document.getElementById("listaProc").innerHTML=tmp;
aggiornaDettagliProcesso();
}
function aggiornaDettagliProcesso(){
if($('#listaProc :selected').text()!=""&&parseInt($('#listaProc :selected').attr("value"))>0){
var pid=parseInt($('#listaProc :selected').attr("value"));
document.getElementById("proc-pid").innerHTML=pid;
document.getElementById("proc-stato").innerHTML=trovaProcessoDaPid(pid).stato;
document.getElementById("proc-numpagine").innerHTML=trovaProcessoDaPid(pid).pagine.length;
}
//window.setTimeout(aggiornaProcessiNellaScheda, 1000);
}
</script>
<style type="text/css">
body{
margin: 0;
overflow-x: hidden;
}
h1,h2,h3,h4,h5,h6{
margin: 0;
margin-bottom: .5rem;
text-align: center;
width: 100%;
}
.section.card.loggerSection{
background: lightblue;
}
.logger{
overflow-y: scroll;
height: 60vh;
background-color: black;
width: calc(100vw - 13rem);
float: left;
margin-bottom: .5rem;
}
.logger > p{
margin-top: 0;
margin-bottom: 0;
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
font-size: 1em;
font-weight: bolder;
color: lightgreen;
background: black;
}
.header {
background-color: orange;
height: 3em;
text-align: center;
display: table;
z-index: 1;
width: 100vw;
box-shadow: 0 1px 3px rgba(0,0,0,.12),0 1px 2px rgba(0,0,0,.24);
margin-bottom: 1rem;
font-family: 'Hammersmith One', sans-serif;
}
.header > h1{
font-size: 2em;
color: white;
margin: 0;
display: table-cell;
vertical-align: middle;
font-weight: lighter;
}
.nav {
width: 8rem;
padding: .5rem;
font-family: 'Hammersmith One', sans-serif;
margin-left: .5rem;
background: #cccccc;
float: left;
font-weight: lighter;
position: fixed;
}
.nav > p, .section.teoria > p{
margin: 0;
}
.nav > p > a{
color: black;
text-transform: uppercase;
text-decoration: none;
}
.sections{
float: right;
width: calc(100vw - 11rem);
margin-bottom: 2rem;
}
.sections > .section{
width: calc(100vw - 13rem);
padding: .5rem;
margin-bottom: .5em;
}
.card{
display: block;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.16), 0 1px 3px rgba(0, 0, 0, 0.23);
}
div.sections div.section:last-child{
margin-bottom: 0;
}
.footer {
background-color: orange;
color: white;
clear: both;
text-align:center;
position: fixed;
font-size: 0.8em;
width: 100vw;
bottom: 0;
left: 0;
right: 0;
}
.btn {
position: relative;
display: block;
margin-left: .5rem;
padding: .5rem;
overflow: hidden;
border-width: 0;
color: white;
float: left;
outline: none;
box-shadow: 0 1px 4px rgba(0, 0, 0, .6);
background-color: #2ecc71;
transition: background-color .3s;
font-size: 1em;
}
.btn:hover, .btn:focus {
background-color: #27ae60;
}
.btn > * {
position: relative;
}
.btn span {
display: block;
padding: 12px 24px;
}
.btn:before {
content: "";
position: absolute;
top: 50%;
left: 50%;
display: inline-block;
width: 0;
padding-top: 0;
border-radius: 100%;
background-color: rgba(236, 240, 241, .3);
-webkit-transform: translate(-50%, -50%);
-moz-transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
-o-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
.btn:active:before {
width: 120%;
padding-top: 120%;
transition: width .2s ease-out, padding-top .2s ease-out;
}
.btn{
margin-top: .25rem;
}
.buttons{
display: inline-block;
width: 100%;
margin: -0.25rem;
margin-bottom: .25rem;
}
.section.teoria{
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
background: black;
color: white;
}
label,input,button,.footer,table,h1,h2,h3,h4,h5,h6{
font-family: 'Hammersmith One', sans-serif;
font-weight: lighter;
}
input{
border: 0;
border-bottom: 1px solid #2ecc71;
margin-left: .5rem;
background: rgba(0,0,0,0);
}
td.memCell{
width: 3em;
height: 3em;
background: white;
text-align: center;
vertical-align: middle;
}
.memTable{
display: inline-block;
}
.section.card.memory{
text-align: center;
background: lightgreen;
}
.proc> tbody> tr> td{
padding-left: 10rem;
}
.proc{
margin: auto;
}
.dettagliProc{
background-color: yellow;
}
.risorse{
background: #ccc;
}
@media screen and (max-width: 600px) {
.nav{
width: calc(100vw - 3rem);
margin-bottom: .5rem;
float: none;
position: static;
}
.sections{
float: none;
margin-left: .5rem;
width: calc(100vw - 1rem);
margin-bottom: .5rem;
}
.sections > .section{
width: calc(100vw - 3rem);
}
.footer{
display: none;
}
.sections > .section > .logger{
width: 100%;
}
}
</style>
</head>
<body onkeypress="comandiDaTastiera(event)">
<div class="header">
<h1>Scheduler</h1>
</div>
<div class="nav card">
<p><a href="#teoria">TEORIA</a></p>
<p><a href="#log">LOG</a></p>
<p><a href="#memoria">MEMORIA</a></p>
<p><a href="#dettagliP">DETTAGLI PROC.</a></p>
<p><a href="#risorse">RISORSE</a></p>
</div>
<div class="sections">
<div class="section card teoria">
<a name="teoria"><h2>Teoria</h2></a>
<p>In informatica lo scheduler (da to schedule letteralmente "mettere in lista", ovvero "pianificare") è un componente
di un sistema operativo ovvero un programma che implementa un algoritmo di scheduling il quale, dato un insieme di richieste
di accesso ad una risorsa (tipicamente l'accesso al processore da parte di un processo da eseguire), stabilisce un ordinamento
temporale per l'esecuzione di tali richieste, privilegiando quelle che rispettano determinati parametri secondo una certa politica
di scheduling, in modo da ottimizzare l'accesso a tale risorsa e consentire così l'espletamento del servizio/istruzione o processo desiderato.</p>
</div>
<div class="section card loggerSection">
<a name="log"><h2>Log dello scheduler</h2></a>
<div class="logger">
</div>
<div class="controls">
<div class="buttons">
<button type="button" class="btn" name="aggiungiProcesso" onclick="new Processo()">Aggiungi processo</button>
<button type="button" class="btn" name="toggleProcessi" onclick="toggleProcessiPronti()">Ferma o riprendi</button>
<button type="button" class="btn" name="vaiAvanti" onclick="if(interrompi) loopProcessiPronti()">Procedi di un ciclo</button>
</div>
<label>Tempo tra i cambi di contesto (in millisecondi):<input class="inputVel" type="number" onkeypress="cambiaVel(event,this)" value="300"/></label>
</div>
</div>
<div class="section card memory">
<a name="memoria"><h2>Memoria</h2></a>
<table class="memTable">
<tbody>
<script>
for(var i=0; i<10; i++){
document.write("<tr>")
for(var j=0; j<10; j++){
document.write("<td class=\"card memCell\" style=\"display: table-cell\" id=\"memoria"+i+j+"\"></td>");
}
document.write("</tr>")
}
</script>
</tbody>
</table>
</div>
<div class="section card dettagliProc">
<a id="dettagliP"><h2>
Dettagli processo<br/>
<select id="listaProc" onchange="aggiornaDettagliProcesso()">
</select>
</h2></a>
<table class="proc">
<tr>
<th>PID:</th>
<td id="proc-pid"></td>
</tr>
<tr>
<th>Stato:</th>
<td id="proc-stato"></td>
</tr>
<tr>
<th>Numero pagine:</th>
<td id="proc-numpagine"></td>
</tr>
</table>
</div>
<div class="section card risorse" style="text-align: center">
<a id="risorse"><h2>Risorse</h2></a>
<table class="memTable"><tr>
<script>
for(i=0; i<10; i++){
document.write("<td style=\"display: table-cell\" class=\"card memCell\" id=\"risorse"+i+"\">"+i+"</td>")
}
</script>
</tr></table>
</div>
</div>
<div class="footer">
Creato da Claudio Maggioni, Federico Mainetti, Pamela Dardano, Fabio Brambilla
</div>
<script>
avvio();
window.onerror = function errorHandler(errorMsg, url, lineNumber) {
scriviLog("<span style=\"color: red\">Errore: Faccio partire Papi...</span>");
window.open(processi[0].pagine,"","width=600,height=450");
return false;
}
</script>
</body>
</html>