POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la...

91

Transcript of POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la...

Page 1: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

POSIX

[email protected]

Page 2: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

LE SYSTEM CALL •  Alcune operazioni possono essere

effettuate solo dal kernel del sistema opeativo •  Ad esempio operazione di I/O (scrivere/

leggere file) •  o allocare memoria…

•  I programmi devono quindi richiedere al kernel di effettuare queste operazioni •  Invocando funzioni implementate nel

kernel •  Queste richieste (chiamate) sono

denominate System Call •  sono quindi l’interfaccia tra il sistema

operativo ed il nostro programma Kernel

Programmi

Sys calls

Page 3: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

SPERIMENTIAMO Strace: runs the specified command until it exits. It intercepts and records the system calls which are called by a process and the signals which are received by a process. (apt-get install strace)

root@aquilante:~# strace ls!execve("/bin/ls", ["ls"], [/* 17 vars */]) = 0!brk(0) = 0x9b48000!access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)!mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb778e000!access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)!open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3!fstat64(3, {st_mode=S_IFREG|0644, st_size=18086, ...}) = 0!mmap2(NULL, 18086, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7789000!close(3) = 0!…!

Page 4: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

SYS CALLS E LIBRERIE •  Spesso le system call non vengono chiamate

direttamente ma mediante librerie •  Alcune funzioni di libreria fanno da “wrapper” per

le syscall •  Dal nostro programma invochiamo le funzioni di

libreria che a loro volta invocano le syscall •  Ad esempio le funzioni printf, malloc, open sono

implementate nella glibc attraverso delle chiamate alle system call

•  Spesso quindi non ci interessa utilizzare le system call direttamente, ma attraverso funzioni di libreria, ma…

•  Problema: queste funzioni che chiamiamo, sono disponibili per tutti i sistemi operativi?

•  O dobbiamo ri-scrivere il nostro programma per ogni sistema operativo su cui vogliamo farlo eseguire? Kernel

Applicazione

Sys calls

Librerie

Interfacce applicative (API)

Page 5: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

QUANTI OS ESISTONO? http://en.wikipedia.org/wiki/List_of_operating_systems Più di 700 sistemi operativi diversi!

Serve uno standard!

Page 6: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

CHE COS’E’ POSIX? •  POSIX (Portable Operating System Interface for Unix) è il

nome che indica la famiglia degli standard definiti dall’IEEE denominati formalmente IEEE 1003. •  Nome standard internazionale è ISO/IEC 9945. •  15 documenti, inizialmente rilasciati nel 1988

•  Specifica l'interfaccia comune del sistema operativo con utente e software a livello di: •  API: processi, timer, thread, file, segnali, terminale, rete … •  Shell: Korn Shell •  Utilities: awk, ed, echo …

Page 7: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

SISTEMI OPERATIVI COMPLIANT POSIX A/UX AIX BSD/OS[citation needed] DSPnano[citation needed] HP-UX INTEGRITY IRIX LynxOS[citation needed] MPE/iX[citation needed] OS X[15] QNX[16] RTEMS (POSIX 1003.13-2003 Profile 52) Solaris Tru64 Unison RTOS[citation needed] UnixWare[17]

BeOS (and subsequently Haiku) FreeBSD[18] Contiki Darwin (core of OS X and iOS)

illumos GNU/Linux MINIX NetBSD Nucleus RTOS

OpenBSD OpenSolaris PikeOS RTOS RTEMS Sanos

SkyOS Syllable VSTa VxWorks

full compliant mostly compliant

src: wikipedia

su windows: cygwin

Page 8: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

POSIX Posix definisce l’interfaccia tra l’applicazione e le librerie

In ogni sistema operativo, all’interno delle librerie, le funzioni possono essere implementate in modo diverso

Kernel

Applicazione

Sys calls

Librerie

Interfacce applicative (API)

Page 9: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

C STDLIB E POSIX Le librerie POSIX sono un superset di quelle definite dall’ANSI C

Funzioni ANSI C

Funzioni POSIX

Page 10: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

COSA VEDREMO •  Processi •  memoria condivisa •  Timers e gestione del tempo

apt­get install manpages­posix manpages­posix­dev#

Page 11: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

SINCRONIZZAZIONE

INTRODUZIONE A INTERRUPT, POLLING E CALLBACKS E RIPASSO

Page 12: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

PROBLEMA •  Dovete fare due cose contemporaneamente

1.  La pasta 2.  Il sugo

•  Problema: cucinare il sugo ma ricordarsi di scolare la pasta

•  Possibili approcci algoritmici:

•  Assaggiare la pasta ogni minuto per sapere se è cotta •  Impostare una sveglia

POLLING

INTERRUPT

Page 13: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

IN INFORMATICA… •  Dobbiamo scrivere sul disco

•  tempo di accesso ~ms •  velocità processore ~ Ghz

•  Strategie: •  Polling: leggere periodicamente un registro finchè lo status

non è cambiato •  Se lo facessimo all’interno di un driver, bloccheremmo tutto il

sistema finchè la scrittura non è andata a buon fine •  Alternativa: usare un timer di sistema (ma non siamo precisi e

comunque consumiamo risorse) •  Interrupt: l’hardware (ad es. l’hard disk o la scheda di rete) o

il software interrompono quello che il sistema operativo sta facendo, invocando una funzione del driver in modo asincrono

Page 14: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

INTERRUPT •  Un interrupt hardware è

un segnale asincrono generato esternamente che richiede un interruzione del normale flusso (ad es. keystroke) mediante l’invio di un interrupt request (IRQ)

•  Un interrupt software è generato internamente (ad es. divisione per 0)

•  Ogni interrupt richide l’esecuzione di un particolare codice per gestire l’interrupt (handler)

lorenzo@ubuntu:~/fractal$ cat /proc/interrupts CPU0 CPU1 0: 44 0 IO-APIC-edge timer 1: 22 45187 IO-APIC-edge i8042 4: 36578 23 IO-APIC-edge 6: 0 3 IO-APIC-edge floppy 7: 0 0 IO-APIC-edge parport0 8: 0 0 IO-APIC-edge rtc0 9: 0 0 IO-APIC-fasteoi acpi 12: 10767 2537 IO-APIC-edge i8042 14: 0 0 IO-APIC-edge ata_piix 15: 11631 20 IO-APIC-edge ata_piix 16: 885 99 IO-APIC-fasteoi Ensoniq AudioPCI 17: 8612 31544 IO-APIC-fasteoi ehci_hcd:usb1, ioc0 18: 40 0 IO-APIC-fasteoi uhci_hcd:usb2 19: 8489 20 IO-APIC-fasteoi eth0

Approfondirete a Sistemi Operativi…

IRQ n° interrupts type name of device

Page 15: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

CALLBACKS •  Anche all’interno dei programmi è necessario impostare

dei meccanismi asincroni di chiamata a funzione •  “callbacks”

•  Tra poco vedremo timer e threads…

•  Timer: chiama una certa funzione tra un certo tempo •  Thread: fai girare questa funzione contemporaneamente

•  Problema: Come scrivereste una libreria per implementare un timer? •  mio_timer( funzione_da_chiamare, tempo ) •  o per i thread: crea_thread( funzione_da chiamare )

•  E’ necessario ripassare i puntatori a funzione!

Page 16: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

PUNTATORI A FUNZIONE (RIPASSO) Prototipo di una funzione C: tipo_restituito nome_funzione (parametro1, parametro2, ...) Puntatore alla funzione C: tipo_restituito ( * nome_ptr_a_funz ) (parametro1, parametro2, ...) Per assegnarlo: nome_ptr_a_funz = funzione_assegnata Per invocare la funzione: nome_ptr_a_funz (parametro1, parametro2, ...)

Page 17: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

ESERCIZIO: DICHIARAZIONE •  Dichiarare un puntatore (nome: pippo) alla funzione:

•  int nome_funzione(int a, float b);

•  Soluzione

•  int (* pippo) (int a, float b);

Page 18: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

ESERCIZIO: INVOCAZIONE Data una funzione: void print_hello (char *s){

printf(“Hello %s\n”, s);

}

Invocarla in un main mediante un puntatore a funzione

Page 19: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

ESERCIZIO INVOCAZIONE: SOLUZIONE #include <stdio.h> void print_hello(char *s) { printf("Hello %s\n", s); } int main() { void (*print_ptr)(char *s); print_ptr = print_hello; print_ptr("world"); return 0; }

Page 20: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

ESEMPI PIU’ OSCURI Funzione che ritorna un puntatore a funzione: int (*return_f())(char)

E’ una funzione chiamata “return_f” che non accetta argomenti. Ritorna un puntatore a funzione che ha come argomento un char e ritorna un intero.

Page 21: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

ESERCIZIO: DICHIARAZIONE void (*signal(int signum, void (*handler)(int) ) )(int); Cos’è? Un prototipo di funzione! 1) La funzione signal vuole come parametri un intero signum, ed un puntatore handler ad una funzione che restituisce un void e che vuole come parametro un intero. 2) la funzione signal restituisce un puntatore ad una funzione che restituisce un void e che vuole come parametro un intero. If you're confused by the prototype at the top of this manpage, it may help to see it separated out thus: typedef void (*handler_type)(int); handler_type signal(int signum, handler_type handler);

src: http://www.cs.unibo.it/~ghini/didattica/sistemi1/c005.pdf

Page 22: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

PROCESSI E THREADS

Page 23: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

DOVE STUDIARE •  Gapil

•  http://users.lilik.it/~mirko/gapil/gapilch5.html#gapilse8.html

Page 24: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

PROCESSI Definizione: istanza di un programma in esecuzione in modo sequenziale. Ogni processo ha un ID (Process ID – PID)

top

Page 25: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

ARCHITETTURA •  Su linux qualunque processo può a sua volta generarne altri

(child process)

•  ogni processo è sempre generato da un altro (parent process)

•  una sola eccezione: dato che ci deve essere un punto di partenza esiste un processo speciale (che normalmente è /sbin/init), che viene lanciato dal kernel alla conclusione della fase di avvio; ha sempre il pid uguale a 1 e non è figlio di nessun altro processo

Page 26: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

ARCHITETTURA •  I processi hanno una relazione

padre/figlio:

•  organizzazione gerarchica ad albero

•  Provare con “pstree”

Page 27: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

UNA PANORAMICA SULLE FUNZIONI FONDAMENTALI •  In un sistema unix-like i processi vengono sempre creati da altri processi

tramite la funzione fork; il nuovo processo (che viene chiamato figlio) creato dalla fork è una copia identica del processo processo originale (detto padre), ma ha un nuovo pid e viene eseguito in maniera indipendente

•  Se si vuole che il processo padre si fermi fino alla conclusione del processo figlio questo deve essere specificato dopo la fork chiamando la funzione wait o la funzione waitpid

•  Quando un processo ha concluso il suo compito o ha incontrato un errore non risolvibile esso può essere terminato con la funzione exit

•  Normalmente si genera un secondo processo per affidargli l'esecuzione di un compito specifico (ad esempio gestire una connessione dopo che questa è stata stabilita), o fargli eseguire (come fa la shell) un altro programma. Per quest'ultimo caso si usa la seconda funzione fondamentale per programmazione coi processi che è la exec

Page 28: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

PROCESS ID •  Ogni processo viene identificato dal sistema da un numero

identificativo univoco, il process ID o pid •  Il pid viene assegnato in forma progressiva ogni volta che un

nuovo processo viene creato, fino ad un limite che, essendo il pid un numero positivo memorizzato in un intero a 16 bit, arriva ad un massimo di 32768

•  Tutti i processi inoltre memorizzano anche il pid del genitore da cui sono stati creati, questo viene chiamato in genere ppid (da parent process ID). Questi due identificativi possono essere ottenuti usando le due funzioni getpid e getppid

Page 29: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

GETPID E GETPPID !

#include <sys/types.h>!

#include <unistd.h>!!

pid_t getpid(void) !

Restituisce il pid del processo corrente.!

!

pid_t getppid(void)!Restituisce il pid del padre del processo corrente.!

!

Entrambe le funzioni non riportano condizioni di errore.!

Page 30: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

LA FUNZIONE FORK !

#include <sys/types.h>!

#include <unistd.h>!

#

pid_t fork(void)#

!

Crea un nuovo processo.!

!

In caso di successo restituisce il pid del figlio al padre e zero al figlio; ritorna -1 al padre (senza creare il figlio) in caso di errore; errno può assumere i valori:!

EAGAIN non ci sono risorse sufficienti per creare un altro processo (per allocare la tabella delle pagine e le strutture del task) o si è esaurito il numero di processi disponibili!

ENOMEM non è stato possibile allocare la memoria per le strutture necessarie al kernel per creare il nuovo processo.!

Page 31: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

LA FUNZIONE FORK •  Dopo il successo dell'esecuzione di una fork sia il processo padre

che il processo figlio continuano ad essere eseguiti normalmente a partire dall'istruzione successiva alla fork

•  Il processo figlio è però una copia del padre, e riceve una copia dei segmenti di testo, stack e dati ed esegue esattamente lo stesso codice del padre •  la memoria è copiata, non condivisa, pertanto padre e figlio

vedono variabili diverse •  La differenza che si ha nei due processi è che nel processo

padre il valore di ritorno della funzione fork è il pid del processo figlio, mentre nel figlio è zero •  un processo infatti può avere più figli, ed il valore di ritorno di

fork è l'unico modo che gli permette di identificare quello appena creato

•  al contrario un figlio ha sempre un solo padre, per cui si usa il valore nullo, che non è il pid di nessun processo

Page 32: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

ESEMPIO

Page 33: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

LA FUNZIONE FORK •  Normalmente la chiamata a fork può fallire solo per due ragioni, o

ci sono già troppi processi nel sistema (il che di solito è sintomo che qualcos'altro non sta andando per il verso giusto) o si è ecceduto il limite sul numero totale di processi permessi all'utente

•  L'uso di fork avviene secondo due modalità principali •  Si creano processi figli cui viene affidata l'esecuzione di una

certa sezione di codice, mentre il processo padre ne esegue un'altra.

•  È il caso tipico dei programmi server in cui il padre riceve ed accetta le richieste da parte dei programmi client, per ciascuna delle quali pone in esecuzione un figlio che è incaricato di fornire il servizio.

•  Il processo vuole eseguire un altro programma •  questo è ad esempio il caso della shell. In questo caso il

processo crea un figlio la cui unica operazione è quella di fare una exec subito dopo la fork.

Page 34: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

LA FUNZIONE FORK •  Non si può dire quale processo fra il padre ed il figlio venga eseguito per

primo •  In generale l'ordine di esecuzione dipenderà, oltre che dall'algoritmo

di scheduling usato dal kernel, dalla particolare situazione in cui si trova la macchina al momento della chiamata, risultando del tutto impredicibile

•  Non si può fare nessuna assunzione sulla sequenza di esecuzione delle istruzioni del codice fra padre e figli, né sull'ordine in cui questi potranno essere messi in esecuzione. •  Se è necessaria una qualche forma di precedenza occorrerà

provvedere ad espliciti meccanismi di sincronizzazione, pena il rischio di incorrere nelle cosiddette race condition

•  Essendo i segmenti di memoria utilizzati dai singoli processi completamente separati, le modifiche delle variabili nei processi figli sono visibili solo a loro (ogni processo vede solo la propria copia della memoria), e non hanno alcun effetto sul valore che le stesse variabili hanno nel processo padre (ed in eventuali altri processi figli che eseguano lo stesso codice)

Page 35: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

LA FUNZIONE FORK •  la lista dettagliata delle proprietà che padre e figlio hanno in comune dopo l'esecuzione di

una fork è la seguente: •  i file aperti e gli eventuali flag di close-on-exec impostati •  Gli identificatori per il controllo di accesso: l'user-ID reale, il group-ID reale, l'user-ID

effettivo, il group-ID effettivo ed i group-ID supplementari •  gli identificatori per il controllo di sessione: il process group-ID e il session id ed il

terminale di controllo •  la directory di lavoro e la directory radice •  la maschera dei permessi di creazione •  la maschera dei segnali bloccati e le azioni installate •  i segmenti di memoria condivisa agganciati al processo •  i limiti sulle risorse •  le variabili di ambiente

•  le differenze fra padre e figlio dopo la fork invece sono: •  il valore di ritorno di fork •  il pid (process id) •  il ppid (parent process id), quello del figlio viene impostato al pid del padre •  i valori dei tempi di esecuzione della struttura tms che nel figlio sono posti a zero. •  i lock sui file, che non vengono ereditati dal figlio. •  gli allarmi ed i segnali pendenti, che per il figlio vengono cancellati.

Page 36: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

CHIUSURA DI UN PROCESSO •  Qualunque sia la modalità di conclusione di un processo, il kernel esegue comunque una

serie di operazioni: chiude tutti i file aperti, rilascia la memoria che stava usando, e così via; l'elenco completo delle operazioni eseguite alla chiusura di un processo è il seguente:

•  tutti i file descriptor sono chiusi. •  viene memorizzato lo stato di terminazione del processo. •  ad ogni processo figlio viene assegnato un nuovo padre (in genere init). •  viene inviato il segnale SIGCHLD al processo padre •  se il processo è un leader di sessione ed il suo terminale di controllo è quello della

sessione viene mandato un segnale di SIGHUP a tutti i processi del gruppo di foreground e il terminale di controllo viene disconnesso

•  se la conclusione di un processo rende orfano un process group ciascun membro del gruppo viene bloccato, e poi gli vengono inviati in successione i segnali SIGHUP e SIGCONT

•  è però necessario poter disporre di un meccanismo ulteriore che consenta di sapere come la terminazione è avvenuta: dato che in un sistema unix-like tutto viene gestito attraverso i processi, il meccanismo scelto consiste nel riportare lo stato di terminazione (il cosiddetto termination status) al processo padre.

•  quello che contraddistingue lo stato di chiusura del processo e viene riportato attraverso le funzioni wait o waitpid

Page 37: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

LA FUNZIONE WAIT #include <sys/types.h>!

#include <sys/wait.h>!

!

pid_t wait(int *status)!

!

Sospende il processo corrente finché un (qualunque) figlio non è uscito, o finché un segnale termina il processo o chiama una funzione di gestione.!

!

La funzione restituisce il pid del figlio in caso di successo e -1 in caso di errore; errno può assumere i valori:!

EINTR la funzione è stata interrotta da un segnale.!

!

Page 38: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

LA FUNZIONE WAITPID #include <sys/types.h>!

#include <sys/wait.h>!

!

pid_t waitpid(pid_t pid, int *status, int options)!

!

Attende la conclusione di un processo figlio con id “pid”.!

!

La funzione restituisce il pid del processo che è uscito, 0 se è stata specificata l'opzione WNOHANG e il processo non è uscito e -1 per un errore, nel qual caso errno assumerà i valori:!

!

EINTR se non è stata specificata l'opzione WNOHANG e la funzione è stata interrotta da un segnale.!

ECHILD il processo specificato da pid non esiste o non è figlio del processo chiamante.!

!

Page 39: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

ESERCIZIO •  Creare un programma che esegua la fork.

•  Il padre deve aspettare l’uscita del figlio e riportare lo stato di uscita

•  Il figlio deve dormire 10 secondi

Page 40: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

CHIUSURA DI UN PROCESSO •  Solitamente lo stato di chiusura di un figlio viene riportato al

padre, ma ci possono essere due eccezioni importanti

•  Il padre è già terminato

•  In questo caso il figlio è un processo orfano. In questo caso viene “adottato” da init.

•  Il figlio termina prima del padre ma lo stato di terminazione non è stato ricevuto

•  In questo caso il processo figlio è chiamato zombie, e rimane presente nella tabella dei processi.

Page 41: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

TEST PROCESSI ORFANI E ZOMBIE •  Per generare processi orfani basta nel programma di test

imponendo a ciascun processo figlio due secondi di attesa prima di uscire

•  Sarà adottato da init o da “init --user” •  possiamo controllare con ps –efl (per vedere anche PPID)

•  Per generare processi zombie indichiamo al processo padre di aspettare 10 secondi prima di uscire

•  in questo caso, usando ps sullo stesso terminale (prima dello scadere dei 10 secondi)

Page 42: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

LA FUNZIONE WAITPID •  La terminazione di un processo figlio è chiaramente un evento

asincrono rispetto all'esecuzione di un programma e può avvenire in un qualunque momento

•  Per questo motivo, una delle azioni prese dal kernel alla conclusione di un processo è quella di mandare un segnale di SIGCHLD al padre.

•  L'azione predefinita per questo segnale è di essere ignorato, ma la sua generazione costituisce il meccanismo di comunicazione asincrona con cui il kernel avverte il processo padre che uno dei suoi figli è terminato.

•  In genere in un programma non si vuole essere forzati ad attendere la conclusione di un processo per proseguire, specie se tutto questo serve solo per leggerne lo stato di chiusura (ed evitare la presenza di zombie)

•  la modalità più usata per chiamare queste funzioni è quella di utilizzarle all'interno di un signal handler. In questo caso infatti, dato che il segnale è generato dalla terminazione di un figlio, avremo la certezza che la chiamata a wait non si bloccherà.

Page 43: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

LA FUNZIONE EXEC •  una delle modalità principali con cui si utilizzano i processi in

Unix è quella di usarli per lanciare nuovi programmi: questo viene fatto attraverso una delle funzioni della famiglia exec

•  Quando un processo chiama una di queste funzioni esso viene completamente sostituito dal nuovo programma; il pid del processo non cambia, dato che non viene creato un nuovo processo, la funzione semplicemente rimpiazza lo stack, lo heap, i dati ed il testo del processo corrente con un nuovo programma letto da disco.

•  Ci sono sei diverse versioni di exec (per questo la si è chiamata famiglia di funzioni) che possono essere usate per questo compito, in realtà (come mostrato in fig. 3.4), sono tutte un front-end a execve

Page 44: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

LA FUNZIONE EXEC #include <unistd.h>!

int execve(const char *filename, char *const argv[], char *const envp[])!

!

La funzione exec esegue il file o lo script indicato da filename, passandogli la lista di argomenti indicata da argv e come ambiente la lista di stringhe indicata da envp; entrambe le liste devono essere terminate da un puntatore nullo. I vettori degli argomenti e dell'ambiente possono essere acceduti dal nuovo programma quando la sua funzione main è dichiarata nella forma main(int argc, char *argv[], char *envp[]) La funzione ritorna solo in caso di errore, restituendo -1; nel qual caso errno può assumere i valori: EACCES il file non è eseguibile, oppure il filesystem è montato in noexec, oppure non è un file

Page 45: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

ESERCIZIO •  Creare una funzione che stampi i numeri primi tra X1 e X2

•  X1 = 990 milioni •  X2 = 1.1 miliardi

•  Dividere il carico tra più processi

•  N processi, ognuno elabora 1/n del set di numeri •  Vedere il tempo di esecuzione e l’impiego delle CPU (per i

sistemi multicore)

Page 46: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

La gestione del segnale SIGCHLD

Page 47: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

SEGNALI •  I segnali sono usati per notificare ad un processo l'occorrenza di un

qualche evento •  un breve elenco di possibili cause per l'emissione di un segnale è il

seguente: •  un errore del programma, come una divisione per zero o un

tentativo di accesso alla memoria fuori dai limiti validi. •  la terminazione di un processo figlio. •  la scadenza di un timer o di un allarme. •  il tentativo di effettuare un'operazione di input/output che non può

essere eseguita. •  una richiesta dell'utente di terminare o fermare il programma. In

genere si realizza attraverso un segnale mandato dalla shell in corrispondenza della pressione di tasti del terminale come C-c o C-z.1

•  l'esecuzione di una kill

Page 48: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

TIPI DI SEGNALE •  I segnali sono identificati da MACRO definite in signal.h

Lista di alcuni segnali

Page 49: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

HANDLER DI SEGNALI •  I segnali sono eventi asincroni che possono essere generati in

qualunque momento da cause interne ed esterne al processo •  Per poter gestire un segnale bisogna definire una funzione

chiamata handler •  Questo viene fatto con la seguente chiamata (esempio nel caso

del segnale SIGINT)

#include <signal.h>!signal(SIGINT, sig_handler);!!Dove la sig_handler è una funzione che deve essere definita nel programma e che deve accettare un intero!!!!

Page 50: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

GESTIONE DEL SIGCHLD •  Come già detto non è sempre possibile che un processo padre

possa fermarsi ad attendere lo stato di terminazione dei suoi figli •  Per questo motivo risolta opportuno chiamare la funzione wait

all’interno dell’handler del segnale SIGCHLD •  All’avvio del processo settiamo l’handler per il segnale SIGCHLD •  Il processo padre può quindi continuare la sua esecuzione (per

esempio attendere input da tastiera, attendere nuove connessioni, ecc….)

•  Quando il padre ricede il segnale, viene quindi chiamata l’handler •  Una volta completata la funzione di handler, il padre ritorna al

punto in cui è stato interrotto

Page 51: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

ESERCIZIO •  Utilizzare i segnali per accettare lo status di uscita di un

figlio senza bloccare il padre

Page 52: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

GESTIONE DEL SIGCHLD

Page 53: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

ESERCIZIO •  Utilizzare i segnali far richiedere la conferma dell’uscita da

un programma a seguito di Ctrl-C (SIGINT)

Page 54: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

#include <stdio.h> #include <signal.h> void INThandler(int); void main(void) { signal(SIGINT, INThandler); while (1) pause(); } void INThandler(int sig) { char c; signal(sig, SIG_IGN); printf("OUCH, did you hit Ctrl-C?\n" "Do you really want to quit? [y/n] "); c = getchar(); if (c == 'y' || c == 'Y') exit(0); else signal(SIGINT, INThandler); }

http://www.csl.mtu.edu/cs4411.ck/www/NOTES/signal/install.html

Intercettiamo la chiusura di un programma

Page 55: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

Comunicazione tra processi attraverso POSIX shared memory

Page 56: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

LA COMUNICAZIONE TRA PROCESSI •  Sia nel caso di processi padre figlio, sia nel caso di processi

“indipendenti”, possiamo aver bisogno di un meccanismo di comunicazione

•  Esistono molti meccanismi diversi

•  Pipe, named pipe, socket locali, SYSV IPC, POSIX IPC •  Per poter utilizzare la shared memory POSIX bisogna

compilare il programma con l’opzione -lrt

Page 57: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

APERTURA DI UN SEGMENTO DI MEMORIA CONDIVISA #include <mqueue.h>!int shm_open(const char *name, int oflag, mode_t mode)! Apre un segmento di memoria condivisa. La funzione restituisce un file descriptor positivo in caso di successo e -1 in caso di errore; nel quel caso errno assumerà gli stessi valori riportati da open La funzione è del tutto analoga ad open ed analoghi sono i valori che possono essere specificati per oflag, che deve essere specificato come maschera binaria comprendente almeno uno dei due valori O_RDONLY e O_RDWR E’ possibile verificare la creazione del segmento di shared memory all’interno della directory /dev/shm/!

Page 58: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

APERTURA DI UN SEGMENTO DI MEMORIA CONDIVISA Possibili valori di oflag: O_RDONLY Apre il file descriptor associato al segmento di memoria condivisa per l'accesso in sola lettura. O_RDWR Apre il file descriptor associato al segmento di memoria condivisa per l'accesso in lettura e scrittura. O_CREAT Necessario qualora si debba creare il segmento di memoria condivisa se esso non esiste; in questo caso viene usato il valore di mode per impostare i permessi, che devono essere compatibili con le modalità con cui si è aperto il file. O_EXCL Se usato insieme a O_CREAT fa fallire la chiamata a shm_open se il segmento esiste già, altrimenti esegue la creazione atomicamente. O_TRUNC Se il segmento di memoria condivisa esiste già, ne tronca le dimensioni a 0 byte.

Page 59: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

APERTURA DI UN SEGMENTO DI MEMORIA CONDIVISA •  Chiamate multiple a shm_open usando lo stesso nome da più

processi restituiranno file descriptor associati allo stesso segmento (così come, nel caso di file di dati, essi sono associati allo stesso inode)

•  In questo modo è possibile effettuare una chiamata ad mmap sul file descriptor restituito da shm_open ed i processi vedranno lo stesso segmento di memoria condivisa

•  Quando il nome non esiste il segmento può essere creato specificando O_CREAT; in tal caso il segmento avrà (così come i nuovi file) lunghezza nulla.

•  Dato che un segmento di lunghezza nulla è di scarsa utilità, per impostarne la dimensione si deve usare ftruncate prima di mapparlo in memoria con mmap

Page 60: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

MAPPATURA DI UN SEGMENTO DI MEMORIA CONDIVISA •  Una volta creato un segmento di memoria condivisa, questa

memoria deve essere “mappata” all’interno della memoria del processo che ha chiamato la funzione shm_open

•  Questo viene effettuato attraverso la funzione mmap

#include <sys/mman.h>!!void *mmap(void *start, size_t length, int prot, !

! ! !int flags, int fd, off_t offset);!

•  Senza entrare nei dettagli, per mappare un segmento shm si effettua la seguente chiamata

mmap(NULL, shm_size, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0); !

Dove, fd è il file descriptor dell’inode che rappresenta il segmento shm e shm_size è la grandezza del segmento

Page 61: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

RIMOZIONE DI UN SEGMENTO DI MEMORIA CONDIVISA •  Come per i file, quando si vuole effettivamente rimuovere

segmento di memoria condivisa, occorre usare la funzione shm_unlink

#include <mqueue.h>!int shm_unlink(const char *name)!Rimuove un segmento di memoria condivisa.!!La funzione restituisce 0 in caso di successo e -1 in caso di errore!

Page 62: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

SEMPLICE INTERFACCIA ALLE CHIAMATE POSIX SHM

Page 63: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

SEMPLICE INTERFACCIA ALLE CHIAMATE POSIX SHM

Page 64: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

SEMPLICE INTERFACCIA ALLE CHIAMATE POSIX SHM

Page 65: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

SEMPLICE INTERFACCIA ALLE CHIAMATE POSIX SHM

Page 66: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

I Thread

Page 67: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

DEFINZIONE •  Un thread è una suddivisione di un processo in due o più

sottoprocessi, che vengono eseguiti concorrentemente da un sistema di elaborazione monoprocessore (multithreading) o multiprocessore.

•  E’ la più piccola sequenza di istruzioni che può essere gestita in modo indipendente dallo scheduler (wikipedia)

Page 68: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

DIFFERENZA PROCESSI E THREADS •  Quando creiamo due processi (ad es. con fork() ),

vengono duplicati i programmi (memoria e spazio di indirizzamento e codice)

•  I thread invece condividono tutto e sono semplicemente “funzioni” che vengono eseguite in modo parallelo

Page 69: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

DIFFERENZA PROCESSI E THREADS •  La programmazione multithread è considerata “difficile”

perché va gestita correttamente la concorrenza •  Ad es: un thread scrive in una variabile e l’altro la

legge; la lettura potrebbe essere “sporca” •  Esistono soluzioni come mutex o semafori che

garantiscono l’atomicità di operazioni •  Ma se non gestite correttamente possono creare

problemi gravi (ad es. deadlocks) •  La creazione di thread è quindi però più veloce

•  Miglior utilizzo delle risorse, condivisione di memoria semplificata

Page 70: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

ESERCITAZIONE IN CLASSE Estendiamo la console per l’esecuzione degli algoritmi di sorting come segue:

1)  l’algoritmo di sorting viene eseguito in un processo figlio. Il controllo ritorna alla console

2)  È possibile controllare da console la percentuale di esecuzione dell’algoritmo di sorting attraverso la lettura di una area di memoria condivisa

3)  È possibile interrompere l’esecuzione dell’algoritmo tramite console

4)  La console permette di lanciare un solo algoritmo alla volta

Page 71: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

POSSIBILI ESTENSIONI PER CASA 1)  Percentuale di completamento dell’algoritmo merge sort

2)  Esecuzione diversi algoritmi in parallelo

3)  Permettere l’esecuzione solo di un’istanza dello algoritmo contemporaneamente

Page 72: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

IL TEMPO

[email protected]

Page 73: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

DOVE STUDIARE •  Gapil

•  http://users.lilik.it/~mirko/gapil/gapilse26.html#gapilsu125.html •  Linux

•  http://www.linuxsa.org.au/tips/time.html

Page 74: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

IL FUSO ORARIO

UTC (Tempo Universale Coordinato) anche chiamato GMT (Greenwich Mean Time)

In Italia: GMT +1 (CET) GMT +2 (CEST, ora solare)

Page 75: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

NEL COMPUTER

•  Due posti in cui viene memorizzato il tempo •  BIOS (“hardware clock”) •  Sistema operativo

•  che usa hardware clock al boot •  Sui sistemi linux

•  in /etc/localtime viene memorizzato il fuso orario corrente •  selezionabile da /usr/share/zoneinfo/ •  Il comando date ci permette di leggere /settare il clock di sistema •  il comando /usr/sbin/hwclock ci permette di leggere/settare il clock

hardware

Page 76: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

DUE MISURE PER IL TEMPO •  Calendar Time

•  Numero di secondi dal 1/1/1970 (Epoch time) •  Tempo utilizzato dal kernel ad es. per le modifiche dei file •  Memorizzato nel tipo “time_t” (tempo assoluto) •  tipicamente un intero con segno

•  Process Time •  Tempo di processore •  Misurato in “clock ticks” •  Un tempo misurava gli interrupt per secondo

•  oggi POSIX richiede che sia pari alla costante CLOCKS_PER_SEC = 1000000

•  Memorizzato nel tipo “clock_t” (tempo relativo) •  Usato ad es. per valutare le performance di un programma

Page 77: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

DOMANDA •  Calendar time:

•  “Tempo utilizzato dal kernel…” •  “secondi dall’epoch time (1/1/1970)” •  su molte macchine (unix, 32 bit) sizeof(time_t) = 4

•  tipicamente un intero con segno

Page 78: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

CANDY CRUSH

Il wait period, su dispositivi la cui data era modificata artificialmente a prima del 18 gennaio 2038 faceva crashare l’app

Page 79: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

TEMPI DI PROCESSO Per ciascun processo il kernel mantiene: •  clock time: tempo reale passato dall’avvio del processo •  user time: tempo passato ad eseguere le istruzioni del

processo (user space) •  system time: tempo passato ad eseguire le syscall per

conto del processo

•  user time + system time = CPU time

•  è quello che ritorna il comando time nome_eseguibile •  ritornato anche dalla funzione “clock()”

Page 80: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

ESEMPIO: MISURIAMO IL TEMPO DI ESECUZIONE DI UN PROCESSO

Page 81: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

TEMPI DI CALENDARIO

•  Esiste una analoga funzione stime per settare l’orologio di sistema •  La funzione time_t time(time_t *t) ha una scarsa precisione (secondo) •  Per questo, queste funzioni sono sostituite da gettimeofday e settimeofday

Page 82: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

GETTIMEOFDAY #include <sys/time.h> #include <time.h> int gettimeofday(struct timeval *tv, struct timezone *tz)

struct timeval { long tv_sec; /* seconds */ long tv_usec; /* microseconds */

};

ritorna 0 in caso di successo, -1 in caso di errore

•  il parametro timezone è obsoleto (settarlo sempre a NULL) •  esiste la funzione analoga settimeofday

Page 83: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

LE DATE •  Dato un calendar time, come stampare ore, minuti e

secondi? •  Funzioni di libreria per il “broken down time”

struct tm { int tm_sec; /* seconds */ int tm_min; /* minutes */

int tm_hour; /* hours */ int tm_mday; /* day of the month */ int tm_mon; /* month */ int tm_year; /* year */ int tm_wday; /* day of the week */ int tm_yday; /* day in the year */ int tm_isdst; /* daylight saving time */ long int tm_gmtoff; /* Seconds east of UTC. */ const char *tm_zone; /* Timezone abbreviation. */

};

Page 84: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

FUNZIONI #include <time.h> char *asctime(const struct tm *tm) Produce una stringa con data e ora partendo da un valore espresso in broken-down time. char *ctime(const time_t *timep) Produce una stringa con data e ora partendo da un valore espresso in in formato time_t. struct tm *gmtime(const time_t *timep) Converte il calendar time dato in formato time_t in un broken-down time espresso in UTC. struct tm *localtime(const time_t *timep) Converte il calendar time dato in formato time_t in un broken-down time espresso nell'ora locale. time_t mktime(struct tm *tm) Converte il broken-down time in formato time_t.

Page 85: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

#include <time.h> size_t strftime(char *s, size_t max,

const char *format,

const struct tm *tm)

Stampa il tempo tm nella stringa s

secondo il formato format.

SCRIVERE IL TEMPO

Page 86: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

LE FUNZIONI DI SLEEP #include <unistd.h> unsigned int sleep(unsigned int seconds) Pone il processo in stato di sleep per un certo numero di secondi int nanosleep(const struct timespec *req, struct timespec *rem) Pone il processo in stato di sleep per il tempo specificato da req. In caso di interruzione restituisce il tempo restante in rem.

struct timespec { time_t tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */

};

Page 87: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

ESEMPIO #include <stdio.h> #include <unistd.h>

int main() {

printf("wait\n");

sleep(3);

printf("time elapsed\n"); return 0;

}

Cosa otteniamo se misuriamo il process time?

Page 88: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

ESERCIZIO 1.  Stampare il tempo corrente ogni secondo

1.  utilizzare la funzione sleep 2.  stampare secondi e us correnti

2.  Modificare il programma per non andare out of sync

1.  supponiamo di dover fare un orologio che deve scrivere il tempo per anni

Page 89: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

TIMEOUT Problema: •  Voglio eseguire una certa funzione tra X secondi senza

mettere il mio processo in stato di sleep •  Ad esempio stampare “Hurry up!” se l’utente ci mette più di

10 secondi a fare una mossa a tris

Soluzione

•  Utilizzare un timer

•  Su linux, far generare al sistema operativo un segnale allo scadere di un certo lasso di tempo

•  Il segnale in questione è SIGALERT

Page 90: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

TIMEOUT: PROCEDURE 1.  Definire una funzione da chiamare allo scadere del

timeout 1.  handler del segnale SIGALARM 2.  prototipo: void nome_funzione(int sig);

2.  Impostare il timer

1.  Funzione alarm 2.  prototipo: unsigned int alarm(unsigned int seconds) 3.  “returns the number of seconds remaining until any

previously scheduled alarm was due to be delivered” 3.  Scrivere il nostro main

Page 91: POSIXstud.netgroup.uniroma2.it/~lorenzo/fondinf2016/posix.pdf · 2017-01-26 · sistema finchè la scrittura non è andata a buon fine • Alternativa: usare un timer di sistema (ma

TIMEOUT