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