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