uniroma1
.*_main.c
.cognome.nome
. Sulle postazioni del laboratorio sarà /home/biar/Desktop/cognome.nome/
.cognome.nome.zip
(zip -r cognome.nome.zip cognome.nome/
).cognome.nome.zip
.rm -rf cognome.nome
).Per maggiori informazioni fate riferimento al regolamento delle esercitazioni.
Tradurre in IA32 la seguente funzione is_prefix
definita in E1-is-prefix/e1.c
che, date due stringhe s1
e s2
, verifica se la s1
è un prefisso di s2
. Ad esempio ham
è prefisso di hamburger
, mentre hum
non lo è.
e1.c
int is_prefix(const char* s1, const char* s2){
while (*s1 && *s1++ == *s2++);
return *s1 == 0;
}
Scrivere la soluzione nel file E1-is-prefix/e1.s
. Usare il file E1-is-prefix/e1_eq.c
per sviluppare la versione C equivalente e E1-is-prefix/e1_main.c
come programma di prova.
Si vogliono usare i segnali per creare un indicatore di progresso per la funzione do_sort
, che implementa un semplice algoritmo di ordinamento a bolle. L’indicatore di progresso è la percentuale di n
coperta da i
, vale a dire 100.0*i/n
. Si scriva la soluzione nel file E2-sort-timer/e2.c
modificandolo e aggiungendo quanto necessario al raggiungimento dell’obiettivo.
e2.c
#include "e2.h"
static void do_sort(int *v, int n) {
int i, j;
for (i=0; i<n; ++i)
for (j=1; j<n; ++j)
if (v[j-1] > v[j]) {
int tmp = v[j-1];
v[j-1] = v[j];
v[j] = tmp;
}
}
void sort(int *v, int n) {
// completare con gestione segnali...
do_sort(v, n);
}
Il risultato atteso deve essere come segue (ovviamente i numeri esatti delle percentuali possono variare):
start sorting...
-------------------------------
5.4%
11.2% <---- percentuali stampate dal gestore del segnale
17.1%
23.3%
29.7%
36.5%
43.7%
51.5%
59.7%
68.7%
79.0%
90.7%
-------------------------------
v[0]=0
v[1]=1
v[2]=2
v[3]=3
v[4]=4
v[5]=5
v[6]=6
v[7]=7
v[8]=8
v[9]=9
Suggerimento: rendere la variabile i
di do_sort
globale (dichiarata fuori dalla funzione) e tenere in un’altra variabile globale max
il valore di n
. In questo modo è possibile accedervi da un handler di un segnale che può stampare il rapporto tra i
e max
. Fare riferimento alla dispensa del corso sul segnali.
Domanda 1 Quale tra le seguenti affermazioni è VERA?
int
può essere usata esclusivamente per invocare le system callDomanda 2 Quale tra le seguenti affermazioni è VERA?
int
seguita da un numero che identifica la system call da eseguireDomanda 3 Dato il seguente codice, quale tra le seguenti affermazione è VERA?
wait
wait
Domanda 4 Dato il seguente codice, selezionare la risposta corretta:
Domanda 5 Dato il seguente codice, selezionare la risposta corretta:
Domanda 6 Quale delle seguenti affermazioni è FALSA?
SIGKILL
non può essere ignorato né catturatoSIGSEGV
non può essere catturatoSIGCHLD
viene ignorato per defaultSIGINT
, se non catturato o ignorato, causa la terminazione del processo che lo riceveSIGQUIT
, se non catturato o ignorato, causa la terminazione del processo che lo riceveDomanda 7 Quale delle seguenti affermazioni è VERA?
kill -9 <pid>
invia il segnale SIGINT
al processo con pid <pid>
kill -SIGINT <pid>
non può essere catturato dal processo con pid <pid>
alarm(s)
invia il segnale SIGALRM
ogni s
secondiualarm(t, n)
invia un segnale dopo t
microsecondi e successivamente ogni n
microsecondie1_eq.c
#include "e1.h"
int is_prefix(const char* s1, const char* s2){
const char* c = s1;
const char* d = s2;
L:; char a = *c;
if (a == 0)
goto E;
char b = *d;
c++;
d++;
if (a != b)
goto E;
goto L;
E: a = *c;
a = a == 0;
return a;
}
e1.s
.globl is_prefix
is_prefix: # int is_prefix(const char* s1, const char* s2)
pushl %ebx
movl 8(%esp), %ecx # const char* c = s1;
movl 12(%esp), %edx # const char* d = s2;
L: movb (%ecx), %al # char a = *c;
testb %al, %al # if (a == 0)
je E # goto E;
movb (%edx), %bl # char b = *d;
incl %ecx # c++;
incl %edx # d++;
cmpb %bl, %al # if (a != b)
jne E # goto E;
jmp L # goto L;
E: movb (%ecx), %al # a = *c;
testb %al, %al # a = a == 0;
sete %al
movsbl %al, %eax
popl %ebx
ret
e2.c
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include "e2.h"
int i, max;
static void do_sort(int *v, int n) {
int j;
for (i=0; i<n; ++i)
for (j=1; j<n; ++j)
if (v[j-1] > v[j]) {
int tmp = v[j-1];
v[j-1] = v[j];
v[j] = tmp;
}
}
void handler(int sig) {
printf("%3.1f%%\n", 100.0*i/max);
ualarm(500000,0);
}
void sort(int *v, int n) {
max = n;
struct sigaction act = { 0 }; // preparazione struttura
act.sa_handler = handler; // gestore segnale
int ret = sigaction(SIGALRM, &act, NULL); // gestore installato
if (ret == -1) {
perror("sigaction");
exit(EXIT_FAILURE);
}
ualarm(500000,0);
do_sort(v, n);
act.sa_handler = SIG_IGN; // segnale ignorato
ret = sigaction(SIGALRM, &act, NULL); // gestore installato
if (ret == -1) {
perror("sigaction");
exit(EXIT_FAILURE);
}
}
C. Il processo figlio entra nello stato zombie dopo aver terminato la propria esecuzione e fino al momento in cui il processo padre raccoglie il suo exit status
Spiegazione: quando un processo termina, il kernel libera le risorse associate, ma deve conservarne alcune, come il PCB, per permettere al processo padre di raccogliere l’exit status tramite wait
/waitpid
. In questo intervallo di tempo il processo entra in uno stato denominato zombie. Quando il padre raccoglie l’exit status il kernel può rilasciare tutte le risorse associate al figlio, che esce dallo stato zombie e non compare più nella lista dei processi. Se il padre termina senza raccogliere l’exit status del figlio (con wait
/waitpid
) il processo figlio viene adottato da un processo antenato del processo padre (storicamente init, nei sistemi moderni un discendente di init) che raccoglie l’exit status del figlio permettendo così al kernel di liberare tutte le risorse associate (questi processi vengono detti anche reaper).
ualarm(t, n)
invia un segnale dopo t
microsecondi e successivamente ogni n
microsecondi [vedi man ualarm]