Home | History | Annotate | Download | only in locks
      1 /* *************************************************
      2  * *********** README ******************************
      3  * *************************************************
      4  *
      5  * COMPILE : make
      6  * RUN : ./locktests -n <number of concurent process> -f <test file> [-P]
      7  *
      8  * GOAL : This test tries to stress the fcntl locking functions.  A
      9  * master process sets a lock on a file region (this is called "byte
     10  * range locking").  Some slave processes try to perform operations on
     11  * this region, such as read, write, set a new lock ... The expected
     12  * results of these operations are known.  If the operation result is
     13  * the same as the expected one, the test suceeds, else it fails.
     14  *
     15  *
     16  *
     17  * Slaves are concurent processes or thread.
     18  * -n <num>  : Number of threads to use (mandatory).
     19  * -f <file> : Run the test on given test file defined by the -f option (mandatory).
     20  * -c <num>  : Number of clients to connect before starting the tests.
     21  *
     22  * HISTORY : This program was written to stress NFSv4 locks.
     23  * EXAMPLE : ./locktests -n 50 -f /file/system/to/test
     24  *
     25  *
     26  * Vincent ROQUETA 2005 - vincent.roqueta (at) ext.bull.net
     27  * BULL S.A.
     28  */
     29 
     30 #include "locktests.h"
     31 
     32 int MAXLEN = 64;
     33 int MAXTEST = 10;
     34 extern int maxClients;
     35 extern int fdServeur;
     36 
     37 char message[M_SIZE];
     38 int esclaveLecteur;
     39 int maitreLecteur;
     40 int esclaveEcrivain;
     41 
     42 /* Quel lock sera appplique par le maitre en debut de test */
     43 /* Which lock will be applied by the master process on test startup */
     44 int LISTE_LOCKS[] = { READLOCK, WRITELOCK,
     45 	READLOCK, WRITELOCK,
     46 	READLOCK, WRITELOCK,
     47 	READLOCK, WRITELOCK,
     48 	BYTELOCK_READ, BYTELOCK_WRITE
     49 };
     50 
     51 /* Les operations que les programes esclaves essaieront de faire */
     52 /* The operations the slave processes will try to perform */
     53 
     54 int LISTE_TESTS[] = { WRONLY, WRONLY,
     55 	RDONLY, RDONLY,
     56 	READLOCK, WRITELOCK,
     57 	WRITELOCK, READLOCK,
     58 	BYTELOCK_READ, BYTELOCK_WRITE
     59 };
     60 
     61 /* List of test names */
     62 char *LISTE_NOMS_TESTS[] = { "WRITE ON A READ  LOCK",
     63 	"WRITE ON A WRITE LOCK",
     64 	"READ  ON A READ  LOCK",
     65 	"READ  ON A WRITE LOCK",
     66 	"SET A READ  LOCK ON A READ  LOCK",
     67 	"SET A WRITE LOCK ON A WRITE LOCK",
     68 	"SET A WRITE LOCK ON A READ  LOCK",
     69 	"SET A READ  LOCK ON A WRITE LOCK",
     70 	"READ LOCK THE WHOLE FILE BYTE BY BYTE",
     71 	"WRITE LOCK THE WHOLE FILE BYTE BY BYTE"
     72 };
     73 
     74 /* Resultat attendu du test - Processus */
     75 /* List of expected test results, when slaves are processes */
     76 
     77 int LISTE_RESULTATS_PROCESS[] = { SUCCES, SUCCES,
     78 	SUCCES, SUCCES,
     79 	SUCCES, ECHEC,
     80 	ECHEC, ECHEC,
     81 	SUCCES, SUCCES
     82 };
     83 
     84 /* List of expected test results, when slaves are threads */
     85 
     86 int LISTE_RESULTATS_THREADS[] = { SUCCES, SUCCES,
     87 	SUCCES, SUCCES,
     88 	SUCCES, SUCCES,
     89 	SUCCES, SUCCES,
     90 	ECHEC, ECHEC
     91 };
     92 
     93 int *LISTE_RESULTATS = NULL;
     94 char *eType = NULL;
     95 
     96 int TOTAL_RESULTAT_OK[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
     97 
     98 void *esclave(void *donnees);
     99 int (*terminer) (int a);
    100 
    101 int terminerProcess(int a)
    102 {
    103 	exit(a);
    104 }
    105 
    106 int (*load) ();
    107 
    108 struct donneesPub dp;
    109 
    110 /* Manipulation des tests/ noms de tests/ resultats de tests */
    111 /* Functions to access tests/tests names/tests results*/
    112 int testSuiv(int n)
    113 {
    114 	return LISTE_TESTS[n];
    115 }
    116 
    117 int resAttSuiv(int n)
    118 {
    119 	return LISTE_RESULTATS[n];
    120 }
    121 
    122 char *nomTestSuiv(int n)
    123 {
    124 	return LISTE_NOMS_TESTS[n];
    125 }
    126 
    127 int lockSuiv(int n)
    128 {
    129 	return LISTE_LOCKS[n];
    130 }
    131 
    132 /* Verifie si le resultat obtenu pour le test est le resultat attendu pour ce test */
    133 /* Verifie the test result is the expected one */
    134 int matchResult(int r, int n)
    135 {
    136 
    137 	P("r=%d\n", r);
    138 	if (r == LISTE_RESULTATS[n])
    139 		return 1;
    140 	else
    141 		return 0;
    142 }
    143 
    144 /* Incremente le nombre de process ayant valide le test */
    145 /* Increments the number of process which have successfully passed the test */
    146 void compteur(int r, int n)
    147 {
    148 	TOTAL_RESULTAT_OK[n] += matchResult(r, n);
    149 }
    150 
    151 /* Validation des resultats pour le lock de fichier octet par octet
    152  * Pour chaque octet on verifie qu'un lock de 1 octet est bien pose
    153  */
    154 /* Special case for test 'lock file byte byte by byte'.
    155  * We ensure each byte is correctly locked.
    156  */
    157 
    158 void validationResultats(int n)
    159 {
    160 	int i, u, l, fsize;
    161 	struct flock request;
    162 
    163 	fsize = dp.nclnt * (maxClients + 1);
    164 	TOTAL_RESULTAT_OK[n] = 0;
    165 	l = FALSE;
    166 	u = TRUE;
    167 	/* Si le resultat de l'operation attendu est un succe on prevoi d'incrementer le nombre de resultats corrects */
    168 	/* If the expected operation result is a success, we will have to increase the number of correct results */
    169 	if (LISTE_RESULTATS[n]) {
    170 		l = TRUE;
    171 		u = FALSE;
    172 	}
    173 
    174 	for (i = 0; i < fsize; i++) {
    175 		request.l_type = F_WRLCK;
    176 		request.l_whence = SEEK_SET;
    177 		request.l_start = i;
    178 		request.l_len = 1;
    179 		fcntl(dp.fd, F_GETLK, &request);
    180 		/* On verifie si le lock est mis ou non */
    181 		/* Ensure the lock is correctly set */
    182 		if (request.l_type != F_UNLCK)
    183 			TOTAL_RESULTAT_OK[n] += l;
    184 		else
    185 			TOTAL_RESULTAT_OK[n] += u;
    186 	}
    187 }
    188 
    189 /* Procedures d'initialisation */
    190 /* Initialisation functions */
    191 
    192 int initTest()
    193 {
    194 
    195 	P("Maitre ouvre %s\n", dp.fname);
    196 	dp.fd = open(dp.fname, OPENFLAGS, MANDMODES);
    197 	if (dp.fd < 0) {
    198 		perror("lock test : can't open test file :");
    199 		terminer(1);
    200 	}
    201 	P("fd=%d\n", dp.fd);
    202 	return 0;
    203 }
    204 
    205 struct donneesFils *initClientFork(int i)
    206 {
    207 	struct donneesPriv *dpr;
    208 	struct donneesFils *df;
    209 
    210 	/* Initialisation des champs de donnees */
    211 	/* Initialize private data fields */
    212 	dpr = malloc(sizeof(struct donneesPriv));
    213 	df = malloc(sizeof(struct donneesFils));
    214 	dpr->whoami = i;
    215 	df->dp = &dp;
    216 	df->dpr = dpr;
    217 	/* Initialisation du tubes de synchronisation */
    218 	/* Initialize master to client pipe */
    219 	dp.lclnt[i] = malloc(sizeof(int) * 2);
    220 	if (pipe(dp.lclnt[i]) < 0) {
    221 		perror("Impossible to create pipe\n");
    222 		exit(1);
    223 	}
    224 	P("Initialization %d\n", i);
    225 	write(0, ".", 1);
    226 	return df;
    227 }
    228 
    229 int initialise(int clnt)
    230 {
    231 
    232 	/* Initialisation des donnees publiques */
    233 	/* Initialize private data fields */
    234 	printf("Init\n");
    235 	dp.nclnt = clnt;
    236 	dp.lclnt = malloc(sizeof(int *) * clnt);
    237 	dp.lthreads = malloc(sizeof(pthread_t) * clnt);
    238 
    239 	/* initialisation de la communication avec le maitre */
    240 	/* Initialize client to master pipe */
    241 	if (pipe(dp.maitre) < 0) {
    242 		perror("Master pipe creation error\n");
    243 		exit(1);
    244 	}
    245 	printf("%s initialization\n", eType);
    246 	load();
    247 	initTest();
    248 
    249 	return 0;
    250 }
    251 
    252 void cleanClient(struct donneesFils *df)
    253 {
    254 	int i;
    255 	i = df->dpr->whoami;
    256 	free(dp.lclnt[i]);
    257 	free(df->dpr);
    258 	free(df);
    259 }
    260 
    261 void clean()
    262 {
    263 	free(dp.lthreads);
    264 	free(dp.lclnt);
    265 }
    266 
    267 int loadProcess()
    268 {
    269 	int i;
    270 	struct donneesFils *df;
    271 	for (i = 0; i < dp.nclnt; i++) {
    272 		df = initClientFork(i);
    273 		if (!fork()) {
    274 			P("Running slave num: %d\n", df->dpr->whoami);
    275 			write(0, ".", 1);
    276 			esclave((void *)df);
    277 			cleanClient(df);
    278 			exit(0);
    279 		}
    280 	}
    281 	return 0;
    282 }
    283 
    284 void lockWholeFile(struct flock *request)
    285 {
    286 	request->l_whence = SEEK_SET;
    287 	request->l_start = 0;
    288 	/* Lock de l'ensemble du fichier */
    289 	/* Lock the whole file */
    290 	request->l_len = 0;
    291 }
    292 
    293 void selectTest(int n, struct s_test *test)
    294 {
    295 
    296 	test->test = testSuiv(n);
    297 	test->resAtt = resAttSuiv(n);
    298 	test->nom = nomTestSuiv(n);
    299 	test->type = lockSuiv(n);
    300 }
    301 
    302 /* Final test report */
    303 void rapport(clnt)
    304 {
    305 	int i;
    306 	int totalClients;
    307 	totalClients = clnt * (maxClients + 1);
    308 	printf
    309 	    ("\n%s number : %d - Remote clients: %d local client 1 - Total client %d - Total concurent tests: %d\n",
    310 	     eType, clnt, maxClients, maxClients + 1, totalClients);
    311 	printf("%s number running test successfully :\n", eType);
    312 	for (i = 0; i < MAXTEST; i++)
    313 		printf("%d %s of %d successfully ran test : %s\n",
    314 		       TOTAL_RESULTAT_OK[i], eType, totalClients,
    315 		       LISTE_NOMS_TESTS[i]);
    316 
    317 }
    318 
    319 int serverSendLocal()
    320 {
    321 	int i;
    322 	/* Synchronisation des processus esclaves. */
    323 	/* Synchronize slave processes */
    324 
    325 	/* On configure les esclaves pour le test */
    326 	/* Configure slaves for test */
    327 
    328 	for (i = 0; i < dp.nclnt; i++)
    329 		write(dp.lclnt[i][1], message, M_SIZE);
    330 	return 0;
    331 
    332 }
    333 
    334 void serverSendNet()
    335 {
    336 	writeToAllClients(message);
    337 }
    338 
    339 int serverReceiveNet()
    340 {
    341 	int i, c;
    342 	for (c = 0; c < maxClients; c++) {
    343 		for (i = 0; i < dp.nclnt; i++) {
    344 			serverReceiveClient(c);
    345 		}
    346 	}
    347 	return 0;
    348 }
    349 
    350 int serverReceiveLocal()
    351 {
    352 	int i;
    353 	for (i = 0; i < dp.nclnt; i++)
    354 		read(maitreLecteur, message, M_SIZE);
    355 	return 0;
    356 }
    357 
    358 int clientReceiveLocal()
    359 {
    360 	read(esclaveLecteur, message, M_SIZE);
    361 	return 0;
    362 }
    363 
    364 int clientSend()
    365 {
    366 	write(esclaveEcrivain, message, M_SIZE);
    367 	return 0;
    368 }
    369 
    370 int serverSend()
    371 {
    372 	serverSendNet();
    373 	serverSendLocal();
    374 	return 0;
    375 }
    376 
    377 int serverReceive()
    378 {
    379 	serverReceiveNet();
    380 	serverReceiveLocal();
    381 	return 0;
    382 }
    383 
    384 /* binary structure <-> ASCII functions used to ensure data will be correctly used over
    385  * the network, especially when multiples clients do not use the same hardware architecture.
    386  */
    387 int serialiseTLock(struct s_test *tLock)
    388 {
    389 	memset(message, 0, M_SIZE);
    390 	sprintf(message, "T:%d:%d:%d::", tLock->test, tLock->type,
    391 		tLock->resAtt);
    392 	return 0;
    393 }
    394 
    395 void unSerialiseTLock(struct s_test *tLock)
    396 {
    397 	sscanf(message, "T:%d:%d:%d::", &(tLock->test), &(tLock->type),
    398 	       &(tLock->resAtt));
    399 	memset(message, 0, M_SIZE);
    400 
    401 }
    402 
    403 void serialiseFLock(struct flock *request)
    404 {
    405 	int len, pid, start;
    406 	memset(message, 0, M_SIZE);
    407 	len = (int)request->l_len;
    408 	pid = (int)request->l_pid;
    409 	start = (int)request->l_start;
    410 	/* Beware to length of integer conversions ... */
    411 	sprintf(message, "L:%hd:%hd:%d:%d:%d::",
    412 		request->l_type, request->l_whence, start, len, pid);
    413 }
    414 
    415 void serialiseResult(int resultat)
    416 {
    417 	memset(message, 0, M_SIZE);
    418 	sprintf(message, "R:%d::", resultat);
    419 
    420 }
    421 
    422 void unSerialiseResult(int *resultat)
    423 {
    424 	sscanf(message, "R:%d::", resultat);
    425 }
    426 
    427 void unSerialiseFLock(struct flock *request)
    428 {
    429 	int len, pid, start;
    430 	sscanf(message, "L:%hd:%hd:%d:%d:%d::",
    431 	       &(request->l_type), &(request->l_whence), &start, &len, &pid);
    432 	request->l_start = (off_t) start;
    433 	request->l_len = (off_t) len;
    434 	request->l_pid = (pid_t) pid;
    435 }
    436 
    437 int serverSendLockClient(struct flock *request, int client)
    438 {
    439 	serialiseFLock(request);
    440 	return serverSendClient(client);
    441 }
    442 
    443 int serverSendLockLocal(struct flock *request, int esclave)
    444 {
    445 	serialiseFLock(request);
    446 	return write(dp.lclnt[esclave][1], message, M_SIZE);
    447 }
    448 
    449 int getLockSection(struct flock *request)
    450 {
    451 	memset(message, 0, M_SIZE);
    452 	clientReceiveLocal();
    453 	unSerialiseFLock(request);
    454 	return 0;
    455 }
    456 
    457 int sendLockTest(struct s_test *tLock)
    458 {
    459 	serialiseTLock(tLock);
    460 	serverSend();
    461 	return 0;
    462 }
    463 
    464 int getLockTest(struct s_test *tLock)
    465 {
    466 	clientReceiveLocal();
    467 	unSerialiseTLock(tLock);
    468 	return 0;
    469 }
    470 
    471 int sendResult(int resultat)
    472 {
    473 	serialiseResult(resultat);
    474 	clientSend();
    475 	return 0;
    476 }
    477 
    478 int getResults(int ntest)
    479 {
    480 	int i, c;
    481 	int resultat = 0;
    482 	/* On comptabilise les resultats distants */
    483 	/* Add remote test results */
    484 	for (c = 0; c < maxClients; c++) {
    485 		for (i = 0; i < dp.nclnt; i++) {
    486 			serverReceiveClient(c);
    487 			unSerialiseResult(&resultat);
    488 			compteur(resultat, ntest);
    489 
    490 		}
    491 	}
    492 	/* On comptabilise les resultats locaux */
    493 	/* Add local test results */
    494 	for (i = 0; i < dp.nclnt; i++) {
    495 		read(maitreLecteur, message, M_SIZE);
    496 		unSerialiseResult(&resultat);
    497 		compteur(resultat, ntest);
    498 	}
    499 
    500 	return 0;
    501 }
    502 
    503 /* Usefull debug macro */
    504 #ifdef DEBUG
    505 #define P(a,b)  memset(dbg,0,16);sprintf(dbg,a,b);write(0,dbg,16);
    506 #endif
    507 
    508 /* Le maitre de l'application client n'est qu'un repetiteur d'information.
    509  * Il retransmet l'information qu'il reoit du maitre du client a ses esclaves
    510  */
    511 /* In the case of a network use, the master of the client application si only
    512  * a 'repeater' of information. It resends server-master instructions to its own slaves.
    513  */
    514 
    515 void maitreClient()
    516 {
    517 	fd_set fdread;
    518 	struct timeval tv;
    519 	int n, i, r, m, start;
    520 #ifdef DEBUG
    521 	char dbg[16];
    522 #endif
    523 	struct flock lock;
    524 	int t;
    525 
    526 	maitreLecteur = dp.maitre[0];
    527 	FD_ZERO(&fdread);
    528 	tv.tv_sec = 50;
    529 	tv.tv_usec = 0;
    530 	n = fdServeur > maitreLecteur ? fdServeur : maitreLecteur;
    531 	printf("Maitre CLient - fdServeur=%d\n", fdServeur);
    532 	while (1) {
    533 		/* On ajoute les descripteurs esclave et serveur */
    534 		/* Add slave and server pipe file descriptors */
    535 		FD_ZERO(&fdread);
    536 		FD_SET(fdServeur, &fdread);
    537 		FD_SET(maitreLecteur, &fdread);
    538 		r = select(n + 1, &fdread, NULL, NULL, &tv);
    539 		if (r < 0) {
    540 			perror("select:\n");
    541 			continue;
    542 		}
    543 		if (r == 0) {
    544 			exit(0);
    545 		}
    546 
    547 		if (FD_ISSET(fdServeur, &fdread)) {
    548 			/* On vient de recevoir une information du serveur
    549 			 * On la retransmet aux esclaves
    550 			 */
    551 			/* We just have received information from the server.
    552 			 * We repeat it to slaves.
    553 			 */
    554 			i = readFromServer(message);
    555 			t = message[0];
    556 			switch (t) {
    557 			case 'L':
    558 				/* Instruction : Lock. Dans ce cas il faut envoyer a chaque processus une section differente a locker */
    559 				/* Lock instruction. We need to send a different section to lock to each process */
    560 
    561 				unSerialiseFLock(&lock);
    562 				start = lock.l_start;
    563 				for (i = 0; i < dp.nclnt; i++) {
    564 					lock.l_start = start + i;
    565 					serialiseFLock(&lock);
    566 					write(dp.lclnt[i][1], message, M_SIZE);
    567 				}
    568 				printf("\n");
    569 				continue;
    570 			case 'T':
    571 				/* Instruction: Test. Il s'agit d'une trame annoncant un nouveau test : on verifie qu'il ne s'agit pas d'une
    572 				 * demande de FIN des tests
    573 				 */
    574 				/* Test instruction. Ensure server is not sending the FIN(ish) instruction to end tests */
    575 
    576 				/* A re-ecrire un peu mieux des que possible */
    577 				/* To be rewritten asap */
    578 				m = atoi(&(message[2]));
    579 				if (m == FIN)
    580 					break;
    581 				if (m == CLEAN)
    582 					printf("\n");
    583 
    584 				serverSendLocal();
    585 				continue;
    586 			}
    587 			break;
    588 		} else {
    589 			/* Dans le cas inverse, on lis les esclaves et on remonte l'information au serveur
    590 			 */
    591 			/* Else, we read information from slaves and repeat them to the server */
    592 			for (i = 0; i < dp.nclnt; i++) {
    593 				r = read(maitreLecteur, message, M_SIZE);
    594 				r = write(fdServeur, message, M_SIZE);
    595 				if (r < 0)
    596 					perror("write : ");
    597 
    598 			}
    599 			continue;
    600 		}
    601 	}
    602 
    603 	/* On vient de recevoir la trame FIN de programme */
    604 	/* Receive the FIN(ish) instruction */
    605 
    606 	/* On la communique a tous les esclaves */
    607 	/* Repeat it to the slaves */
    608 	printf("Fin du programme en cours...\n");
    609 	serverSendLocal();
    610 
    611 	/* Et c'est fini! */
    612 	/* Ok, we can quit */
    613 	printf("Bye :)\n");
    614 
    615 }
    616 
    617 void maitre()
    618 {
    619 	int i, n, bl;
    620 	int clnt;
    621 	char tmp[MAXLEN], *buf;
    622 #ifdef DEBUG
    623 	char dbg[16];
    624 #endif
    625 	struct flock request;
    626 	struct s_test tLock;
    627 	enum etat_t etat;
    628 	int offset;
    629 	/* A test sentence written in the file */
    630 	char phraseTest[] =
    631 	    "Ceci est une phrase test ecrite par le maitre dans le fichier";
    632 	bl = -1;
    633 	clnt = dp.nclnt;
    634 	maitreLecteur = dp.maitre[0];
    635 	etat = SELECT;
    636 	/* On commence par le premier test. C'est original ;) */
    637 	/* Start with the first test ;) */
    638 	n = 0;
    639 	printf("\n--------------------------------------\n");
    640 	while (1) {
    641 		switch (etat) {
    642 		case SELECT:
    643 			/* Selection du test a effectuer */
    644 			/* Select the test to perform   */
    645 			printf("\n");
    646 			E("Maitre: SELECT");
    647 			selectTest(n, &tLock);
    648 			etat = tLock.type;
    649 			bl = 0;
    650 			if (n < MAXTEST) {
    651 				memset(tmp, 0, MAXLEN);
    652 				sprintf(tmp, "TEST : TRY TO %s:",
    653 					LISTE_NOMS_TESTS[n]);
    654 				write(0, tmp, strlen(tmp));
    655 			} else
    656 				etat = FIN;
    657 			P("etat=%d\n", etat);
    658 			n += 1;
    659 			continue;
    660 
    661 		case RDONLY:
    662 		case WRONLY:
    663 
    664 		case READLOCK:
    665 			P("Read lock :%d\n", etat);
    666 			request.l_type = F_RDLCK;
    667 			etat = LOCK;
    668 			continue;
    669 
    670 		case WRITELOCK:
    671 			P("Write lock :%d\n", etat);
    672 			request.l_type = F_WRLCK;
    673 			etat = LOCK;
    674 			continue;
    675 
    676 		case LOCK:
    677 			/* On applique le lock que l'on veut */
    678 			/* Apply the wanted lock */
    679 			E("Maitre: LOCK");
    680 			write(dp.fd, phraseTest, strlen(phraseTest));
    681 			lockWholeFile(&request);
    682 			if (fcntl(dp.fd, F_SETLK, &request) < 0) {
    683 				perror("Master: can't set lock\n");
    684 				perror("Echec\n");
    685 				exit(0);
    686 			}
    687 			E("Maitre");
    688 			etat = SYNC;
    689 			continue;
    690 
    691 		case BYTELOCK_READ:
    692 			bl = 1;
    693 			request.l_type = F_RDLCK;
    694 			etat = SYNC;
    695 			continue;
    696 
    697 		case BYTELOCK_WRITE:
    698 			bl = 1;
    699 			request.l_type = F_WRLCK;
    700 			etat = SYNC;
    701 			continue;
    702 
    703 		case BYTELOCK:
    704 			/*
    705 			 * L'idee est de faire locker l'ensemble du fichier octet par octet par un ensemble de sous processus
    706 			 * Il nous faut donc
    707 			 * -creer un fichier ayant autant d'octet que le nombre de processus passe en parametres
    708 			 * -passer les sections a locker a chacun des esclaves
    709 			 * -verifier que les locks sont bien appliques
    710 			 *
    711 			 */
    712 
    713 			/* The main idea is to lock all the bytes in a file. Each slave process locks one byte.
    714 			 *
    715 			 * We need :
    716 			 * - To create a file of a length equal to the total number of slave processes
    717 			 * - send the exact section to lock to each slave
    718 			 * - ensure locks have been correctly set
    719 			 */
    720 
    721 			/* On cree une chaine de caracteres a enregistrer dans le fichier qui contienne exactement un octet par
    722 			 * processus.
    723 			 */
    724 			/* Create a string to record in the test file. Length is exactly the number of sub process */
    725 			P("Maitre: BYTELOCK: %d\n", etat);
    726 			buf = malloc(clnt * (maxClients + 1));
    727 			memset(buf, '*', clnt);
    728 			write(dp.fd, buf, clnt);
    729 			free(buf);
    730 
    731 			/* Chaque processus esclave reecrit son champs a locker. */
    732 			/* Each slave process re-writes its own field to lock */
    733 			request.l_whence = SEEK_SET;
    734 			request.l_start = 0;
    735 			request.l_len = 1;
    736 
    737 			/* On commence par les envois reseau */
    738 			/* Start to send sections to lock to remote process (network clients) */
    739 
    740 			for (i = 0; i < maxClients; i++) {
    741 				/* On renseigne la structure avec le lock qui va bien */
    742 				/* Set the correct byte to lock */
    743 				offset = (i + 1) * clnt;
    744 				request.l_start = (off_t) offset;
    745 				serverSendLockClient(&request, i);
    746 			}
    747 
    748 			/* Puis les envois locaux */
    749 			/* Now send sections to local processes */
    750 			for (i = 0; i < clnt; i++) {
    751 				request.l_start = i;
    752 				serverSendLockLocal(&request, i);
    753 			}
    754 			etat = RESULTAT;
    755 			continue;
    756 
    757 		case SYNC:
    758 			sendLockTest(&tLock);
    759 			if (bl) {
    760 				etat = BYTELOCK;
    761 				continue;
    762 			}
    763 
    764 			if (n < MAXTEST + 1)
    765 				etat = RESULTAT;
    766 			else
    767 				etat = FIN;
    768 			continue;
    769 
    770 		case RESULTAT:
    771 			/* On lit les resultats un par un */
    772 			/* Read results by one */
    773 			getResults(n - 1);
    774 			if (bl)
    775 				validationResultats(n - 1);
    776 			etat = CLEAN;
    777 			continue;
    778 
    779 		case CLEAN:
    780 			/* On demande aux clients d'arreter le test */
    781 			/* Ask the clients to stop testing ... */
    782 			tLock.test = CLEAN;
    783 			serialiseTLock(&tLock);
    784 			serverSend();
    785 			/* ... et on attend un accuse de reception avant de fermer */
    786 			/* ... and wait for an ack before closing */
    787 			serverReceive();
    788 			/* On ignore les resultats, ce n'est qu'un accuse de reception */
    789 			/* Ignore message content : that is only an ack */
    790 
    791 			/* close and open file */
    792 			close(dp.fd);
    793 			initTest(dp);
    794 			etat = SELECT;
    795 			continue;
    796 		case FIN:
    797 			tLock.test = FIN;
    798 			serialiseTLock(&tLock);
    799 			serverSend();
    800 			sleep(2);
    801 			break;
    802 
    803 			printf("(end)\n");
    804 			exit(0);
    805 
    806 		}		/* switch */
    807 		break;
    808 	}			/* while */
    809 
    810 	rapport(clnt);
    811 }
    812 
    813 /* Slave process/thread */
    814 
    815 void *esclave(void *donnees)
    816 {
    817 	struct donneesFils *df;
    818 	int i, a, resultat, ftest;
    819 	struct s_test tLock;
    820 	struct flock request;
    821 	char tmp[16];
    822 #ifdef DEBUG
    823 	char dbg[16];
    824 #endif
    825 	char *phraseTest = "L'ecriture a reussi";
    826 	int len;
    827 	enum etat_t etat;
    828 
    829 	resultat = -1;
    830 	ftest = -1;
    831 	len = strlen(phraseTest);
    832 	df = (struct donneesFils *)donnees;
    833 	i = df->dpr->whoami;
    834 	P("Esclave n=%d\n", i);
    835 	esclaveLecteur = dp.lclnt[i][0];
    836 	esclaveEcrivain = dp.maitre[1];
    837 	etat = SYNC;
    838 	errno = 0;
    839 	memset(tmp, 0, 16);
    840 	while (1) {
    841 		switch (etat) {
    842 		case SELECT:
    843 		case SYNC:
    844 			getLockTest(&tLock);
    845 			etat = tLock.test;
    846 			P("Esclave Etat=%d\n", etat);
    847 
    848 			continue;
    849 		case RDONLY:
    850 			/* On tente de lire un fichier */
    851 			/* Try to read a file */
    852 			P("TEST READ ONLY %d\n", RDONLY);
    853 			if ((ftest = open(dp.fname, O_RDONLY | O_NONBLOCK)) < 0) {
    854 				resultat = ECHEC;
    855 				etat = RESULTAT;
    856 				if (dp.verbose)
    857 					perror("Open:");
    858 				continue;
    859 			}
    860 			P("fd=%d\n", ftest);
    861 			a = read(ftest, tmp, 16);
    862 			if (a < 16)
    863 				resultat = ECHEC;
    864 			else
    865 				resultat = SUCCES;
    866 			etat = RESULTAT;
    867 			continue;
    868 
    869 		case WRONLY:
    870 			/* On tente d'ecrire un fichier */
    871 			/* Try to write a file */
    872 			P("TEST WRITE ONLY %d\n", WRONLY);
    873 			if ((ftest = open(dp.fname, O_WRONLY | O_NONBLOCK)) < 0) {
    874 				resultat = ECHEC;
    875 				etat = RESULTAT;
    876 				if (dp.verbose)
    877 					perror("Open read only:");
    878 				continue;
    879 			}
    880 			P("fd=%d\n", ftest);
    881 			if (write(ftest, phraseTest, len) < len)
    882 				resultat = ECHEC;
    883 			else
    884 				resultat = SUCCES;
    885 			etat = RESULTAT;
    886 			continue;
    887 
    888 		case LOCK:
    889 
    890 		case READLOCK:
    891 			/* On essaie de lire une section lockee en lecture sur le fichier */
    892 			/* Try to read a read-locked section */
    893 			P("READ LOCK %d\n", F_RDLCK);
    894 			if ((ftest = open(dp.fname, O_RDONLY | O_NONBLOCK)) < 0) {
    895 				resultat = ECHEC;
    896 				etat = RESULTAT;
    897 				if (dp.verbose)
    898 					perror("Open read-write:");
    899 				continue;
    900 			}
    901 
    902 			P("fd=%d\n", ftest);
    903 			/* Lock de l'ensemble du fichier */
    904 			/* Lock the whole file */
    905 			request.l_type = F_RDLCK;
    906 			request.l_whence = SEEK_SET;
    907 			request.l_start = 0;
    908 			request.l_len = 0;
    909 
    910 			if (fcntl(ftest, F_SETLK, &request) < 0) {
    911 				if (dp.verbose || errno != EAGAIN)
    912 					perror("RDONLY: fcntl");
    913 				resultat = ECHEC;
    914 			} else
    915 				resultat = SUCCES;
    916 			etat = RESULTAT;
    917 			continue;
    918 
    919 		case WRITELOCK:
    920 			/* On essaie d'ecrire le fichier */
    921 			/* Try to write a file */
    922 			P("WRITE LOCK %d\n", F_WRLCK);
    923 			if ((ftest = open(dp.fname, O_WRONLY | O_NONBLOCK)) < 0) {
    924 				resultat = ECHEC;
    925 				etat = RESULTAT;
    926 				if (dp.verbose)
    927 					perror("\nOpen:");
    928 				continue;
    929 			}
    930 			/* Lock de l'ensemble du fichier */
    931 			/* Lock the whole file */
    932 			P("fd=%d\n", ftest);
    933 			request.l_type = F_WRLCK;
    934 			request.l_whence = SEEK_SET;
    935 			request.l_start = 0;
    936 			request.l_len = 0;
    937 
    938 			if (fcntl(ftest, F_SETLK, &request) < 0) {
    939 				if (dp.verbose || errno != EAGAIN)
    940 					perror("\nWRONLY: fcntl");
    941 				resultat = ECHEC;
    942 			} else
    943 				resultat = SUCCES;
    944 			etat = RESULTAT;
    945 			continue;
    946 
    947 		case BYTELOCK_READ:
    948 			P("BYTE LOCK READ: %d\n", etat);
    949 			etat = BYTELOCK;
    950 			continue;
    951 
    952 		case BYTELOCK_WRITE:
    953 			P("BYTE LOCK WRITE: %d\n", etat);
    954 			etat = BYTELOCK;
    955 			continue;
    956 
    957 		case BYTELOCK:
    958 			/* On se met en attente de la section a locker. L'ensemble de la structure est
    959 			 * donnee par le maitre et transmise par le tube.
    960 			 */
    961 			/* Wait for the exact section to lock. The whole file is sent by the master */
    962 
    963 			P("BYTE LOCK %d\n", etat);
    964 			getLockSection(&request);
    965 			if ((ftest = open(dp.fname, O_RDWR | O_NONBLOCK)) < 0) {
    966 				resultat = ECHEC;
    967 				etat = RESULTAT;
    968 				if (dp.verbose)
    969 					perror("\nOpen:");
    970 				continue;
    971 			}
    972 
    973 			if (fcntl(ftest, F_SETLK, &request) < 0) {
    974 				if (dp.verbose || errno != EAGAIN)
    975 					perror("\nBTLOCK: fcntl");
    976 				resultat = ECHEC;
    977 				etat = RESULTAT;
    978 				continue;
    979 			}
    980 			/* On change le caractere a la place donnee pour verification */
    981 			/* Change the character at the given position for an easier verification */
    982 			a = lseek(ftest, request.l_start, SEEK_SET);
    983 			write(ftest, "=", 1);
    984 			resultat = SUCCES;
    985 			etat = RESULTAT;
    986 			continue;
    987 
    988 		case RESULTAT:
    989 			if (resultat == SUCCES)
    990 				write(0, "=", 1);
    991 			else
    992 				write(0, "x", 1);
    993 			P("RESULTAT: %d\n", resultat);
    994 			sendResult(resultat);
    995 			etat = SYNC;
    996 			continue;
    997 
    998 		case CLEAN:
    999 			close(ftest);
   1000 			/* Send CLEAN Ack */
   1001 			sendResult(resultat);
   1002 			etat = SYNC;
   1003 			continue;
   1004 
   1005 		case FIN:
   1006 			E("(End)\n");
   1007 			terminer(0);
   1008 			printf("Unknown command\n");
   1009 			terminer(1);
   1010 
   1011 		}
   1012 	}
   1013 
   1014 }
   1015 
   1016 char *nextArg(int argc, char **argv, int *i)
   1017 {
   1018 	if (((*i) + 1) < argc) {
   1019 		(*i) += 1;
   1020 		return argv[(*i)];
   1021 	}
   1022 	return NULL;
   1023 }
   1024 
   1025 int usage()
   1026 {
   1027 	printf("locktest -n <number of process> -f <test file> [-T]\n");
   1028 	printf("Number of child process must be higher than 1\n");
   1029 	printf("\n");
   1030 	printf("Send bugs to vincent.roqueta (at) ext.bull.net\n");
   1031 	exit(0);
   1032 	return 0;
   1033 }
   1034 
   1035 int main(int argc, char **argv)
   1036 {
   1037 	int i, nThread = 0;
   1038 	char *tmp;
   1039 	int type = 0;
   1040 	int clients;
   1041 	type = PROCESS;
   1042 	dp.fname = NULL;
   1043 	dp.verbose = 0;
   1044 	int serveur = 1;
   1045 	char *host;
   1046 
   1047 	host = NULL;
   1048 	clients = 0;
   1049 
   1050 	for (i = 1; i < argc; i++) {
   1051 
   1052 		if (!strcmp("-n", argv[i])) {
   1053 			if (!(tmp = nextArg(argc, argv, &i)))
   1054 				usage();
   1055 			nThread = atoi(tmp);
   1056 			continue;
   1057 		}
   1058 
   1059 		if (!strcmp("-f", argv[i])) {
   1060 			if (!(dp.fname = nextArg(argc, argv, &i)))
   1061 				usage();
   1062 			continue;
   1063 		}
   1064 		if (!strcmp("-v", argv[i])) {
   1065 			dp.verbose = TRUE;
   1066 			continue;
   1067 		}
   1068 		if (!strcmp("-c", argv[i])) {
   1069 			if (!(clients = atoi(nextArg(argc, argv, &i))))
   1070 				usage();
   1071 			continue;
   1072 		}
   1073 
   1074 		if (!strcmp("--server", argv[i])) {
   1075 			if (!(host = nextArg(argc, argv, &i)))
   1076 				usage();
   1077 			serveur = 0;
   1078 			continue;
   1079 		}
   1080 		/* Option inconnue */
   1081 		printf("Ignoring unknown option: %s\n", argv[i]);
   1082 	}
   1083 
   1084 	if (serveur) {
   1085 		if (!(dp.fname && nThread))
   1086 			usage();
   1087 		if (clients > 0) {
   1088 			configureServeur(clients);
   1089 			setupClients(type, dp.fname, nThread);
   1090 		}
   1091 	} else {
   1092 		configureClient(host);
   1093 		dp.fname = malloc(512);
   1094 		memset(dp.fname, 0, 512);
   1095 		getConfiguration(&type, dp.fname, &nThread);
   1096 	}
   1097 
   1098 	if (dp.verbose)
   1099 		printf("By process.\n");
   1100 	load = loadProcess;
   1101 	eType = "process";
   1102 	terminer = terminerProcess;
   1103 	LISTE_RESULTATS = LISTE_RESULTATS_PROCESS;
   1104 	initialise(nThread);
   1105 	if (serveur) {
   1106 		maitre();
   1107 
   1108 	} else {
   1109 		maitreClient();
   1110 		free(dp.fname);
   1111 	}
   1112 	clean();
   1113 
   1114 	return 0;
   1115 }
   1116