/* Ecrire un programme dans lequel on s'assure que les threads ont installé leur masque de
cancels avant de leur envoyer des cancels. L'attente par la thread mère doit être
faite à l'aide de sémaphores mutex utilisés comme des sémaphores privés
*/
/* A compiler avec l'option -threads ou -lpthread selon les systèmes */
/* setcanc.c */

#include <pthread.h>

#define NbTh 4
int compteur[NbTh]={0,0,0,0}; pthread_t tid[NbTh];

pthread_mutex_t mutex[NbTh];
void * fille1(void *);	void * fille2(void *);	void * fille3(void *);	void * fille4(void *);
void * Filles[]={fille1, fille2, fille3, fille4};

/* *************   fonction executee par  fille1 */
void *fille1 (void *k) {
/* masquage des cancels pendant toute l'execution */
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
pthread_mutex_unlock(mutex); 		/* autorise la mere d'envoyer le cancel */
while (compteur[0]<20000000) compteur[0]++;
}

/* *************   fonction executee par  fille2 */
void *fille2 (void *k) {
/* aucun masquage => recoit les cancels uniquement quand elle le desire */
pthread_mutex_unlock(mutex+1); 		/* autorise la mere d'envoyer le cancel */
while( compteur[1] < 100000000 ) compteur[1]++; /* 1ere boucle */
pthread_testcancel();
/* 2eme boucle  : s'il y a eu un cancel, cette boucle ne sera pas du tout executee */
while( compteur[1] < 200000000 ) compteur[1]++;
}

/* *************   fonction executee par fille3 */
void *fille3 (void *k){
/* recoit les cancels de facon asynchrone: n'importe quand */
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
pthread_mutex_unlock(mutex+2); 		/* autorise la mere d'envoyer le cancel */
while( compteur[2] < 900000000 ) compteur[2]++;
}

/* *************   fonction executee par fille4 */
void *fille4 (void *k){
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);  	/* masquage des cancels */
pthread_mutex_unlock(mutex+3); 		/* autorise la mere d'envoyer le cancel */
while( compteur[3] < 100000000 ) compteur[3]++;	/* 1ere boucle */
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);  		/* demasquage des cancels */
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
/* 2eme boucle  : s'il y a un cancel, cette boucle sera interrompue */
while( compteur[3] < 200000000 ) compteur[3]++;
}

main(){
int i,  num;

for(i=0; i<NbTh; i++) {
	pthread_mutex_init(mutex+i, 0);
	pthread_mutex_lock(mutex+i); 	/* mise a 0 de tous les mutex */
}

/* creation des threads */
for(num=0;num<NbTh;num++)
	pthread_create(tid+num, 0, (void *(*)())Filles[num], (void *) num);

/* attend que toutes les threads aient mis leurs masques de signaux */
for(i=0;i<NbTh;i++) 	pthread_mutex_lock(mutex+i); 

/* envoi d'un cancel a toutes les threads */
for(i=0;i<NbTh;i++)	pthread_cancel(tid[i]); 

for(i=0;i<NbTh;i++)    pthread_join(tid[i], NULL); 

printf("Affichage des compteurs\n");
printf("%d \t%d \t%d \t%d\n", compteur[0], compteur[1], compteur[2], compteur[3]);
exit(0); 
}
