Process Race (Prova pratica 18-07-2013)

From Sistemi Operativi
Jump to navigation Jump to search
Esercizio 1: Linguaggio C (obbligatorio): (20 punti)
Una gara fra processi.
Scrivere un programma C che prenda in input (da standard input) alcune righe contenenti comandi con relativi parametri. La lista dei comandi termina quando viene inserita una riga vuota.
A questo punto tutti i comandi vengono eseguiti in modo concorrente e deve venir stampato l'ordine di terminazione.
(E' vietato usare system, popen o simili)
Es.
$ prorace
sleep 30
sleep 10
sleep 20
ls -l
input di una riga vuota .... output di ls -l ....
1 arrivato: ls -l
2 arrivato: sleep 10
3 arrivato: sleep 20
4 arrivato: sleep 30

Esercizio 2: completamento (10 punti)
Si estenda l'esercizio 1 in modo da avere una partenza piu' sincronizzata dei processi.
Tutti i processi devono attendere un evento che li sblocchi tutti insieme, per esempio tutti i processi possono mettersi in
attesa con poll o select sul canale di lettura di una pipe. Quando “prorace” scrive un carattere sulla pipe tutti i processi diventano ready.

Soluzione di Federico Giuggioloni

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <poll.h>
#include <string.h>

struct list_el
{
   pid_t pid;
   char* comando;
   struct list_el* next;
};

void insert_el(struct list_el** head, char* command, pid_t id)
{
   struct list_el *new_el = malloc(sizeof(struct list_el));
   new_el->comando = malloc(sizeof(char) * strlen(command) + 1);
   strcpy(new_el->comando, command);
   new_el->next = NULL;
   new_el->pid = id;


   if(*head == NULL)
   {
      *head = new_el;
   }
   else
   {
      struct list_el* tmp = (*head)->next;
      (*head)->next = new_el;
      new_el->next = tmp;
   }

}

int strspl(char*** split, char* string, const char* delim)
{
   char* result;
   char* parsed = malloc(strlen(string)+1);
   char* tofree = parsed;
   int size = 2;

   char* ptr = string;
   while(*ptr != 0)
   {
      if(*ptr == *delim) size++;
      ptr++;
   }

   if(*split == NULL)
   {
      *split = malloc(sizeof(char*) * size);
   }

   strcpy(parsed, string);

   int i = 0;
   while((result = strtok(parsed, delim)) != NULL)
   {
      //subsequent calls to strtok must have NULL in the first
      //parameter
      parsed = NULL;

      //(*split)[i] = result;
      (*split)[i] = malloc(strlen(result) * sizeof(char) + 1);
      strcpy((*split)[i], result);

      i++;
   }

   (*split)[i] = (char*) 0;

   free(tofree);
   return i;
}

struct list_el* head = NULL;

char* printNamePid(pid_t pid)
{
   struct list_el* p = head;
   while(p != NULL)
   {
      if(p->pid == pid) return p->comando;
      p = p->next;
   }
}

int main(int argc, char* argv[])
{
   int n;
   char *string;
   string = NULL;//malloc(MAX_BUFF * sizeof(char));
   int bytes_read;
   pid_t pid;
   char** splitargs = NULL;
   char delim = ' ';
   int nFork = 0;
   int err;
   int pipe_read = 0;
   char pipe_char = ' ';

   int pipefd[2];
   pipe(pipefd);

   struct pollfd pipe_read_poll;
   pipe_read_poll.fd = pipefd[0];
   pipe_read_poll.events = POLLIN;

   while((bytes_read = getline(&string, &n, stdin)) != 0)
   {
      if(strcmp(string, "\n") == 0) break;

      string[strlen(string)-1] = 0;
      strspl(&splitargs, string, &delim);

      pid = fork();
      switch(pid)
      {
         case -1:
            printf("Error fork: %s (%d)", strerror(errno), errno);
            exit(2);
            break;
         case 0:
            //pipe_read = read(pipefd[0], &pipe_read, 1);
            poll(&pipe_read_poll, 1, -1);
            err = execvp(splitargs[0], splitargs);
            if(err < 0)
            {
               printf("Error exec: %s (%d)", strerror(errno), errno);
               exit(1);
            }
            exit(0);
            break;
         default: //PADRE, continua pure
            nFork++;
            insert_el(&head, string, pid);
            break;
      }


      //free(splitargs); //TODO anche di tutte le stringhe all'interno
      splitargs = NULL;
   }

   int status = 0;
   char buf = 'g';
   char* comando = NULL;
   int ordineArrivo[nFork];
   int i = 0;

   write(pipefd[1], &buf, 1);

   while(i < nFork)
   {
      pid = wait(&status);
      ordineArrivo[i] = pid;
      i++;
   }

   printf("\n\n");
   for(i = 0; i < nFork; i++)
   {
      comando = printNamePid(ordineArrivo[i]);
      printf("%d : %s Terminated\n", i, comando);
   }
   return 0;
}

Soluzione di Claudio Kerov

Questa è la versione dell'esercizio 1 senza sincronizzazione della partenza dei processi.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>


struct lista{
    struct lista *next;
    char* stringa;
};

void leggiArgomenti(char* comando) //prendo il comando dalla stringa, la divido in programma e argomenti, poi la eseguo
{
    char* temp;
    char delim= ' ';
    char* args[64]; //alla fine uso questo
    char** next = args; //ma questo e' quello che riempio
    temp= strtok(comando, &delim );
    
    while (temp != NULL)
    {
        *next++ = temp;
        temp = strtok(NULL, &delim);
    }
    *next = NULL;
    execvp(args[0], args);
}

void ins(struct lista *l, char* comando) 
{
    struct lista *tmp = malloc(sizeof(struct lista));
    tmp->stringa = malloc(sizeof(char)*strlen(comando)+1);
    tmp->next= l->next;
    strcpy(tmp->stringa, comando);
    l->next = tmp;
    
}


int main  (int argc, char *argv[])
{
    
    size_t n;
    int status = 0;
    char *riga= (char*)malloc(sizeof(char));
    struct lista *lista_arrivi=(struct lista*) malloc(sizeof(struct lista));
    struct lista *tmp = lista_arrivi;
    lista_arrivi->next = NULL;
    
    while( (getline(&riga, &n, stdin)!=0)) 
    {
        if (strcmp(riga, "\n")==0)
            break;
        
        ins(lista_arrivi, riga);
        counter++;
        
    }
    
    while(lista_arrivi!=NULL)
    {
        pid_t pid = fork();
        switch(pid)
        {
            case -1: exit(2);
                break;
            case 0: //processo figlio che prende in input i comandi
                
                leggiArgomenti(lista_arrivi->stringa);
                break;
            default: //processo padre che stampera' la lista
                lista_arrivi= lista_arrivi->next;
                break;
        }
        
    }
    
    tmp = tmp->next;
    
    while(tmp!=NULL)
    {
        wait(&status);
        printf("Terminato: %s\n", tmp->stringa);
        tmp= tmp->next;
    }
    
    return 0;
}