Sistemi di Calcolo

Corso di Laurea in Ingegneria Informatica e Automatica - A.A. 2017-2018

HomePage | Avvisi | Diario lezioni | Programma | Materiale didattico | Esami | Forum | Login

System call interrotte da segnali


Esempio: gestore SIGINT, interruzione system call pause

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

void miogestore(int num_segnale) {
    printf("catturato segnale %d\n", num_segnale);
}

#define USE_PERROR 0 // vedere anche quando: valore 1

int main() {
    struct sigaction act = { 0 };
    act.sa_handler = miogestore;
    int res = sigaction(SIGINT, &act, NULL);
    if (res == -1) {
        perror("errore nella sigaction");
        exit(1);
    }

    res = pause();

    printf("return value pause: %d\n", res);
    if (res == -1) {

        #if USE_PERROR
        perror("causa errore pause");
        #else

        switch (errno) {

            case EINTR:
                printf("Interrotta da segnale.\n");
                break;

            // pause ammette solo EINTR come errore, vedere: man pause
            // quindi SOLO per questa system call ha poco considerare casi errno != EINTR
            default:
                perror("causa errore pause");
        }
        #endif
       
    }
    return 0;
}


Esempio: gestore SIGCHLD, interruzione system call

sigaction-3.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

void myhandler(int signo) {
    printf("figlio e' terminato\n");
}


int main() {

    struct sigaction sa = {0};
    sa.sa_handler = myhandler;
    int res = sigaction(SIGCHLD, &sa, NULL);

    printf("[pid=%d] genitore\n", getpid());

    pid_t pid = fork();

    if (pid == -1) {
        perror("errore nella fork");
        exit(EXIT_FAILURE);
    }

    if (pid == 0) { // processo figlio

        printf("[pid=%d] figlio\n", getpid());
        _exit(EXIT_SUCCESS);
    }

    int s = 30;
    res = sleep(s); // genitore potrebbe fare qualcosa di piu' utile
                          // in questo esempio invoca una system call

    if (res > 0)
        printf("Genitore termina: sleep terminata prematuramente dopo %d secondi\n", s - res);
    else
        printf("Genitore termina: sleep eseguita interamente per %d secondi\n", s);

    return EXIT_SUCCESS;
}


System call open, read, write, close


Scrittura di file

Versione 1:
#include <unistd.h> // read, write, close
#include <fcntl.h>  // open
#include <stdlib.h> // exit
#include <stdio.h>  // perror

char text[] = "This is a test\n";

int main(int argc, char* argv[]) {

    int flags = O_WRONLY | O_CREAT | O_TRUNC;   // O_WRONLY: file aperto in sola scrittura
                                                // O_CREAT: se il file non esiste, verra' creato
                                                // O_TRUNC: se il file esiste, trancare il contenuto

    // se il file non esiste, allora dobbiamo indicare i permessi
    mode_t mode = 0640; // Una costante che inizia con 0 (e non 0x) in C e' in notazione ottale
                        // 0640: user => rw, group => r, others => nessuno

    // alternativa ad usare numero ottale: usare le costanti definite da POSIX
    // mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP; // corrisponde a 0644

    int fd = open("test.txt", flags, mode);

    if (fd == -1) {
        perror("Error in open");
        exit(1);
    }
   
    if (write(fd, text, sizeof(text)) != sizeof(text)) { // verifica che abbiamo scritto tutto quello che volevamo scrivere
        // se non e' cosi', terminiamo...
        perror("Error in write");
        exit(1);
    }
   
    if (close(fd)) {
        perror("Error in close");
        exit(1);
    }
   
    return 0;
}


Versione 2 (gestione EINTR):
#include <unistd.h> // read, write, close
#include <fcntl.h>  // open
#include <stdlib.h> // exit
#include <stdio.h>  // perror
#include <errno.h>

char text[] = "This is a test\n";

int main(int argc, char* argv[]) {

    int flags = O_WRONLY | O_CREAT | O_TRUNC;  
    mode_t mode = 0640;

    int fd = open("test.txt", flags, mode);

    if (fd == -1) {
        perror("Error in open");
        exit(1);
    }
   
    ssize_t byte_scritti = 0;
    ssize_t byte_da_scrivere = sizeof(text); // sizeof funziona correttamente solo text e' dichiarato come array e non un puntatore ad una stringa!

    printf("Byte da scrivere: %d\n", byte_da_scrivere);

    while (byte_scritti < byte_da_scrivere) {

        ssize_t res = write(fd, text + byte_scritti, sizeof(text) - byte_scritti);
        if (res == -1) { // errore
            // analizziamo la causa dell'errore
            switch (errno) {
                case EINTR:
                    // se e' arrivato un segnale, non e' un errore fatale possiamo ritentare la scrittura
                    continue;
                    break;
                default:
                    // consideriamo le altre cause come errori fatali non recuperabili
                    perror("errore write");
                    exit(EXIT_FAILURE);
            }
        }
        byte_scritti += res;
        printf("Byte scritti: %d\n", res);
    }
   
    if (close(fd)) {
        perror("Error in close");
        exit(EXIT_FAILURE);
    }
   
    return 0;
}


Comando cat

Realizzazione comando cat:

#include <unistd.h> // read, write, close
#include <fcntl.h>  // open
#include <stdlib.h> // exit
#include <stdio.h>  // printf
#include <errno.h>  // errno, EINTR

int main(int argc, char* argv[]) {

    char buffer[256];
    ssize_t res;

    if (argc < 2) {
        printf("Usage: %s filename\n", argv[0]);
        exit(1);
    }

    int fd = open(argv[1], O_RDONLY);
    if (fd == -1) {
        perror("Error in open");
        exit(1);
    }

    while(1) {
        res = read(fd, buffer, sizeof(buffer));
        if (res == -1) {
            <