UNIVERSITA’ POLITECNICA DELLE MARCHE
Facoltà di Ingegneria
Corso di Laurea in Ingegneria Informatica e
dell’Automazione
Tesi di Laurea
Progettazione e sviluppo di un modulo per il task-scheduling
per il CMS Drupal 6.
Laureando: Danilo del Conte
Relatore: Prof. Aldo Franco Dragoni
ANNO ACCADEMICO 2010-2011
1
Indice
Introduzione ………………………………………………… 3
CMS ………………………………………………………………………………………4
Formato RSS e Feed Web ……………………………………………………………….10
Drupal ……………………………………………………………………………………12
Algoritmo ………………………………………………………………………………..16
Processo ………………………………………………………………………………….18
Scheduler ………………………………………………………………………………...23
Scheduling della CPU ……………………………………………………………………24
Sistema operativo Real-Time ……………………………………………………………27
Specifiche progetto …………………………………………32
Realizzazione progetto ……………………………………..35
Drupal operazioni iniziali ………………………………………………………………..36
Organizzazione del lavoro ……………………………………………………………….53
Implementazione algoritmi nel linguaggio C ……………………………………………54
Creazione della directory del modulo “algoritmi” ………………………………………69
Creazione del file algoritmi.info ………………………………………………………...70
Creazione del file algoritmi.module ……………………………………………………..75
Creazione del file crea_gantt.php ………………………………………………………100
Installazione e funzionamento del modulo algoritmi …………………………………..115
Conclusioni ………………………………………………..121
Bibliografia ………………………………………………..124
2
INTRODUZIONE
3
CMS
Content Management System, in acronimo CMS, letteralmente sta per “sistema di gestione
dei contenuti”. È uno strumento software installato su un web server studiato per facilitare la
gestione (creazione, modifica, rimozione, ecc.) dei contenuti di un sito web (portale informativo)
attraverso un’interfaccia semplice ed intuitiva, che svincola l'amministratore del sito da conoscenze
tecniche di programmazione web e gli permette di ottenere il controllo sulla creazione e sulla
distribuzione delle informazioni contenute in esso.
In poche parole, garantisce all’amministratore la totale autonomia nella gestione dei
contenuti del sito senza la necessità che esso conosca i linguaggi di programmazione web (HTML,
PHP, JavaScript, ecc.) e senza il bisogno di rivolgersi ad un web master (colui che ha creato il sito o
semplicemente chi conosce i linguaggi di programmazione web).
Il reale valore aggiunto di un sito internet, rispetto al cartaceo, dovrebbe essere il costante
aggiornamento dei contenuti e la visibilità di questi a livello mondiale. Solo un sito costantemente
aggiornato può essere seguito dalle altre persone con interesse.
Ogni sito web, ai suoi albori, presenta poco contenuto. Con lo scorrere del tempo,
l’organizzazione responsabile del sito sente il bisogno di pubblicare nuove informazioni sul web, ed
il sito deve essere aggiornato. Probabilmente il sito è content-driven, cioè fortemente basato sul
contenuto; magari sul portale vengono pubblicati articoli e news con una frequenza molto alta, per
cui occorre prestare molta attenzione a come possa essere aggiornato e modificato il sito stesso.
Con il CMS si vuole creare il sito in modo da poter essere facilmente modificato da persone
non esperte di programmazione o web development (sviluppatori di siti internet), permettendo la
gestione efficace di una gran mole di informazioni di diverse tipologie.
Per far fronte a queste esigenze è indispensabile appoggiare la nostra base di informazioni su un
CMS, una piattaforma per la pubblicazione delle informazioni e la gestione dei contenuti di un
portale.
Grazie al CMS la fase di realizzazione dell'architettura del sito e della information architecture è
distinta dalla fase di inserimento dei dati veri e propri. Mentre la prima fase richiede il lavoro di un
esperto informatico, nella seconda fase i contenuti effettivi del portale possono essere gestiti da
personale interno all'organizzazione, precedentemente istruito per l'operazione, attraverso pochi
semplici passi.
Facciamo qualche esempio
L'attività commerciale che decide di proporre un' offerta promozionale ha la necessità di
pubblicizzare l'evento sul proprio sito, quindi ha bisogno di tempestivi aggiornamenti. Oppure,
l’associazione X vuole aggiornare l'elenco degli iscritti o inserire delle news nel proprio sito. O
ancora, un’agenzia di viaggi vuole pubblicizzare le offerte last minute.
Normalmente, per queste operazioni, come per ogni seppur minimo aggiornamento, si segue
la stessa noiosa procedura. L'interessato (autore del sito, o amministratore) fornisce i contenuti da
pubblicare a chi ha realizzato le pagine (web master) e dopo aver spiegato nel migliore dei modi
quello che gli serve, aspetta diligentemente il suo turno. Ovviamente non sarà il solo utente che ha
la necessità di aggiornare il proprio sito (perché anche altre persone potrebbero rivolgersi allo stesso
webmaster), quindi l'operazione sarà lenta (il web master deve soddisfare le richieste di più
4
persone), dispendiosa (gli aggiornamenti si pagano) e soprattutto genera un rapporto di dipendenza
nei confronti del web master o della web agency che ha realizzato il sito.
Come altro ulteriore esempio descriviamo uno scenario molto comune tra le piccole aziende:
viene commissionato il sito ad una Web Agency o ad un professionista del settore, il sito viene
realizzato in HTML e CSS, e l’azienda è molto contenta del risultato. Dopo alcuni mesi la ditta
sente la necessità di dover aggiornare delle informazioni, ma nessuno all’interno della ditta conosce
HTML. Il contenuto del sito deve essere modificato da una persona esterna, che funge da
responsabile del sito. Ora tutto il contenuto che deve essere pubblicato sul sito passa per le sue
mani. Potrebbe accadere che questa persona si renda irreperibile per qualsiasi motivo ed ogni
aggiornamento sarebbe impossibilitato. Oppure viene affidata la gestione del sito ad un dipendente
interno all’azienda, con poche conoscenze informatiche, dopo un breve corso di HTML. Questa
persona si occupa dell’inserimento dei dati, ed il procedimento funziona, ma dopo qualche tempo ci
si accorge che il sito ha bisogno di un serio restyling, dato che le informazioni venivano aggiunte
ogni volta in modo approssimativo, senza un vero metodo, una organizzazione dei dati.
In ambedue i casi, in presenza di frequenti aggiunte di contenuto al sito, potrebbe accadere
che la persona incaricata di aggiornare il sito si trovi in una situazione nota come “bottleneck”
(collo di bottiglia) per il flusso delle informazioni dall’azienda al suo pubblico, con dei conseguenti
ritardi negli aggiornamenti dei siti (deve soddisfare le richieste di più aziende).
In sintesi: effettuare la manutenzione e l'aggiornamento di un sito può rivelarsi
un’operazione molto complessa ed onerosa, ma è impossibile pensare di non farlo. Il CMS è
un’ottima soluzione perché è economicamente competitivo e consente di essere autonomi e
tempestivi negli aggiornamenti di un sito.
Estendere la Gestione del Contenuto
Il tempo in cui un’azienda creava un sito web solo per avere una “presenza” su Internet è
finito; oggigiorno un sito Internet serve ad informare i clienti, risolvere i loro problemi e cercare di
attirare nuove opportunità.
La gestione del contenuto del sito deve essere resa disponibile anche a delle persone che non
hanno un background tecnico, non sanno né come è composta una pagina HTML né come è
strutturato un sito Internet. E non vogliono saperlo. Vogliono solo aggiungere contenuto al sito
Web.
Bisogna ricorrere ad un software che possa creare un framework (struttura di supporto su cui
un software può essere organizzato e progettato) intorno al sito, in modo che, definita una struttura
portante ed un design attraente, le informazioni inserite nel sito vengano strutturate in modo
automatico, coerente ed intuitivo, senza che la crescita della mole di informazioni porti il sito fuori
controllo. Questo software è appunto il CMS.
Caratteristiche comuni di ogni CMS
Un CMS:
• Permette di aggiornare il sito senza essere degli esperti di html, php, ecc.
• Permette di realizzare in modo facilitato l’architettura dei dati progettata, attraverso la
definizione di diverse sezioni e categorie in cui classificare gli articoli.
• Permette di separare nettamente i dati dalla loro presentazione.
• Permette di gestire in modo semplice la pubblicazione delle informazioni e decidere quando
esse devono essere tolte dal sito.
5
•
•
•
•
Permette la gestione di siti e portali informativi di ogni dimensione.
Integrazione con contenuti provenienti da diverse fonti come database o RSS.
Gestione degli utenti, con mailing list e messaggistica.
Funzionalità di ricerca dei contenuti che vanno oltre la disposizione in categorie.
Tecnicamente un CMS è un’applicazione lato server che, appoggiandosi su un database
preesistente per lo stoccaggio (sistemazione e conservazione) dei contenuti, permette una
generazione dinamica di questi, prelevandoli proprio dal database. L'applicazione è composta da
una serie di script che permettono a chiunque, anche digiuno di linguaggi di programmazione, di
aggiornare il sito “retto” dal CMS, inserendo i contenuti direttamente online, fondamentalmente
tramite una serie di form (più o meno "avanzate").
Gli script, lavorando sul server, memorizzano le informazioni immesse dall'utente
(amministratore o redattore) traducendole in dati “digeribili” dal server (record del database, altri
script) e le restituiscono all'utente finale in modo completamente trasparente (all'utente finale arriva
comunque una pagina HTML “standard”, come avrebbe potuto scriverla in codice il web master).
Proprio per questo, in un CMS si distingue di solito la parte front-end (che viene presentata ai
navigatori) da quella back-end, che contiene la parte gestionale (amministrazione, opzioni, editing):
• la sezione applicativa (front end), che l'utente web usa per beneficiare dei contenuti e delle
applicazioni del sito;
• la sezione di amministrazione (back end), che serve all’amministratore del sito per
organizzare e supervisionare la produzione dei contenuti.
La parte back-end:
• non richiede (almeno per tutte le operazioni quotidiane più comuni) conoscenze maggiori di
quelle necessarie a navigare su internet e di saper scrivere con un word-processor;
• non richiede software proprietari, reti private virtuali, plugins esotici, ma un semplice
Browser Internet.
In pratica l'amministratore del CMS effettua tutte le operazioni di gestione connettendosi al
sito dal proprio terminale, immettendo username e password (per ricevere gli eventuali permessi di
gestione) e sfogliando delle pagine composte da form (spuntando, scrivendo, scegliendo opzioni da
menù a discesa), che sarebbero i pannelli di interfaccia grafica che permettono il controllo e la
gestione del sito (inserire, modificare, eliminare i vari contenuti).
I CMS possono essere realizzati tramite programmazione in vari linguaggi web tra cui più
comunemente in ASP, PHP, .NET; il tipo di linguaggio adoperato è indifferente a livello di
funzionalità. Alcuni linguaggi rendono il CMS multipiattaforma, mentre altri lo rendono utilizzabile
solo su piattaforme proprietarie.
Tipi di CMS
Esistono CMS specializzati, cioè appositamente progettati per un tipo preciso di contenuti
(un'enciclopedia on-line, un blog, un forum, una rivista ecc.) e CMS generici, che tendono a essere
più flessibili per consentire la pubblicazione di diversi tipi di contenuti. Anche se la tendenza attuale
è quella della convergenza (i CMS specializzati fanno sempre più cose e quelli generalisti
implementano sempre più servizi specializzati), è possibile ancora fare qualche distinzione. Senza
voler fare una tassonomia esaustiva, fra i sistemi specializzati vi sono:
• LMS (Learning Management Systems): sistemi per la formazione online, orientati alla
diffusione di materiale didattico e alla sua erogazione; hanno classi, corsi, calendari, test di
apprendimento, fino a esami online.
6
•
•
•
piattaforme per i Blog: sistemi dedicati alla creazione di blog e forum; permettono la
pubblicazione di un "diario online", con coordinate ormai consolidate: commenti dei lettori,
pubblicazione di un flusso "puro" xml (feed) per l'utilizzo degli articoli fuori dal contesto del
sito, anche con strumenti diversi dai browser internet, strumenti per la creazione di una rete
esterna al blog.
sistemi di e-commerce: sistemi dedicati al commercio online di beni e servizi; includono il
carrello, l'interfaccia con i più diffusi sistemi di pagamento online, la gestione di articoli,
categorie, fornitori, diversi strumenti di marketing, calcolo dei costi.
piattaforme per i WIKI: i wiki sono siti la cui peculiarità è la contribuzione (più o meno)
orizzontale di tutti gli utenti alla creazione e modifica dei contenuti. L'esempio più
conosciuto è senz'altro wikipedia.
I web content management system (WCMS)
Nonostante i CMS non siano stati concepiti per il Web, oggi il loro utilizzo più diffuso è
rivolto alla gestione di siti web, soprattutto se sono di grandi dimensioni e richiedono un frequente
aggiornamento. I CMS utilizzati per il Web sono chiamati con l’acronimo di WCMS.
Una delle applicazioni più utili dei sistemi di WCMS, infatti, è nella gestione dei portali (intranet,
extranet, community, siti di e-commerce...), dove vengono impiegati come strumento di
pubblicazione, flessibile e multiutente.
Ad esempio, gestione di contenuti testuali (notizie, articoli ecc.), link, immagini, liste di
discussione, blog, forum, materiale scaricabile. Può essere modificata anche la struttura stessa delle
pagine in numero ed organizzazione.
I WCMS consentono di definire utenti, gruppi e diritti in modo da poter permettere una
distribuzione del lavoro tra più persone e da poter assegnare ad un preciso “tipo” di utente,
identificato da username e password, determinati privilegi. Per esempio, è possibile definire una
classe di utenti abilitati esclusivamente all'inserimento delle notizie, mentre si può riservare la
scrittura di articoli ad un altro gruppo, e limitare tutti gli altri alla sola consultazione; tutto questo
grazie ad un log in tramite username e password che identifica la classe di appartenenza dell’utente
e in base a quest’ultima ne conferisce i vari permessi.
La scelta di un software di WCMS è strategica per le aziende che generano la maggior parte
di volume d'affari su Internet, ma (in proporzione diversa) è molto importante anche per il libero
professionista che vuole utilizzare il medium Internet per farsi conoscere.
Vantaggi dei CMS
Un CMS permette di costruire e aggiornare un sito dinamico, anche molto grande, senza
necessità di scrivere una riga di HTML e senza conoscere linguaggi di programmazione lato server
(es. PHP) o progettare un apposito database. L'aspetto esteriore delle pagine può essere
personalizzato scegliendo un foglio di stile CSS (il CSS si occupa della presentazione grafica del
sito: colori, caratteri, posizione testo e immagini, ecc.) appositamente progettato per un determinato
CMS.
7
Limiti dei CMS
•
•
Un CMS è tanto più efficiente quanto più è specializzato.
Molti piccoli portali fanno ricorso a CMS (scritti da altri e messi a disposizione
gratuitamente o a pagamento) di tipo generico; per quanto un CMS possa essere flessibile,
un sito basato su questa struttura in genere presenta un aspetto poco personalizzato se non è
possibile intervenire direttamente sul codice sorgente del prodotto per modificarlo.
Analogamente i contenuti saranno sempre ancorati a quanto previsto da chi ha progettato il
CMS e non alle esigenze di chi pubblica il sito.
Quindi i CMS generici hanno sì come vantaggio il fatto di essere molto flessibili e possono
essere utilizzati per gestire diversi tipi di contenuti, ma hanno come limite una modesta
efficienza, nel senso che non sono improntati su nessun tipo di contenuto specifico, cioè
offrono una gestione generica e non specifica a qualsiasi tipo di contenuto (tutti i contenuti
vengono gestiti allo stesso modo, non c’è distinzione ad esempio tra contenuti testuali e
contenuti immagini).
Problemi di gestione: derivano dal fatto che chi pubblica o gestisce il sito può usare il CMS
per intervenire sui contenuti e sull'aspetto, ma generalmente (caso di chi acquista il
software) non è in grado di intervenire direttamente (o far intervenire) sulla struttura del
CMS stesso; questo è un limite strettamente connesso al vantaggio primario dei CMS:
pubblicare un portale senza doverne progettare la struttura o senza possedere le conoscenze
tecniche (o le risorse finanziarie) per uno sviluppo personalizzato.
Questi problemi sono risolvibili utilizzando software open source: la possibilità di accedere
al codice sorgente del prodotto permette di personalizzare il software sulla base delle proprie
esigenze a patto di non avere necessità di apportare modifiche al prodotto adottato. Anche in
questo caso, vanno messi in conto i costi per lo sviluppo di moduli personalizzati o funzioni
particolari a meno di non possedere in proprio o nella propria struttura aziendale le
conoscenze tecniche per intervenire nel codice sorgente (essere un webmaster o avere un
webmaster in azienda).
I portali di una certa importanza generalmente non fanno mai ricorso a CMS distribuiti,
bensì usano programmi e database progettati su misura; ovvero "CMS personalizzati" e
dunque necessariamente specializzati. In questo modo la struttura e la presentazione
vengono realizzate tenendo presente i contenuti che il sito dovrà ospitare e potranno essere
modificati in seguito a nuove esigenze. Non mancano però i casi in cui grandi aziende o
società si siano affidate a CMS open source liberi.
Perché usare un CMS
Con un CMS l'editore del sito (colui che lo amministra e ne gestisce i contenuti) è
potenzialmente in grado di affrancarsi, dopo il primo setup, da agenzie e programmatori.
Ne guadagna l'editore e ne guadagnano i navigatori: al posto del vecchio sito-depliant, fatto e
lasciato lì a ingiallire, i visitatori possono avere notizie fresche, modi di interazione (più o meno
spinti) con l'editore o altri utenti, servizi utili come la ricerca o l'e-commerce; insomma quello che,
oggi, il navigatore medio si aspetta da qualsiasi sito.
8
Funzioni “standard” di un CMS
È molto difficile trovare un sottoinsieme comune (fermo restando che qui si parla dei CMS
generalisti), ma si evidenziano di seguito le funzioni standard principali che accomunano i vari
CMS:
• gestione dei contenuti: creazione di sezioni, sottosezioni e pagine; editing della maggior
parte dei contenuti con tools WYSIWYG (scrittura trasparente di testo formattato -html- con
immagini, link, ecc.);
• tools: news, faq, calendario;
• motore di ricerca interno;
• gestione degli utenti: possibilità di autoiscrizione, permessi su pagine/contenuti, gestione di
gruppi;
• gestione del flusso di pubblicazione: gerarchia di permessi per scrittura, approvazione e
messa online agli utenti finali;
• community: forum, sondaggi, possibilità per gli utenti di gestire i propri dati (sino a
pubblicare, su CMS particolarmente orientati al Web 2.0, contenuti propri orizzontalmente
rispetto all'editore);
• sistemi di pubblicazione alternativa: feed RSS, versioni accessibili, eventualmente invio
per email agli utenti registrati (in realtà queste caratteristiche sono implicite nella struttura
fondamentale di ogni CMS, che separa la nuda interfaccia, detta template, dai contenuti veri
e propri).
Inoltre quasi tutti i CMS, in ogni caso, hanno dei sistemi di plugin (moduli nel caso di
Drupal) con cui è possibile estendere le funzionalità base in ogni direzione. Ovviamente, quanto più
un CMS è diffuso (o quanto è più ampia la comunità di sviluppatori interessati) tanto è più facile
trovare senza fatica la “pappa pronta” di un plug-in che fa al caso nostro.
A titolo di esempio verrà mostrato di seguito un backend di una piattaforma CMS:
9
Formato RSS e feed web
RSS (acronimo della sua ultima versione 2.0 Really Simple Syndication) è uno dei più
popolari formati per la distribuzione di contenuti Web; è basato su linguaggio XML, da cui ha
ereditato la semplicità, l'estensibilità e la flessibilità. L'applicazione principale per cui è noto sono i
feed RSS.
RSS definisce una struttura adatta a contenere un insieme di notizie, ciascuna delle quali sarà
composta da vari campi (nome autore, titolo, testo, riassunto, ...). Quando si pubblicano delle
notizie in formato RSS, la struttura viene aggiornata con i nuovi dati; visto che il formato è
predefinito, un qualunque lettore RSS potrà presentare in una maniera omogenea notizie provenienti
dalle fonti più diverse.
Il feed web è un’unità di informazioni formattata secondo specifiche (di genesi XML)
stabilite precedentemente. Ciò per rendere interoperabile ed interscambiabile il contenuto fra le
diverse applicazioni o piattaforme.
Un feed è usato per fornire agli utilizzatori una serie di contenuti aggiornati di frequente. I
distributori del contenuto rendono disponibile il feed e consentono agli utenti di iscriversi.
L’aggregazione consiste in un insieme di feeds accessibili simultaneamente, ed è eseguita da un
aggregatore Internet.
L’uso principale dei feed RSS (detti anche flussi RSS) attualmente è legato alla possibilità
di creare informazioni di qualunque tipo che un utente potrà vedere molto comodamente, con l'aiuto
di un lettore apposito, nella stessa pagina, nella stessa finestra, senza dover andare ogni volta nel
sito principale. Quindi permettono agli utenti di essere aggiornati su nuovi articoli o commenti
pubblicati nei siti di interesse senza doverli visitare manualmente uno a uno. Questo è dovuto al
fatto che il formato XML è un formato dinamico.
Il web feed presenta alcuni vantaggi, se paragonato al ricevere contenuti postati
frequentemente tramite e-mail:
• Nell'iscrizione ad un feed, gli utenti non rivelano il loro indirizzo di posta elettronica; in
questo modo non si espongono alle minacce tipiche dell'email: lo spam, i virus, il phishing,
ed il furto di identità.
• Se gli utenti vogliono interrompere la ricezione di notizie, non devono inviare richieste del
tipo "annulla la sottoscrizione"; basta che rimuovano il feed dal loro aggregatore.
Gli RSS sono particolari formati dei dati che permettono di pubblicare in modo standard
risorse che sono (o possono essere) aggiornate in modo frequente, quali notizie, blog, audio e video.
Un documento RSS (chiamato in gergo feed ) consiste di un elenco delle risorse cui il documento si
riferisce, insieme ad un loro sommario e ad altri dati importanti quali la loro data di pubblicazione,
quella di eventuale scadenza, l’autore ecc. Un feed, dunque, raccoglie documenti simili e li rende
disponibili in modo sintetico, automatico e in formato standard. Questo formato può essere letto da
molti software diversi (chiamati "lettori RSS", "feed reader" o anche "aggregatori").
Le modalità di utilizzo di un documento RSS più diffuse sono due:
- come applicazione a se stante: attraverso appositi software che interpretano un feed (detto
anche flusso RSS) permettendo agli utenti di visualizzarne i contenuti;
- attraverso un’altra applicazione per l’accesso a Internet (come un browser, eventualmente
mediante un plug-in, o come un’applicazione per l’accesso e la riproduzione di media
digitali, quale ad esempio Apple iTunes): integrando i contenuti del feed all'interno di un
sito Web.
10
Per utilizzare i contenuti in formato RSS è necessario utilizzare un programma ad hoc,
chiamato aggregatore RSS.. Copiando con il tasto destro del mouse il collegamento (il link,
l'indirizzo URL)) della pagina RSS in questione
question e quindi incollandolo nel programma aggregatore si
riesce finalmente a vederne i contenuti in modo chiaro e coerente: una lista di notizie.
notizie Cliccando su
ciascuna notizia si ha generalmente la possibilità di averne un breve riassunto e un link alla pagina
web che la contiene per intero.
Dunque il feed RSS offre la possibilità di avere una specie di indice aggiornato dei contenuti,
contenuti delle
novità di un sito. Piuttosto che andare ogni volta su quel sito per vedere se ci sono novità, basterà
aprire l'aggregatore RSS e sarà lui stesso a collegarsi al
al sito ed eventualmente mettere in evidenza
che c'è un articolo, una notizia, in generale un contenuto nuovo
nuovo su quel sito che si può andare a
consultare.
In pratica l’utente può avere sul proprio aggregatore
ore notifica delle novità e degli aggiornamenti
avvenuti sui vari siti di suo interesse (attraverso i loro rispettivi feed RSS) e andare effettivamente
effettivamen
sul sito solo se la novità
ovità è di suo interesse e visionarla per intero. Abituandosi
Abituandos all'uso dei feed RSS,
si potrebbe anche non aprire mai il browser web o farlo solo su particolari e selezionate novità.
I feed RSS sono facilmente riconoscibili in un sito da icone quali: e
.
Quando si vuole essere sempre aggiornati dei contenuti di un sito,
sito basta cliccare con il tasto
destro del mouse su tali icone
ne (se il sito le offre), copiare
copiar il relativo collegamento (si dovrebbe
ottenere l'URL di un pagina che finisce con .xml) e infine incollarlo nell’aggregatore
nell’
preferito.
Alcuni dei principali aggregatori RSS
RS gratuiti sono: Feedreader e Sharpreader (Windows),
(
Sage
plug-in (FireFox/ThunderBird), Urss plug-in (Mozilla), Straw Linux (Gnome),
(Gnome) Netnewswire Lite
(Mac OS X).
Un esempio di feed RSS è stato preso della home page del sottostante sito:
http://www.espertoweb.it/espertoweb_rss2.xml
http://www.espertoweb.it/espertoweb_rss2.xml.
11
Drupal
Drupal è uno strumento software che permette di realizzare una grande varietà di siti WEB.
Il nome è lo spelling inglese per la parola tedesca druppel che significa goccia.
goccia
Più precisamente è una piattaforma di CMS (Content Management System) scritto in PHP che
poggia su un database per memorizzare i contenuti; necessita dunque di un software DBMS (Data
Base Menagement System) ed il più utilizzato è MySQL.. Questo consente all'amministratore del
sito
ito ed eventualmente ad altri utenti di inserire ed aggiornare i contenuti senza dover conoscere
particolari linguaggi di programmazione (come HTML, PHP, ecc) o far uso di programmi come
Dreamweaver, Frontpage, Nvu.
Drupal è multipiattaforma
piattaforma, cioè funziona su diversi sistemi operativi,
operativi tra cui Windows,
Mac OS X, Linux e qualsiasi piattaforma che supporti i web server Apache o IIS.
IIS
Drupal, come molti CMS contemporanei, offre
offr un'interfaccia di amministrazione con cui
l'amministratore può gestire ogni aspetto del sito web, senza il bisogno di possedere conoscenze
conoscen
tecniche particolari di programmazione Web.
Web
È possibile cambiare la grafica del sito semplicemente scegliendo un tema grafico tra quelli
disponibili o personalizzando il foglio di stile CSS associato.
Drupal è un framework con sviluppo modulare,
modulare, che consente di partire dal sito base e
aggiungere solo le funzionalità necessarie al progetto sistema modulare;
modulare cioè è espandibile,
scalabile,
alabile, sicuro, robusto, flessibile e permette anche la possibilità di manutenzione.
manutenzione Le varie
caratteristiche e funzionalità del sito possono essere estese installando
i
gli opportuni moduli (nome
dato ai plugin di Drupal) aggiuntivi realizzati e distribuiti dalle comunity (drupal.org,
(
druplaitalia.org, drupal.it) o da utenti generici.
generici Risulta così semplicee realizzare un sito multilingue
con gallerie fotografiche, calendario degli eventi, forum, blog, e-commerce
e ommerce e molto altro. È
possibile anche creare personalmente dei propri moduli; consente quindi di aggiungere numerose
funzionalità al sistema base.
Drupal è un software
tware open source con licenza GPL (licenza di software libero, essa
concede ai licenziatari il permesso di modificare il programma, di copiarlo e di ridistribuirlo con o
senza modifiche, gratuitamente o a pagamento),
pagamento), gestito e sviluppato da una comunità molto vasta.
Esso quindi può essere scaricato,, installato e rilasciato liberamente e gratuitamente, utilizzato sia a
scopo personale che commerciale e modificato sulla base delle diverse esigenze. Il sito ufficiale è
www.drupal.org mentre i riferimenti italiani sono www.drupalitalia.org e www.drupal.it.
www.drupal.it
Piattaforma dinamica per la realizzazione di siti web, Drupal consente
ente a un individuo o a
una comunità
unità di utenti di pubblicare, gestire e organizzare una varietà
vari tà di contenuti, integrando in un
unico pacchetto pronto all'uso molte apprezzate funzionalità di gestione contenuti, weblog,
12
strumenti di collaborazione e software per comunità di discussione. Consente quindi la
realizzazione di siti Web basati sulla logica contenuti/commenti.
Attivando e configurando i singoli moduli, un amministratore può disegnare un sito unico,
che può essere utilizzato per una combinazione di gestione della conoscenza, per funzioni di
pubblicazione sul web e interazione di una community.
Le principali funzionalità di Drupal, organizzate per caratteristiche comuni alle piattaforme
web, sono:
Gestione dei Contenuti: attraverso un'interfaccia semplice e utilizzabile via browser, i
membri possono pubblicare contenuti nei diversi moduli disponibili: storie, blog, sondaggi,
immagini, forum, scaricamenti, ecc. Gli amministratori possono scegliere tra diversi
template di temi (modelli di temi già preesistenti e contenuti nel database) o crearne uno essi
stessi per dare al sito un look e uno stile unico. Il sistema di classificazione flessibile
consente una classificazione gerarchica, indici incrociati di messaggi e diversi insiemi di
categorie per la maggior parte dei tipi di contenuti. L'accesso al contenuto da parte dei vari
utenti è controllato attraverso ruoli e rispettivi permessi per ciascun utente definiti
dall'amministratore. Le pagine del sito possono mostrare messaggi per tipo di modulo o per
categorizzazione del contenuto, con fonti RSS separate, disponibili per ogni tipo pubblicato.
Gli utenti possono anche cercare per parola chiave all'interno dell'intero sito.
Weblog: una singola installazione può essere configurata come sito weblog personale
individuale o per diversi individui. Drupal supporta le API Blogger, fornisce fonti RSS per
ogni blog individuale e può essere impostato per lanciare un ping (programma che misura il
tempo, impiegato da uno o più pacchetti ICMP a raggiungere un altro computer o server in
rete ed a ritornare indietro all’origine; è utilizzato soprattutto a verificare la presenza e la
raggiungibilità di un altro computer connesso in rete e per misurare le latenze -intervallo di
tempo che intercorre tra uno stimolo e la reazione da esso provocata- di trasmissione di rete)
alle directory di weblog come blo.gs e weblog.com quando un nuovo contenuto è inserito
nella home page.
Comunità basate sulla discussione: un sito Drupal può comportarsi come un sito di notizie
e/o fare uso di un forum di discussione tradizionale. Degli spazi per i commenti, collegati
alla maggior parte dei tipi di contenuto, rendono semplice per i membri discutere nuovi
messaggi. Gli amministratori possono determinare se il contenuto e i commenti possono
essere inseriti senza approvazione, con l'approvazione di un amministratore o per
moderazione della comunità. Grazie all'aggregatore di notizie interno, le comunità possono
registrarsi su altri siti e discutere contenuti provenienti da essi.
Collaborazione: utilizzato per gestire la realizzazione di Drupal, il modulo progetto si
presta per supportare altri progetti di software open source. Il modulo tipo wiki (libro in
collaborazione) include il controllo di versione, rendendo semplice per un gruppo creare,
revisionare e aggiornare documentazione o altri tipi di testo.
Drupal, opera dello sviluppatore Dries Buytaert, è stato concepito con l'intenzione di mettere
a disposizione degli utilizzatori un potente e flessibile CMS con cui gestire e catalogare svariate
tipologie di contenuti: testi, immagini, documenti, archivi e molto altro.
I contenuti potranno essere inseriti e manipolati da più utenti dotati di diversi privilegi, questo CMS
integra infatti un avanzato sistema di iscrizione e di autenticazione che permette ad un
13
amministratore, vero e proprio "utente di root" della piattaforma, di concedere ai diversi utilizzatori
differenti permessi che vanno dalla semplice lettura alla possibilità di editare i contenuti. Quindi
Drupal consente agli utenti di registrarsi e autenticarsi e permette agli amministratori di creare
livelli d’accesso differenziati secondo i ruoli (utente non iscritto, utente iscritto, amministratore del
sito, amministratore root, ecc).
Drupal è anche uno strumento per la condivisione di contenuti e l'interazione tra autori e
utenti e tra utenti fra loro; l'amministratore ha infatti la possibilità di concedere permessi di
moderazione/amministrazione a singoli utenti o gruppi di utenti, abilitare moduli ed installare
estensioni grazie a cui sarà possibile postare commenti, partecipare alle discussioni di un forum,
mettere a disposizione e condividere materiali in formato digitale, ecc.
I contenuti possono essere organizzati in base alla tipologia (Story, Page, Image…): questo
consente di dividere i contenuti in modo flessibile, rendendone semplice l’inserimento e la
visualizzazione, e consentendo di realizzare uno schema di navigazione del sito estremamente
funzionale.
Drupal è un'applicazione completamente Web based, potrà quindi essere utilizzata
attraverso un semplice browser. Drupal, come detto precedentemente, è un CMS realizzato in PHP
e, pertanto, per funzionare necessita unicamente di:
• un'interprete per PHP;
• un Web server (è raccomandato l'utilizzo di Apache ma il CMS funziona egregiamente
anche con IIS di Microsoft, Drupal potrà quindi essere installato sia in ambiente Linux che
Windows);
• un DBMS (Database Manager System) MySQL , per la memorizzazione dei dati (è possibile
utilizzare anche PostgreSQL mentre MSSQL e Oracle per il momento non sono supportati).
Con Drupal possono essere realizzati siti Web pubblici, locali, dinamici e statici. Alcuni
esempi di siti realizzabili con Drupal sono blog, forum, gallerie d’immagini, e-commerce, multisiti
e multilingua.
La struttura di Drupal
Drupal ha ricevuto elogi da web master, progettisti e programmatori, in parte grazie al suo
design modulare che permette al suo livello base, o «core» di fornire solo le funzioni essenziali
nella sua configurazione predefinita. Funzioni e capacità di visualizzazione aggiuntive possono
estendere il «core» tramite l'installazione di moduli e temi.
Moduli
Il «core» di Drupal contiene i propri moduli, cioè le funzionalità base del sito. I moduli
sviluppati dalla comunità possono comunque essere scaricati e installati in un'area dell'installazione
di Drupal non destinata al «core». Il «core» di Drupal è stato progettato con un sistema di «hook»
(ganci) o callback (chiamata ad una funzione), che permettono ai moduli sviluppati dalla comunità o
da un utente di inserire funzioni nel processo di esecuzione di Drupal.
I moduli inclusi nel «core» forniscono le seguenti funzionalità:
Inserire, modificare e catalogare i contenuti
Eseguire ricerche
14
Inserire commenti
Partecipare a forum
Rispondere a sondaggi
Lavorare a progetti di scrittura collaborativa
Inserire e visualizzare i profili degli utenti
Comunicare tra gli utenti e con gli amministratori del sito
Modificare l'aspetto del sito utilizzando temi grafici già sviluppati e pronti all'uso
Creare menu su più livelli della struttura di navigazione
Localizzare l'interfaccia in diverse lingue, permettendo all'utente di scegliere
Fornire feed RSS
Aggregare e presentare i contenuti RSS di altri siti
Registrare nuovi utenti e gestirne gli account
Gestire in modo granulare permessi e ruoli per i singoli utenti o per interi gruppi
Usare regole per impedire l'accesso al sito a determinati utenti in base a nome, indirizzo
email, indirizzo IP
Collezionare e presentare statistiche dettagliate del sito
Gestire il caching (Il Web caching è la caching di documenti web (pagine HTML,
immagini, ecc.) che permette di ridurre l'uso della banda e il tempo di accesso ad un Sito
web. Una web cache memorizza copie di documenti richiesti dagli utenti, successive
richieste possono essere soddisfatte dalla cache se si presentano certe condizioni) delle
pagine ed il throttling (funzionalità che permette di disabilitare alcuni moduli/blocchi in caso
di alto traffico del sito)
Creare e specificare vari filtri sull'input degli utenti e diversi modelli di contenuto
Generare indirizzi semplici da ricordare, permettendo una migliore catalogazione ai motori
di ricerca.
Inoltre, il sito di Drupal contiene centinaia di moduli gratuiti sviluppati dalla comunità.
Alcune delle funzionalità fornite o migliorate dai moduli sviluppati dagli utenti:
• Sistemi e-commerce
• Flusso di lavoro redazionale
• Gallerie fotografiche
• Gruppi autogestiti
• Sitemap di Google
• Gestione di mailing list (liste di posta)
• Integrazione con CVS (Concurrent Versions System, implementa un sistema di controllo
versione: mantiene al corrente di tutto il lavoro e di tutti i cambiamenti in un insieme di file,
tipicamente è l'implementazione di un software in via di sviluppo, in progetto, e permette a
molti sviluppatori -potenzialmente distanti- di collaborare)
• Gestire immagini e video
• Gestire servizi di terze parti
Critiche
L'installazione di Drupal (e dei suoi moduli) richiede l'accesso a un database ed alcuni
permessi avanzati, ad esempio la possibilità di usare comandi SQL (come select, insert, update,
delete, create, drop, index, alter e lock tables). Alcuni fornitori di hosting web non offrono queste
funzioni. Chi voglia usare Drupal deve accertarsi che il suo server offra queste funzioni prima di
installare.
15
Come per altri sistemi di gestione dei contenuti, è possibile configurare il database di
partenza da riga di comando oppure con phpMyAdmin. A partire dalla versione 5.0, è possibile
installare Drupal e configurare il database quasi interamente tramite un'interfaccia web.
Alcuni considerano più difficile imparare a usare Drupal e installarlo, rispetto ad altri CMS o a
semplici piattaforme per blog come WordPress. Drupal 6.0, pubblicato il 13 febbraio 2008 ha una
metodologia d’installazione più semplice rispetto alle versioni precedenti.
Alcuni programmatori criticano Drupal perché non lo considerano sviluppato con la
Programmazione Orientata agli Oggetti (Object Oriented Programming), ma programmare
Drupal da una prospettiva orientata agli oggetti spiega come i principi della OOP e della
programmazione orientata agli aspetti (AOP) siano applicati anche a Drupal.
Algoritmo
Intuitivamente, un algoritmo si può definire come un procedimento che consente di ottenere
un risultato atteso eseguendo, in un determinato ordine, un insieme di passi semplici corrispondenti
ad azioni scelte solitamente da un insieme finito. Quindi con il termine algoritmo si intende, in
genere, un metodo per ottenere un certo risultato (risolvere un certo tipo di problema) attraverso un
numero finito di passi. Nel senso più ampio della parola, "algoritmo" è anche una ricetta di cucina,
o la sezione del libretto delle istruzioni di una lavatrice che spiega come programmare un lavaggio.
Di norma, comunque, la parola viene usata in contesti matematici (fin dalle origini) e soprattutto
informatici (più recentemente). Un esempio più appropriato di algoritmo potrebbe essere, quindi, il
procedimento per il calcolo del massimo comune divisore o del minimo comune multiplo.
Da questa definizione si evincono le quattro proprietà fondamentali dell'algoritmo:
o la sequenza di istruzioni deve essere finita (finitezza);
o la sequenza di istruzioni deve portare ad un risultato (effettività);
o le istruzioni devono essere eseguibili materialmente (realizzabilità);
o le istruzioni devono essere espresse in modo non ambiguo (non ambiguità).
Affermando che i passi costituenti di un algoritmo debbano essere "semplici", si intende
soprattutto che essi siano specificati in modo non ambiguo, ovvero immediatamente evidenti a chi
sarà chiamato ad applicare l'algoritmo, cioè il suo esecutore.
Il concetto di algoritmo
Il calcolatore elettronico per risolvere un problema utilizza un algoritmo, cioè un insieme di azioni
(o istruzioni) che, eseguite secondo un ordine prestabilito, permettono di trovare il risultato cercato
sulla base dei dati in ingresso.
Un computer è un rapidissimo esecutore di sequenze di istruzioni (gli algoritmi).
Algoritmo: procedura di trasformazione di un insieme di dati iniziali in un insieme di risultati finali
mediante una sequenza di istruzioni.
Linguaggio di programmazione: linguaggio (insieme di simboli e regole) per rappresentare le
istruzioni di un algoritmo e la loro concatenazione.
16
Programma: algoritmo scritto in un linguaggio di programmazione al fine di comunicare al
calcolatore elettronico le azioni da eseguire, cioè esso è memorizzato su disco e attende di essere
caricato in RAM per poi essere eseguito (entità passiva, statica).
Processo: programma in esecuzione sul computer, cioè è caricato in RAM e la CPU esegue una ad
una l’insieme di istruzioni del programma (entità attiva, dinamica).
In informatica, con il termine algoritmo si intende un metodo per la soluzione di un
problema adatto a essere implementato sotto forma di programma. In fase di progettazione di un
software l’algoritmo consiste nella soluzione di un problema, che si è analizzato, seguendo una
serie di operazioni sequenziali rappresentate sotto forma di diagramma a blocchi o di
pseudocodifica.
Esistono cinque tipi di blocchi elementari:
La combinazione di questi blocchi elementari serve per rappresentare graficamente un
algoritmo, e questo può essere fatto solo se:
- viene usato un numero finito di blocchi;
- lo schema inizia con un blocco iniziale e termina con un blocco finale;
- ogni blocco soddisfa delle condizioni di validità.
Tale sequenza di operazioni deve essere applicabile ad ogni linguaggio di programmazione.
Un programma può essere visto come un insieme di algoritmi diversi che interagiscono per
risolvere problemi complessi.
17
Processo
Concetti generali di un processo
Ecco alcuni concetti e definizioni di base che caratterizzano lo studio della teoria e degli
algoritmi della schedulazione real-time.
Processo: Per processo o task si intende una sequenza di istruzioni che, in assenza di altre attività,
viene eseguita dal processore in modo continuativo fino al suo completamento.
La situazione di riferimento per un ambiente real-time è quella in cui sono presenti
numerosi processi, ciascuno con particolari esigenze di schedulazione. In questo caso è necessario
individuare una strategia di assegnazione della CPU che sequenzializzi l’uso della risorsa fisica
secondo un criterio stabilito a priori.
Un processo da quando viene caricato in RAM e durante tutto il tempo dell’esecuzione può
trovarsi in uno dei 5 stati seguenti:
1) new (nuovo o inizio): il processo è stato appena creato, più precisamente è stato creato
sulla RAM il suo descrittore di processo (struttura dati contenente le informazioni sul
processo);
2) ready (pronto): il processo è pronto per essere eseguito dalla CPU, cioè tutte le sue
istruzioni sono state caricate in RAM ed ha tutto ciò che gli serve per l’esecuzione
tranne la disponibilità della CPU;
3) running (in esecuzione): il processo è sulla CPU, ovvero la CPU sta eseguendo le
istruzioni di quel processo;
4) waiting (bloccato o in attesa): il processo è in attesa di un evento, cioè non può essere
pronto perché sta aspettando che si verifichi una certa condizione (di solito legata ai
dispositivi I/O, ma può dipendere anche da altri motivi);
5) terminated (in terminazione): il processo sta per terminare, cioè il processo rimane in
questo stato da quando viene dato il comando di terminazione fino a quando il processo
non scompare dalla memoria del Sistema Operativo.
La seguente illustrazione mostra il ciclo di vita di un processo:
18
Definiamo attivo un processo potenzialmente in grado di eseguire su un processore (CPU).
Un processo attivo in attesa di un processore (occupato nell’esecuzione di un altro processo) viene
definito pronto e accodato in una coda di attesa detta ready queue (coda pronti).
Un processo che correntemente utilizza il processore viene indicato come processo in esecuzione.
L’insieme delle regole che determinano l’esecuzione di un processo pronto presente nella
ready queue costituisce l’algoritmo di schedulazione. Solitamente le regole di schedulazione sono
applicate all’ingresso della coda di attesa in modo da ottenere una ready queue già ordinata secondo
la precedenza di esecuzione, in altre parole, l’ordinamento della coda viene realizzato in modo che
il processo da eseguire sia nella prima posizione di uscita.
In alcuni sistemi è prevista la possibilità di interrompere in qualsiasi istante il processo in
esecuzione per riportarlo nella coda pronti, e dare la possibilità ad un processo a priorità superiore
di disporre del processore. L’operazione di sospensione dell’esecuzione e reinserimento nella ready
queue di un processo è nota con il termine preemption (prelazione o “revoca della CPU”).
Si osservi che l’assegnazione effettiva del processore al processo pronto che viene schedulato è
indicata con il termine dispatching, e viene effettuata dal sistema operativo alla terminazione di un
task o dopo un’operazione di preemption.
Quindi in definitiva possiamo dire che il cambio di processo, che utilizza la CPU, avviene quando:
o il processo corrente viene prelazionato da un altro di maggiore priorità,
ritornando nella ready queue, passa cioè dallo stato running a quello ready;
o il processo corrente si blocca su qualche condizione, passa dallo stato running
allo stato waiting (deve verificarsi prima una certa condizione affinché il
processo ritorni allo stato ready);
o il processo corrente termina il suo “round”, cioè termina il tempo di utilizzo
(continuo) della CPU che gli è stato riservato, passa dallo stato running allo stato
ready;
o il processo corrente termina tutte le istruzioni di cui è composto, cioè passa dallo
stato running allo stato terminated.
La figura seguente illustra sinteticamente l’architettura di uno schedulatore:
Schedulazione fattibile: Una schedulazione è detta fattibile se esiste un’assegnazione di task al
processore tale che tutti i task siano completati rispettando un insieme di vincoli prefissati.
Insieme di task schedulabile: Un insieme di task (task-set) è detto schedulabile se per esso esiste
una schedulazione fattibile.
19
Vincoli sui processi
La definizione di schedulazione fattibile richiede che l’esecuzione dei task avvenga
rispettando i vincoli a cui questi sono sottoposti. In generale esistono tre categorie di vincoli sui
processi: vincoli temporali, vincoli di precedenza, e vincoli su risorse condivise.
1) Vincoli temporali
Nei sistemi real time i task sono soggetti a vincoli temporali che devono essere rispettati
perché l’elaborazione sia valida. Un tipico esempio di vincolo temporale è la deadline di un
processo, che rappresenta l’istante temporale entro cui il processo deve terminare la propria
esecuzione e produrre un risultato. Il concetto di deadline è centrale nella teoria dello scheduling
real time, tanto da determinare una classificazione di base dei processi real time relativamente alle
conseguenze di una mancata deadline.
In generale, i task di un sistema real-time possono essere di 2 tipi:
Processo hard real time: Un processo real-time è di tipo hard se il mancato rispetto della
propria deadline (cioè il task non finisce di computare totalmente entro la sua deadline)
comporta un danno irreparabile sul sistema, impedendone il corretto funzionamento.
- Processo soft real time: Un processo real-time è di tipo soft se il mancato rispetto della
propria deadline comporta un danno non irreparabile al sistema, quindi non compromette il
corretto funzionamento del sistema. Il superamento della deadline produce un degrado delle
prestazioni proporzionale al tempo di superamento della deadline. Si osservi che un
processo soft real-time non è vincolato da una deadline “rigida” e può essere completato
anche oltre il termine da questa indicato.
Sostanzialmente questa distinzione si traduce nella diversa quantificazione dei costi di una possibile
inesattezza temporale del sistema. Un esempio di task soft real-time può essere un riproduttore
DVD, in cui il mancato rispetto dei vincoli si traduce in un degrado della qualità del filmato, ma
non pregiudica il proseguimento della riproduzione; mentre un task hard real-time può essere il
controllore della temperatura del nocciolo di una centrale nucleare, dove il mancato rispetto dei
vincoli temporali può provocare un evidente disastro.
-
I parametri principali che caratterizzano il comportamento temporale di un processo sono i
seguenti:
• tempo di arrivo (a): istante di tempo in cui il task arriva nella ready queue e quindi diventa
pronto per l’esecuzione;
• tempo di computazione (C): tempo necessario al processore per eseguire completamente
un task senza interruzioni, oppure tempo che il task deve usufruire della CPU affinché esso
termini tutte le sue istruzioni;
• deadline (d): istante di tempo entro cui il task deve essere completato;
• istante di inizio (s): istante di tempo in cui il task va in esecuzione per la prima volta;
• istante di fine (f): istante di tempo in cui il task termina la sua esecuzione;
• latenza (L): rappresenta il ritardo di completamento del task rispetto alla deadline ed è così
definita: L = f − d
(si osservi che un task che completa la propria esecuzione prima della deadline è
caratterizzato da latenza negativa).
Il significato e le relazioni tra i parametri sopra definiti sono chiariti nella seguente figura, la quale
illustra i parametri temporali caratteristici di un processo:
20
Un’altra possibile caratterizzazione temporale dei processi è quella che riguarda la
regolarità delle attivazioni dei processi stessi. Da questo punto di vista si può fare la distinzione
fra processi periodici e processi aperiodici.
• Processo periodico: Un processo è detto periodico se è caratterizzato da una sequenza
infinita di attività identiche, dette istanze, che si presentano con cadenza regolare. Il
parametro T rappresenta il periodo del processo (cioè il lasso di tempo che intercorre tra due
esecuzioni di un task periodico), ma un processo periodico è caratterizzato anche da un
tempo di computazione C e da una deadline D (relativa al periodo); si suppone che i
parametri T, C, e D siano costanti per ogni istanza. Quindi un task periodico si ripresenta
nella ready queue ad intervalli di tempo regolari e presenta sempre lo stesso tempo di
computazione, la stessa deadline e lo stesso periodo.
La seguente figura mostra un esempio di processo periodico:
•
Processo aperiodico: Un processo è detto aperiodico se è costituito da una sequenza di
attività identiche, ciascuna delle quali caratterizzata da un tempo di arrivo, un tempo di
calcolo, e una deadline ma che si presentano ad intervalli irregolari, quindi non prevedibili a
priori.
Nei sistemi operativi nei quali non esiste un meccanismo di gestione esplicita dei vincoli
temporali è possibile comunque gestire tali vincoli trasformandoli in priorità. Intuitivamente, un
task con caratteristiche temporali molto stringenti si vedrà assegnata una priorità maggiore di quella
assegnata a un task con vincoli temporali meno critici. Con questo approccio è possibile utilizzare
uno schedulatore su base prioritaria per gestire i vincoli temporali dei processi.
La seguente illustrazione mostra uno schema concettuale di uno scheduler che gestisce vincoli
temporali:
21
2) Vincoli di precedenza
Esistono applicazioni nelle quali i processi non possono essere eseguiti in ordine arbitrario.
In questi casi i processi presenti nel sistema sono legati tra loro da relazioni di precedenza che sono
rappresentabili attraverso un grafo orientato e aciclico, detto grafo di precedenza.
- Si dice che il task J1 precede il task J2 (J1<J2) se esiste un cammino sul grafo di precedenza che
parte dal nodo J1 e arriva al nodo J2.
- Si dice che J1 è immediato predecessore di J2 (J1→J2) se esiste nel grafo di precedenza un arco
diretto uscente dal nodo J1 ed entrante nel nodo J2.
Nella Figura 1.3.4 è illustrato un grafo di precedenza. Si osservi che J1 è l’unico processo che può
essere eseguito immediatamente e i processi J2, J3 e J4 sono vincolati ad essere eseguiti solo dopo la
sua terminazione; J5 può essere eseguito solo dopo il completamento dei task J2 e J3.
Di seguito viene mostrato un esempio di grafo di precedenza tra processi:
22
3) Vincoli su risorse
Per risorsa intendiamo una qualunque entità software che può essere utilizzata da uno o più
processi durante l’esecuzione. Tipicamente una risorsa può essere una struttura dati, una zona di
memoria, o una porzione di codice. Una risorsa che può essere utilizzata da più processi è detta
condivisa (es. RAM, periferiche di I/O), mentre se essa è riservata solo ad un particolare processo
viene detta dedicata.
Le risorse condivise che non ammettono accessi contemporanei da parte di più di un
processo, allo scopo ad esempio di mantenere la coerenza delle strutture dati interne, sono dette
risorse mutuamente esclusive (es. CPU); gli accessi a queste risorse devono essere serializzati per
garantire il corretto funzionamento del sistema (gestiscono un solo processo alla volta). Per
garantire un accesso mutuamente esclusivo alle risorse, il sistema operativo necessita di un
meccanismo di sincronizzazione degli accessi.
Quando si parla di vincoli su risorse, si intende riferirsi a vincoli di mutua esclusione su
risorse condivise. Il rispetto di un vincolo su risorsa è ottenuto sincronizzando i processi che
utilizzano tale risorsa facendo in modo che l’accesso ad essa sia mutuamente esclusivo.
I vincoli su risorse hanno importanti conseguenze sulla schedulazione dei processi perché la CPU,
essendo una risorsa mutuamente esclusiva, può gestire un solo task alla volta e quindi se la CPU è
già occupata da un task gli altri task, eventualmente presenti nella ready queue, per essere eseguiti
devono aspettare che la CPU si liberi (a meno di eventuali priorità se l’algoritmo di scheduling è
con prelazione).
Processo bloccato: Un processo è detto bloccato (waiting) se è in attesa di una risorsa condivisa
occupata da un altro processo. I processi bloccati sono accodati in una coda associata al
meccanismo di protezione della risorsa condivisa. Il sistema operativo prevede uno stato apposito
per la sospensione dei processi bloccati su risorse. Un processo in esecuzione entra nello stato
waiting se prova ad accedere ad una risorsa occupata, e resta in questo stato fino a quando la risorsa
non viene liberata dal processo che la stava utilizzando precedentemente. Un processo bloccato esce
dallo stato waiting quando la risorsa occupata viene liberata e quindi può e va ad utilizzarla esso
stesso.
Scheduler
Lo scheduler (da to schedule letteralmente "mettere in lista", ovvero "pianificare") è un
componente fondamentale dei sistemi operativi multitasking (più processi in RAM
contemporanemente) in grado di far eseguire, al processore di un computer, attraverso l'omonima
operazione di scheduling, più processi (task) concorrentemente attraverso varie politiche di
scheduling. Esso rappresenta dunque il gestore del multitasking attraverso criteri di assegnazione
delle risorse di elaborazione ai vari processi e implementati attraverso vari tipi di algoritmi di
scheduling.
Generalmente, infatti, computer con un processore sono in grado di eseguire un processo per
volta; quindi per poter far convivere più task è necessario usare uno scheduler. Nel dettaglio lo
scheduler si occupa di fare avanzare un processo interrompendone temporaneamente un altro,
realizzando così quello che è chiamato cambio di contesto (context switch) all'interno del ciclo del
23
processore. Quindi lo scheduler decide i tempi e i modi con cui i processi possono usare la CPU in
base a vari algoritmi di scheduling che permettono di scegliere nella maniera più efficiente possibile
a quale task assegnare la CPU.
Scheduling della CPU
Lo scheduling è un'operazione molto importante per il corretto ed efficiente funzionamento
del calcolatore. Infatti, non solo consente di eseguire più processi contemporaneamente, ma
consente anche di migliorare l'utilizzo del processore.
Ad esempio, quando è necessario eseguire un'operazione di I/O, il processore non può
proseguire l'elaborazione del processo attualmente in esecuzione fino al completamento della stessa.
Dato che le operazioni di I/O sono molto più lente del processore sarebbe un inutile spreco di
risorse se il processore rimanesse bloccato fino al completamento delle stesse. Per evitare questo, le
operazioni di I/O vengono gestite unicamente dal Sistema Operativo che, nel frattempo, assegna
l'uso del processore ad un altro processo. In questo modo si massimizza l'uso delle risorse del
sistema.
È importante la distinzione tra scheduling con diritto di prelazione (scheduling preemptive)
e scheduling senza diritto di prelazione (scheduling non-preemptive o scheduling cooperative).
Nel primo caso lo scheduler può sottrarre il possesso del processore al processo anche quando
questo potrebbe proseguire nella propria esecuzione. Nel secondo caso, invece, lo scheduler deve
attendere che il processo termini o che cambi il suo stato da quello di esecuzione a quello di attesa o
di pronto, a seguito, ad esempio, di una richiesta di I/O oppure a causa di un segnale di interruzione
(interrupt).
Esistono vari algoritmi di scheduling che tengono conto di varie esigenze e che possono
essere più indicati in alcuni contesti piuttosto che in altri. La scelta dell'algoritmo da usare dipende
da cinque principali criteri:
• Utilizzo del processore: percentuale di tempo in cui la CPU esegue le istruzioni dei processi
rispetto al tempo in cui essa svolge le operazioni del sistema operativo o rimane inutilizzata;
la CPU deve essere attiva il più possibile, ovvero devono essere ridotti al minimo i possibili
tempi morti, quindi questo parametro è da massimizzare;
• Produttività: il numero di processi completati in una determinata quantità di tempo, quindi
questo parametro è da massimizzare;
• Tempo di completamento: il tempo che intercorre da quando il processo viene creato (new)
a quando viene completata la sua esecuzione (terminated), quindi è da minimizzare;
• Tempo d'attesa: il tempo in cui un processo pronto per l'esecuzione (ready) rimane in
attesa, nella ready queue, della CPU, quindi è da minimizzare;
• Tempo di risposta: il tempo che trascorre tra la sottomissione del processo e l'ottenimento
della prima risposta, quindi è da minimizzare.
Gli algoritmi di scheduling incidono fortemente sul tempo di attesa e solo parzialmente sugli altri
parametri. Quindi essi vengono valutati in base al tempo medio di attesa.
24
Obiettivi dello scheduling
Un algoritmo di scheduling si pone i seguenti obiettivi:
• Equità: processi dello stesso tipo devono avere trattamenti simili;
• Bilanciamento: tutte le parti del sistema devono essere sfruttate.
Inoltre bisogna effettuare un distinguo tra i sistemi batch e i sistemi interattivi. Nei primi
la produttività, ossia la massimizzazione del numero di job completati deve essere massimizzata e il
tempo di completamento deve essere minimizzato. Nei secondi il tempo di risposta deve essere il
minimo possibile per dare l'idea di continuità all'utente e la proporzionalità deve essere rispettata,
ossia il tempo di risposta deve essere proporzionale alla complessità dell'azione.
Problema generale dello scheduling
Dato un task-set, ovvero un insieme di n task J = {J1, J2, …, Jn}, di cui siano noti i vincoli
temporali, il grafo dei vincoli di precedenza e le modalità di utilizzo delle risorse condivise, il
problema generale dello scheduling consiste nella determinazione di una schedulazione fattibile
dell’insieme J.
In altre parole, la risoluzione del problema generale dello scheduling deve individuare una
sequenza di assegnazione dei task al processore tale che:
o tutti i task terminino la propria elaborazione entro la deadline;
o i vincoli di precedenza espressi dal grafo di precedenza siano rispettati;
o l’accesso alle risorse mutuamente esclusive sia correttamente sequenzializzato.
Il problema dello scheduling nella sua forma più generale sopra enunciata è
computazionalmente intrattabile in tempo polinomiale rispetto al numero di processi; cioè non
esiste alcun algoritmo con complessità polinomiale di grado n capace di individuare una
schedulazione fattibile.
Al fine di individuare algoritmi con complessità polinomiale si introducono delle ipotesi
semplificative rispetto al problema generale dello scheduling. Se si considerano, ad esempio, casi
nei quali i vincoli di precedenza sono assenti, oppure è ammissibile avere una preemptive, oppure
non sono presenti vincoli sulle risorse, il problema della schedulazione viene notevolmente
semplificato e può essere risolto con algoritmi noti.
Classificazione degli algoritmi di scheduling
Di seguito viene riportata una sintetica classificazione dei possibili algoritmi di
scheduling. Si noti che le tipologie di algoritmi considerate sono tra loro ortogonali.
•
•
Uniprocessore: se il calcolatore presenta un’unica CPU;
Multiprocessore: se il calcolatore presenta due o più CPU;
•
Preemptive: lo scheduler ha la possibilità di sospendere l’esecuzione di un task che utilizza
la CPU e di assegnare quest’ultima ad un altro task con priorità maggiore;
Non preemptive: lo scheduler non può togliere la CPU ad un task per assegnarla ad un altro
task (anche se quest’ultimo ha priorità maggiore), la CPU può essere assegnata solo quando
il task che la stava utilizzando ha terminato (o tutte le sue istruzioni o il “round” di tempo
previsto).
•
25
•
•
•
•
•
•
Statici: le decisioni dello scheduler sono basate su parametri “fissi” assegnati ai task prima
della loro attivazione;
Dinamici: le decisioni dello scheduler sono basate su parametri assegnati ai task che
“possono variare” durante l’evoluzione del sistema;
Off–line: lo scheduling è effettuato prima dell’attivazione dei task (all’attivazione del taskset);
On–line: lo scheduling è effettuato ad ogni attivazione o termine di un task;
Best–effort: questi algoritmi massimizzano o minimizzano (a seconda dei casi) gli indici di
prestazioni ma non garantiscono la fattibilità, usati per il soft real-time;
Guaranteed: questi algoritmi garantiscono la fattibilità ponendosi nell’ottica dello scenario
worst case (caso peggiore, cioè tutti i task hanno come tempo di arrivo 0 -arrivano tutti
contemporaneamente-) ma non si curano degli indici di prestazione, usati per l’hard realtime;
•
Clairvoyant: lo scheduling prevede l’arrivo di un nuovo task;
•
Optimal: lo scheduling minimizza una qualche funzione di costo;
La prima classificazione riguarda semplicemente il tipo di sistema di elaborazione
considerato e in particolare la presenza di uno o più processori.
Gli algoritmi di schedulazione preemptive prevedono la possibilità di sospendere in
qualsiasi istante l’esecuzione di un processo a favore di un altro; nel caso in cui non è prevista la
preemption ogni decisione riguardante la schedulazione viene presa a seguito della autosospensione
di un task o del suo completamento.
Gli algoritmi statici utilizzano una regola di decisione che si basa su parametri fissi,
assegnati ai processi una volta per tutte prima della loro attivazione; nel caso dinamico al contrario,
i parametri utilizzati dalla regola di decisione sono soggetti a variazioni durante la vita del processo.
La classificazione off–line/on–line distingue tra algoritmi che realizzano la schedulazione
prima dell’attivazione dei processi, sulla base di informazioni note a priori (off–line), e algoritmi
che operano durante il run–time ricalcolando l’ordinamento dei task a ogni nuova attivazione.
Infine per algoritmo best–effort si intende un algoritmo che massimizza (o minimizza) un
indice di prestazione definito globalmente sull’insieme dei task. Adottando una strategia di questo
tipo si privilegiano le prestazioni medie del sistema e sono possibili violazioni di vincoli temporali
relativi a qualche task. Gli algoritmi guaranteed assicurano il rispetto dei vincoli temporali di ogni
singolo task utilizzando un test di garanzia eseguito sull’intero insieme dei task ogni volta che un
nuovo processo entra nel sistema.
26
Sistema operativo real-time
Un sistema operativo real-time o in tempo reale (abbreviato in RTOS) è un sistema
operativo specializzato per il supporto di applicazioni software real-time. Questi sistemi vengono
utilizzati tipicamente in ambito industriale (controllo di processo, pilotaggio di robot, trasferimento
dati nelle telecomunicazioni) o comunque dove sia necessario ottenere una risposta dal sistema
entro un tempo prefissato.
Un sistema operativo real-time non deve essere necessariamente veloce: non è importante
l'intervallo di tempo in cui il sistema operativo/applicativo deve reagire; l'importante è che risponda
entro un tempo massimo pre-determinato. In altre parole il sistema deve essere prevedibile.
In pratica un sistema real-time deve garantire che una elaborazione (o task) termini entro un dato
vincolo temporale o scadenza (detta in gergo deadline). Per garantire questo è richiesto che la
schedulazione delle operazioni sia fattibile. Il concetto di fattibilità di schedulazione è alla base
della teoria dei sistemi real-time ed è quello che ci permette di dire se un insieme di task sia
eseguibile o meno in funzione dei vincoli temporali dati (periodo del task -se il task è periodico-,
deadline, tempo di computazione del task sulla CPU, tempo di arrivo del task nella ready queue).
Sistemi Hard real-time e soft real-time
I sistemi real-time si possono dividere quindi in due categorie:
• I sistemi "hard" sono quelli che possono garantire la fattibilità di schedulazione di un
insieme di task hard e soft real-time.
• I sistemi "soft" sono quelli che possono garantire la fattibilità di schedulazione di un
insieme di soli task soft real-time (meno rigidi dei sistemi hard real-time).
Caratteristiche di un sistema real-time
Un sistema real-time dovrebbe possedere le seguenti caratteristiche:
• Schedulazione ottima: tutti i task sono noti a priori così come i vincoli temporali; dovrebbe
essere possibile, dunque, avere uno schedulatore che implementi una schedulazione che
minimizzi al massimo il costo delle operazioni,cioè tutti i task, appartenenti al task-set,
dovrebbero terminare regolarmente senza andare i overflow e il tempo di occupazione della
CPU necessario affinché tutto il task-set termini dovrebbe essere il minore possibile.
• Condivisione delle risorse: i task sono entità separate ma che concorrono ad uno stesso
scopo, pertanto non è necessario avere spazi di indirizzamento separati.
• Garanzia di esecuzione: tutti i task di tipo hard real-time devono terminare entro le proprie
deadline quindi, nel caso in cui arrivi un nuovo task o un task non possa completare entro la
deadline, una notifica anticipata del sistema può essere utilizzata per impedire l'esecuzione
del nuovo task o di recuperare l'esecuzione del task che sta per sfondare.
• Prevedibilità delle chiamate di sistema: il sistema deve essere in grado di valutare i tempi
di calcolo di ogni task per determinare la schedulazione fattibile; quindi ogni chiamata di
sistema deve avere un tempo di esecuzione massimo ben definito in modo da non introdurre
ritardi indefiniti.
27
I fattori che minano la prevedibilità
I prodotti delle famiglie Windows e Unix non soddisfano le caratteristiche tipiche di un
sistema real-time: ad esempio, pur gestendo l'esecuzione di più processi con pre-rilascio, non è
possibile prevedere in alcun modo quale sarà il tempo di esecuzione di un singolo processo. Inoltre,
l'utilizzo di hard disk per la conservazione dei dati, dispositivi USB o altri dispositivi che
introducono forti latenze di esecuzione da parte della CPU, rende impossibile stabilire con certezza
quanto tempo sarà necessario per reperire l'informazione utile alla corretta esecuzione del codice.
Ci sono diversi fattori che causano la non prevedibilità nella risposta del sistema operativo.
Tra di essi, i principali sono i seguenti:
•
Il DMA: può rubare il bus (il bus è unico) alla CPU ritardando l'esecuzione di un task
critico. In un sistema real-time si preferisce quindi disattivarlo o usarlo in modalità timeslice
(fetta di tempo) dove si assegna in maniera costante e fissa il bus al DMA anche se non ci
sono operazioni da fare (un intervallo di tempo il bus è utilizzabile dal DMA un altro
intervallo no).
DMA (Direct Memory Access, «accesso diretto alla memoria») è un meccanismo che
permette ad alcuni sottosistemi hardware di un computer (periferiche) di accedere
direttamente alla memoria di sistema per scambiarsi dati, oppure leggere o scrivere, senza
chiamare in causa la CPU per ogni byte trasferito tramite il meccanismo usuale dell'interrupt
(con l’interrupt ogni operazione prima di essere eseguita deve essere comunicata alla CPU,
la quale, interrompendo l’operazione che già stava eseguendo, governa poi l’esecuzione
della nuova operazione se questa ha priorità maggiore di quella già in esecuzione) e la
successiva richiesta di operazione desiderata, ma generando un singolo interrupt per blocco
trasferito (la CPU viene interrotta solo a termine dell’operazione eseguita direttamente dalla
periferica senza l’ausilio della CPU). Il DMA, tramite il rispettivo elemento hardware, ha
quindi il compito di gestire i dati passanti nel bus permettendo a periferiche che lavorano a
velocità diverse di comunicare senza assoggettare la CPU a un enorme carico di interrupt
che ne interromperebbero continuamente il rispettivo ciclo di elaborazione.
•
La cache: può causare non prevedibilità poiché esistono casi in cui essa fallisce e può
causare ritardi nell’accesso alla memoria da parte della CPU. Dovendo considerare quindi il
caso peggiore si preferisce non usarla affatto.
•
Meccanismi di gestione della memoria (tecniche di allocazione dei dati nella RAM):
queste tecniche non devono introdurre ritardi non prevedibili durante l'esecuzione di task
critici, ad esempio la paginazione può causare dei page fault (non viene trovata nella RAM
la pagina di memoria contenente l’istruzione da eseguire in quel preciso momento)
intollerabili per un sistema hard real-time. Tipicamente si usa la segmentazione o la
partizione statica della memoria.
•
Le interruzioni: sono generate da dispositivi periferici quando hanno qualche informazione
da scambiare con la CPU. Queste interruzioni durante l'esecuzione di un task critico
generano ritardi non prevedibili e quindi si preferisce disattivarle.
•
I sistemi di power management: sono meccanismi hardware che possono rallentare la CPU
o far eseguire ad essa del codice utile a dissipare minor energia. È chiaro che in un sistema
real-time è importante non sfondare una deadline piuttosto che consumare poca energia,
quindi questi meccanismi vengono disattivati.
28
Scheduling Real-time dei task periodici
I task periodici vengono indicati con il simbolo τ ed hanno i seguenti parametri:
• Tempo di computazione C: tempo necessario affinché il task termini tutte le sue istruzioni;
• Deadline relativa D: vincolo temporale entro il quale il task dovrebbe finire la
computazione; questo è un valore fisso del task che si ripete sempre ad ogni periodo;
• Deadline assoluta d: tempo rimanente al task affinché esso finisca la sua computazione;
questo è un valore che varia da periodo a periodo in base al passare del tempo (più passa il
tempo, più mi avvicino alla deadline relativa D e più la deadline assoluta d diminuisce);
• Periodo T: tempo che intercorre tra due esecuzioni di un task periodico, una volta terminato
un periodo il task si ripresenta con gli stessi valori dei parametri del periodo precedente.
• Tempo di arrivo a: istante di tempo in cui il task arriva nella ready queue e quindi diventa
pronto per l’esecuzione;
• Istante iniziale s: istante di tempo in cui il task va in esecuzione per la prima volta;
• Istante finale f: istante di tempo in cui il task termina la sua esecuzione;
• Latenza L: rappresenta il ritardo di completamento del task rispetto alla deadline ed è così
definita: L = f − d
L’immagine seguente mostra i parametri principali di un task periodico:
29
Tra i vari algoritmi di scheduling applicati ai task periodici τ vi sono:
1) EDF (Earliest Deadline First)
Questo algoritmo ordina i task in base alla deadline d, nel senso che ad ogni istante la CPU è
assegnata al task con la deadline “assoluta” d più vicina. In pratica, privilegia quei task aventi la
deadline d più breve in quell’istante di tempo. In sintesi la priorità è inversamente proporzionale
alla deadline assoluta d.
Attenzione: per deadline assoluta d non si intende il valore “statico” che ogni preciso task ha
in ciascun periodo (cioè il valore proprio della deadline D di quel task che ha in ogni periodo T), ma
il valore “dinamico” che assume la deadline d del task in quell’istante di tempo (più aumenta il
tempo più il valore della deadline d diminuisce, questo riferito ad un solo periodo T); cioè all’inizio
di un periodo T il task ha una precisa deadline D “relativa” (questo valore è fisso per il task i-esimo
ed è uguale anche nei periodi successivi di questo) ma durante il periodo questa deadline d
“diminuisce” al passare del tempo (all’interno del periodo il valore della deadline d diminuisce).
Dato quindi un task-set, il task a cui verrà assegnata per prima la CPU sarà quello avente la
deadline assoluta d minore rispetto agli altri, e così via per i task successivi; in sintesi: il task con
la deadline assoluta d minore ha maggiore priorità.
Questo algoritmo è inoltre:
Con prelazione: se so ha un task che in un preciso istante di tempo ha una deadline assoluta
d minore rispetto al task che sta usando la CPU; a quest’ultimo gli viene tolta la CPU per
assegnarla al task con maggiore priorità.
Dinamico: le decisioni dello scheduler sono basate sul valore dinamico che le varie deadline
assumono in ogni istante di tempo, quindi la priorità di ogni task varia col variare del tempo
(la deadline assoluta d non è un parametro fisso).
2)RM (Rate Monotonic)
Questo algoritmo ordina i task in base al periodo, nel senso che ad ogni istante la CPU è
assegnata al task con il periodo T più breve. Ad ogni task è associata una priorità “fissa”
proporzionale alla sua frequenza (rate), ovvero più è elevata la frequenza del task e più esso avrà
una priorità elevata. Siccome la frequenza è l’inverso del periodo (f=T^-1) quanto detto si può
riscrivere in un altro modo: più è piccolo il periodo del task è più esso avrà una priorità elevata. In
pratica privilegia quei task aventi il periodo più breve in quel preciso istante di tempo. In sintesi la
priorità è inversamente proporzionale al periodo T.
Attenzione: per periodo T si intende il valore “statico” T di ogni preciso task (essendo il task
periodico ha un preciso periodo T).
Dato quindi un task-set, il task a cui verrà assegnata per prima la CPU sarà quello avente il
periodo T minore rispetto agli altri, e così via per i task successivi; in sintesi: il task con il periodo
T minore ha maggiore priorità.
30
Questo algoritmo è inoltre:
Con prelazione: se si ha un task che in un preciso istante di tempo ha il periodo T minore
rispetto al task che sta usando la CPU; a quest’ultimo gli viene tolta la CPU per assegnarla
al task con maggiore priorità.
Statico: le decisioni dello scheduler sono basate sul valore fisso dei vari periodi T di ogni
task che hanno in ogni istante di tempo, quindi la priorità di ogni task è definita a priori e
non varia col variare del tempo per tutta la durata dell’applicazione (il periodo T è un
parametro fisso).
31
SPECIFICHE DI PROGETTO
32
Il mio progetto ha come obiettivo la creazione di un modulo per Drupal che,
implementando degli algoritmi di scheduling real-time, mostri agli utenti della piattaforma, dopo
che essi hanno inserito i vari parametri richiesti per i task, il risultato dell’elaborazione di questi
algoritmi sotto una forma grafica rappresentata dal diagramma di Gantt. Quindi il mio ruolo in
questo progetto è quello del web master perché vado io stesso a creare un modulo utilizzando i
linguaggi di programmazione e successivamente mettendo lo stesso modulo a disposizione degli
utenti che accedono alla piattaforma. Il modulo che vado a creare può essere tranquillamente
aggiunto come ogni altro modulo di Drupal e quindi ogni utente, una volta che lo ha scaricato ed
installato correttamente, può farne uso. Inoltre, esso ha un’interfaccia grafica semplice quindi è
rivolto ad ogni tipologia di utenza.
WERTHER è l'acronimo di WEb Real Time HElper Resolver, tradotto in italiano web realtime aiutante risolutore.
Scopo del modulo è quello di fornire un supporto per la didattica degli algoritmi di scheduling in
tempo reale. Tale supporto si manifesterà in modo chiaro ed evidente nella produzione a schermo di
un diagramma di Gantt che illustri la schedulazione di un task-set definito in maniera interattiva
dall'utente.
L'interfaccia principale del modulo sarà costituita da una pagina dinamica. Inizialmente in
tale pagina sarà visualizzata, in alto a sinistra, un riquadro con riferimento al primo task in cui sarà
possibile inserire i parametri fondamentali dei task da schedulare.
Tali parametri sono WCET o tempo di computazione (C), deadline relativa (D) e periodo (T). I
parametri di ciascun task saranno inseriti dall’utente in dei riquadri, con i nomi di essi riferiti al
relativo task; ogni riquadro dovrà contenere i parametri relativi ad un solo task, quindi in pratica
saranno visualizzati tanti riquadri quanti sono il numero dei task che l’utente sceglierà di elaborare.
Inizialmente, il form sarà costituito da un solo riquadro, riferito al primo task; l'utente potrà
aumentare il numero di task da schedulare (e dunque i riquadri) cliccando su un apposito pulsante
situato immediatamente a destra del riquadro. Si dovrà prevedere anche un pulsante per ridurre il
numero di task da schedulare; ovvero i riquadri, da situare immediatamente a destra del pulsante
precedente. Il form dovrà contenere da un minimo di uno ad un massimo di dieci riquadri.
Per questi due pulsanti ho apportato delle modifiche grafiche, spostandoli in basso sotto tutti
i riquadri dei task; in questo modo, ho dedicato tutto lo spazio superiore ai riquadri contenenti i task
e i loro parametri, ottenendo quindi una migliore visualizzazione grafica di ciò che l’utente
inserisce. Inoltre, avendo stabilito a priori che il numero minimo di task da schedulare deve essere
uno e il numero massimo di task deve essere dieci, ho fatto in modo che:
• se il form presenta un solo riquadro (quindi non si può eliminare) allora verrà visualizzato
solo il pulsante che permette di aggiungere un altro riquadro, cioè un altro task;
• se il form presenta dieci riquadri (quindi non se ne possono aggiungere altri) allora verrà
visualizzato solo il pulsante che permette di eliminare l’ultimo riquadro, cioè l’ultimo task.
Per migliorare la visualizzazione del form all’utente, ho fatto in modo che ogni riquadro,
chiamato con il nome del relativo task, può essere ridotto al solo nome del task i-esimo
semplicemente cliccando su di esso, e ri-cliccando su di esso il riquadro viene nuovamente esteso.
In questo modo l’utente può avere una visione parziale e specifica del form (ad esempio solo sul
task i-esimo che deve inserire i parametri), senza che sia costretto a scorrere in giù la pagina per
visualizzare tutti i riquadri. Quindi, viene data all’utente anche la possibilità di mostrare e
nascondere i contenuti dei riquadri semplicemente cliccando sul nome del riquadro.
Nella sezione in alto a destra della pagina, saranno situati un menù di riepilogo a discesa che
consentirà di scegliere l'algoritmo da applicare sul task-set, ed un pulsante che, cliccato, provocherà
la visualizzazione del diagramma di Gantt nella parte bassa della pagina.
Anche per questi due pulsanti ho apportato delle modifiche grafiche, cioè li ho spostati in
33
basso sotto tutti i riquadri dei task e sotto i tasti di aggiungi ed elimina task; in questo modo ho
dedicato tutto lo spazio superiore ai riquadri contenenti i task e i loro parametri ottenendo quindi
una migliore visualizzazione grafica di ciò che l’utente inserisce.
Tutti questi spostamenti, oltre che per una questione grafica, sono stati fatti per evidenziare
all’utente la sequenzializzazione ed i passi da compiere per utilizzare il modulo; cioè prima inserire
i vari parametri dei task ed eventualmente scegliere il numero, successivamente selezionare
l’algoritmo di scheduling da applicare ed infine cliccare sul tasto “Schedula” che attiva la submit
del modulo e procede con l’elaborazione dei dati inseriti dall’utente.
Il flusso di lavoro dell'utente potrà essere così schematizzato:
1. L'utente accede al modulo cliccando su un link sul menù del portale.
2. L'utente inserisce i parametri del primo task;
3. Eventualmente clicca sul pulsante per aggiungere riquadri al form ed inserisce ulteriori
parametri;
4. Oppure se ha inserito un task in più, clicca sul pulsante per eliminare riquadri al form;
5. L'utente sceglie l'algoritmo di scheduling da utilizzare tra quelli disponibili nella SELECT;
6. L'utente clicca sul bottone “Schedula” per far partire l’elaborazione dei dati inseriti;
7. Il modulo visualizza il risultato a schermo tramite diagramma di Gantt.
Inizialmente si prevede l'implementazione degli algoritmi di scheduling EDF e RM. Il
modulo dovrà prevedere possibili estensioni ad altri algoritmi di scheduling sia altri per la gestione
di task periodici sia algoritmi per la gestione di task aperiodici.
Non si prevedono restrizioni di alcun tipo riguardo l'accesso alle funzionalità del modulo; cioè
qualsiasi utente che ha scaricato il modulo e lo ha installato può usufruirne senza il bisogno di
particolari permessi; oppure ogni utente che accede ad una piattaforma contenente questo modulo
può utilizzarlo anche essendo un utente non registrato alla piattaforma.
34
REALIZZAZIONE PROGETTO
35
Drupal operazioni iniziali
Dato che dovevo realizzare un modulo per Drupal, per prima cosa ho cercato di capire il
modo di installazione di questo software, quindi l’ho installato e successivamente sono andato a
documentarmi sulle sue principali funzionalità.
Siccome dovevo lavorare in “locale” mi serviva un programma che mi emulava un web
server vero e proprio e, grazie alle conoscenze derivate dall’esame di “Linguaggi e programmazione
web”, ho deciso di utilizzare per questo XAMPP. XAMPP è un pacchetto software gratuito
contenente Apache HTTP Server, il database MySQL e tutti gli strumenti necessari per utilizzare i
linguaggi di programmazione PHP e Perl. Il programma è rilasciato sotto la GNU General Public
License ed è un utile web server, gratuito e caratterizzato da un approccio user friendly.
Mediante XAMPP è possibile avere un application server capace di interpretare pagine web
dinamiche PHP. La versione XAMPP Lite contiene i seguenti componenti di base:
• Il Web server: Apache HTTP Server;
• Il database management system (o database server): MySQL e SQLite;
• Il server FTP: ProFTPD;
• Il Mail server: Mercury Mail Transport System (solo per Windows);
• I linguaggi di scripting: Perl, PHP e/o Python.
Poi su indicazione del professore sono andato sul sito www.drupal.org per trovare il setup di Drupal
e tutta la documentazione ad esso inerente (guida sull’installazione, sull’utilizzo, sulle funzionalità,
sui moduli, sui temi, ecc.).
Installare Xampp e Drupal
Di seguito andrò a descrivere passo passo il procedimento da utilizzare per installare e
configurare Xampp e Drupal 6.
Inizialmente bisogna scaricare il setup di Xampp Lite dal sito:
http://www.apachefriends.org/it/xampp-windows.html#4532.
36
Installare XAMPP Lite nella directory C: e rispondere alle domande poste dal prompt dei comandi
che appariranno successivamente in sequenza nel modo seguente:
1. y (per creare un icona sul desktop)
2. y (per creare i giusti percorsi)
3. n (per non rendere XAMPP Portable)
4. x (per uscire)
Dopo aver installato Xampp sarà la volta di Drupal.
Dal sito http://drupal.org/ scaricare l’ultima versione disponibile di Drupal 6.
37
Decomprimere il formato .rar scaricato (nel mio caso drupal-6.16.rar), ottenendo una cartella
decompressa denominata “drupal-6.16”, al cui interno saranno contenuti i file di Drupal.
Copiare l’intera cartella drupal-6.16 nella directory C/xampplite/htdocs e rinominarla con il nome
“drupal”
Avremo quindi in C/xampplite/htdocs la cartella “drupal” con dentro i vari file di Drupal.
Entrare in C/xampplite/htdocs/drupal/sites/default, copiare (non rinominare!) il file
default.settings.php ed incollarlo nella stessa cartella (C/xampplite/htdocs/drupal/sites/default)
Fatto questo apparirà nella cartella corrente un file chiamato “Copia di default.settings.php”,
38
rinominare quest’ultimo con il nuovo nome “settings.php”.
Avremo quindi in C/xampplite/htdocs/drupal/sites/default due file: default.settings.php e
settings.php (settings.php serve per il corretto funzionamento del DB).
Aprire XAMPP Control Panel.
Mettere la spunta solo su "svc" di Apache (lasciare "svc" di MySql deselezionato)
Cliccare su "Start" sia per Apache sia per MySql per avviare il server locale.
Quando entrambi sono diventati running cliccare su "Admin" di MySql.
Aprire con un browser il database, scrivendo nell’URL http://localhost/phpmyadmin/, e sulla
colonna a sinistra di questa pagina cliccare sul tasto Home (icona a forma di casa)
Nel campo di tipo textfield del form di nome "Crea un nuovo database" scrivere "drupal" e
cliccare poi sul tasto "Crea". Così facendo abbiamo creato un database vuoto su cui poi far
appoggiare Drupal.
39
Accedere a Drupal, scrivendo nell’URL http://localhost/drupal, e, una volta entrati nella pagina,
cliccare "Install Drupal in English" per installare Drupal.
40
Nel campo "Database name" scrivere: drupal (cioè il nome del database, creato in precedenza, su
cui si appoggerà Drupal)
Nel campo "Database username" scrivere: root
Lasciare in bianco il campo "Database password"
Infine cliccare su “Save and continue” per procedere con l’installazione.
41
Apparirà una nuova schermata con altri campi dove inserire del testo, questi campi sono:
"Site name": dove bisogna scrivere “localhost”
"Username": dove bisogna scrivere “admin”
"Password": dove bisogna scrivere “admin”
Vi sono altri due campi dove si deve immettere un indirizzo email per il sito (io ho scritto
[email protected]) e per l'admin (io ho scritto [email protected]).
42
Infine spuntare il checkbox (quadratino selezionabile) chiamato “Check for updates automatically”
e cliccare sul bottone “Save and continue” per terminare l’installazione di Drupal.
Non appena l’installazione sarà terminata apparirà una pagina contenente un testo, il quale informa
l’utente che si è verificato un errore sull’email (perché si sono messe delle email inesistenti), ma a
noi non interessa, quindi possiamo tranquillamente ignorarlo.
43
Una volta ignorato quest’errore verremo rediretti immediatamente nella pagina home di Drupal, alla
quale possiamo accedere d’ora in poi immettendo nel campo URL del browser
http://localhost/drupal.
Da questa pagina ora, dopo aver fatto ovviamente il log-in ed essere entrato come “admin” della
piattaforma, possiamo andare a personalizzare la nostra piattaforma attraverso l’aggiunta di nuovi
moduli e temi, andare a creare dei blog, delle pagine, dei forum, ecc.
Quindi gli URL principali per l’utilizzo di Drupal sono:
http://localhost ---> consente l’accesso a XAMPP Lite
http://localhost/phpmyadmin/ ---> consente l’accesso al database MySQL
http://localhost/drupal ---> consente l’accesso a Drupal
44
Operazioni da svolgere subito dopo aver installato Drupal
•
Impostare cron.
•
Controllare che l'opzione Clean URLs sia attivata (Administer >> Site configuration >>
Clean urls).
Installare e abilitare il modulo "Pathauto" (Richiede l'abilitazione del modulo "Path" e
l'installazione ed abilitazione del modulo "Token").
Il modulo Pathauto permette di sostituire le path assegnate da Drupal con delle path alias più
user-friendly.
Operazione da fare prima di pubblicare il sito o appena pubblichiamo una nuova pagina, in
modo che il motore di ricerca indicizzi le path alias e non quelle originali è la seguente:
Administer >> Site building >> URL aliases ("Automated alias settings" tab); ciò
permetterà la sostituzione delle path assegnate da Drupal con delle path alias amichevoli.
Creare vocabolari e termini, abilitando il modulo Taxonomy.
•
•
45
Da ricordare
•
Dopo aver abilitato un modulo:
o abilitarne anche il relativo block;
o dare agli utenti (ruoli) la possibilità di usarlo (permessi);
o modificare le caratteristiche del content type.
•
Dopo aver creato un nuovo content type (o aver installato un modulo che crea un suo
content type) dobbiamo abilitare il relativo block e dare i permessi agli utenti.
•
Dopo aver cambiato un tema riabilitare i vari blocks.
Installare un modulo aggiuntivo
Di seguito andrò ad elencare le operazioni da eseguire per installare su Drupal un modulo.
1. Il modulo da installare deve essere compatibile con la versione di Drupal installata
2. Scaricare il modulo (file.tar.gz) (ad esempio da http://drupal.org/project/modules)
3. Decomprimerlo con WinRar
4. Mettere il modulo (cartella contenente vari files e cartelle riguardanti il modulo stesso) in
C/xampplite/htdocs/drupal/sites/all/modules
46
Se è il primo modulo ad essere aggiunto dobbiamo creare una cartella “modules” in
C/xampplite/htdocs/drupal/
C/xampplite/htdocs/drupal/sites/all,
, la quale andrà a contenere tutti i vari moduli
eventualmente aggiunti dall’utente
Ad esempio se abbiamo scaricato ed estratto il file “pathauto-6.x
6.x-1.5tar.gz” (cartella
pathauto contenente i vari file del modulo pathauto) metteremo la cartella "pathauto"
"pathauto in
C/xampplite/htdocs/drupal/sites/all/mo
C/xampplite/htdocs/drupal/sites/all/modules
Attenzione a non mettere i moduli aggiuntivi in C/xampplite/htdocs/drupal/modules (qui ci
sono i moduli del core di Drupal)
5. Leggere il file INSTALL.txt o README.txt (contenuto nel modulo) per sapere se il modulo
necessita di particolari procedure/files/altri moduli/... per funzionare correttamente
47
6. Andare su Drupal in Administer >> Site building >> Modules (indirizzo
http://localhost/drupal/admin/build/modules) e mettere la spunta sul checkbox del modulo
per abilitarlo
7. Infine cliccare sul bottone “Save configuration” per salvare la configurazione e abilitare
definitivamente il modulo.
48
Note:
Alcuni moduli, per funzionare, richiedono che vengano cambiati i permessi (Administer >> User
management >> Permissions).
Se il modulo ha delle impostazioni, possono essere raggiunte andando in Administer >> Site
building o Administer >> Site configuration.
Disinstallare un modulo aggiuntivo
Per disinstallare un modulo procedere nel modo seguente.
1. Disabilitare il modulo (andando in Administer >> Site building >> Modules)
2. In Administer >> Site building >> Modules cliccare sul tab "Uninstall" e disinstallare il
modulo scegliendolo fra quelli in lista
3. Se il modulo non è nella lista, dopo averlo disabilitato, cancellarlo manualmente (eliminare
la cartella contenente i files del modulo da .../sites/all/modules)
4. Se si disinstalla manualmente il modulo eliminandone la cartella, eseguire il modulo
aggiuntivo "System Table Cleaner" il quale eliminerà tutti i riferimenti che il modulo ha
creato nel database (infatti cancellando la cartella del modulo tutti i riferimenti che il
modulo aveva creato nel database non vengono rimossi)
Aggiornare un modulo esistente
Per aggiornare un modulo già esistente ed installato si va inizialmente a controllare se per il preciso
modulo è presente un nuovo aggiornamento. Per far questo si va su: Administer >> Reports >>
Available updates. Se è presente un nuovo aggiornamento lo si scarica in formato .rar e lo si
decomprime.
Successivamente bisogna disabilitare su Drupal il modulo vecchio da aggiornare e dopo eliminare
la cartella contenente i file del modulo da .../sites/all/modules.
Mettere in .../sites/all/modules la cartella contenente i file del modulo aggiornato, in modo tale che
questo riappaia nell’elenco di Drupal dei moduli da abilitare. Entrare in Drupal ed andare ad
abilitare il nuovo modulo (contenente gli aggiornamenti).
Eseguire lo script update.php per aggiornare il database (il nuovo modulo può infatti apportare
modifiche al database):
• Andare
all'indirizzo
"http://www.example.com/update.php"
(oppure
"http://www.example.com/test_site/update.php")
• Se abbiamo installato Drupal seguendo questa guida l'indirizzo esatto è
"http://localhost/drupal/update.php"
• Fare un backup del database
• Fare un backup del vecchio modulo (sorgente)
• Mettere il sito offline (Administer >> Site configuration >> Site maintenance)
• Seguire le istruzioni a schermo
• Rimettere il sito online
• Controllare in Administer >> Reports >> Available updates se il modulo è stato
correttamente aggiornato
49
Installare un tema aggiuntivo
Per installare un tema aggiuntivo su Drupal procedere in tal modo.
1. Il tema da installare deve essere compatibile con la versione di Drupal installata
2. Scaricare il tema (file.tar.gz) (ad esempio da http://drupal.org/project/themes)
50
3. Decomprimerlo con WinRar
4. Mettere il tema (cartella contenente vari files e cartelle che compongono il tema)
tema in
C/xampplite/htdocs/drupal/sites/all/themes
ocs/drupal/sites/all/themes
Se è il primo tema ad essere aggiunto dobbiamo creare una cartella “themes” in
C/xampplite/htdocs/drupal/sites/all
htdocs/drupal/sites/all,, la quale andrà a contenere tutti i vari temi
eventualmente aggiunti dall’utente
Ad esempio Marinelli se abbiamo scaricato ed estratto il file marinelli-6.x-2.96.tar.gz
marinelli
(cartella marinelli contenente i vari file del tema marinelli) metteremo la cartella "marinelli"
"marinelli
in C/xampplite/htdocs/drupal/sites/all/themes
Attenzione a non mettere i temi aggiuntivi in C/xampplite/htdocs/drupal/themes (qui ci sono
i temi del core di Drupal)
5. Leggere il file INSTALL.txt o README.txt (contenuto nel tema) per sapere se il tema
necessita di particolari procedure/files/... per funzionare correttamente
6. Andare in Administer > Site building > Themes e mettere la spunta sul tema per abilitarlo e
sul radio button per impostarlo come tema di default e infine disabilitare il tema precedente
7. Infine cliccare sul bottone “Save configuration” per salvare la configurazione e abilitare
definitivamente il tema.
51
Dopo aver abilitato un tema si può notare subito il cambiamento dello sfondo, del font, ecc.
Ad esempio il tema Marinelli è il seguente:
52
Organizzazione del lavoro
Dopo aver visto a grandi linee come funziona la piattaforma Drupal, non ho iniziato
direttamente a sviluppare il progetto, cioè non ho implementato subito il modulo task-scheduling.
Infatti per prima cosa mi sono fatto uno schema mentale su come organizzarmi il lavoro, una
strategia di elaborazione dell’informazione e delle conoscenze per poter realizzare il modulo
software. Ho deciso che la strategia che più si addiceva alla realizzazione per questo tipo di progetto
potesse essere un approccio bottom-up; cioè prima ho creato ed elaborato nel dettaglio ogni singola
funzione che avrebbe composto il mio modulo, successivamente ho connesso le funzioni che si
susseguivano logicamente (cioè quelle funzioni che messe insieme avevano uno scopo comune, ad
esempio più funzioni assieme mi davano come risultato il form composto da tanti riquadri quant’è il
numero di task che compongono il task-set) al fine di formare dei componenti (insiemi di funzioni)
più grandi; infine ho interconnesso tutte queste macro componenti per formare l’intero programma.
Ho optato per questa strategia di progettazione per le seguenti motivazioni:
• Siccome il progetto da realizzare era abbastanza lungo, non volevo verificare l’esito del mio
lavoro solo a modulo completo ma volevo controllarlo e testarlo in intervalli di tempo brevi;
• Componendo una funzione alla volta avevo anche la possibilità di correggere, ove presenti,
gli errori passo per passo, infatti in questo modo essi erano riconoscibili più facilmente
grazie al fatto che il codice di cui era formata ogni funzione non era per niente lungo rispetto
al codice che è andato a formare l’intero modulo;
• È stata la prima idea di strategia adottabile che mi è venuta in mente dopo aver letto le
specifiche, perché sono subito riuscito a separare i vari concetti e quindi ad individuare
subito i macro componenti che dovevano andare a formare il mio modulo.
L’utilizzo di questa strategia mi ha permesso di sviluppare il modulo pezzo per pezzo, senza essere
per forza vincolato ad un ordine preciso da seguire nelle operazioni da svolgere e nello scrivere il
codice delle funzioni, alla fine poi avrei messo insieme il tutto nell’ordine corretto.
Dopo aver scelto la strategia di progettazione, ho individuato precisamente quali dovevano
essere i miei macro componenti e da quante e quali funzioni dovevano essere composti. Il modulo
finale era il risultato dell’interconnesione di queste tre macro componenti di funzioni:
• Form composto da riquadri che si mostrano e nascondono all’utente quando esso clicca
sull’etichetta di ciascuno: insieme di funzioni che andavano a costituire la parte iniziale del
modulo, cioè quella dove l’utente andava ad inserire i dati;
• Algoritmi EDF e RM: insieme di funzioni che lavorano in background (operazioni non
visibili all’utente) ed elaborano i dati inseriti dall’utente;
• Diagramma di Gantt: insieme di funzioni che visualizzano graficamente all’utente il
risultato dell’elaborazione dei dati, da lui inseriti, tramite diagramma di Gantt.
Di seguito andrò a descrivere i vari passi che ho eseguito per creare il modulo in ordine temporale
di come li ho svolti.
53
Implementazione algoritmi nel linguaggio C
Stimolato principalmente dalla curiosità, ho preso la decisione di dedicarmi inizialmente
all’implementazione dei due algoritmi di scheduling EDF e RM. Siccome volevo aver subito la
conferma della funzionalità corretta degli algoritmi creati, grazie alla conoscenza del linguaggio C,
derivata dall’esame di “Fondamenti di Informatica”, e inoltre essendo il PHP un linguaggio avente
le istruzioni e la struttura delle variabili molto simile al C, ho sviluppato gli algoritmi nel linguaggio
C. Questo mi avrebbe dato modo di ottenere un feedback diretto e rapido di come lavorano gli
algoritmi da me creati. Ora vado a descrivere in dettaglio i ragionamenti eseguiti e il codice scritto
per implementare i due algoritmi.
Algoritmo EDF
Inizialmente ho incluso nel mio file C la libreria di input/output del C, grazie al comando
#include, e ho definito due costanti N e M che contengono rispettivamente il numero massimo dei
task e il numero massimo dei parametri di ogni task, grazie al comando #define.
La costante N=10 perché dalle specifiche abbiamo detto che il numero massimo di task che l’utente
può inserire è 10; la costante M=5 perché i parametri che prendo in considerazione per ogni task
sono il tempo di computazione C, la dealine relativa D, il periodo T, il numero di computazioni fatte
dal task e un flag che verifica se il task è presente o no nella ready queue.
Dopo questi passaggi necessari ho iniziato l’algoritmo vero e proprio grazie all’istruzione
main.
In tutti i programmi C prima di utilizzare una variabile bisogna definirla ed infatti è questa la
prima cosa che sono andato a fare.
Ho definito dieci variabili intere (int), numero minimo necessario per implementare l’algoritmo;
queste sono:
• num_task: contiene il numero dei task da elaborare, inserito dall’utente;
• task[N][M]: è un array bidimensionale (detto anche matrice) dove in ogni riga verranno
memorizzati i parametri di un task inseriti dall’utente (riga i-esima contiene tutti e solo i
paramentri del task i-esimo), una volta inseriti dall’utente essi non variano più fino al
termine dell’algoritmo;
• ready_queue[N][M]: è un array bidimensionale dove in ogni riga si andranno a
memorrizzare i parametri di un task durante l’elaborazione dell’algoritmo, essi variano ad
ogni iterazione dell’algoritmo;
• secondi: variabile contatore dei secondi che passano dall’inizio dell’algoritmo fino al
termine di esso, ad ogni secondo ho un iterazione;
• i, j: contatori che utilizzo per passare da un task all’altro e/o da un parametro all’altro nei
vari cicli for;
• min_task: conterrà il numero del task avente la deadline assoluta minore;
54
•
•
•
min_dead: conterrà il valore della deadline assoluta minore;
overflow: la utilizzo in modalità booleana per decidere se fermare o no le iterazioni fatte
secondo per secondo;
invio: mi serve solo a bloccare la visualizzazione dei risultati prodotti fino a quando non
premo un tasto, una volta premuto il tasto procede con l’iterazione successiva.
Prima di iniziare con l’algoritmo vero e proprio devo richiedere all’utente il valore del
numero dei task e i valori dei parametri dei task grazie a due cicli for e al comando scanf; come
detto prima il numero dei task verrà memorizzato nella variabile num_task, mentre l’array task[i][j]
memorizzerà il parametro j-esimo appartenente al task i-esimo, per j=0 il parametro è il tempo di
computazione C, per j=1 il parametro è la deadline relativa D e per j=2 il parametro è il periodo T.
Gli ultimi due parametri j=3 e j=4, rispettivamente il numero di computazioni di un task e un flag
ready (può assumere valore 0 o 1) per vedere se un determinato task è presente nella ready queue,
inizialmente sono fissati a priori ed hanno un valore ben preciso; il numero di computazioni è 0,
dato che nessuno di loro ha mai computato inizialmente (ipotesi: nessuna computazione precedente
da parte di un task), mentre il flag ready è invece 1, dato che con 0 vado ad indicare i task che non
sono presenti nella ready queue ed invece con 1 i task che sono presenti (per ipotesi: inizialmente
tutti i task sono presenti nella ready queue, caso critico). In questi passaggi vado a costruire l’intero
array task con i dati inseriti dall’utente e i valori iniziali fissi dati dalle ipotesi fatte.
Inizializzo i valori delle variabili secondi e overlflow uguali a 0, per la prima variabile
perché l’algoritmo parte dall’istante 0 secondi, la seconda variabile invece è un flag (può assumere
valore 0 o 1) e quando è uguale a 0 indica che nessun task è in overflow mentre quando è 1 indica
che uno o più task sono in overflow.
Questo codice visualizzerà ad esempio:
55
Siccome c’è anche la possibilità che tutti i task inseriti dall’utente finiscano le loro
computazioni prima dell’inizio del loro prossimo periodo, quindi la CPU resta inutilizzata per
alcuni secondi; bisogna tenere conto anche di questo caso. Quindi nell’array task inserisco anche un
indice i-esimo aggiuntivo a quelle dei task che mi tiene conto dei tempi morti della CPU (è come
un task invisibile); questo indice per non essere mai selezionato dall’algoritmo deve avere un tempo
di computazione, una deadline relativa e un periodo molto maggiore rispetto ai task e, inoltre, per
ipotesi deve avere il numero di computazioni=0 ed essere sempre presente nella ready queue quindi
flag ready=1. Siccome gli elementi di un array partono dall’indice 0 (i=0 corrisponde al task1, i=1
al task2,…) l’ultimo task inserito dall’utente corrisponde all’indice num_task-1, quindi l’indice che
avrà il “task per i tempi morti” sarà num_task.
L’ultima cosa di cui ho bisogno prima di partire con l’elaborazione dell’algoritmo è la
creazione della ready queue. Questa viene fatta grazie all’array ready_queue, il quale ha la stessa
struttura dell’array task. Inizialmente ha anche gli stessi valori dell’array task, quindi attraverso due
cicli for copio tutti i valori che contiene task in ready_queue. La differenza tra questi due array si
vede durante l’elaborazione dell’algoritmo:
task: i valori dei parametri inseriti dall’utente non variano mai durante l’elaborazione e
restano sempre gli stessi fino alla fine, array statico;
ready_queue: i valori dei parametri, inizialmente uguali a quelli di task, variano ad ogni
iterazione, array dinamico.
Per verificare lo stato iniziale della ready queue prima di iniziare l’algoritmo stampo a
schermo i parametri di ready_queue grazie a due cicli for e al comando printf, questo lo faccio per
avere un riepilogo dei dati inseriti dall’utente e per verificare che la procedura dell’inserimento di
tutti i dati si è svolta correttamente.
56
Questo codice visualizzerà ad esempio:
Adesso posso iniziare a sviluppare l’algoritmo.
L’algoritmo di scheduling ha come compito quello di selezionare il task con priorità maggiore ed
assegnargli la CPU. Questo controllo ed assegnazione deve essere fatto per ogni secondo, quindi
deve essere ripetuto (iterato) continuamente; esso termina solo quando uno o più task vanno in
overflow. Quindi ho deciso di iniziare l’algoritmo con un ciclo while, esso itera l’algoritmo (tutte le
istruzioni contenute dal ciclo while) secondo per secondo (secondi++) e termina quando il flag
overflow è diverso da 0. Si vedrà dopo che questo flag viene messo a 1 quando uno o più task vanno
in overflow.
Sapendo che l’algoritmo si ripete ciclicamente, la prima operazione che faccio è quella di resettare
le variabili min_dead e min_task dai valori assunti dal ciclo precedente. Questo perché il controllo
sulla deadline assoluta d viene fatto secondo per secondo e, se ad esempio, min_dead conteneva al
secondo precedente un valore di deadline piccolo appartenente ad un task che ha finito di computare
e non resetto questo valore, al prossimo controllo anche se il task non sarà più presente nella ready
queue i valori di min_dead e min_task resteranno quelli del ciclo precedente (essendo appartenuti ad
un task con priorità maggiore). Ho deciso di resettare queste due variabili inizializzandole in modo
tale che assumano i valori della deadline e della posizione nell’array ready_queue del “task dei
tempi morti”, sia perché la sua deadline ha un valore elevato e quindi ai controlli qualsiasi task
presente nella ready queue avrà una priorità maggiore di esso (ecco perché ho posto
min_dead=ready_queue[num_task][1]) e sia perché se eventualmente non sono presenti task nella
ready queue automaticamente il task selezionato dall’algoritmo è il nostro “task invisibile” (ecco
perché ho posto min_task=num_task).
57
Ora tocca alla parte di controllo, selezione e assegnazione del task avente priorità maggiore
tra tutti i task presenti nella ready queue, cioè quella che riguarda direttamente lo scheduling di un
task-set. Ricordiamo a questo punto che l’algoritmo EDF dà priorità maggiore, cioè seleziona, il
task avente deadline assoluta d minore (deadline dinamica, varia da secondo a secondo quindi ad
ogni iterazione).
Per selezione di un task intendo, nel mio algoritmo, la memorizzazione del valore della
deadline assoluta minore nella variabile min_dead=ready_queue[i][1] e la memorizzazione della
posizione occupata dal task, avente deadline minore, nella ready queue nella variabile min_task=i.
La prima scansione mi seleziona il primo task presente nella ready queue avente un qualsiasi valore
della deadline assoluta (mi interessa solo se è presente nella ready queue, ready_queue[i][4]==1),
infatti appena ne trova uno il ciclo for termina grazie all’istruzione break.
La seconda scansione parte dal task selezionato in precedenza e continua a controllare tutti i task
presenti nella ready queue fino alla fine. In questa scansione viene selezionato il task avente
deadline assoluta minore rispetto a tutti gli altri task presenti nella ready queue.
Grazie a delle printf stampo a schermo il risultato delle scansioni precedenti; esse
visualizzano il secondo di tempo in cui ci troviamo, la posizione dell’array in cui si trova il task
selezionato e il valore della deadline assoluta di questo task.
Questo codice visualizzerà ad esempio:
Dopo aver scelto il task a cui deve essere assegnata la CPU devo passare alla fase di
computazione, cioè, oltre a fare in modo che il task selezionato computi per quel secondo (il tempo
di computazione diminuisce), devo aggiornare lo stato temporale di tutti i task presenti nella ready
queue (la deadline assoluta diminuisce, il tempo per arrivare a fine periodo diminuisce).
Quindi per ogni task diminuisco di 1 (perché itero secondo per secondo) il periodo assoluto e la
deadline assoluta, mentre solo per il task selezionato diminuisco di 1 il tempo di computazione
58
assoluto. E infine aumento di 1 la variabile secondi (per indicare il passare del tempo ad ogni
iterazione).
Ora grazie ancora a delle printf e a due cicli for (ne servono due per scorrere un array
bidimensionale) stampo a schermo la situazione di tutti i task (presenti e non nella ready queue) con
i valori dinamici assunti dai parametri in quel preciso secondo. Ogni riga è attribuita ad un singolo
task e i parametri sono, in ordine di visualizzazione: tempo di computazione assoluto, deadline
assoluta, periodo assoluto, numero di computazioni, presenza o no nella ready queue.
Questo codice visualizzerà ad esempio:
L’ultima cosa da fare prima di poter terminare l’algoritmo e quindi chiudere il ciclo while è
la gestione della ready queue. Infatti non dobbiamo solo aggiornare i parametri dei task secondo
per secondo ma anche la situazione della ready queue e più precisamente col passare dei secondi
possono verificarsi tre casi:
la fine del tempo di computazione di un task: sta ad indicare che dobbiamo togliere il task
dalla ready queue;
l’inizio di un nuovo periodo di un task: sta ad indicare che dobbiamo re-inserire il task nella
ready queue;
l’andata in overflow di uno o più task: sta ad indicare che dobbiamo terminare l’algoritmo.
Con un controllo if verifico se il task che ha computato in questo secondo ha finito
totalmente il suo tempo di computazione assoluto (cioè se è uguale a 0). Se si verifica questo fatto
allora devo incrementare di 1 il parametro che conteggia il numero di computazioni di quel task e
devo togliere il task dalla ready queue (ready_queue[min_task][4] da 1 a 0) a cui non serve più la
CPU. Infine con una printf visualizzo il task che ha finito la computazione in quel secondo,
ovviamente se in quell’istante di tempo vi è un task che ha terminato.
59
Questo codice visualizzerà ad esempio:
Con un ciclo for scansiono tutta la ready queue e mi concentro (grazie all’istruzione if) sui
task che hanno finito la computazione, che hanno terminato il loro periodo assoluto e che non sono
presenti nella ready queue e sui task che non hanno finito la computazione e sono andati in
overflow, cioè il loro periodo assoluto è scaduto senza che hanno finito di computare.
Nel primo caso reinserisco il task i-esimo nella ready queue, cambiando il parametro
ready_queue[i][4] da 0 ad 1 e, siccome tratto i task periodici, riprendendo i valori iniziali del tempo
di computazione C, deadline relativa D e periodo T. Poi con una printf visualizzo il task che
eventualmente rientra nella ready queue in quell’istante di tempo.
Questo codice visualizzerà ad esempio:
Nel secondo caso devo bloccare le iterazioni, cioè devo terminare il ciclo while. Questo lo faccio
semplicemente cambiando il flag overflow da 0 a 1, così che alla prossima iterazione la condizione
del while non sarà vera e tutto il contenuto del ciclo si interrompe, fermando a sua volta
l’elaborazione dell’algoritmo. Poi con una printf visualizzo il task che è andato in overflow.
Questo codice visualizzerà ad esempio:
A titolo di esempio, di seguito verrà mostrato l’intero output prodotto dal file EDF.exe
(eseguibile del file EDF.c) con un task-set scelto a caso.
60
61
62
Algoritmo RM
Quasi tutti i ragionamenti fatti (e quindi il codice scritto) per l’algoritmo EDF sono validi
anche per l’algoritmo RM, quindi non andrò a ripetere e spiegare tutto l’algoritmo RM ma esporrò
solo le parti ed i ragionamenti in cui questo si differenzia dal precedente riassumendo brevemente
però i concetti generali di come funziona l’algoritmo.
Inizialmente vi sono le inclusioni delle librerie e le definizioni delle costanti.
Successivamente, con l’inizio del programma (main), vado a dichiarare tutte le variabili che
utilizzo nel codice e a richiedere all’utente l’inserimento dei dati (numero dei task e parametri di
essi). Qui l’unica differenza dal precedente sta nella dichiarazione di una variabile: mentre prima
avevo la variabile min_dead, che conteneva il valore della deadline assoluta minore, ora ho la
variabile min_perio, che contiene il valore del periodo relativo minore. Una volta creato totalmente
l’array task vado a generare anche l’array ready_queue tramite copia di tutti i parametri dell’array
task e infine stampo a schermo l’array ready_queue con tutti i suoi parametri.
63
Questo codice visualizzerà ad esempio:
Anche qui l’algoritmo vero e proprio inizia con il ciclo while e il reset delle variabili
min_task e min_perio inizializzandole ai valori del “task dei tempi morti”.
Ora tocca alla parte di controllo, selezione e assegnazione del task avente priorità maggiore
tra tutti i task presenti nella ready queue, cioè quella che riguarda direttamente lo scheduling di un
task. Ed è qui che l’algoritmo RM presenta le differenze maggiori rispetto all’algoritmo EDF.
Ricordiamo a questo punto che l’algoritmo RM dà priorità maggiore, cioè seleziona, il task avente
periodo relativo T minore (periodo statico, non varia da secondo a secondo quindi ad ogni
64
iterazione). Per selezione di un task intendo, nel mio algoritmo, la memorizzazione del valore del
periodo relativo minore nella variabile min_perio=ready_queue[i][2] e la memorizzazione della
posizione occupata dal task, avente periodo minore, nella ready queue nella variabile min_task=i.
La prima scansione mi seleziona il primo task presente nella ready queue avente un qualsiasi valore
del periodo relativo (mi interessa solo se è presente nella ready queue, ready_queue[i][4]==1),
infatti appena ne trova uno il ciclo for termina grazie all’istruzione break.
La seconda scansione parte dal task selezionato in precedenza e continua a controllare tutti i task
presenti nella ready queue fino alla fine. In questa scansione viene selezionato il task avente periodo
relativo minore rispetto a tutti gli altri task presenti nella ready queue.
Grazie a delle printf stampo a schermo il risultato delle scansioni precedenti; esse
visualizzano il secondo di tempo in cui ci troviamo, la posizione dell’array in cui si trova il task
selezionato e il valore del periodo relativo di questo task.
Questo codice visualizzerà ad esempio:
La fase di computazione è identica all’algoritmo precedente, cioè il task selezionato
computa per quel secondo (il tempo di computazione diminuisce) e devo aggiornare lo stato
temporale di tutti i task presenti nella ready queue (la deadline assoluta diminuisce, il tempo per
arrivare a fine periodo diminuisce). Quindi per ogni task diminuisco di 1 (perché itero secondo per
secondo) il periodo assoluto e la deadline assoluta, mentre solo per il task selezionato diminuisco di
1 il tempo di computazione assoluto. E infine aumento di 1 la variabile secondi (per indicare il
passare del tempo ad ogni iterazione).
65
Ora con l’uso dell’istruzione printf e di due cicli for (ne servono due per scorrere un array
bidimensionale) stampo a schermo la situazione di tutti i task (presenti e non nella ready queue) con
i valori dinamici assunti dai parametri in quel preciso secondo. Ogni riga è attribuita ad un singolo
task e i parametri sono, in ordine di visualizzazione: tempo di computazione assoluto, deadline
assoluta, periodo assoluto, numero di computazioni, presenza o no nella ready queue.
Questo visualizzerà ad esempio:
L’ultima cosa da fare prima di poter terminare l’algoritmo e quindi chiudere il ciclo while è
la gestione della ready queue. Infatti non dobbiamo solo aggiornare i parametri dei task secondo
per secondo ma anche la situazione della ready queue e più precisamente col passare dei secondi
possono verificarsi tre casi:
la fine del tempo di computazione di un task: sta ad indicare che dobbiamo togliere il task
dalla ready queue;
l’inizio di un nuovo periodo di un task: sta ad indicare che dobbiamo re-inserire il task nella
ready queue;
l’andata in overflow di uno o più task: sta ad indicare che dobbiamo terminare l’algoritmo.
Questa procedura è identica a quella spiegata per l’algoritmo EDF e quindi non descrivo per non
essere ripetitivo. Anche qui l’algoritmo termina (la condizione del while non è soddisfatta) non
appena un task va in overflow.
Alla fine comunque con l’uso delle printf vado a visualizzare, se eventualmente presente:
il task che in quel secondo ha finito di computare;
il task che in quel secondo va in overflow.
66
Questo codice visualizzerà ad esempio:
A titolo di esempio, di seguito verrà mostrato l’intero output prodotto dal file RM.exe (eseguibile
del file RM.c) con un task-set scelto a caso.
67
Testing degli algoritmi
Una volta terminati gli algoritmi, sono andato a testare il loro funzionamento utilizzando il
metodo seguente:
mi sono inventato dei task-set: numero task di cui era composto ciascun task-set e valori dei
parametri per ciascun task;
ho schedulato a mano ciascun task-set in base al comportamento dei due algoritmi
implementati;
ho inserito i dati nei programmi C da me creati;
ho confrontato i risultati per vedere se gli algoritmi codificati da me erano esatti.
Di seguito vado a mostrare un esempio di un task-set schedulato a mano:
68
Grazie a questo metodo ed al fatto che, per come avevo scelto di implementare gli algoritmi
(con tante printf che mi visualizzavano come procedevano passo passo gli algoritmi), ottenevo per
ogni secondo un feedback di come questi si comportavano sono riuscito in poche prove a capire e
correggere alcuni piccoli errori che si erano presentati inizialmente ed a produrre un codice
comprensibile (facilitato anche dal nome che ho dato alle variabili e dai tanti commenti messi in
ogni riga), corretto e comunque non troppo complesso.
Creazione della directory del modulo “algoritmi”
Il primo passo da fare per creare un modulo di Drupal è quello di creare una nuova cartella
dentro
la
directory
di
Drupal
che
contiene
i
moduli
(percorso:
C:\xampplite\htdocs\drupal\sites\all\modules). Questa cartella andrà a contenere tutti i file
riguardanti il modulo. Per coerenza, con il mio progetto e quindi con lo scopo del modulo che
andavo a creare, ho scelto “algorimi” come nome della cartella, quindi il percorso del mio modulo
sarà C:\xampplite\htdocs\drupal\sites\all\modules\algoritmi.
69
I file riguardanti il modulo possono essere di vari tipi:
file .info: informa Drupal dell’esistenza del modulo
file .module: contiene il codice principale del modulo
file .php: contiene altre funzioni che vengono utilizzate dal modulo
file .install: viene eseguito la prima volta che un modulo è attivato, e viene utilizzato per
eseguire procedure di configurazione, come richiesto dal modulo. Il compito più comune è
la creazione di tabelle del database e campi. Il file .install non ha alcuna sintassi speciale, si
tratta semplicemente di un file PHP con una diversa estensione. I file .install sono utilizzati
anche per effettuare gli aggiornamenti quando è presnte una nuova versione del modulo.
file .js (javascript): contiene altre funzioni che vengono utilizzate dal modulo
ecc.
I principali, quelli che permettono l’esistenza di un modulo Drupal, sono il file .info ed il file
.module.
Il mio modulo è formato dal file algoritmi.module, algoritmi.info e crea_gantt.php; oltre a questi
sono andato a creare una cartella file_immagine che andrà a contenere l’immagine creata e salvata
dalla dal file crea_gantt.
Creazione del file algoritmi.info
La sintassi del file .info è simile al file INI (INItialization, formato standard per i file di
configurazione, file di testo con una struttura di base). Il file .info è sostanzialmente un file di testo
statico che contiene meta informazioni sul modulo, quindi serve per la dichiarazione dell’esistenza
del modulo e per la configurazione del tema. Senza questo file il modulo non si mostrerà
nell’elenco dei moduli.
L’elemento di base contenuto in un file .info è la proprietà. Ogni proprietà del file di testo è
una coppia di due elementi separati da un “segno di uguale = ”, quello a sinistra dell’uguale è il
nome della proprietà mentre quello a destra è il valore della proprietà (esempio: nome = valore ).
Il nome deve iniziare con un carattere alfabetico, può contenere numeri e caratteri di sottolineatura,
ma non trattini, spazi o segni di punteggiatura. Esso verrà utilizzato da Drupal nella formazione di
varie funzioni in PHP e quindi ha le stesse limitazioni. Attenzione: non scegliere nomi già utilizzati
per altri moduli; come tutti i componenti installati ogni modulo deve avere un nome univoco.
70
Le proprietà possono essere raggruppate in sezioni denominate arbitrariamente. Il nome
della sezione appare su una riga a sé, tra due parentesi quadre [ ]. Tutte le proprietà dopo la
dichiarazione della sezione sono associate a quella sezione. Non c'è un "esplicito" delimitatore di
fine per una sezione; essa termina appena viene dichiarato l’inizio di un’altra o alla fine del file. Le
sezioni non possono essere nidificate (esempio: [sezione]). La sezione sarebbe quindi un elenco di
valori associati, simile ad un array.
Il punto e virgola “ ; ” indica l’inizio di un commento. Esso si prolunga fino alla fine della
riga, quindi tutto quello scritto alla destra del punto e virgola fino alla fine della stessa riga è
considerato commento.
Poiché il file .info è memorizzato nella cache, è necessario cancellare la cache prima che
eventuali modifiche vengono visualizzate nel vostro sito.
Nel file .info è possibile inoltre specificare quali impostazioni del tema dovrebbero essere
accessibili dall'interfaccia di amministrazione di Drupal.
Drupal comprende i nomi delle proprietà elencati di seguito ed userà i valori di default per
i tasti opzionali non presenti nel file .info:
•
•
•
•
•
•
•
•
•
•
•
•
Nome (richiesto)
Descrizione (consigliato)
Screenshot
versione (sconsigliato)
core (richiesto)
motore (richiesto nella maggior parte dei casi)
base tema
regioni
Dipendenze (opzionale)
fogli di stile CSS
script
php
Nome (richiesto)
Il nome pubblicato del modulo. Deve seguire lo standard di capitalizzazione di Drupal 6,
quindi solamente la prima lettera del testo deve essere scritta in maiuscolo.
name = Nome del modulo
Descrizione (consigliato)
Una descrizione corta del modulo, preferibilmente di una linea, che informa
l’amministratore del sito cosa fa il modulo una volta abilitato.
description = Descrizione dello scopo del modulo.
Screenshot (opzionale, solo per i temi e non per i moduli)
L’attributo di screenshot dice a Drupal dove trovare un'immagine di anteprima del tema,
utilizzato sulla pagina di selezione del tema (admin/build/themes). Se quest’attributo viene
omesso dal file .info, Drupal utilizza il file "screenshot.png" nella directory del tema.
Utilizzare questa chiave solo se il file di anteprima non si chiama "screenshot.png" o se si
desidera inserire in una directory al di fuori della directory dei temi di base la tua (per
esempio, screenshot = immagini/screenshot.png ).
screenshot = immagine.png
71
Versione (sconsigliato)
La stringa di versione verrà automaticamente aggiunta da drupal.org quando il modulo o
tema creato viene immesso in rete. Così si può omettere questo valore. Tuttavia, se il
modulo o il tema non viene ospitato sulle infrastrutture drupal.org, si può dare al modulo e
tema qualunque versione stringa abbia un senso.
version = 1.0
Core (richiesto)
Da 6.x in poi, per tutti i file .info per moduli e temi bisogna indicare versione corretta del
core. Il nucleo di Drupal si rifiuterà di abilitare o avviare dei moduli o temi dove non vi è
scritta esplicitamente la versione corretta del core. Il valore dato all’attributo “core” è
confrontato direttamente con la costante DRUPAL_CORE_COMPATIBILITY, se non
corrisponde, il modulo o il tema sarà subito disabilitato o non abilitato proprio.
core = 6.x
Motore (richiesto nella maggior parte dei casi, per i temi)
Il motore di tema, che viene utilizzato dal tema. Se non viene fornito, il tema viene
considerato stand alone, cioè, implementato con un file ".theme". La maggior parte dei temi
dovrebbero usare "phptemplate" come motore predefinito.
Il lavoro di PHPTemplate è quello di scoprire tema funzioni e modelli per il comportamento
del tema. Si può omettere questa voce solo se si sa cosa si sta facendo.
engine = phptemplate
Tema base (solo per i temi)
Dichiarando un tema di base è possibile avere dei sotto-temi. Questo permette l’ereditarietà
di un tema, nel senso che le risorse del "tema base" possono essere riutilizzate all'interno del
sotto-tema. Posso dichiarare anche dei sotto-sotto-temi che hanno come tema base un sottotema, questo permette più livelli di ereditarietà.
base theme = nome tema base
Regioni (solo per i temi)
Le regioni blocco a disposizione del tema sono definite specificando la chiave “regions”
seguito, tra parentesi quadre, dal nome della posizione dove si andrà a trovare la regione e, a
destra dell’uguale, dal nome umano della posizione come valore (esempio,
regions[posizione_regione] = Nome della regione).
Drupal 6 default regioni:
o regions [left] = barra laterale sinistra
o regions [right] = barra laterale destra
o regions [content] = contenuto
o regions [header] = intestazione
o regions [footer] = piè di pagina
Dipendenze (per i moduli)
La dipendenza dei moduli è un opzione extra che può essere inserita nel file .info. Per
dipendenza si intende quando un modulo, per essere abilitato, richiede l’abilitazione
precedente di uno o più moduli. Questa dipendenza di un modulo nei confronti di altri
moduli viene rappresentata con la seguente sintassi:
o dependences[] = Nome modulo1 da cui dipendere
72
o dependences[] = Nome moduloN da cui dipendere
Se un modulo ha delle dipendenze nei confronti di altri moduli, Drupal non ne permette
l’attivazione fino a quando tutti i moduli da cui questo dipende non sono stati abilitati.
Fogli di stile
Tradizionalmente i temi di default utilizzano style.css automaticamente e si possono
aggiungere ulteriori fogli di stile chiamando drupal_add_css( ) nei loro file template.php. A
partire da Drupal 6, si può aggiungere ai temi i fogli di stile anche attraverso i loro file .info.
stylesheets [all] [] = theStyle.css
Script
Tradizionalmente si poteva aggiungere ai temi il Javascripts chiamando drupal_add_js( )
nelle loro file template.php. A partire dal 6.x, se un file denominato script.js è presente nella
directory dei temi allora è automaticamente inclusa. Tuttavia, in Drupal 7, questo
comportamento è stato cambiato nuovamente in modo che script.js è incluso solo se è stato
specificato nel file .info:
scripts [] = myscript.js
Php
Questo definisce la minima versione PHP che il modulo o il tema sosterrà. Il valore di
default è derivato dalla costante DRUPAL_MINIMUM_PHP, che è la versione minima
richiesta per il resto del nucleo. Questo può essere ridefinito per una versione più recente, se
necessario.
php = 4.3.3
Dopo questa parentesi generale su come può essere costituito il file .info, vado a spiegare
come ho creato il mio file algoritmi.info.
La prima riga è costituita da un commento (c’è il ; ) dove ho scritto il nome del modulo con
la relativa estensione, la versione del modulo e la data di creazione del file .info.
Le altre tre righe sono gli attributi obbligatori e principali di un file .info ovvero il nome del
modulo, la descrizione del modulo e la versione del core per cui è stato scritto il modulo.
Il nome e la descrizione verranno visualizzati nella pagina di abilitazione moduli di Drupal
(http://localhost/drupal/admin/build/modules).
73
Creazione del file algoritmi
lgoritmi.module
Dopo aver letto la documentazione, presente sul sito di Drupal, sono riuscito a comprendere
le nozioni base ed i passi standard su come creare un modulo.
Gancio hook_help
Il primo passo da fare è l’implementazione
l
del gancio hook_help(
_help( ).
) Grazie a questo
vengono offerti aiuto ed informazioni addizionali circa il nostro modulo. A causa del file .info
l’utilizzo di questo gancio è opzionale, comunque è buona norma renderlo effettivo. Per rendere
effettivo qualsiasi gancio in Drupal bisogna sostituire “hook” sul nome del gancio con il nome
del nostro modulo e creare la funzione avente come nome nome modulo_nomegancio( ) sul file
.module.
Nel mio caso ho chiamato
to la funzione algoritmi_help( ).
Il parametro $path contiene il percorso del menù del router, come definito in hook_menu,
per l’aiuto che viene richiesto (ad esempio: admin/nodo); se il percorso router include un carattere
jolly%, questo verrà visualizzato in $path (ad esempio: le pagine nodo sarebbero
sarebbe pari a $path
'node/%'). L'implementazione gancio può anche essere chiamato con i descrittori speciali dopo un #
74
"segno" e in questo caso il modo consigliato per processare la variabile $path è attraverso
un’istruzione per la scelta multipla chiamata switch-case.
Il parametro $arg è un array che corrisponde al valore di ritorno della funzione arg( ), per i
moduli che vogliono fornire un aiuto che è specifico a determinati valori di caratteri jolly in $path.
Ad esempio, è possibile fornire un aiuto per il percorso 'user /1', cercando per il percorso di 'user /%'
e $arg [1] == '1 '. Questo array deve essere sempre utilizzato, piuttosto che richiamando
direttamente arg( ), perché l'implementazione del suo gancio può essere chiamata per altri scopi
oltre a quello di costruire questa pagina di aiuto. Si noti che a seconda di quale modulo si invoca
hook_help, $arg può contenere solo stringhe vuote; indipendentemente da ciò, da $arg[0] a $
arg[11] sarà sempre impostato.
Inizialmente dichiaro una variabile con il nome $output che andrà a contenere il mio output,
questa variabile grazie ad = ‘ ’ la dichiaro in modo tale che sia di tipo stringa.
Poi gestisco la variabile $path con lo switch-case; in generale prevedo solo il caso
admin/help#algoritmi (in generale: admin/help#nomemodulo) che è usato dal core di Drupal per
collegarsi dalla pagina principale di aiuto (/admin/help), dove sono visualizzati tutti gli aiuti
generali (soprattutto quelli del core), alla pagina specifica di aiuto del mio modulo, dove sono
visualizzati solo gli aiuti riguardanti il mio modulo.
Successivamente memorizzo nella variabile stringa $output il testo che contiene il
messaggio d’aiuto rivolto all’utente (<p> e </p> sono le tag che indicano l’inizio e la fine del
paragrafo, mentre in t( ) è contenuto il testo che sarà mostrato all’utente).
Con l’istruzione break termino lo switch-case.
Il valore di ritorno della funzione (return $output) è la variabile $output, cioè una stringa
localizzata contenente il testo d’aiuto visualizzabile dall’utente.
75
Gancio hook_menu
Dopo aver agganciato l’hook_help al mio modulo ho implementato l’hook_menu. Esso
permette di definire le voci di menù e di callback (chiamate di ritorno) di pagina; cioè di creare il
link per il mio modulo e il conseguente collegamento URL. Questo con lo scopo di agganciare i
moduli per registrare i percorsi, che determinano quali richieste sono da trattare. A seconda del tipo
di iscrizione richiesta da ciascun percorso, un link si trova nel blocco di navigazione e/o un
elemento appare nella pagina di amministrazione di menù (admin/menu). Ogni item (indice
dell’array $items) definisce un URL (o percorso, path) per il sito di Drupal.
Drupal chiamerà questo gancio due volte: una con $may_cache impostato su TRUE, e una volta con
esso impostato su FALSE. Pertanto, ogni voce di menù dovrebbe essere registrata quando
$may_cache è VERO o FALSO, non in entrambe le volte. Impostazione di una voce di menù che si
verifica per entrambe le due volte si tradurrà in un comportamento non specificato.
Questo gancio è anche un buon posto per inserire il codice che dovrebbe essere eseguito una sola
volta per ogni pagina visualizzata; mettetela in un if(!may_cache) blocco.
$may_cache è un valore booleano che indica se le voci di menù cacheable devono essere restituite.
La cache menù è per il singolo utente, per cui gli elementi possono essere memorizzati nella cache
fintanto che non dipendono dall'attuale posizione dell'utente.
Il valore di ritorno di questa funzione è una serie di voci (array con i vari indici) di menù.
Ogni elemento (o voce, item) di menu è un array $items[ ] associativo che può contenere le
seguenti coppie nome-valore:
• path (percorso): obbligatorio. Il percorso per il collegamento quando l'utente seleziona
l'elemento.
• title (titolo): obbligatorio. La traduzione del titolo della voce di menù.
• callback (chiamata di ritorno): La funzione da chiamare per visualizzare una pagina web
quando l'utente visita il percorso. Se omesso, sarà richiamato ed utilizzato l’elemento parent
(padre) del menù.
• callback arguments (argomenti di callback): una serie di argomenti da passare alla
funzione di callback.
• access (accesso): un valore booleano che determina se l'utente dispone di diritti di accesso a
questa voce di menù. Di solito determinata da una chiamata a user_access( ). Se la ometto e
anche callback è assente, verranno utilizzati i diritti di accesso degli elementi parent (padre)
di menù.
• weight (peso): un numero intero che determina la posizione relativa degli elementi del
menù; di default è 0. Nel dubbio, si lasci stare, quella predefinita ordine alfabetico di solito è
meglio.
• type (tipo): una maschera di bit di flag che descrivono le proprietà degli elementi di menù;
maschere di bit di scelta rapida sono forniti come costanti nel menu.inc e le principali sono:
MENU_NORMAL_ITEM: voci di menù normale mostrate nella struttura dei menù
e può essere spostato o nascosto da parte dell'amministratore.
MENU_ITEM_GROUPING: i raggruppamenti delle voci sono usati per le pagine
come "node/add" che semplicemente è un elenco delle sottopagine da visitare.
MENU_CALLBACK: nelle callback viene semplicemente registrato un percorso in
modo che il corretto funzionamento viene attivato quando si accede all’URL.
MENU_DYNAMIC_ITEM: voci di menù dinamiche che cambiano di frequente, e
quindi non devono essere conservate nella banca dati per la personalizzazione
amministrativa.
MENU_SUGGESTED_ITEM: i moduli possono "suggerire" le voci di menù che
l'amministratore può abilitare.
MENU_LOCAL_TASK: task locali vengono visualizzati come schede di default.
76
MENU_DEFAULT_LOCAL_TASK: ogni task-set locale dovrebbe fornire un
task di default, che collega allo stesso percorso del suo task padre quando esso
viene cliccato.
Se il tasto type è omesso, si assume MENU_NORMAL_ITEM per default.
Dopo aver spiegato anche qui i concetti generali del gancio hook_menu ora vado a
descrivere in che modo ho sviluppato la mia funzione hook_menu.
Innanzitutto ho reso effettivo il mio gancio dandogli il nome algoritmi_menu( ); questa
funzione permette di mostrare (nel frame a sinistra di Drupal) all’utente il link del modulo
Algoritmi e, una volta cliccato su di esso, apre la pagina vera e propria che dovrà contenere il
contenuto del mio modulo.
Fatto questo vado a definire una variabile $items (elementi o voci di menù) come tipo array;
ogni indice dell’array corrisponde ad una pagina del modulo, quindi per aggiungere più pagine al
modulo basta aggiungere più item (indici dell’array) all’array $items. Definisco per l’array $items
l’indice ‘algoritmi’, cioè vado a definire l’URL del modulo algoritmi quindi vado a creare il link
“Algoritmi Scheduling”. Le coppie nome-valore di questo array sono:
Il titolo: cioè il nome del link;
La descrizione: cioè la frase che verrà visualizzata all’utente quando esso posiziona il
puntatore sul link;
Il nome (quindi il tipo) della funzione di callback da richiamare una volta cliccato sul link:
in questo caso chiamo una funzione che mi genera una form (drupal_get_form);
I parametri che devono essere passati alla funzione di callback, i campi callback e callback
arguments assieme sono quelli che mi generano la pagina che sarà visualizzata all’utente
una volta cliccato sul link: in questo caso chiamo la funzione algoritmi_form la quale
conterrà le istruzioni che mi andranno a generare la pagina;
I permessi di accesso alla pagina che sarà visualizzata dopo aver cliccato sul link: in questo
caso, rispettando le specifiche, ho permesso l’accesso alla pagina a tutti i tipi di utenti
(dall’amministratore agli utenti non registrati);
La posizione e il percorso da compiere per trovare il link appena creato: in questo caso ho
fatto in modo che, una volta abilitato il modulo, il link sia visibile nella pagina del menù
principale di navigazione di Drupal visibile quindi nel frame a sinistra.
Questa funzione ritorna l’array $items[ ] con l’unico indice che ho stabilito per esso, cioè
‘algoritmi’. Quindi verrà visualizzato un unico link con le caratteristiche descritte in precedenza. Se
qualche utente visita questo URL (http://localhost/drupal/algoritmi) la funzione drupal_get_form,
con i parametri passati dalla ‘algoritmi_form’, viene usata per generare il contenuto della pagina.
77
La funzione drupal_get_form è la funzione “chiave” nel form API che si occupa di
recuperare, processare e mostrare automaticamente un form elaborata HTML per i moduli.
moduli Nel suo
uso di base ci vuole solo un argomento, uno string che sia l’ID del modulo e anche il nome della
funzione che costruisce l’array $form.
$form Poiché il modulo di identificazione è generalmente anche il
nome di una funzione, seguita da un numero qualsiasi di lettere, numeri o caratteri di sottolineatura,
spazi e trattini non sono ammessi. La funzione drupal_get_form può prendere argomenti opzionali
aggiuntivi,
untivi, che saranno semplicemente trasferiti alla funzione costruttrice $form. La funzione
drupal_get_form fa principalmente quanto segue:
Comincia il processo intero di costruzione del form ottenendo l’array $form dalla funzione
costruttrice;
Traduce i nomi degli item di $form[‘nome’] in elementi attuali del form;
Esegue qualsiasi validazione, cioè chiama le funzioni di validazione personalizzate, se esse
sono state dichiarate;
Invia il form, se una funzione di invio (submit) è stata dichiarata e se l’utente ha cliccato sul
tasto di submit;
Chiama qualsiasi funzione personalizzata di temi che sono stati dichiarati;
Restituisce uno string HTML che contiene il form attuale.
Gancio hook_form
Dopo aver agganciato al file .module le funzioni di help e di menù ho iniziato a creare le
funzioni che generano il form di inserimento dati, che verrà visualizzato all’utente una volta
cliccato sul link Algoritmi.
La prima funzione da analizzare è quella che ha come gancio hook_form.
hook_form Questo gancio
permette di visualizzare un modulo nodo di modifica, cioè un form dove l’utente può inserire dei
78
dati. Esso è realizzato con moduli nodo ed è chiamato a recuperare il form che viene visualizzato
per creare o modificare un nodo. Questo modulo viene visualizzato nel nodo di percorso /add /[tipo
di nodo] o nodo/[nodo ID]/modificare. La presentazione e pulsanti di anteprima, i controlli
amministrativi e display, e le sezioni aggiunte da altri moduli (ad esempio, le impostazioni del
percorso, le impostazioni del menù, impostazioni commenti, ecc) vengono visualizzati
automaticamente dal modulo di nodo. Questo gancio ha solo bisogno di tornare il titolo del nodo e
la modifica dei campi specifici di form per il tipo di nodo.
I parametri da immettere nell’hook_form sono:
&$node: il nodo che viene aggiunto o modificato.
$form_state: l’array di stato form.
Il valore di ritorno dell’hook_form è un array $form che contiene il titolo e le informazioni degli
eventuali elementi che costituiscono il form.
I vari elementi del form sono dichiarati in modo array (hanno una struttura gerarchica e
possono essere anche nidificati), cioè ogni indice dell’array $form[ ] si riferisce ad un singolo
elemento del form e per ognuno di questi ne sono memorizzate le caratteristiche (tipo form, nome
form, ecc.).
Le proprietà e gli attributi di ciascun elemento del form sono indicate con coppie di
chiavi-valori, dove la chiave è il nome della proprietà e/o attributo mentre il valore è il valore della
proprietà e/o attributo. La proprietà del nome dell’elemento del form viene dichiarato nell’array
$form, alla fine dell’albero dell’array. Ad esempio se un elemento dell’albero è stato strutturato in
questo modo: $form[‘account_setting’][‘username’]. Quindi la proprietà del nome di un elemento è
‘username’ e questa è la chiave che sarà disponibile in $form_state[‘values’], utilizzabile nelle
funzioni successive come ad esempio quelle di validazione e di elaborazione.
Le chiavi di proprietà e/o attributi sono dichiarate con quotazioni circostanti, cominciando con un
segno # ed i valori di esse sono ‘stringhe’.
Il tipo di elemento del form è dichiarato come un attributo con la proprietà ‘#type’.
L’ordine in cui vengono dichiarate le proprietà e attributi di ogni elemento dell’array non
importa, e tutti gli attributi di cui esso non ha bisogno non devono essere dichiarati. Molte proprietà
e attributi hanno anche un valore predefinito (di default), che viene preso in considerazione quando
esse non sono dichiarate esplicitamente.
Non utilizzare l’attributo ‘#value’ per nessun elemento dell’array che possa essere
modificato dall’utente, utilizzare invece l’attributo ‘#default_value’. Inoltre non collocare dei valori
da $form_state[‘values’] (o da $_POST), perché di questo se ne occupa automaticamente
FormsAPI, collocare solo il valore originale del campo.
Uno dei grandi vantaggi di questo sistema è che le chiavi nominate esplicitamente rendono
molto più semplice la decifrazione dell’elemento del form.
Le versioni precedenti di FormAPI usavano una combinazione di $form_values, variabili
globali, e flag personalizzate nella definizione del modulo stesso per acquisire informazioni sul
flusso di lavoro del modulo ed il suo stato attuale durante la lavorazione. In Drupal 6, un solo array
($form_state) è passato per riferimento (grazie al simbolo &) in ogni fase di lavorazione del form.
Diversi indici standard di $form_state sono utilizzati in FormAPI come valori di default:
• $form_state ['values']
L’array $_POST è utilizzato per raccogliere i valori dei dati, inseriti dagli utenti nei form,
inviati con method=‘post’; le informazioni inviati da un form con il metodo POST è
79
invisibile agli altri e non ha limiti sulla quantità di informazioni da inviare. La chiave
'values' viene utilizzata per memorizzare questa raccolta di dati; inoltre essa sostituisce la
vecchia distinta variabile $form_values che è stata passata ai gestori (handler) di validazione
e di sottomissione.
Le seguenti tre variabili con indici standard possono essere utilizzate per controllare
l’interpretazione e l’elaborazione del flusso di lavoro del form. I gestori di validazione e di
sottomissione possono modificare i dati in queste tre chiavi per alterare il flusso di lavoro del form
basato su input dell'utente.
• $form_state ['redirect']
La chiave 'redirect' (rifare) controlla che cosa succede dopo che l'elaborazione di un form è
completa. Per impostazione predefinita ‘redirect’, quando viene ricaricata la pagina
contenente il form al termine di una sottomissione, i campi di questo, riempiti in precedenza
dall’utente, vengono cancellati (clear, cioè tornano vuoti). Se 'redirect' è impostato su un
percorso di Drupal (come user/edit), l'utente sarà reindirizzato a questa strada, invece. Se
'redirect' è impostata su FALSE, l'utente non verrà reindirizzato dopo che il form viene
elaborato, i valori sono entrati nel form e rimarranno nei campi.
• $form_state ['rebuild']
La chiave 'rebuild' (ricostruzione) sovrascrive la chiave 'redirect': quando è impostata su
TRUE, il form sarà ricostruito da zero e visualizzato sullo schermo. Questo dà alla
costruzione del codice del form la possibilità di aggiungere altri campi o modificare la
struttura del form in base all’input dell’utente (ad esempio, ri-costruire il form con i campi
aggiuntivi se l'utente fa clic su 'Aggiungi task'). Se questo flag è impostato da un gestore di
validazione, ogni gestore di 'submit' sarà saltato. Se è impostato da un gestore di 'submit', il
form sarà ricostruito e visualizzato dopo che tutti i gestori di submit hanno terminato
l'elaborazione.
• $form_state ['storage']
Quando si costruiscono form complessi, che richiedono più passaggi per la realizzazione
(per esempio, un sondaggio di tre pagine), è necessario preservare i dati da tutti i passaggi in
modo che possano essere trattati insieme alla fine. Tutti i dati immessi nel ‘bidone della
conservazione’ della collezione $form_state verranno automaticamente memorizzati nella
cache e ri-caricati quando il form viene presentato la prossima volta, permettendo al vostro
codice di accumulare dati di gradino in gradino fino alla fase finale del processo senza alcun
codice aggiuntivo . Gli sviluppatori che desiderano un maggiore controllo possono utilizzare
i loro meccanismi di caching per memorizzare i propri dati temporanei del form (la sessione
utente - session - e campi form nascosti – hidding - sono due alternative a questo), ma il
bidone
di
'conservazione'
è
gestito
automaticamente
da
FormAPI.
Si noti che se $form_state ['storage'] è popolata, $form_state ['rebuild'] viene
automaticamente impostato su TRUE.
•
•
•
$form_state ['submitted']
$form_state ['submit_handlers'] (gestore di sottomissione)
$form_state ['validate_handlers'] (gestore di validazione)
Queste tre chiavi memorizzano le informazioni sullo stato attuale di trasformazione del
form. Se 'submitted' è TRUE, l'input dell'utente è attualmente in fase di elaborazione. Le
chiavi 'submit_handlers' e 'validate_handlers' permettono di personalizzare i gestori di
validazione e di sottomissione che sono stati allegati al pulsante specifico cliccato
dall'utente.
80
•
$form_state ['clicked_button']
Una copia completa dell'elemento bottone su cui è stato fatto clic per inviare il form. Questo
è più affidabile rispetto al vecchio nome $form_values['op'], e svolge anche ogni ulteriore
informazione che è stata posta nella definizione del form che costituisce l'elemento bottone.
Gestori di validazione e di sottomissione possono inserire dati aggiuntivi nei raccoglitori
personalizzati in $form_state.
Il gancio hook_form mi è servito per generare il form contenente i vari riquadri dei task
dove l’utente può inserire i dati (tempo di computazione, deadline e periodo), aggiungere e/o
rimuovere un riquadro, scegliere l’algoritmo da eseguire e ovviamente inviare il tutto al server
perché possa essere elaborato.
Come detto in precedenza, anche qui ho reso effettivo il gancio hook_form chiamandolo
algoritmi_form( ).
Dalle specifiche appare scontata ed essenziale (inizialmente bisogna visualizzare un solo
task e deve esserci almeno un task per poter sottomettere il form) la presenza iniziale del primo
riquadro, riferito al task1, sulla pagina contenente il form. Questo mi ha portato a dover trattare il
primo task, o task1, in maniera separata dagli eventuali task successivi.
E, sempre dalle specifiche, per poter realizzare i riquadri con i nomi dei rispettivi task, che al click
su di essi si chiudono e si aprono a tendina, ho avuto la necessità prima di definire il riquadro con il
nome del task i-esimo e poi ad ogni riquadro di definire i vari campi di inserimento dati relativi al
task i-esimo. In parole povere il nome del task fungerà da etichetta per il riquadro, contenente i
campi per l’inserimento dei dati, che potrà mostrarsi e nascondersi all’utente grazie ad un click
sull’etichetta.
81
Per il task1:
Creo nella variabile $form, dandogli come indice ‘task1’ cioè il nome del task
$form[‘task1’], un array il quale avrà come attributi:
o Tipo: il tipo dell’array sarà campo di testo;
o Titolo: il testo, posto all’interno di t( ), che sarà visualizzato come nome del
riquadro;
o Collapsible (pieghevole): impostato su TRUE renderà il riquadro pieghevole al click
sulla sua etichetta;
o Collapsed (collassato): impostato su FALSE inizialmente renderà il riquadro non
collassato e lo mostrerà per intero, cioè non compresso alla sola etichetta;
Creo nella variabile $form, dandogli come indici ‘task1’ il nome del task e ‘comp1’ tempo di
computazione del task o ‘dead1’ deadline del task o ‘perio1’ periodo del task, degli array
bidimensionali
$form[‘task1’][‘comp1’],
$form[‘task1’][‘dead1’]
e
$form[‘task1’][‘perio1’] i quali definiscono i campi del form dove l’utente andrà ad inserire
i parametri del task1.
Gli attributi di questi tre array sono identici, tranne ovviamente il testo scritto nel titolo e il
secondo indice della variabile $form_state[‘values’][‘comp1’ o ‘dead1’ o ‘perio1’] che sarà
relativo al campo che si prende in considerazione, e sono:
o Tipo: il tipo dell’array sarà campo di testo;
o Titolo: il testo, posto all’interno di t( ), sarà visualizzato come nome del campo;
o Descrizione: il testo, posto all’interno di t( ), sarà visualizzato come descrizione sotto
al campo;
o Taglia: la dimensione dei caratteri di cui sarà composto il campo di testo dove
l’utente può inserire i dati;
o Lunghezza massima: il numero dei caratteri che potrà inserire l’utente nel campo di
testo.
o Valore di default: il valore di default, modificabile dall’utente, che verrà visualizzato
nel campo ogni volta che verrà ricaricato il form (e non la pagina!!!); il
ricaricamento del form verrà fatto ogni volta si cliccherà sui bottoni “Aggiungi task”
e “Rimuovi task”, che spiegherò successivamente.
Il valore assegnato al valore di default è frutto di alcune operazioni precise, le quali
sono molto vantaggiose perchè fanno risparmiare all’utente reinserimenti ripetitivi
quindi tempo. In pratica vengono impostati come valori di default i dati,
eventualmente inseriti in precedenza (prima che il form viene ricaricato) dall’utente;
quindi l’utente non dovrà reinserirli al ricaricamento del form perché essi sono già
presenti.
Di seguito analizziamo le operazioni che vengono fatte per determinare il valore di
default:
82
Per prima cosa viene controllata, grazie all’istruzione !empty, che la
variabile $form_state[‘values’][‘comp1’ o ‘dead1’ o ‘perio1’], nella quale
eventualmente è stato inviato il relativo dato inserito dall’utente nel rispettivo
campo prima di aver cliccato su un bottone di sottomissione (nel mio caso
sono Aggiungi task, Rimuovi task e Schedula) NON sia vuota (il non è
perché davanti ad empty c’è il “ ! ”);
Grazie poi all’operatore “ ? ”:
• se questa variabile non è vuota, cioè contiene un valore inserito in
precedenza dall’utente in quel preciso campo, viene assunto come
valore di default il valore precedente (primo valore dopo i “ : ”),
contenuto nella variabile $form_state[‘values’][‘…’];
• se questa variabile è vuota, cioè l’utente in precedenza non ha inserito
nessun valore in quel preciso campo, viene assunto come valore di
default il valore di stringa vuota, cioè “ ” (secondo valore dopo i “:”).
Nota: come nome degli indici dell’array $form ho utilizzato dei nomi semplici e significativi che si
rifanno agli eventuali valori che andranno a contenere, in modo tale che anche leggendo il codice si
riesce a capire facilmente cosa essi trattano e cosa andranno a contenere. Cioè l’indice ‘task1’ vuol
dire che i valori contenuti riguardano il task1, l’indice ‘comp1’ (abbreviativo di computazione)
indica che il valore contenuto riguarda il tempo di computazione del task1, l’indice ‘dead1’
(abbreviativo di deadline) indica che il valore contenuto riguarda la deadline del task1 e l’indice
‘perio1’ (abbreviativo di periodo) indica che il valore contenuto riguarda il periodo del task1.
83
Per i task successivi al primo (vanno dal task2 al task10):
Prima di stampare a schermo i riquadri riguardanti i task dal secondo al decimo vado a fare
un controllo sulla variabile $form_state[‘storage’][‘num_task’], nella quale viene memorizzato il
numero dei task che l’utente sceglie. $form_state[‘storage’] è una variabile standard di Drupal 6
che mantiene memorizzati nella cache i dati inseriti in essa, quindi ad ogni ricaricamento del form
le informazioni che contiene vengono conservate e non vengono perse.
Il controllo fatto, con l’istruzione if, su di essa verifica che non sia vuota (!empty):
Se è vuota restituisce FALSE: vuol dire che il form è stato caricato per la prima volta, cioè
alla variabile $form_state[‘storage’][‘num_task’] non gli è stato assegnato ancora nessun
valore e perciò è vuota; quindi il blocco di istruzioni situato dentro all’if non viene eseguito
e viene mostrato solo il primo task (il quale è stato definito prima dell’if).
Se non è vuota restituisce TRUE: vuol dire che il form è già stato ricaricato una o più volte,
cioè alla variabile $form_state[‘storage’][‘num_task’] gli è stato assegnato già un valore;
quindi il blocco di istruzioni situato dentro all’if viene eseguito e vengono mostrati tanti task
quant’è il valore presente nella variabile.
Nota: il valore vuoto può essere espresso in diversi modi, tramite:
o Stringa vuota: “ ”
o Zero come stringa: “ 0 ”
o Zero come numero: 0
o NULL
o FALSE
o Un array vuoto: array( )
o Una variabile dichiarata ma senza valore: $var
Per creare gli altri riquadri successivi al primo, ho utilizzato una procedura semplificata
composta da un ciclo for, il quale crea tanti riquadri (ripete in cascata gli elementi all’interno del
ciclo) quant’è il valore numerico contenuto nella variabile $form_state[‘storage’][‘num_task’].
Utilizzo come variabile contatore la $i che viene incrementata di 1 ad ogni iterazione, essa viene
inizializzata a 2 perché se devo creare altri riquadri parto dal task2 dato che il task1 è stato creato in
precedenza. Per iterare tante volte quanti sono i task scelti dall’utente ho previsto il controllo
$i<=$form_state[‘storage’][‘num_task’], il quale fa in modo che fino a quando questa condizione
risulta verificata allora itera tutte le istruzioni contenute all’interno del ciclo for.
Gli elementi da ripetere in cascata sono il nome dell’etichetta del riquadro relativo al task i-esimo e
i rispettivi campi per l’inserimento del tempo di computazione, per l’inserimento della deadline e
per l’inserimento del periodo. Cioè saranno gli stessi elementi aventi le stesse caratteristiche (type,
title, collapside, collapsed, size, maxlenght, description, default_value) di quelli scritti ed esaminati
per il riquadro relativo al primo task. L’unica differenza che si trova in questo caso sono gli indici
degli elementi, in cui si evidenzia la presenza della variabile contatore $i; questo perché ad ogni
iterazione vado a ricreare un nuovo riquadro relativo ad uno specifico task, il quale dovrà avere una
variabile con indice differente dagli altri task:
• $form[‘task’ . $i]
ad esempio per il task2 sarà $form[‘task2’], per il task3 sarà
$form[‘task3’], ecc
ad esempio per il task2 sarà $form[‘task2’][‘comp2’], per
• $form[‘task’ . $i][‘comp’ . $i]
il task3 sarà $form[‘task3’][comp3’], ecc
84
•
•
$form[‘task’ . $i][‘dead’ . $i]
ad esempio per il task2 sarà $form[‘task2’][‘dead2’], per il
task3 sarà $form[‘task3’][dead3’], ecc
$form[‘task’ . $i][‘perio’ . $i]
ad esempio per il task2 sarà $form[‘task2’][‘perio2’], per
il task3 sarà $form[‘task3’][perio3’], ecc
Una volta creati gli elementi del form che andranno a costituire i riquadri per l’inserimento
dei parametri dei vari task restano da creare gli elementi rimanenti.
Per quanto riguarda i due tasti per aggiungere e rimuovere un riquadro sono andato a
mettere un controllo if sul valore della variabile $form_state[‘storage’][‘num_task’]; questo
permette la visualizzazione dei tasti solo se il risultato dell’if dà come esito TRUE.
Siccome da specifiche si possono avere al massimo dieci task, il controllo fa in modo che il
bottone “Aggiungi task” compaia fino a quando i task siano in numero inferiore a dieci; infatti
quando si hanno dieci riquadri l’esito dell’if è FALSE e questo fa in modo che le istruzioni
contenute al suo interno, le quali generano il bottone “Aggiungi task”, non vengano eseguite e di
conseguenza non venga visualizzato il relativo bottone. Inizialmente, quando il form viene caricato
per la prima volta, la variabile $form_state[‘storage’][‘num_task’] ha come valore di default il
valore vuoto, quindi risulta TRUE al controllo if, perché il valore vuoto può essere anche 0 e 0
risulta minore di 10.
Siccome da specifiche si può avere minimo un task, il controllo fa in modo che il bottone
“Rimuovi task” non compaia quando i task siano in numero inferiore a due; infatti quando si ha un
solo riquadro l’esito dell’if è FALSE e questo fa in modo che le istruzioni contenute al suo interno,
le quali generano il bottone “Rimuovi task”, non vengano eseguite e di conseguenza non venga
visualizzato il relativo bottone. Inizialmente, quando il form viene caricato per la prima volta, la
variabile $form_state[‘storage’][‘num_task’] ha come valore di default il valore vuoto, quindi
risulta FALSE al controllo if, perché il valore vuoto può essere anche 0 e 0 non risulta maggiore di
1.
Nel caso di questi due bottoni gli indici sono ‘aggiungi_task’ e ‘rimuovi_task’ e gli attributi sono:
Tipo di form: submit, bottone di sottomissione;
Valore: testo che verrà visualizzato sul bottone (nel mio caso sarà “Aggiungi task” e
“Rimuovi task”;
Validazione: mostra al rispettivo bottone il nome del suo gestore di convalidazione.
Quando l’utente andrà a cliccare su uno di questi due bottoni, verrà aggiunto o rimosso un task, cioè
un riquadro, dal form.
85
Ora devo creare un form che permetta all’utente di selezionare un algoritmo tra quelli
disponibili come valori del form (visualizzati nel menù a tendina che si apre una volta cliccatoci
sopra). L’indice di questo form è ‘tipo_alg’ e gli attributi sono:
Tipo di form: select, selezione di una voce presente nel menù a tendina;
Titolo: testo, visualizzato all’utente, presente vicino al form select;
Opzioni: è un array che contiene le varie voci (value) che saranno visualizzate nel menù a
tendina e quindi selezionabili dall’utente;
Valore: testo di una voce del menù a finestra, mostrato all’utente.
Infine l’ultimo form da generare è il bottone di sottomissione dell’intero form (quindi
dell’intera pagina, dato che questa pagina è composta totalmente da form). Il form che rappresenta
il bottone di submit ha come indice ‘submit’ ed i seguenti attributi:
Tipo di form: submit, bottone di sottomissione del form;
Valore: testo che verrà visualizzato sul bottone, nel mio caso “Schedula”.
La funzione algoritmi_form( ) ritorna come valore l’intero array $form[ ] dove sono
contenuti tutti gli elementi (individuati dai vari indici) che compongono il form.
Funzione algoritmi_aggiungi_task
La funzione algoritmi_aggiungi_task( ), avente come ID il nome del form stesso (algoritmi)
e il nome dell’indice del bottone di submit (aggiungi_task), contiene varie istruzioni che vengono
eseguite non appena l’utente clicca sul bottone di submit “Aggiungi task”. Cliccando su questo
bottone le istruzioni contenute nella funzione algoritmi_aggiungi_task( ) permettono di rivisualizzare il form con un riquadro in più, ovvero danno la possibilità all’utente di poter inserire
altri tre parametri relativi ad un altro task.
Gli argomenti in ingresso a questa funzione sono l’array $form, che contiene tutti i dati dei
form da visualizzare, e l’indirizzo (grazie al simbolo &, che indica il passaggio per riferimento)
dell’array $form_state.
In pratica questa funzione viene attivata ogni volta che l’utente clicca sul bottone
“Aggiungi task” ed essa:
Fa un controllo sul valore contenuto nella variabile $form_state[‘storage’][‘num_task’],
cioè controlla il numero di task che erano presenti prima che l’utente cliccasse sul bottone;
Aggiorna il valore della variabile $form_state[‘storage’][‘num_task’], inizializzandola al
valore numerico successivo rispetto a quello contenuto da essa;
86
Richiama nuovamente la funzione che costruisce il form, questo viene fatto impostando a
TRUE un'altra variabile di default di Drupal 6 cioè $form_state[‘rebuild’]; quindi il form
verrà ri-caricato solo che questa volta si avrà il valore contenuto nella variabile
$form_state[‘storage’][‘num_task’] incrementato di una unità.
Avendo trattato nella funzione algoritmi_form( ) il primo task in maniera separata da quelli
successivi, anche in questa funzione bisogna fare la stessa cosa. Questo perché nella variabile
$form_state[‘storage’][‘num_task’] l’esistenza del task1 è indicata con il valore di default vuoto
(che può essere anche lo 0), mentre l’esistenza dei task successivi è indicata con il valore numerico
proprio dei task presenti, cioè dai riquadri visualizzati nel form (cioè se vi sono due task il valore
sarà 2, se vi sono 3 task il valore sarà 3, ecc.).
Il controllo sul numero dei task presenti viene fatto con un istruzione if che verifica se la variabile
$form_state[‘storage’][‘num_task’] è vuota (grazie all’istruzione empty):
Se questa condizione risulta TRUE (quindi siamo nel caso che solo il task1 è presente) viene
eseguito il blocco di istruzioni contenuto nell’if, cioè viene aggiornata la variabile
$form_state[‘storage’][‘num_task’] inizializzandola a 2 (il numero dei riquadri è stato
aggiornato in modo tale che venga aggiunto il secondo task) e viene richiamata la funzione
che genera il form. Il risultato di queste operazioni produrrà un form che ora visualizzerà
due riquadri.
Se questa condizione risulta FALSE (quindi siamo nel caso che sono presenti altri task oltre
al task1) viene eseguito il blocco di istruzioni contenuto nell’else; questo blocco è costituito
da un costrutto switch-case, il quale in base al numero contenuto nella variabile
$form_state[‘storage’][‘num_task’] individua il valore di questa (che rappresenta il numero
di task presenti), aggiorna questo valore aumentandolo di una unità rispetto a quello presente
e richiama la funzione che genera il form. Il risultato di queste operazioni produrrà un form
che ora visualizzerà da tre fino a dieci riquadri.
Nota: la presenza del break alla fine di ogni case fa in modo che non vengano eseguiti in
cascata i case successivi a quello che verifica la condizione del valore contenuto nella
variabile $form_state[‘storage’][‘num_task’].
87
Funzione algoritmi_rimuovi_task
La funzione algoritmi_rimuovi_task( ), avente come ID il nome del form stesso (algoritmi)
e il nome dell’indice del bottone di submit (rimuovi_task), contiene varie istruzioni che vengono
eseguite non appena l’utente clicca sul bottone di submit “Rimuovi task”. Cliccando su questo
bottone le istruzioni contenute nella funzione algoritmi_rimuovi_task( ) permettono di rivisualizzare il form con un riquadro in meno.
Gli argomenti in ingresso a questa funzione sono l’array $form, che contiene tutti i dati dei
form da visualizzare, e l’indirizzo (grazie al simbolo &, che indica il passaggio per riferimento)
dell’array $form_state.
In pratica questa funzione viene attivata ogni volta che l’utente clicca sul bottone “Rimuovi
task” ed essa:
Fa un controllo sul valore contenuto nella variabile $form_state[‘storage’][‘num_task’],
cioè controlla il numero di task che erano presenti prima che l’utente cliccasse sul bottone;
Aggiorna il valore della variabile $form_state[‘storage’][‘num_task’], inizializzandola al
valore numerico precedente rispetto a quello contenuto da essa;
Richiama nuovamente la funzione che costruisce il form, questo viene fatto impostando a
TRUE un'altra variabile di default di Drupal 6 cioè $form_state[‘rebuild’]; quindi il form
verrà ri-caricato solo che questa volta si avrà il valore contenuto nella variabile
$form_state[‘storage’][‘num_task’] decrementato di una unità.
In questa funzione non è necessario trattare il primo task in maniera separata dagli altri
perché il bottone “Rimuovi task” non viene visualizzato quando si ha solo il task1, ma viene
visualizzato quando ci sono due o più task, quindi di sicuro avremo a che fare con più di un task.
Anche in questo caso però nella variabile $form_state[‘storage’][‘num_task’] l’esistenza del task1
è indicata con il valore di default vuoto (che può essere anche lo 0), mentre l’esistenza dei task
successivi è indicata con il valore numerico proprio dei task presenti, cioè dai riquadri visualizzati
nel form (cioè se vi sono due task il valore sarà 2, se vi sono 3 task il valore sarà 3, ecc.).
Il controllo sul numero dei task presenti viene fatto direttamente con il costrutto switchcase,
il
quale
verifica
il
valore
numerico
presente
nella
variabile
$form_state[‘storage’][‘num_task’] e, in base a questo numero (che rappresenta il numero di task
presenti), individua il relativo case; quest’ultimo contiene le istruzioni per aggiornare il valore
numerico diminuendolo di una unità rispetto a quello presente e richiama la funzione che genera il
form. Il risultato di queste operazioni produrrà un form che ora visualizzerà da uno fino a nove
riquadri.
Nota: la presenza del break alla fine di ogni case fa in modo che non vengano eseguiti in
cascata i case successivi a quello che verifica la condizione del valore contenuto nella variabile
$form_state[‘storage’][‘num_task’].
88
Gancio hook_validate
Il gancio hook_validate permette di validare i form, o meglio verificare la correttezza dei
valori inseriti nei form dall’utente (se i valori rispettano determinate specifiche stabilite a priori). Il
nome della funzione di validazione è l’ID della form stessa con _validate allegato ad essa, nel mio
caso algoritmi_validate( ). Poiché la funzione di convalida ha lo stesso nome della funzione che
genera i form (algoritmi), Drupal userà questa funzione di convalida automaticamente non appena il
form sarà sottomesso (submit).
La funzione ha due argomenti in ingresso:
$form: l’array del modulo del form eseguito, cioè il form appartenente ad ‘algoritmi’ che
voglio validare;
$form_state[‘values’]: l’array che contiene i valori del modulo in cui si può eseguire la
convalidazione.
Mentre non prevede nessun valore di ritorno.
Venendo alla mia funzione di validazione, per prima cosa prelevo dalla variabile standard,
prevista da Drupal 6 per il deposito dei dati, $form_state[‘storage’][‘num_task’] il numero dei task
inseriti dall’utente e memorizzo questo valore in una variabile chiamata $num_task.
Anche per questa funzione bisogna trattare il primo task in maniera separata da quelli
successivi. In questo caso la motivazione è la differenza del metodo di indicizzazione dato all’array
$form_state[‘values’] per il task1 rispetto a quelli successivi; ad esempio l’indice della variabile
contenente il tempo di computazione per il task1 è $form_state[‘values’][‘comp1’], mentre per i
task successivi al primo è $form_state[‘values’][‘comp’ . $i] dove $i è la variabile contatore che va
da 2 a 10.
Per il primo task memorizzo direttamente i tre parametri, inseriti dall’utente e inviati dopo
la sottomissione del form alla variabile di default di Drupal 6 $form_state[‘values’], nelle rispettive
variabili $c, dove memorizzo il tempo di computazione, $d, dove memorizzo la deadline relativa, e
89
$t, dove memorizzo il periodo. E su queste tre variabili che contengono i parametri del task1
verranno fatti diversi controlli per verificarne l’esistenza e la correttezza.
Per i task successivi al primo adopero un ciclo for che va da $i=2 fino al valore contenuto
nella variabile $num_task, quindi itera il blocco di istruzioni contenuto al suo interno tante volte
quant’è il numero dei task meno uno (perché il task1 è stato considerato a parte). In questo blocco
de istruzioni viene fatta la scansione di tutti i task e ad ogni iterazione memorizzo i parametri
(tempo di computazione, deadline e periodo) del task i-esimo nelle rispettive variabili $c, $d e $t;
questi valori i-esimi sono contenuti nell’array $form_state[‘values’] rispettivamente agli indici
[‘comp’ . $i], [‘dead’ . $i] e [‘perio’ . $i], quindi utilizzo il ciclo for per scorrere i valori dei
parametri dei task attraverso la variabile contatore $i. E ad ogni iterazione su queste tre variabili,
che contengono i parametri del task i-esimo, verranno fatti diversi controlli per verificarne
l’esistenza e la correttezza.
90
Vi sono diversi controlli da fare sui parametri di ciascun task.
• Sulla variabile $c che riguarda il tempo di computazione del task i-esimo:
o Controlla che la variabile $c contenga un numero intero e compreso tra 0 e 99.
Il tempo di computazione deve essere espresso in millisecondi ed essi devono
appartenere all’insieme dei numeri interi, inoltre il loro valore deve essere compreso
tra 0 e 99.
Per prima cosa, controllo che il valore di $c non sia un numero intero
(if(!is_numeric($c)) ), e se la condizione non è verificata, con l’istruzione
form_set_error, visualizzo all’utente il tipo di errore che ha commesso
nell’inserimento dei dati e a quale particolare valore faccio riferimento; blocco poi il
submit del form.
Successivamente, appurato quindi che il valore inserito è un numero intero, controllo
se il numero in questione non è compreso tra 0 e 99 ( if($c<0 && $c>99) ) e se la
condizione non è verificata, quindi con l’istruzione form_set_error visualizzo
all’utente il tipo di errore che ha commesso nell’inserimento dei dati e a quale
particolare valore faccio riferimento; blocco poi il submit del form.
o Controlla che la variabile $c sia minore della variabile $t.
Il tempo di computazione del task i-esimo deve essere per forza minore del periodo
del task i-esimo; se così non fosse il task andrebbe in overflow già in partenza,
perché finirebbe sempre il periodo e mai la computazione.
In questo caso verifico che il tempo di computazione del task i-esimo, contenuto in
$c, sia maggiore del periodo del task i-esimo, contenuto in $t, se ciò accade il task va
in overflow a priori e quindi devo segnalare all’utente un errore di inserimento nei
dati. Quest’errore come sempre viene segnalato grazie all’istruzione
form_set_error, che inoltre blocca anche la sottomissione del form.
o Controlla che la variabile $c sia minore della variabile $d.
Il tempo di computazione del task i-esimo deve essere per forza minore della
deadline del task i-esimo; se così non fosse il task andrebbe in overflow già in
partenza, perché finirebbe sempre prima la deadline della computazione.
In questo caso verifico che il tempo di computazione del task i-esimo, contenuto in
$c, sia maggiore rispetto alla deadline del task i-esimo, contenuta in $d, se ciò
accade il task va in overflow a priori e quindi devo segnalare all’utente un errore di
91
inserimento nei dati. Quest’errore come sempre viene segnalato grazie all’istruzione
form_set_error, che inoltre blocca anche la sottomissione del form.
•
Sulla variabile $d che riguarda la deadline del task i-esimo:
o Controlla che la variabile $d contenga un numero intero e compreso tra 0 e 99.
La deadline deve essere espresso in millisecondi ed essi devono appartenere
all’insieme dei numeri interi, inoltre il loro valore deve essere compreso tra 0 e 99.
Per prima cosa, controllo che il valore di $d non sia un numero intero
(if(!is_numeric($d)) ) e se la condizione non è verificata, con l’istruzione
form_set_error, visualizzo all’utente il tipo di errore che ha commesso
nell’inserimento dei dati e a quale particolare valore faccio riferimento; blocco poi il
submit del form.
Successivamente, appurato quindi che il valore inserito è un numero intero, controllo
se il numero in questione non è compreso tra 0 e 99 ( if($d<0 && $d>99) ) e se la
condizione non è verificata, con l’istruzione form_set_error visualizzo all’utente il
tipo di errore che ha commesso nell’inserimento dei dati e a quale particolare valore
faccio riferimento; blocco poi il submit del form.
•
Sulla variabile $t che riguarda il periodo del task i-esimo:
o Controlla che la variabile $t contenga un numero intero e compreso tra 0 e 99.
Il periodo deve essere espresso in millisecondi ed essi devono appartenere
all’insieme dei numeri interi, inoltre il loro valore deve essere compreso tra 0 e 99.
Per prima cosa, controllo che il valore di $t non sia un numero intero
(if(!is_numeric($t)) ) e se la condizione non è verificata, con l’istruzione
form_set_error, visualizzo all’utente il tipo di errore che ha commesso
nell’inserimento dei dati e a quale particolare valore faccio riferimento; blocco poi il
submit del form.
Successivamente, appurato quindi che il valore inserito è un numero intero, controllo
se il numero in questione non è compreso tra 0 e 99 ( if($t<0 && $t>99) ) e se la
condizione non è verificata allora, con l’istruzione form_set_error, visualizzo
all’utente il tipo di errore che ha commesso nell’inserimento dei dati e a quale
particolare valore faccio riferimento; blocco poi il submit del form.
Funzione algoritmi_submit
La funzione algoritmi_submit( ) contiene le istruzioni ed il codice principale di tutto il
modulo. Infatti, questa funzione, in base all’algoritmo selezionato ed ai parametri inseriti
dall’utente, compie le operazioni di scheduling dei task.
Come prima cosa, grazie all’istruzione drupal_set_message, visualizzo all’utente un
messaggio per informarlo che il form è stato sottomesso correttamente, cioè che i dati inseriti e
selezionati dall’utente sono corretti e sono stati inviati al server per essere elaborati.
Sapendo che i valori dei dati inseriti dall’utente nei form vengono raccolti nell’array
$form_state[‘values’], per ricavare un determinato valore di un elemento del form basta riferirsi al
92
nome che si è dato a quel preciso elemento, quindi basta scrivere esplicitamente il secondo indice
(l’indice deve essere il nome di un elemento dell’array $form) nell’array $form_state.
Dopo questo messaggio iniziale, bisogna andare a vedere quale algoritmo di scheduling è
stato selezionato dall’utente, in modo tale da sapere a quali parametri dare la priorità e quali
istruzioni compiere per l’elaborazione dei task. Il valore della SELECT “Tipo algoritmo”
selezionato dall’utente viene raccolto nell’array $form_state[‘values’][‘tipo_alg’], dove ‘tipo_alg’
è l’indice dell’array $form che costruisce la SELECT “Tipo algoritmo”. Per sapere quindi quale
algorirmo l’utente ha selezionato tra quelli disponibili nella SELECT basta fare un controllo con
l’istruzione if, cioè se il valore contenuto nella variabile $form_state[‘values’][‘tipo_alg’] è uguale
a ‘EDF’ allora l’utente ha selezionato l’algoritmo di scheduling EDF se invece è uguale a ‘RM’
allora l’utente ha selezionato l’algoritmo RM. A seconda dell’algoritmo scelto verranno eseguite
differenti istruzioni per elaborare i dati.
Siccome il linguaggio C, come detto prima, è molto simile al linguaggio PHP, i
ragionamenti illustrati in precedenza per il C sono identici a quelli da fare in PHP e il codice scritto
in C e spiegato precedentemente viene riportato in PHP quasi identicamente nel nostro file .module.
Di seguito verranno spiegate solamente le parti che si differenziano dagli algoritmi scritti in C.
Il primo passo da compiere è quello della raccolta dei dati.
Inizialmente viene fatto un controllo, con l’istruzione if, per verificare se la variabile
$form_state[‘storage’][‘num_task’] non è vuota:
Se l’esito è TRUE allora la variabile contiene un valore numerico che va da 2 a 10 (il taskset è composto anche dai task successivi al task1); il valore di questa variabile viene
memorizzato in un'altra variabile chiamata, per comodità, $num_task.
Se l’esito è FALSE allora la variabile contiene un valore vuoto, può essere anche lo 0, (il
task-set è composto solo dal task1); la variabile $num_task viene inizializzata con il valore
numerico 1, ad indicare la presenza di un solo task. (Nota: non posso memorizzare in
$num_task il valore contenuto da $form_state[‘storage’][‘num_task’] perché il valore
vuoto, che può essere anche 0, è diverso dal valore 1; e per sviluppare gli algoritimi di
scheduling bisogna tener conto del numero effettivo di task che compongono il task-set).
Quindi la variabile $num_task andrà a contenere il valore che indica il numero dei task che
compongono il task-set.
Successivamente nell’array bidimensionale $task vado a memorizzare i parametri di tutti i
task inseriti dall’utente, quest’array ha come indici:
[$i]: è il primo indice ed indica il task i-esimo preso in considerazione;
[‘c’] o [‘d’] o [‘t’]: è il secondo indice ed indica rispettivamente o il tempo di computazione
o la deadline relativa o il periodo, cioè i parametri del task i-esimo.
93
Anche in questo caso, siccome nel form gli indici del task1 sono stati definiti in maniera
separata dagli indici dei task successivi, è necessario scindere in task1 dai task successivi ad esso.
Per tener conto di tutti i task e di tutti i loro parametri è stato creato un array bidimensionale
chiamato $task e avente la seguente sintassi: $task[‘posizione_task’][‘parametro_task’].
Quindi i tre parametri del task1, inseriti dall’utente nel primo riquadro del form, vengono
memorizzati nell’array bidimensionale $task avente come indice il numero 0 (perché negli array
l’indice parte da 0 e non da 1). Questo mi permette:
• di memorizzare nell’elemento con indice [0] e indice [‘c’] dell’array associativo $task il
valore del tempo di computazione del task1 inserito dall’utente nel form che è contenuto
nell’elemento dell’array $form_state aventi indici [‘values’] e [‘comp1’];
• di memorizzare nell’elemento con indice [0] e indice [‘d’] dell’array associativo $task il
valore della deadline relativa del task1 inserito dall’utente nel form che è contenuto
nell’elemento dell’array $form_state aventi indici [‘values’] e [‘dead1’];
• di memorizzare nell’elemento con indice [0] e indice [‘t’] dell’array associativo $task il
valore del tempo periodo del task1 inserito dall’utente nel form che è contenuto
nell’elemento dell’array $form_state aventi indici [‘values’] e [‘perio1’].
Anche i tre parametri di ogni task successivo al task1, inseriti dall’utente nei vari riquadri
del form, vengono memorizzati tutti nell’array bidimensionale $task grazie ad un ciclo for che itera
l’array $task[$i], dove $i è la variabile contatore ed il ciclo parte da $i=1 e itera tante volte quant’è
il valore contenuto in $num_task meno uno (perché il task1 è trattato a parte), in modo tale che i tre
parametri corrispondenti al task i-esimo vengono memorizzati correttamente nel task i-esimo.
Questo mi permette:
• di memorizzare nell’elemento con indice i-esimo [$i] e indice [‘c’] dell’array associativo
$task il valore del tempo di computazione del task i-esimo inserito dall’utente nel form che
è contenuto nell’elemento i-esimo dell’array $form_state aventi indici [‘values’] e [‘comp’ .
$i];
• di memorizzare nell’elemento con indice i-esimo [$i] e indice [‘d’] dell’array associativo
$task il valore della deadline relativa del task i-esimo inserito dall’utente nel form che è
contenuto nell’elemento i-esimo dell’array $form_state aventi indici [‘values’] e [‘dead’ .
$i];
• di memorizzare nell’elemento con indice i-esimo [$i] e indice [‘t’] dell’array associativo
$task il valore del tempo periodo del task i-esimo inserito dall’utente nel form che è
contenuto nell’elemento i-esimo dell’array $form_state aventi indici [‘values’] e [‘perio’ .
$i].
In sintesi l’array $task[0] con indice ‘0’ conterrà i tre parametri del task1, $task[1] con
indice ‘1’ conterrà i tre parametri del task2, $task[2] con indice ‘2’ conterrà i tre parametri del
task3, …, $task[9] con indice ‘9’ conterrà i tre parametri del task10.
94
Con questi passaggi sono andato a raccogliere tutti i dati inseriti nel form dall’utente, ma
mancano ancora alcune variabili da dichiarare e da definire per poter iniziare l’algoritmo vero e
proprio.
Per rispettare i ragionamenti e le operazioni fatte per il linguaggio C anche qui vado ad
aggiungere, grazie al ciclo for, altri due elementi all’array $task. Questi elementi, aventi indice
[‘num_comp’] e [‘ready’], assumono lo stesso significato e lo stesso ruolo assunto in precedenza
per il C; il primo tiene conto delle computazioni terminate dal task i-esimo (ecco perché
inizialmente viene inizializzato a 0), il secondo tiene conto della presenza del task i-esimo nella
ready queue (inizialmente viene messo ad 1, che indica la presenza del task nella ready queue,
mentre 0 indica l’assenza del task i-esimo nella ready queue).
In questo modo ora l’array bidimensionale $task[ ][ ] del PHP ha la stessa struttura dell’array
bidimensionale task[ ][ ] del C. L’unica differenza è che mentre in C gli indici devono essere per
forza numeri che vanno da 0 a n-1, in PHP gli indici possono essere anche stringhe qualsiasi; di
seguito elenco la corrispondenza degli indici dal C al PHP per una maggiore comprensione:
i $i (il primo indice è una variabile)
0 ‘c’ (il secondo indice è una precisa costante)
1 ‘d’
2 ‘t’
3 ‘num_comp’
4 ‘ready’
Dopo la creazione dell’array $task vado a dichiarare e definire (come fatto in C) le altre
variabili che verranno utilizzate per la codifica dell’algoritmo. Queste variabili sono:
$secondi=0: definizione della variabile che porterà il conto di ogni secondo che passa
dall’inizio dell’algoritmo di scheduling fino alla fine di questo (parto da 0 secondi);
$overflow=0: definizione del flag che eventualmente fermerà il ciclo iterativo while
(contenente le istruzioni dell’algoritmo) se il valore di questo flag sarà uguale a 1, in caso
contrario il ciclo while continuerà ad iterare le istruzioni contenute in esso (all’inizio nessun
task è in overlfow, quindi pongo 0 come valore);
$min_task: dichiarazione della variabile che conterrà la posizione del task i-esimo avente
deadline assoluta minore (in EDF) o periodo minore (in RM);
95
$min_dead (in EDF): variabile che conterrà il valore della deadline assoluta minore tra tutte
quelle dei task presenti nella ready queue;
$min_perio (in RM): variabile che conterrà il valore del periodo minore tra tutti quelli dei
task presenti nella ready queue;
$scheduling_array: dichiarazione dell’array di scheduling.
Mi soffermo a spiegare in maniera più approfondita l’array $scheduling_array dato che
questo è la vera e propria novità del PHP rispetto al codice C. La motivazione che mi ha spinto a
dichiarare questo array sta nella necessità di tener conto del task specifico che computa in un
preciso secondo di tempo, ecco anche perchè l’unico indice dell’array è la variabile $secondi. In
questo array quindi verrà memorizzato il task i-esimo che computa (occupa la CPU) in quel preciso
secondo, perciò come ad ogni iterazione la variabile $secondi aumenta di 1 (il tempo passa) anche
l’array $scheduling_array ad ogni iterazione assumerà il valore della posizione del task avente
priorità maggiore. Detto questo è di facile intuizione che quando l’indice $secondi è uguale a 0
anche il valore di $scheduling_array è 0, dato che nessun task computa nell’istante 0.
Siccome anche qui c’è la possibilità che tutti i task inseriti dall’utente finiscano le loro
computazioni prima dell’inizio del loro prossimo periodo, quindi che la CPU resti inutilizzata per
alcuni secondi, bisogna tenere conto anche di questo caso. Quindi nell’array $task inserisco anche
un task aggiuntivo per tener conto dei tempi morti della CPU (è come un task invisibile); questo
task per non essere mai selezionato dall’algoritmo deve avere un tempo di computazione, una
deadline relativa e un periodo molto maggiore rispetto ai task e, inoltre, deve avere per ipotesi il
numero di computazioni=0 ed essere sempre presente nella ready queue quindi flag ready=1.
Siccome gli elementi di un array partono dall’indice 0 (i=0 corrisponde al task1, i=1 al task2,…)
l’ultimo task inserito dall’utente corrisponde all’indice $num_task-1, quindi l’indice che avrà il
“task per i tempi morti” sarà $num_task.
Infine, prima di procedere con l’elaborazione vera e propria dell’algoritmo, vado a creare
anche qui l’array $ready_queue. In PHP, a differenza del C, posso copiare tutti i valori di un array
in un altro array semplicemente uguagliandolo.
96
Con il ciclo while inizia l’algoritmo di scheduling vero e proprio. Qui quasi tutti i
ragionamenti e, di conseguenza, tutte le istruzioni sono identiche a quelle fatte per il linguaggio C.
L’algoritmo EDF dà la priorità al task avente deadline assoluta minore:
Per l’algoritmo RM dà la priorità al task avente periodo minore:
Le uniche differenze evidenti sono dovute alla presenza delle istruzioni che riguardano
l’array $scheduling_array, quindi di seguito andrò a descrivere solo queste.
$scheduling_array[$secondi] = $min_task+1
Quest’istruzione memorizza nell’array $scheduling_array, secondo per secondo, il numero
che identifica la posizione del task con priorità maggiore, occupata nell’array $task, che ha
computato in quel determinato secondo (metto $min_task+1 perché gli array partono
dall’indice 0).
Quest’istruzione è posizionata subito dopo che è stato scelto il task con maggiore priorità e
che quest’ultimo ha computato, quindi nel blocco che riguarda la computazione del task.
Nota: se in quel preciso secondo nessun task ha computato (perché nessuno è presente nella
ready queue) nell’array $scheduling_array viene memorizzata la posizione del “task
invisibile” con priorità maggiore (è l’unico task presente nella ready queue), occupata
nell’array $task, che tiene conto dei tempi morti, questo viene automaticamente fatto con la
stessa istruzione grazie al fatto di aver posto inizialmente nell’array $task la presenza di un
altro task, appunto il “task invisibile”.
97
$scheduling_array[$secondi+1] = $i+1
Quest’istruzione memorizza nell’array $scheduling_array, al secondo successivo dell’ultima
computazione ($secondi+1), la posizione del task i-esimo, occupata nell’array $task, che va
in overflow (metto $i+1 perché gli array partono dall’indice 0).
Quest’istruzione è posizionata nel blocco dove c’è il controllo di overflow su tutti task
presenti nella ready queue. Considero il secondo successivo all’ultima computazione perché
nel secondo corrente avviene l’ultima computazione e quando si verifica l’overflow di un
task il ciclo while viene interrotto (grazie al flag $overflow=1) quindi i secondi non
avanzano più e non ci sono più computazioni.
Devo tener conto del task i-esimo che va in overflow in modo tale che successivamente, nel
diagramma di Gantt, posso evidenziarlo con un colore diverso rispetto a quello dei task che
computano (vedi specifiche).
Successivamente, nella funzione algoritmi_schedula( ) è presente una chiamata alla
funzione crea_gantt( ), la quale, in base agli argomenti passategli in ingresso, genera un digramma
di Gantt che visualizza graficamente all’utente i risultati dell’elaborazione dell’algoritmo di
scheduling selezionato. Gli argomenti passati alla funzione crea_gantt( ) sono: l’array
$scheduling_array, la variabile $secondi, la variabile $num_task e l’array $task.
Nota: $scheduling_array[$secondi] contiene la posizione del task i-esimo, occupata
nell’array $task, che computa nell’ultima iterazione del ciclo while; mentre
$scheduling_array[$secondi+1] contiene la posizione del task i-esimo, occupata nell’array $task,
che va in overlflow, questa posizione viene memorizzata al secondo successivo dopo la
terminazione del ciclo while.
98
Una volta che la funzione crea_gantt( ) è terminata, cioè ha generato e salvato il diagramma
di gantt in un file immagine, devo poter visualizzare quest’immagine caricandola da questo file
chiamato “diagramma.png”(Drupal non può visualizzare le immagini direttamente da codice PHP).
L’istruzione print permette proprio di richiamare (quindi di caricare) e di visualizzare a schermo il
contenuto di un file immagine. Il parametro da passare a quest’istruzione è semplicemente il
percorso e il nome del file immagine che si vuole visualizzare.
Creazione del file crea_gantt.php
Nozioni principali sulla libreria GD del PHP
Prima di passare alla spiegazione della funzione crea_gantt( ) da me realizzata, vado a fare
un introduzione dei concetti generali e delle funzioni principali della libreria GD, dato che ho creato
la mia funzione basandomi proprio su questa libreria.
La libreria GD serve per la creazione di immagini tramite codice PHP. Le librerie GD sono
infatti in grado di creare tramite semplice codice PHP numerosi tipi di immagini, quali jpeg, png,
tiff, ecc. Il supporto al formato gif è stato recentemente abolito, in quanto si tratta di un formato
proprietario della Sun, mentre le librerie GD sono open source. Dalla versione 2.0.28 tale supporto
è stato però ripristinato, e dalla versione 2.0.32 le librerie GD hanno anche la possibilità di creare
gif animate.
L'utilità di questa libreria è enorme, basti pensare alla creazione di grafici o report in tempo reale,
analizzando i dati da un database o inseriti da un utente tramite form.
Per prima cosa bisogna assicurarsi che sul server la libreria GD sia installata: basta
controllare che ci sia tra le librerie disponibili. Per fare ciò bisogna scrivere:
<?php
phpinfo( );
>
e salvare il file php. Quando eseguite questo file avrete una tabella con tutte le caratteristiche del
web server, di php e delle librerie disponibili.
Oppure per controllare che siano presenti nella versione PHP installato sul server basta
verificare che nella cartella C:/Programmi(x86)/phpDesigner/PHP/ext (extensions) ci siano i due
file php_gd.dll e/o php_gd2.dll.
Istruzioni basilari per la preparazione di un foglio da disegno
Istruzione: imagecreate
È un’istruzione che crea un foglio da disegno bianco su cui disegnare successivamente,
cioè si va a creare la “base” per l’immagine. Su di esso si potrà disegnare utilizzando le
funzioni fornite da PHP di interfaccia verso la libreria GD.
99
Istruzione: imagecreatetruecolor
Prepara un foglio da disegno bianco su cui disegnare.
Scrivendo ad esempio:
<?php
$immagine= imagecreatetruecolor (200,100);
?>
viene creato un foglio di disegno che in orizzontale, ovvero sull’asse x, è lungo 200 pixel (cioè 200
punti luminosi elementari che costituiscono il disegno); mentre in verticale, sull’asse y, è di 100
pixel. I pixel si contano partendo dal punto superiore sinistro dello schermo, che ha coordinate x=0
ed y=0; inoltre l'asse x in orizzontale è orientato verso destra, mentre l'asse y verticale è orientato
verso il basso, cioè più aumentano i pixel sull’asse x e più ci si sposta in orizzontale verso destra
mentre più aumentano i pixel sull’asse y e più ci si sposta in verticale verso il basso. Questo foglio
di disegno viene memorizzato in una variabile chiamata $immagine.
Questo foglio da disegno viene disegnato nella memoria del server e non è quindi visibile
all'utente; infatti, se viene eseguito non si vedrà niente. Per poterlo vedere occorre utilizzare
l’istruzione: header; quest’istruzione è un pò delicata, in quanto essa deve essere la prima
istruzione ad apparire nella pagina, non vi devono essere nemmeno spazi vuoti o altre scritte prima
del suo uso, altrimenti non si vede niente; perché questa invia al browser un’intestazione che
specifica che si tratta di un’immagine. Senza questa informazione il browser considererebbe i dati
come codice HTML, e l'immagine non sarebbe interpretata come tale. Non si può nemmeno usare il
tag iniziale <html>, altrimenti non funziona. L’istuzione header indica il formato che assumerà il
disegno. Modificando, ora il codice scritto in precedenza nel modo seguente:
<?php
$immagine= imagecreatetruecolor (200,100);
header ("Content-type: image/png");
?>
In quest’esempio l’istruzione header indica che il disegno sarà in formato png; si possono anche
utilizzare altri formati come quello gif: header ("Content-type: image/gif");
però esso non funziona con le librerie php_gd2.dll ma solo con le librerie php_gd.dll
oppure il formato jpeg: header ("Content-type: image/jpeg");
che funziona con entrambe le librerie.
Infine ci serve un’istruzione image che mostri qual è il disegno vero e proprio che si è creato
in memoria e lo restituisce al browser che provvede a stamparlo a schermo.
- Per esempio: imagepng ($immagine);
mostra sullo schermo un disegno in formato png che si trova in memoria nella variabile $immagine;
- Invece: imagejpeg ($immagine);
mostra sullo schermo un disegno in formato jpeg che si trova in memoria nella variabile
$immagine;
- Infine: imagegif ($immagine);
mostra sullo schermo un disegno in formato gif che si trova in memoria nella variabile $immagine.
100
Dopo quest’introduzione, si può facilmente dedurre che il seguente programma mostrerà
all’utente il foglio nero da disegno vuoto e pronto per essere riempito di dimensioni 200x100 pixel e
in formato png:
<?php
$immagine= imagecreatetruecolor (200,100);
header ("Content-type: image/png");
imagepng ($immagine);
?>
Salvando il programma col nome di: disegno1.php ed eseguendolo (aprendo il file con un browser)
si ottiene:
I colori
Per i colori si usa lo standard RGB, cioè i tre colori rosso, verde, blu. Mediante le
combinazioni esadecimali dei tre colori fondamentali si ottengono tutti i 16 milioni di colori, cioè
16.581.375. Ricordiamo per inciso che un colore in esadecimale si indica con, ad esempio,
#FFBB00. Dove i caratteri raggruppati a due a due corrispondono ai valori delle componenti RGB:
quindi FF è il valore esadecimale per il rosso, BB per il verde e 00 per il blu.
La funzione da utilizzare per definire un colore è: imagecolorallocate. A questa funzione
deve essere passata l’immagine (nel nostro caso contenuta nella variabile $immagine), creata
precedentemente con imagecreate( ), e i valori esadecimali corrispondenti ai colori RGB. Questa
funzione restituisce un intero che identifica il colore. Questo intero può essere memorizzato in una
vaiabile e passato ad altre funzioni per disegnare oggetti o testo di quel dato colore.
-
Scrivendo: $colore = imagecolorallocate ($immagine, 255, 255, 255);
I valori da dare per ciascuno dei tre colori variano da 0 fino a 255; avendo messo:
Rosso=255; Verde= 255; blu = 255; otterremo il colore bianco.
-
Scrivendo: $colore2 = imagecolorallocate ($immagine, 0, 0, 0);
otteniamo il colore nero.
-
Scivendo: $colore3 = imagecolorallocate ($immagine, 255, 0, 0);
otteniamo il colore rosso.
101
-
Scrivendo: $colore4 = imagecolorallocate ($immagine, 0, 0, 255);
otteniamo il colore blu, e così via.
I colori vengono salvati nelle rispettive variabili da noi scelte a piacere ($colore, $colore2,
ecc.) e potranno essere usati in ogni momento quando vi è la necessità.
Disegnare una linea
La funzione per disegnare una linea è: imageline. Se si scrive:
imageline ($immagine, 10, 20, 100, 50, $colore);
la funzione imageline disegna sull’immagine, contenuta nella variabile $immagine, che si trova in
memoria, una linea che parte da due punti; i punti vanno messi nell'ordine con la rispettiva x ed y;
nel nostro caso:
x1 = 10;
y1 = 20;
x2 = 100;
y2 = 50.
Infine, come ultimo parametro da passare a questa funzione, ci sarà una variabile (nel nostro caso
$colore), nella quale è stato memorizzato in valori esadecimali un colore che poi sarà quello assunto
dalla linea.
Scrivendo il seguente listato, salvandolo come disegno2.php ed eseguendolo si ottiene una
linea rossa:
<?php
$immagine = imagecreatetruecolor (200,100);
$colore = imagecolorallocate ($immagine, 255, 0, 0);
imageline ($immagine, 10, 20, 100, 50, $colore);
header ("Content-type: image/png");
imagepng ($immagine);
?>
Liberare spazio in memoria
La creazione di immagini occupa dello spazio in memoria che è opportuno liberare usando
la funzione: imagedestroy. Scrivendo:
imagedestroy ($immagine);
102
viene liberato lo spazio di memoria occupato dalla variabile $immagine; questo normalmente
viene fatto alla fine del disegno, quando oramai si presuppone che la variabile non serva più.
Disegnare un rettangolo
L’istruzione utilizzata per creare un rettangolo è: imagerectangle. Scrivendo:
imagerectangle ($immagine, 20,20, 180, 80, $colore);
viene disegnato un rettangolo vuoto in base alla coordinate di due vertici, quello superiore sinistro
(nel nostro esempio quello con x1=20 ed y1 = 20) e quello inferiore destro (nel nostro esempio
quello con x2=180 ed y2 = 80).
Un esempio di listato per il rettangolo sarà:
<?php
$immagine = imagecreatetruecolor (200,100);
$colore = imagecolorallocate ($immagine, 255, 0, 0);
imagerectangle ($immagine, 20,20, 180, 80, $colore);
header ("Content-type: image/png");
imagepng ($immagine);
imagedestroy ($immagine);
?>
Salvandolo con il nome di disegno3.php ed eseguendolo possiamo notare che il rettangolo di
contorno rosso è vuoto all’interno, cioè è stato disegnato solo il perimetro.
Volendo riempire il rettangolo tutto di colore dobbiamo aggiungere “filled” all’istruzione
imagerectangle, cioè:
imagefilledrectangle ($immagine, 20,20, 180, 80, $colore);
Salvandolo col nome di disegno4.php ed eseguendolo si ottiene un rettangolo tutto rosso sul foglio
nero iniziale.
103
Scrivere un testo
Per scrivere un testo si utilizza la funzione imagestring, la quale mi disegna su un immagine
un testo in orizzontale.
Aggiungendo al listato precedente:
imagestring ($immagine, 4, 60, 82, "RETTANGOLO", $colore);
ottenendo il seguente codice:
<?php
$immagine = imagecreatetruecolor (200,100);
$colore = imagecolorallocate ($immagine, 255, 0, 0);
$colore2 = imagecolorallocate ($immagine, 255, 255, 255);
imagefilledrectangle ($immagine, 20,20, 180, 80, $colore);
imagestring ($immagine, 4, 60, 82, "RETTANGOLO", $colore2);
header ("Content-type: image/png");
imagepng ($immagine);
imagedestroy ($immagine);
?>
Salvandolo come disegno5.php ed eseguendolo si ottiene il disegno precedente (rettangolo tutto
rosso) con in aggiunta la scritta RETTANGOLO di colore bianco (memorizzato nella variabile
$colore) e avente dimensione 4 e coordinate x1=60 e y1=82.
104
Il primo numero (cioè nell’esempio 4) indica la dimensione del carattere (font) che va da 1,
carattere molto piccolo a 5, carattere molto grande.
Gli altri due numeri rappresentano nell'ordine le coordinate iniziali x1 e y1 in cui scrivere il testo
(nell’esempio x1=60 ed y1 = 82), cioè la posizione del testo dall’angolo superiore sinistro
dell’immagine.
Successivamente viene scritto il testo da visualizzare tra virgolette oppure una variabile che
contiene del testo.
Infine vi è la variabile che contiene il colore del testo che verrà visualizzato.
Tuttavia questa funzione è un pò “primitiva”. È molto più conveniente utilizzare
imagettftext( ), che permette di definire più parametri, come ad esempio la rotazione, e utilizzare i
font TrueType. Inoltre con la funzione imagettfbbox( ) è possibile conoscere le dimensioni del box
entro il quale il testo sarà scritto prima di disegnarlo: ciò è molto utile nel caso in cui si voglia ad
esempio effettuare in tempo reale alcuni test per definire la dimensione massima di un dato testo
affinchè questo rimanga entro certi limiti di dimensioni.
Disegnare una circonferenza e un cerchio
L’istruzione per disegnare un cerchio vuoto, cioè una circonferenza è: imagearc.
Scrivendo ad esempio:
imagearc ($immagine, 100, 50, 60, 60, 0, 360, $colore3);
I primi due numeri indicano le coordinate del centro della circonferenza (nel nostro caso: x1=100 ed
y1 = 50).
La seconda coppia di numeri indica la larghezza in orizzontale e in verticale (nel nostro caso
larghezza=60 ed altezza=60); essendo questi due valori uguali si ottiene una circonferenza, ma se
invece sono diversi quello che si ottiene sarà un’ellisse.
L’ultima coppia di numeri riguarda i gradi di rotazione, cioè da 0° fino a 360°; se si vuole disegnare
tutta la circonferenza si dovranno mettere come valori 0 e 360, mentre se si vuole disegnare solo un
arco, cioè una parte della circonferenza basta decidere liberamente questi due valori (l’importante è
che la rotazione non venga chiusa).
Infine bisogna scegliere il colore della figura inserendo come ultimo parametro una variabile che
contiene il valore di un colore (nel nostro caso $colore3).
Il listato sarà:
<?php
$immagine = imagecreatetruecolor (200,100);
$colore = imagecolorallocate ($immagine, 255, 0, 0);
$colore2 = imagecolorallocate ($immagine, 255, 255, 255);
$colore3 = imagecolorallocate ($immagine, 0,0, 255);
105
imagefilledrectangle ($immagine, 20,20, 180, 80, $colore);
imagearc ($immagine, 100, 50, 60, 60, 0, 360, $colore3);
imagestring ($immagine, 4, 0, 83, "Rettangolo e circonferenza", $colore2);
header ("Content-type: image/png");
imagepng ($immagine);
imagedestroy ($immagine);
?>
Salvandolo come disegno6.php ed eseguendolo verranno visualizzati una circonferenza blu inscritta
in un rettangolo pieno rosso e una scritta “Rettangolo e circonferenza” di colore bianco, il tutto
sullo sfondo di disegno nero.
Nota: la lettera “a” di “circonferenza” non viene visualizzata perché le dimensioni della
stringa di testo e la lunghezza di questa risultano maggiori rispetto allo sfondo nero stabilito su cui
ci si può disegnare.
Mentre l’istruzione per disegnare un cerchio pieno è: imagefilledarc. Scrivendo quindi ad
esempio:
imagefilledarc ($immagine, 100, 50, 60, 60, 0, 360, $colore3, IMG_ARC_PIE);
I primi due numeri indicano le coordinate del centro del cerchio (nel nostro caso: x1=100 ed y1 =
50).
La seconda coppia di numeri indica la larghezza in orizzontale e in verticale (nel nostro caso
larghezza=60 ed altezza=60); essendo questi due valori uguali si ottiene un cerchio, ma se invece
sono diversi quello che si ottiene sarà un’ellisse piena.
L’ultima coppia di numeri riguarda i gradi di rotazione, cioè da 0° fino a 360°; se si vuole disegnare
tutto il cerchio si dovranno mettere come valori 0 e 360, mentre se si vuole disegnare solo un arco,
cioè una parte del cerchio basta decidere liberamente questi due valori (l’importante è che la
rotazione non venga chiusa).
Successivamente bisogna scegliere il colore della figura inserendo come ultimo parametro una
variabile che contiene il valore di un colore (nel nostro caso $colore3).
L'ultimo argomento della funzione può essere:
- IMF_ARC_PIE per disegnare un cerchio o semicerchio pieno;
- IMF_ARC_CHORD per disegnare un semicerchio pieno con la corda che unisce i due
raggi (settore circolare pieno);
- IMF_ARC_NOFILL | IMF_ARC_EDGED per disegnare un semicerchio vuoto, con i
due raggi ai bordi.
106
Scrivendo a titolo di esempio il listato seguente, salvandolo come disegno7.php ed eseguendolo si
ottiene:
<?php
$immagine = imagecreatetruecolor (500,200);
$colore = imagecolorallocate ($immagine, 255, 0, 0);
$colore2 = imagecolorallocate ($immagine, 255, 255, 255);
$colore3 = imagecolorallocate ($immagine, 0,0, 255);
imagefilledarc($immagine, 100, 100, 100, 100, 0, 270, $colore3,IMG_ARC_PIE);
imagefilledarc($immagine, 200, 100, 100, 100, 0, 270, $colore3,IMG_ARC_CHORD);
imagefilledarc($immagine, 350, 100, 100, 100, 0, 270, $colore3,
IMG_ARC_NOFILL|IMG_ARC_EDGED);
header ("Content-type: image/png");
imagepng ($immagine);
imagedestroy ($immagine);
?>
Come ultimo appunto vado a citare per completezza altre due funzioni:
imagepolygon( ): disegna un qualsiasi altro poligono vuoto;
imagefilledpolygon( ): disegna un qualsiasi altro poligono pieno.
File crea_gantt.php
Come detto precedentemente, ho creato la funzione crea_gantt( ) basandomi principalmente
sulla libreria GD e sulle istruzioni messe a disposizione da essa. Di seguito andrò a spiegare, blocco
per blocco, il codice da cui è composto questa funzione.
Nella parte iniziale del codice viene definito il nome della funzione e le variabili che
dovranno essere passate come argomento alla funzione. Subito dopo, prima di iniziare le operazioni
107
vere e proprie della funzione, vengono fatti dei controlli sulle variabili passate come argomento
per verificarne la coerenza. Questo controllo, fatto attraverso l’istruzione if, interrompe la funzione
e ritorna il valore booleano FALSE anche se una sola delle condizioni contenute dall’if è rispettata:
!isset($sceduling_array): verifica se l’array non è stato definito;
empty($scheduling_array): verifica se l’array è vuoto;
$num_task>10: verifica se il numero contenuto all’interno della variabile è maggiore di 10.
Fatto questo si potrà passare alla fase relativa della creazione dell’immagine che conterrà i
dati. Per fare questo verrà utilizzata la funzione imagecreatetruecolor( ), la quale ha il compito di
creare una “tela” la cui dimensione viene stabilita sulla base di due semplici coordinate numeriche
separate da una virgola (nel mio caso altezza=700 pixel e larghezza=350 pixel).
La fase successiva sarà quella dedicata alla definizione dei colori che andranno a
caratterizzare i diversi elementi del grafico. Per fare questo verrà utilizzata la funzione
imagecolorallocate( ), la quale ha il compito di memorizzare il dato relativo ad un determinato
colore per una specifica porzione di immagine identificata da una variabile. Nel mio caso ho
previsto 17 diversi colori, ognuno avente uno scopo ben preciso, i quali sono stati definiti con valori
RGB esadecimali e memorizzati in variabili a cui ho dato un nome semplice ed esplicativo, in modo
tale da poter ricondursi facilmente allo scopo di ogni variabile che contiene un colore.
Definita la parte relativa all’allocazione dei colori si potrà passare a quella necessaria per il
riempimento dell’immagine di sfondo grazie all’utilizzo della funzione imagefill( ), questa si
occupa di colorare una determinata immagine sulla base di quattro parametri:
• la variabile relativa all'immagine da colorare;
• la coordinata "x" che definisce il punto di partenza sull'asse orizzontale;
• la coordinata "y" che definisce il punto di partenza sull'asse verticale;
• il colore da utilizzare per la colorazione.
Dato che nel caso specifico le coordinate relative ad entrambi gli assi cartesiani avranno un valore
pari a "0", l'immagine verrà riempita completamente con il colore precedentemente definito per lo
sfondo tramite l'utilizzo della funzione imagecolorallocate( ), nel mio caso il colore è contenuto
nella variabile $colore_sfondo.
108
Sarà ora possibile passare alla fase relativa del disegno della griglia destinata a contenere i
dati. Questo procedimento si basa in particolare sull'utilizzo della funzione imageline( ) che ha il
compito di disegnare una linea sulla base delle coordinate passate come parametri.
Creazione delle linee orizzontali del diagramma
Le righe orizzontali del diagramma di Gantt andranno a separare un task da un altro
task e l’ultima sarà l’asse x del diagramma. Essendo il numero dei task variabile (può
deciderlo l’utente) da 1 a 10, anche il numero delle linee da disegnare sarà variabile. Quindi
mentre lo spazio dedicato al diagramma di Gantt è fisso, quello dedicato alle linee
orizzontali che separano i vari task sarà variabile (dipende dal numero dei task), cioè meno
task ci sono e più grande sarà la distanza che separerà le linee orizzontali. Per essere delle
linee orizzontali rette devo fare in modo che i valori delle cordinate x1,x2 devono essere
fissi e y1,y2 devono essere uguali, altrimenti avrei delle linee oblique.
In base a quanto detto prima, cioè che lo spazio tra una riga e l’altra è variabile in
base al numero dei task, devo potermi calcolare il valore di quest’entità dinamica in modo
tale da far risultare il diagramma proporzionato. Sapendo di avere a disposizione 300 pixel
in verticale (definito in imagecreatetruecolor, ne sono 350 ma ne considero di meno perché
lascio i restanti per visualizzare le stringhe di testo) e conoscendo il numero di task (quindi il
numero di righe orizzontali) da visualizzare (contenuto nella variabile $num_task) posso
calcolarmi il valore in pixel dello spazio dinamico che separerà, in base al numero di task, le
varie righe orizzontali. Memorizzo quindi nella variabile $spazio il valore intero (grazie alla
funzione intval) del rapporto tra pixel totali e numero di task, in modo tale da sapere quanto
deve essere la distanza in pixel tra una linea orizzontale e la successiva.
Ora grazie ad un ciclo for vado a creare tante linee orizzontali quant’è il numero dei
task. Siccome l’ultima linea del diagramma è l’asse x deve avere un colore differente
rispetto alle linee orizzontali che separano i vari task, quindi con un’istruzione if vado a
trattarla in modo diverso, nel senso che mantengo sempre le stesse dimesioni ma vario il
colore di questa. Con l’istruzione imageline traccio le linee orizzontali che vanno da 30+10
a 630 pixel in direzione X e si ripetono in direzione Y con una frequenza in pixel di
$i*$spazio (qui vario la posizione delle linee orizzontali variando, grazie alla presenza di $i,
le coordinate y1 e y2).
Creazione delle linee verticali del diagramma
Le colonne verticali del diagramma di Gantt andranno ad identificare la durata dei
secondi, cioè ad ogni riga corrisponde un determinato secondo. La prima colonna verticale
sarà l’asse y del diagramma. Essendo il numero dei secondi costante, la distanza tra un
secondo e il successivo è un valore fisso, quindi anche le linee verticali da disegnare
avranno la stessa distanza l’una dall’altra. Quindi sia lo spazio dedicato al diagramma di
Gantt sarà fisso e sia lo spazio dedicato alle linee verticali che definiscono i secondi sarà
fisso (durata sempre costante da un secondo ad un altro). Per essere delle linee verticali rette
devo fare in modo che i valori delle cordinate y1,y2 devono essere fissi e x1,x2 devono
essere uguali, altrimenti avrei delle linee oblique.
109
Essendo, come detto prima, la distanza tra una colonna e l’altra fissa, devo stabilire il
valore di questa distanza in pixel in modo tale da far risultare il diagramma proporzionato,
cioè graficamente la distanza tra un secondo e quello successivo deve essere uguale.
Stabilisco come distanza tra una linea verticale e quella successiva il valore di 10 pixel.
Ora grazie ad un ciclo for vado a creare tante linee verticali quanti sono il numero dei
secondi, passati per computare il task-set e contenuti nella variabile $secondi.
Siccome la prima linea del diagramma è l’asse y deve avere un colore differente rispetto alle
linee verticali che rappresentano i secondi, quindi con un istruzione if vado a trattarla in
modo diverso, nel senso che mantengo sempre le stesse dimesioni ma vario il colore di
questa.
Con l’istruzione imageline traccio le linee verticali che vanno da 15 a 310 pixel in
direzione Y e si ripetono in direzione X con una frequenza in pixel di $i*10 (qui vario la
posizione delle linee verticali variando, grazie alla presenza di $i, le coordinate x1 e x2).
Creazione delle linee verticali del diagramma che evidenziano i periodi e le deadline
Dopo aver creato la base del diagramma di Gantt devo andare ad evidenziare, con un
diverso colore, alcune colonne verticali che identificano i vari periodi e le varie deadline di
ogni task (ogni task avrà eventualmente questi due valori diversi dagli altri task). Siccome
considero l’intero diagramma in entrambe le coordinate, perchè devo potermi spostare sia da
task a task, (coordinata y) sia da secondo a secondo (coordinata x), devo poter variare
(quindi avere una variabile, sia la coordinata x che la coordinata y, quindi avrò a che fare
con una matrice di valori variabili (mentre nei due casi precendenti avevo una coordinata
della matrice variabile e una fissa). Per essere delle linee verticali rette (deadline e periodo si
verificheranno ogni tot secondi) devo fare in modo che i valori delle cordinate y1,y2 devono
essere fissi e x1,x2 devono essere uguali, altrimenti avrei delle linee oblique.
Essendo, come detto prima, la distanza tra una colonna e l’altra fissa, devo stabilire il
valore di questa distanza in pixel in modo tale da far risultare il diagramma proporzionato,
cioè graficamente la distanza tra un secondo e quello successivo deve essere uguale.
Stabilisco come distanza tra una linea verticale e quella successiva il valore di 10 pixel;
questo perché le deadline e i periodi si ripetono periodicamente ogni tot secondi.
Ora, grazie ad un primo ciclo for e la variabile contatore $i, mi muovo lungo le righe
orizzontali, cioè da task a task, solo dopo che un task ha terminato i suoi secondi.
Memorizzo nelle variabili $d e $t il valore della deadline e del periodo del task i-esimo.
Successivamente, grazie alla nidificazione di un secondo ciclo for e la variabile contatore $j,
vado a creare tante linee verticali quante sono le deadline e i periodi del task i-esimo,
scansionando un secondo alla volta muovendomi quindi lungo le colonne verticali (ad ogni
secondo passato inoltre andavo a decrementare di 1 il valore delle variabili $d e $t).
Utilizzando l’istruzione if sono andato poi a stabilire dei controlli, i quali mi hanno
permesso di tracciare, non appena si verificava la condizione stabilita, le deadline e i periodi
del task i-esimo. Una volta scaduto il periodo, oltre che disegnarlo graficamente, resetto
(uguagliandolo al valore iniziale) i valori della deadline e del periodo del task i-esimo
(perché tratto i task periodici).
110
Ricapitolando l’uso dei due cicli for:
o Il primo (contatore $i) viene utilizzato per scorrere da task a task, cioè da riga a riga;
o Il secondo (contatore $j) viene utilizzato per scorrere da secondo a secondo, cioè da
colonna a colonna.
Quindi faccio due scansioni: la prima (quella interna, variabile $j) è una scansione
orizzontale, la seconda (quella esterna, variabile $i) è una scansione verticale.
Con l’istruzione imageline traccio le linee verticali che vanno da 15+$i*$spazio a
15+$i*$spazio+$spazio pixel in direzione Y e si ripetono in direzione X con una frequenza
in pixel di 30+10*$j (qui vario la posizione delle linee verticali variando, grazie alla
presenza di $j, le coordinate x1 e x2 e la posizione delle linee orizzontali variando, grazie
alla presenza di $i, le coordinate y1 e y2).
Creazione delle stringhe di testo che conterranno il nome degli assi cartesiani
Utilizzando l’istruzione imagestring scrivo le due stringhe di testo “task[t]” e
“secondi[s]” ai lati degli assi cartesiani. La dimesione del font di queste due stringhe è 2. La
prima stringa si riferisce all’asse Y, quindi le sue coordinate sono state scelte in modo tale
che sia visualizzata in alto a sinistra di quest’asse; in proporzione al disegno le sue
coordinate sono x=0 e y=0. La seconda stringa si riferisce all’asse X, quindi le sue
coordinate sono state scelte in modo tale che sia visualizzata in basso a destra di quest’asse;
in proporzione al disegno le sue coordinate sono x=620 e y=311 pixel.
Creazione delle stringhe di testo che andranno ad identificare i task
Grazie ad un ciclo for, che itera l’istruzione imagestring tante volte quant’è il
numero dei task, vado a scrivere riga per riga il testo “task$i”. La variabile $i, venendo usata
come variabile contatore del ciclo for, parte dal valore 1 e aumenta di 1 ad ogni iterazione,
in modo tale da visualizzare ad ogni riga del diagramma di Gannt il valore del task i-esimo
corrispondente. Queste stringhe di testo avranno la dimensione del font uguale a 1. Le
coordinate in cui queste verranno visualizzate sono fisse per quanto riguarda x=7 pixel;
mentre, siccome il numero di task è variabile e la distanza delle righe orizzontali
proporzionale ad esso, sono variabili per quanto riguarda y=15+$i*$spazio-20 pixel (dove
$i è la variabile contatore e $spazio è la variabile calcolata in precedenza che contiene il
valore della distanza tra una riga orizzontale e la successiva).
111
Dopo aver terminato il disegno della griglia del diagramma di Gantt, posso passare
all’ultima fase della funzione crea_gantt( ): la rappresentazione nel diagramma dei task che
computano secondo per secondo. Questo giustifica la precedente creazione, nelle funzioni che
hanno elaborato gli algoritmi (contenute in algoritmi_submit), dell’array $scheduling_array: il
quale contiene il numero del task, secondo per secondo, che computa (scelto in base a determinati
criteri di priorità).
Con un ciclo for scansiono $scheduling_array secondo per secondo (dove $j è la variabile
contatore dei secondi) e grazie a delle istruzioni if vado ad individuare il determinato del task iesimo che computa in quel determinato secondo. Essendo il numero dei task minimo uno e
massimo dieci, prevedo dieci casi, cioè dieci controlli if, uno per ogni task nel caso si verificasse il
caso limite con dieci task.
Per disegnare le singole computazioni di ogni task utilizzo l’istruzione imagefilledrectangle, la
quale mi permette di disegnare dei rettangoli pieni. Per ogni task ho previsto un determinato colore
e una determinata posizione nella griglia (cioè le computazioni del task1 saranno disegnate
esclusivamente nella prima riga, quelle del task2 nella seconda riga, e così via).
Esaminando più a fondo il contenuto dell’istruzione imagefilledrectangle, essa disegna la
computazione del task i-esimo:
In direzione X: dal secondo j-esimo*10 (=x1) al j-esimo*10+10 pixel (=x2), dove 10 pixel è
graficamente la durata di un secondo.
Nota: ad x1 e x2 aggiungo 30 pixel in modo da shiftare il tutto di 30 pixel a destra, perché lo
spazio lasciato libero è stato utilizzato per la visualizzazione delle stringhe di testo.
In direzione Y: l’altezza del rettangolo da y1=15+$spazio/2+0*$spazio pixel (dove 0 è il
valore riferito al task1, per il task2 devo mettere 1, per il task3 devo mettere 2, …, per il
task10 devo mettere 9) a y2=15+1*$spazio pixel (dove 1 è il valore riferito al task1, per il
task2 devo mettere 2, per il task3 devo mettere 3, …, per il task10 devo mettere 10).
Nota: nella coordinata y1 vado a dividere per $spazio/2 in modo tale che il rettangolo è alto
la metà rispetto allo spazio riservato ad ogni task e non copre interamente le linee che
delimitano i secondi.
Nota: ad y1 e y2 aggiungo 15 pixel in modo da shiftare il tutto di 15 pixel in basso, perché
lo spazio lasciato libero è stato utilizzato per la visualizzazione delle stringhe di testo.
112
Nell’array $scheduling_array è contenuta pure l’informazione sul task che eventualmente
va in overflow. Alla fine del ciclo for precedente, il valore di $scheduling_array contenuto al
secondo j-esimo sarà quello del task in overflow; questo perché alla fine del ciclo for precedente $j
è stato incrementato di 1, quindi $scheduling_array[$j] conterrà il task i-esimo al secondo
successivo dell’ultima computazione, cioè il task in overflow. Anche in questo caso rappresento il
task in overflow grazie all’istruzione imagefilledrectangle e per quanto riguarda la dimensione e la
posizione del rettangolo di overflow le coordinate x1,x2,y1,y2 risultano essere calcolate con lo
stesso ragionamento fatto in precedenza. Ho previsto, come scritto anche nelle specifiche, un colore
preciso ed uguale per tutti i task in modo tale da evidenziare il concetto di overflow.
Come ultima cosa da fare resta di scrivere la parte relativa alla generazione dell’output.
Con l’istruzione header vado a definire il tipo di contenuto MIME dell’immagine (in questo modo
il browser sarà in grado di riconoscere il tipo MIME inviato dal server): l’immagine avrà il formato
png. Essendo Drupal un CMS non stampa a schermo l’immagine direttamente dal codice php;
questa per essere visualizzata deve essere prima salvata su un file immagine (avente come
estensione png, jpeg, gif, ecc.) e poi questo file immagine deve essere caricato da Drupal.
Per salvare sul disco l’immagine appena creata, contenuta nella variabile $immagine,
utilizzo l’istruzione imagepng (dato che l’immagine avrà il formato png), la quale ha i seguenti
parametri:
- nome della variabile che contiene l’immagine che si vuole salvare sul disco: questa
variabile è contenuta in RAM e bisogna salvarla in maniera permanente in un file (nel mio
caso il nome è $immagine);
- percorso e nome del file in cui si deve salvare l’immagine (nel mio caso ho creato un
apposita cartella, chiamata file_immagine, nella cartella del modulo “algoritmi”);
- la qualità con cui salvare l’immagine: questo parametro è, di solito, caratteristico delle
immagini jpeg e consiste in un indice che specifica la qualità con la quale salvare
l'immagine. Tale indice può andare da un minimo di 1 (immagine di bassissima qualità praticamente inintellegibile) ad un massimo di 100 (immagine ad altissima qualità). Molto
spesso valori troppo alti di questo parametro fanno crescere di molto le dimensioni (in Kb)
delle immagini, senza portare reali benefici alla qualità complessiva. Consiglio quindi di
utilizzare valori compresi tra 65 e 85 (75 è il valore predefinito). Quindi viene utilizzata solo
per l’istruzione imagejpeg, ma non per le altre come imagepng e imagegif.
Nota: ogni volta che si va a schedulare un task-set l’immagine del diagramma di gantt risultante
verrà salvato sempre nello stesso file, quindi ci sarà una sovrascrittura di esso e di conseguenza
non si verificherà uno spreco di memoria (ad esempio, se ogni immagine veniva salvata con un
113
nome diverso, si andavano a creare tanti file quante volte un utente andava a schedulare un taskset, di conseguenza tutti questi file andavano a riempire la memoria del disco).
Un volta salvata l’immagine in un file, lo spazio di memoria RAM da esso occupato
potrà essere liberato passando la variabile relativa all'immagine generata (nel mio caso
$immagine) alla funzione imagedestroy che si occuperà di eliminarla.
Dopo aver inserito queste ultime operazioni, con il comando return ritorno al file
algoritmi.module (file da dove è stata chiamata la funzione crea_gantt( ) ), e il file
crea_gantt.php può ritenersi terminato.
Nota: per utilizzare la funzione crea_gantt( ) nel mio file principale algoritmi.module, devo:
per prima cosa dichiararla, cioè tramite il comando include includerla all’inizio del file
algoritmi.module (prima di fare qualsiasi altra operazione);
successivamente, quando voglio utilizzarla in algoritmi.module, devo semplicemente
chiamarla nel punto preciso di utilizzo e passargli i parametri relativi.
Installazione e funzionamento del modulo algoritmi
Una volta terminato di scrivere il codice del modulo, passo alla verifica, cioè la fase di
testing. Ovvero vado ad installarlo su Drupal e a mostrare come esso deve essere utilizzato.
Per quanto riguarda l’installazione essa viene fatta come un qualsiasi altro modulo di Drupal; cioè
viene copiata la cartella “algoritmi”, contenente i file algoritmi.info, algoritmi.module,
crea_gantt.php
e
la
cartella
file_immagine
nella
cartella
C/xampplite/htdocs/drupal/sites/all/modules, dove vi sono tutti gli altri moduli di Drupal.
Contenuto della cartella “algoritmi”:
114
“modules”
Contenuto della cartella “modules”:
Dopo aver fatto questo, bisogna andare su Drupal in Administer >> Site building >>
Modules (indirizzo URL http://localhost/drupal/admin/build/modules)
http://localhost/drupal/admin/build/modules e mettere la spunta sul
checkbox del modulo “Algoritmi” per abilitarlo e cliccare sul bottone “Save configuration”.
115
Mentre prima dell’abilitazione nel menù rapido del frame a sinistra vi erano i collegamenti
standard, ora, per come ho impostato i parametri del mio modulo, apparirà un altro link “Algoritmi
“
Scheduling” che, al clic, porterà l’utente direttamente alla prima pagina di cui è composto il modulo
modu
“algoritmi”.
Ora che il modulo è stato installato ed abilitato non resta che testarlo.
testarlo Appena si clicca sul
link “Algoritmi Scheduling” si verrà rediretti su una nuova pagina (con URL
http://localhost/drupal/algoritmi).
). Questa è la pagina iniziale che mostra all’utente un form
contenente inizialmente un solo riquadro (dove poter inserire i dati relativi a tempo di
computazione, deadline e periodo dei task), un bottone che permette di aggiungere un task cioè
cio un
altro riquadro (assente solo quando sono presenti 10 righe della tabella, perché è il numero massimo
di task stabilito), un bottone che permette di eliminare un task cioè l’ultimo riquadro (assente solo
quando è presente una riga della tabella, perché è il numero minimo di task stabilito), una select che
permette di scegliere un tipo di algoritmo tra quelli proposti nel menù a finesta che si apre al clic,
cl un
pulsante di submit “Schedula” che raccoglie i dati inseriti dall’utente e li invia al server per farli
elaborare.
Pagina visualizzata al clic del link “Algoritmi Scheduling” (Nota: è presente solo il bottone
“Aggiungi task”):
116
Pagina ri-visualizzata dopo aver premuto una volta sul bottone “Aggiungi task” (Nota: sono
presenti entrambi i bottoni “Aggiungi task” e “Rimuovi task”):
Pagina ri-visualizzata dopo aver premuto nove volte consecutive sul bottone “Aggiungi task” (Nota:
è presente solo il bottone “Rimuovi task”):
117
Pagina con form compilato dall’utente e pronta per essere sottomessa tramite il bottone “Schedula”:
118
Dopo che i dati sono stati inseriti dall’utente e inviati al server (cliccando sull’apposito
bottone “Schedula”), essi vengono acquisiti correttamente, controllati nella loro esattezza ed
elaborati. Il risultato di questa elaborazione viene poi visualizzato all’utente in maniera chiara ed
esplicativa tramite un diagramma di Gantt. In quest’ultimo viene mostrato all’utente in maniera
grafica (tramite un immagine) il comportamento di tutti i task secondo per secondo, quale di questi
computa, quale di questi va in overflow, quale di questi computa anche dopo la sua deadline (sono
dei task soft real-time), ecc.
Reinserendo il task-set avente gli stessi parametri che sono stati utilizzati per l’esempio in C e per il
testing fatto a mano; ottengo, per l’algoritmo EDF, il seguente diagramma di Gantt:
119
Reinserendo il task-set
set avente gli stessi parametri che sono stati utilizzati per l’esempio in C e per il
testing fatto a mano; ottengo, per l’algoritmo RM, il seguente diagramma di Gantt:
120
CONCLUSIONI
121
Utilizzo reale del progetto
Il modulo realizzato ha come scopo principale quello di mostrare all’utente il
comportamento di un algoritmo di scheduling real-time.
Il grado di libertà lasciato all’utente è molto ampio per quanto riguarda l’inserimento dei
dati; infatti non solo può arrivare ad inserire un massimo di 10 task ma di questi può deciderne
liberamente i tre parametri caratteristici di ciascuno di essi (ovviamente i parametri, per coerenza,
devono essere numeri interi e positivi e devono avere il periodo maggiore o al massimo uguale di
deadline e tempo di computazione).
Oltre alla composizione del task-set poi l’utente potrà, grazie ad una SELECT, scegliere con
quale algoritmo di scheduling, tra quelli disponibili elaborare il task-set.
A questo proposito il modulo è stato previsto anche per eventuali aggiornamenti e
ampliamenti; cioè si possono facilmente aggiungere altri algoritmi di scheduling, oltre ai due già
esistenti. Fare questo è semplicissimo e verrà descritto di seguito in brevi passi dove si andrà a
modificare il file algoritmi.module:
aggiungere alla SELECT un altro campo, ad esempio ‘#value3’, con il nome del nuovo
algoritmo, in modo tale che l’utente possa selezionarlo;
aggiungere
alla
funzione
algoritmi_submit
un
altro
controllo
if(form_state[‘values’][‘tipo_alg’] == ‘nome nuovo algoritmo’), in modo tale che venga
riconosciuto il nuovo algoritmo selezionato dall’utente;
aggiungere, dopo il controllo if, il codice che comprenderà il nuovo algoritmo, in modo tale
che i task-set vengano elaborati con le istruzioni riguardanti il nuovo algoritmo.
Il risultato della schedulazione del task-set, inserito dall’utente, verrà mostrato come
output con un diagramma di Gantt, il quale illustrerà le computazioni di ciascun task secondo per
secondo e gli eventuali task che andranno in overlflow.
Quindi un utente qualsiasi, accedendo alla piattaforma Drupal, utilizzando il suddetto
modulo (se su questa è stato installato ed abilitato), sarà in grado di sapere subito qual è la
schedulazione di un task-set rispetto ad un algoritmo di scheduling real-time e di prevedere
eventualmente quale task e in quale secondo esso andrà in overflow.
Valutazione personale
Questo modulo risulterà molto utile a chiunque andrà ad utilizzarlo per vari motivi.
Come prima cosa sarà utile a chi non conosce i principi su cui si basano gli algoritmi di
scheduling EDF e RM e come essi lavorano, perché attraverso delle prove interattive (l’utente
inserisce dei task-set in maniera casuale, giusto per farsi un’idea generale) vengono mostrate in
maniera chiara e semplice i comportamenti dei vari task a seconda del diverso algoritmo di
scheduling scelto, in modo tale che l’utente possa capire il funzionamento di ogni algortimo di
scheduling.
È utile anche a chi già è a conoscenza del funzionamento di questi algortimi, perché,
utilizzando questo modulo, gli utenti principalmente possono:
ottenere delle risposte rapide su come si comporta un task-set utilizzando un determinato
algoritmo di scheduling, quindi ricavare subito i risultati senza doverli calcolarseli a mano;
ottenere uno strumento di verifica, nel caso essi calcolino il comportamento di un task-set
manualmente, quindi andranno a confrontare il risultato del loro lavoro con il risultato
mostrato graficamente dal modulo, per correggere eventuali errori commessi durante la
procedura manuale;
122
ottenere dei paragoni tra un algoritmo e un altro, ad esempio vedere in quale algoritmo di
scheduling i task non vanno in overflow oppure, se l’overflow si presenta in ogni algoritmo
utilizzato, vedere in quale algoritmo esso si presenta il più tardi possibile.
Mi è piaciuto molto svolgere questo progetto perché gli argomenti trattati sono stati
interessanti e soprattutto perché ho dovuto programmare un intero modulo per una piattaforma del
Web. La programmazione C e quella per il Web (PHP, HTML, ecc.) sono le cose che mi sono
piaciute particolarmente in questi anni di università, perché, anche se sono state per me argomenti
totalmente nuovi, mi hanno appassionato da sempre e inoltre sono riuscito facilmente ad intuirle e a
comprenderle. Aggiungo anche che facendo questo progetto ho accresciuto il mio sapere in campo
informatico, facendo la conoscenza dei CMS, di Drupal e di come funziona, della schedulazione
real-time e dei suoi principali algoritmi di scheduling.
Oltre all’interesse del progetto e al piacere di svolgerlo vi è poi anche l’aspetto che riguarda
l’utilità di questo. Infatti, come ho spiegato prima, questo modulo oltre che essere utile per vari
scopi è anche utilizzabile da una fascia di utenti molto ampia e non è dedicato ad un settore preciso
di utenza (può essere utilizzato da chi ci lavora con gli algoritmi di scheduling, da chi ne studia i
comportamenti, da chi vorrebbe impararli, ecc.).
Posso concludere quindi che sono soddisfatto del mio lavoro, in quanto è stato un progetto
mirato, concreto, piacevole, utile a terzi e interessante.
123
Bibliografia
Linguaggio C (A.Bellini, A.Guidi – McGraw-Hill 2006)
Sistemi in tempo reale (G.Buttazzo - Pitagora Editrice 2006)
http://www.deit.univpm.it/~dragoni/RealTime/index.html (sito internet del Prof. Aldo
Franco Dragoni sui sistemi operativi in tempo reale)
http://dida.laboratorium.dist.unige.it/AltreDispense/schedulazione.pdf
(dispense
sulla
schedulazione real-time della facoltà di ingegneria di Genova)
www.wikipedia.org (CMS, feed RSS, Drupal)
www.espertoweb.it (feed RSS)
http://www.scuolaelettrica.it/3ai/parte3/lezione17.shtml (sito internet sulla libreria GD del
PHP)
http://php.html.it/articoli/leggi/2896/come-creare-grafici-da-un-array-con-php-e-le-libreriegd/ (sito internet per creare grafici con la libreria GD)
http://www.alessioluffarelli.it/guide_tutorial/web/ridimensionamento_immagini_thumbnail.
php (sito internet che spiega come salvare un immagine su disco)
http://www.alessioluffarelli.it/guide_tutorial/web/ridimensionamento_immagini_thumbnail.
php (sito internet per salvare le immagini come file)
Esperienza e sapere personale derivati da esami svolti in precedenza e ripetute prove nel
comporre il codice
http://www.drupalitalia.org/ (guida installazione Drupal)
http://drupal.org/ (guida su Drupal e sui vari hook che ho utilizzato)
http://www.apachefriends.org/it/xampp-windows.html#4532 (setup di Xampp)
http://drupal.org/node/97368 (setup di Drupal 6)
http://www.mpsoftware.dk/downloads.php (setup di phpDesigner 7)
http://www.xnavigation.net/view/557/devc/download.html (setup di Dev C++)
124
Scarica

Progettazione e sviluppo di un modulo per il task