Warning: Undefined array key "view" in /var/www/html/wp-content/uploads/classes/so/lab-exams/index.php on line 2
Warning: Cannot modify header information - headers already sent by (output started at /var/www/html/wp-content/uploads/classes/so/lab-exams/index.php:2) in /var/www/html/wp-content/uploads/classes/so/lab-exams/index.php on line 47
Warning: Cannot modify header information - headers already sent by (output started at /var/www/html/wp-content/uploads/classes/so/lab-exams/index.php:2) in /var/www/html/wp-content/uploads/classes/so/lab-exams/index.php on line 48
Warning: Cannot modify header information - headers already sent by (output started at /var/www/html/wp-content/uploads/classes/so/lab-exams/index.php:2) in /var/www/html/wp-content/uploads/classes/so/lab-exams/index.php on line 49
Warning: Cannot modify header information - headers already sent by (output started at /var/www/html/wp-content/uploads/classes/so/lab-exams/index.php:2) in /var/www/html/wp-content/uploads/classes/so/lab-exams/index.php on line 50
Warning: Cannot modify header information - headers already sent by (output started at /var/www/html/wp-content/uploads/classes/so/lab-exams/index.php:2) in /var/www/html/wp-content/uploads/classes/so/lab-exams/index.php on line 51
/* Sistemi Operativi - prova di laboratorio
* compito del 16/09/2016 - soluzione */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DEFAULT_NUM_SAMPLES 30
#define PAUSE_SECS 1
#define MAX_LEN_BUFFER 1024
#define PROC_PATHNAME "/proc/stat"
#define DISPLAY_COLUMNS 60
/* 3 semafori */
enum SEM_TYPE { S_EMPTY = 0, S_RAW, S_DELTA };
typedef struct {
long int user;
long int system;
long int idle;
} raw_data;
typedef struct {
float user;
float system;
} delta_data;
typedef struct {
union {
raw_data raw;
delta_data delta;
} content;
char raw_eof;
char delta_eof;
} shm_data;
/**
* l'utilizzo della union nella struttura shm_data permette di utilizzare un
* segmento più piccolo; è accettabile anche utilizzare campi distinti che
* coprano tutti i casi di utilizzo previsti, ovvero:
* typedef struct {
* long int raw_user;
* long int raw_system;
* long int raw_idle;
* float delta_user;
* float delta_system;
* char raw_eof;
* char delta_eof;
* } shm_data;
*/
int WAIT(int sem_des, short unsigned int sem_num) {
struct sembuf ops[1] = {{sem_num, -1, 0}};
return semop(sem_des, ops, 1);
}
int SIGNAL(int sem_des, short unsigned int sem_num) {
struct sembuf ops[1] = {{sem_num, +1, 0}};
return semop(sem_des, ops, 1);
}
/* il figlio sampler che si occupa di campionare dal file-system /proc/ */
void sampler(shm_data *data, int sem, int num_samples) {
FILE *proc_fs;
char buffer[MAX_LEN_BUFFER];
long int ignore_it;
for (int i = 0; i < num_samples; i++) {
if ((proc_fs = fopen(PROC_PATHNAME, "r")) == NULL) {
perror(PROC_PATHNAME);
exit(1);
}
if (fgets(buffer, MAX_LEN_BUFFER, proc_fs) == NULL) {
perror(PROC_PATHNAME);
exit(1);
}
fclose(proc_fs);
/* aspetto che si liberi l'area condivisa */
WAIT(sem, S_EMPTY);
sscanf(buffer, "cpu %ld %ld %ld %ld %ld %ld %ld",
&(data->content.raw.user), &ignore_it,
&(data->content.raw.system), &(data->content.raw.idle),
&ignore_it, &ignore_it, &ignore_it);
/* se si tratta dell'ultimo sample campionato, lo segnalo */
if (i == num_samples - 1)
data->raw_eof = 1;
/* segnalo a chi attende dati raw (Analyzer), che questi
* sono disponibili */
SIGNAL(sem, S_RAW);
sleep(PAUSE_SECS);
}
exit(0);
}
/* il figlio analyzer che si occupa di tradurre i sample sugli utilizzi delle
* CPU in percentuali di variazione */
void analyzer(shm_data *data, int sem) {
long int last_user = -1, last_system = -1, last_idle = -1;
long int total;
float new_user, new_system;
while (!data->delta_eof) {
/* attendo che ci sia dati raw nell'area condivisa */
WAIT(sem, S_RAW);
/* se si tratta dell'ultimo campione raw, allora
* il deta che stiamo per calcolare sarà anche l'ultimo */
if (data->raw_eof)
data->delta_eof = 1;
/* se questo è il primo campione ricevuto, non posso ancora
* calcolare i valori delta; in questo caso Analyzer si deve
* occupare di segnare come libera l'area condivisa (in genere
* viene fatto da Plotter) */
if (last_user < 0) {
last_user = data->content.raw.user;
last_system = data->content.raw.system;
last_idle = data->content.raw.idle;
SIGNAL(sem, S_EMPTY);
} else {
total = (data->content.raw.user - last_user) +
(data->content.raw.system - last_system) +
(data->content.raw.idle - last_idle);
/* dobbiamo usare le variabili locali new_user e new_system perchè
* altrimenti rischieremmo di sovrascivere i dati raw.user e
* raw.system nella union durante il calcolo */
new_user =
(float)(data->content.raw.user - last_user) / (float)total;
new_system =
(float)(data->content.raw.system - last_system) / (float)total;
last_user = data->content.raw.user;
last_system = data->content.raw.system;
last_idle = data->content.raw.idle;
data->content.delta.user = new_user;
data->content.delta.system = new_system;
/* segnalo a chi attende dati delta (Plotter), che questi
* sono disponibili */
SIGNAL(sem, S_DELTA);
}
/* nota importante: formalmente sto estraendo dati raw e sto
* inserendo dati delta, quindi la sequenza sui semafori dovrebbe
* essere:
* WAIT(sem, S_RAW); SIGNAL(sem, S_EMPTY); ...
* WAIT(sem, S_EMPTY); SIGNAL(sem, S_DELTA);
* in questo modo però rischieremmo uno stallo: lo vedete? */
}
exit(0);
}
void print_chars(unsigned int n, char c) {
for (unsigned int i = 0; i < n; i++)
putc(c, stdout);
}
/* il figlio plotter che si occupa di visualizzare i dati di variazione */
void plotter(shm_data *data, int sem) {
unsigned int user_chars, system_chars, idle_chars;
while (!data->delta_eof) {
/* attendo che ci sia dati delta nell'area condivisa */
WAIT(sem, S_DELTA);
user_chars = data->content.delta.user * DISPLAY_COLUMNS;
system_chars = data->content.delta.system * DISPLAY_COLUMNS;
idle_chars = DISPLAY_COLUMNS - user_chars - system_chars;
print_chars(system_chars, '#');
print_chars(user_chars, '*');
print_chars(idle_chars, '_');
printf(" s:%5.2f%% u:%5.2f%%\n", data->content.delta.system * 100,
data->content.delta.user * 100);
/* segnalo che adesso l'area condivisa è libera */
SIGNAL(sem, S_EMPTY);
}
exit(0);
}
int main(int argc, char **argv) {
shm_data *data;
int shm_des, sem_des;
int num_samples;
if ((argc == 1) || ((num_samples = atoi(argv[1])) < 2))
num_samples = DEFAULT_NUM_SAMPLES;
if ((shm_des = shmget(IPC_PRIVATE, sizeof(shm_data), IPC_CREAT | 0600)) ==
-1) {
perror("shmget");
exit(1);
}
if ((data = (shm_data *)shmat(shm_des, NULL, 0)) == (shm_data *)-1) {
perror("shmat");
exit(1);
}
/* inizializza i valori di EOF nella struttura condivisa */
data->raw_eof = data->delta_eof = 0;
if ((sem_des = semget(IPC_PRIVATE, 3, IPC_CREAT | 0600)) == -1) {
perror("semget");
exit(1);
}
if (semctl(sem_des, S_EMPTY, SETVAL, 1) == -1) {
perror("semctl SETVAL S_EMPTY");
exit(1);
}
if (semctl(sem_des, S_RAW, SETVAL, 0) == -1) {
perror("semctl SETVAL S_RAW");
exit(1);
}
if (semctl(sem_des, S_DELTA, SETVAL, 0) == -1) {
perror("semctl SETVAL S_DELTA");
exit(1);
}
if (fork() == 0)
sampler(data, sem_des, num_samples);
if (fork() == 0)
analyzer(data, sem_des);
if (fork() == 0)
plotter(data, sem_des);
wait(NULL);
wait(NULL);
wait(NULL);
shmctl(shm_des, IPC_RMID, NULL);
semctl(sem_des, 0, IPC_RMID, 0);
exit(0);
}