/*********************************************************************** * Code contenant les fonctions qui doivent etre adaptees par * * l'etudiant pour son TP note * ***********************************************************************/ #include #include #include #include #include #include #include #include #include #include #include void handle_connection (int connection_fd); void *thread_gestion_connexion_entrante(void *arg); void *thread_gestion_sauvegarde(void *arg); #define NOMFICHIER "./sauvegardeCompteurReponse" #define NBTHREADSDANSPOOL 20 /* Cle d'acces a la memoire partagee */ #define SHMKEY "/42" #define MUTEX_COMPTEUR_KEY (SHMKEY + 1) /*************************************/ /* Definition des variables globales */ /*************************************/ int *pCompteurReponse; sem_t mutexCompteur; int fd; int descfich[2]; typedef struct { int compteurReponse; sem_t mutexCompteur; }shm_t; shm_t *p_shm; /********************************************/ /* Procedures appelees par le reste du code */ /********************************************/ /* Procedure chargee de toutes les initialisations specifiques au code de l'etudiant */ void init(){ pthread_t thread; int rc; int i; int shm_id; struct flock verrou; int need_init = 1; /*recherche segment partage */ shm_id = shm_open(SHMKEY, O_CREAT|O_EXCL|O_RDWR, 0666); if(shm_id < 0 && errno == EEXIST){ /* segment deja cree, donc pas besoin d'initialiser le mutex/le compteur */ need_init = 0; shm_id = shm_open(SHMKEY, O_RDWR, 0666); } assert(shm_id>=0); assert(ftruncate(shm_id, sizeof(shm_t)) >= 0); /* attachement a ce segment */ p_shm = mmap(NULL, sizeof(shm_t), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); assert(p_shm >= 0); /* Initialisaton du mutex qui va nous permettre de controler l'acces */ /* au compteur */ if(need_init) { p_shm->compteurReponse = 0; if(sem_init(&p_shm->mutexCompteur, 1, 1) !=0 ) { perror("sem_init"); exit(EXIT_FAILURE); } } /* Initialisation de *p_shm->CompteurReponse. On essaye d'ouvrir le fichier (avec */ /* l'option O_SYNC pour que l'ecriture se fasse au plus tot sur disque et */ /* qu'on perde donc le moins d'increments de CompteurReponse possible en */ /* cas de panne) */ fd = open(NOMFICHIER, O_RDWR|O_SYNC, 0); if (fd < 0){ if (errno == ENOENT){ /* Le fichier n'existe pas : on le cree donc (meme argument que precedemment */ /* pour O_SYNC) */ fd = open(NOMFICHIER, O_CREAT|O_RDWR|O_SYNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); if (fd < 0){ perror("open fichier"); exit(EXIT_FAILURE); } /* Le fichier venant d'etre cree, *pCompteurReponse vaut forcement 0 */ p_shm->compteurReponse = 0; }else{ perror("open fichier2"); exit(EXIT_FAILURE); } }else{ /* Pas d'erreur a l'ouverture du fichier : on recupere donc la valeur de */ /* CompteurReponse */ /* Il faut poser un verrou pour proteger cette lecture. En effet, */ /* l'autre processus peut etre en train d'ecrire le fichier ! */ verrou.l_whence = SEEK_SET; verrou.l_start = 0; verrou.l_len = sizeof(*pCompteurReponse); verrou.l_type = F_WRLCK; if (fcntl(fd, F_SETLKW, &verrou) < 0){ perror("Pose verrou"); exit(EXIT_FAILURE); } /* On doit faire ce lseek car l'autre processus a peut-etre bouger */ /* le pointeur de fichier. */ if (lseek(fd, 0, SEEK_SET) < 0){ perror("lseek"); exit(EXIT_FAILURE); } if (read(fd, &p_shm->compteurReponse, sizeof(p_shm->compteurReponse)) != sizeof(p_shm->compteurReponse)){ perror("Pb lors de l'initialisation de compteurReponse"); exit(EXIT_FAILURE); } verrou.l_type = F_UNLCK; if (fcntl(fd, F_SETLK, &verrou) < 0){ perror("Relachement verrou"); exit(EXIT_FAILURE); } } /* Demarrage de la thread chargee de faire les sauvegardes */ /* NB : Inutile de detacher ce thread, vu qu'il tournera eternellement */ /* (plus precisement jusqu'a la mort du processus) */ rc = pthread_create(&thread, NULL, thread_gestion_sauvegarde, NULL); if (rc < 0){ perror("pthread_create"); exit(EXIT_FAILURE); } /* Creation du tube sur lequel attendront les NBTHREADSDANSPOOL threads */ /* du pool */ if (pipe(descfich) != 0){ perror("pipe"); exit(EXIT_FAILURE); } /* Creation des NBTHREADSDANSPOOL threads du pool */ for (i=0; icompteurReponse += 1; sem_post(&mutexCompteur); return p_shm->compteurReponse; } /********************************************/ /* Procedures specifiques a l'etudiant */ /********************************************/ /* Procedure chargee des traitements liees a une reponse a une requete http */ void *thread_gestion_connexion_entrante(void *arg){ do{ int connection_fd; if (read(descfich[0], &connection_fd, sizeof(connection_fd)) != sizeof(connection_fd)){ perror("read pipe"); exit(EXIT_FAILURE); } handle_connection(connection_fd); }while(1); pthread_exit(NULL); } void *thread_gestion_sauvegarde(void *arg){ struct timespec sleeptime={1,0}; struct flock verrou; verrou.l_whence = SEEK_SET; verrou.l_start = 0; verrou.l_len = sizeof(p_shm->compteurReponse); do{ int compteurReponseLocal; /* On recupere la valeur courante de *pCompteurReponse (dans une variable */ /* locale pour que la recuperation de cette valeur bloque le moins de */ /* temps possible les autres threads) */ sem_wait(&mutexCompteur); compteurReponseLocal = p_shm->compteurReponse; sem_post(&mutexCompteur); /* Ecriture de compteurReponse dans le fichier en posant un verrou */ /* pour eviter les problemes de competition avec l'autre processus */ verrou.l_type = F_WRLCK; if (fcntl(fd, F_SETLKW, &verrou) < 0){ perror("Pose verrou"); exit(EXIT_FAILURE); } if (lseek(fd, 0, SEEK_SET) < 0){ perror("lseek"); exit(EXIT_FAILURE); } if (write(fd, &compteurReponseLocal, sizeof(compteurReponseLocal)) != sizeof(compteurReponseLocal)){ perror("write"); exit(EXIT_FAILURE); } verrou.l_type = F_UNLCK; if (fcntl(fd, F_SETLK, &verrou) < 0){ perror("Relachement verrou"); exit(EXIT_FAILURE); } /* On dort */ if (nanosleep(&sleeptime, NULL) != 0){ perror("nanosleep"); exit(EXIT_FAILURE); } }while(1); pthread_exit(NULL); }