• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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 
terminerProcess(int a)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*/
testSuiv(int n)112 int testSuiv(int n)
113 {
114 	return LISTE_TESTS[n];
115 }
116 
resAttSuiv(int n)117 int resAttSuiv(int n)
118 {
119 	return LISTE_RESULTATS[n];
120 }
121 
nomTestSuiv(int n)122 char *nomTestSuiv(int n)
123 {
124 	return LISTE_NOMS_TESTS[n];
125 }
126 
lockSuiv(int n)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 */
matchResult(int r,int n)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 */
compteur(int r,int n)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 
validationResultats(int n)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 
initTest()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 
initClientFork(int i)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 
initialise(int clnt)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 
cleanClient(struct donneesFils * df)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 
clean()261 void clean()
262 {
263 	free(dp.lthreads);
264 	free(dp.lclnt);
265 }
266 
loadProcess()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 
lockWholeFile(struct flock * request)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 
selectTest(int n,struct s_test * test)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 */
rapport(clnt)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 
serverSendLocal()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 
serverSendNet()334 void serverSendNet()
335 {
336 	writeToAllClients(message);
337 }
338 
serverReceiveNet()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 
serverReceiveLocal()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 
clientReceiveLocal()358 int clientReceiveLocal()
359 {
360 	read(esclaveLecteur, message, M_SIZE);
361 	return 0;
362 }
363 
clientSend()364 int clientSend()
365 {
366 	write(esclaveEcrivain, message, M_SIZE);
367 	return 0;
368 }
369 
serverSend()370 int serverSend()
371 {
372 	serverSendNet();
373 	serverSendLocal();
374 	return 0;
375 }
376 
serverReceive()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  */
serialiseTLock(struct s_test * tLock)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 
unSerialiseTLock(struct s_test * tLock)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 
serialiseFLock(struct flock * request)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 
serialiseResult(int resultat)415 void serialiseResult(int resultat)
416 {
417 	memset(message, 0, M_SIZE);
418 	sprintf(message, "R:%d::", resultat);
419 
420 }
421 
unSerialiseResult(int * resultat)422 void unSerialiseResult(int *resultat)
423 {
424 	sscanf(message, "R:%d::", resultat);
425 }
426 
unSerialiseFLock(struct flock * request)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 
serverSendLockClient(struct flock * request,int client)437 int serverSendLockClient(struct flock *request, int client)
438 {
439 	serialiseFLock(request);
440 	return serverSendClient(client);
441 }
442 
serverSendLockLocal(struct flock * request,int esclave)443 int serverSendLockLocal(struct flock *request, int esclave)
444 {
445 	serialiseFLock(request);
446 	return write(dp.lclnt[esclave][1], message, M_SIZE);
447 }
448 
getLockSection(struct flock * request)449 int getLockSection(struct flock *request)
450 {
451 	memset(message, 0, M_SIZE);
452 	clientReceiveLocal();
453 	unSerialiseFLock(request);
454 	return 0;
455 }
456 
sendLockTest(struct s_test * tLock)457 int sendLockTest(struct s_test *tLock)
458 {
459 	serialiseTLock(tLock);
460 	serverSend();
461 	return 0;
462 }
463 
getLockTest(struct s_test * tLock)464 int getLockTest(struct s_test *tLock)
465 {
466 	clientReceiveLocal();
467 	unSerialiseTLock(tLock);
468 	return 0;
469 }
470 
sendResult(int resultat)471 int sendResult(int resultat)
472 {
473 	serialiseResult(resultat);
474 	clientSend();
475 	return 0;
476 }
477 
getResults(int ntest)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 re�oit 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 
maitreClient()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 
maitre()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 
esclave(void * donnees)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 
nextArg(int argc,char ** argv,int * i)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 
usage()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@ext.bull.net\n");
1031 	exit(0);
1032 	return 0;
1033 }
1034 
main(int argc,char ** argv)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