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 32int MAXLEN = 64; 33int MAXTEST = 10; 34extern int maxClients; 35extern int fdServer; 36 37char message[M_SIZE]; 38int slaveReader; 39int masterReader; 40int slaveWriter; 41 42/* Which lock will be applied by the master process on test startup */ 43int LIST_LOCKS[] = { READLOCK, WRITELOCK, 44 READLOCK, WRITELOCK, 45 READLOCK, WRITELOCK, 46 READLOCK, WRITELOCK, 47 BYTELOCK_READ, BYTELOCK_WRITE 48}; 49 50/* The operations the slave processes will try to perform */ 51int LIST_TESTS[] = { WRONLY, WRONLY, 52 RDONLY, RDONLY, 53 READLOCK, WRITELOCK, 54 WRITELOCK, READLOCK, 55 BYTELOCK_READ, BYTELOCK_WRITE 56}; 57 58/* List of test names */ 59char *LIST_NAMES_TESTS[] = { "WRITE ON A READ LOCK", 60 "WRITE ON A WRITE LOCK", 61 "READ ON A READ LOCK", 62 "READ ON A WRITE LOCK", 63 "SET A READ LOCK ON A READ LOCK", 64 "SET A WRITE LOCK ON A WRITE LOCK", 65 "SET A WRITE LOCK ON A READ LOCK", 66 "SET A READ LOCK ON A WRITE LOCK", 67 "READ LOCK THE WHOLE FILE BYTE BY BYTE", 68 "WRITE LOCK THE WHOLE FILE BYTE BY BYTE" 69}; 70 71/* List of expected test results, when slaves are processes */ 72int LIST_RESULTS_PROCESS[] = { SUCCES, SUCCES, 73 SUCCES, SUCCES, 74 SUCCES, ECHEC, 75 ECHEC, ECHEC, 76 SUCCES, SUCCES 77}; 78 79/* List of expected test results, when slaves are threads */ 80int LIST_RESULTS_THREADS[] = { SUCCES, SUCCES, 81 SUCCES, SUCCES, 82 SUCCES, SUCCES, 83 SUCCES, SUCCES, 84 ECHEC, ECHEC 85}; 86 87int *LIST_RESULTS = NULL; 88char *eType = NULL; 89 90int TOTAL_RESULT_OK[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 91 92void *slave(void *data); 93int (*finish) (int a); 94 95int finishProcess(int a) 96{ 97 exit(a); 98} 99 100int (*load) (void); 101 102struct dataPub dp; 103 104/* Functions to access tests/tests names/tests results*/ 105int testSuiv(int n) 106{ 107 return LIST_TESTS[n]; 108} 109 110int resAttSuiv(int n) 111{ 112 return LIST_RESULTS[n]; 113} 114 115char *nomTestSuiv(int n) 116{ 117 return LIST_NAMES_TESTS[n]; 118} 119 120int lockSuiv(int n) 121{ 122 return LIST_LOCKS[n]; 123} 124 125/* Verify the test result is the expected one */ 126int matchResult(int r, int n) 127{ 128 129 P("r=%d\n", r); 130 if (r == LIST_RESULTS[n]) 131 return 1; 132 else 133 return 0; 134} 135 136/* Increments the number of process which have successfully passed the test */ 137void counter(int r, int n) 138{ 139 TOTAL_RESULT_OK[n] += matchResult(r, n); 140} 141 142/* Special case for test 'lock file byte byte by byte'. 143 * We ensure each byte is correctly locked. 144 */ 145void validationResults(int n) 146{ 147 int i, u, l, fsize; 148 struct flock request; 149 150 fsize = dp.nclnt * (maxClients + 1); 151 TOTAL_RESULT_OK[n] = 0; 152 l = FALSE; 153 u = TRUE; 154 155 /* If the expected operation result is a success, we will have to increase the number of correct results */ 156 if (LIST_RESULTS[n]) { 157 l = TRUE; 158 u = FALSE; 159 } 160 161 for (i = 0; i < fsize; i++) { 162 request.l_type = F_WRLCK; 163 request.l_whence = SEEK_SET; 164 request.l_start = i; 165 request.l_len = 1; 166 fcntl(dp.fd, F_GETLK, &request); 167 /* Ensure the lock is correctly set */ 168 if (request.l_type != F_UNLCK) 169 TOTAL_RESULT_OK[n] += l; 170 else 171 TOTAL_RESULT_OK[n] += u; 172 } 173} 174 175int initTest(void) 176{ 177 178 P("Master opens %s\n", dp.fname); 179 dp.fd = open(dp.fname, OPENFLAGS, MANDMODES); 180 if (dp.fd < 0) { 181 perror("lock test : can't open test file :"); 182 finish(1); 183 } 184 P("fd=%d\n", dp.fd); 185 return 0; 186} 187 188struct dataChild *initClientFork(int i) 189{ 190 struct dataPriv *dpr; 191 struct dataChild *df; 192 193 /* Initialize private data fields */ 194 dpr = malloc(sizeof(struct dataPriv)); 195 df = malloc(sizeof(struct dataChild)); 196 dpr->whoami = i; 197 df->dp = &dp; 198 df->dpr = dpr; 199 /* Initialize master to client pipe */ 200 dp.lclnt[i] = malloc(sizeof(int) * 2); 201 if (pipe(dp.lclnt[i]) < 0) { 202 perror("Impossible to create pipe\n"); 203 exit(1); 204 } 205 P("Initialization %d\n", i); 206 write(0, ".", 1); 207 return df; 208} 209 210int initialize(int clnt) 211{ 212 213 /* Initialize private data fields */ 214 printf("Init\n"); 215 dp.nclnt = clnt; 216 dp.lclnt = malloc(sizeof(int *) * clnt); 217 dp.lthreads = malloc(sizeof(pthread_t) * clnt); 218 219 /* Initialize client to master pipe */ 220 if (pipe(dp.master) < 0) { 221 perror("Master pipe creation error\n"); 222 exit(1); 223 } 224 printf("%s initialization\n", eType); 225 load(); 226 initTest(); 227 228 return 0; 229} 230 231void cleanClient(struct dataChild *df) 232{ 233 int i; 234 i = df->dpr->whoami; 235 free(dp.lclnt[i]); 236 free(df->dpr); 237 free(df); 238} 239 240void clean(void) 241{ 242 free(dp.lthreads); 243 free(dp.lclnt); 244} 245 246int loadProcess(void) 247{ 248 int i; 249 struct dataChild *df; 250 for (i = 0; i < dp.nclnt; i++) { 251 df = initClientFork(i); 252 if (!fork()) { 253 P("Running slave num: %d\n", df->dpr->whoami); 254 write(0, ".", 1); 255 slave((void *)df); 256 cleanClient(df); 257 exit(0); 258 } 259 } 260 return 0; 261} 262 263void lockWholeFile(struct flock *request) 264{ 265 request->l_whence = SEEK_SET; 266 request->l_start = 0; 267 /* Lock the whole file */ 268 request->l_len = 0; 269} 270 271void selectTest(int n, struct s_test *test) 272{ 273 274 test->test = testSuiv(n); 275 test->resAtt = resAttSuiv(n); 276 test->nom = nomTestSuiv(n); 277 test->type = lockSuiv(n); 278} 279 280/* Final test report */ 281int report(int clnt) 282{ 283 int rc = 0; 284 int i; 285 int totalClients; 286 totalClients = clnt * (maxClients + 1); 287 printf 288 ("\n%s number : %d - Remote clients: %d local client 1 - Total client %d - Total concurent tests: %d\n", 289 eType, clnt, maxClients, maxClients + 1, totalClients); 290 printf("%s number running test successfully :\n", eType); 291 for (i = 0; i < MAXTEST; i++) { 292 if (TOTAL_RESULT_OK[i] != totalClients) 293 rc = 1; 294 295 printf("%d %s of %d successfully ran test : %s\n", 296 TOTAL_RESULT_OK[i], eType, totalClients, 297 LIST_NAMES_TESTS[i]); 298 } 299 return rc; 300} 301 302int serverSendLocal(void) 303{ 304 int i; 305 /* Synchronize slave processes */ 306 /* Configure slaves for test */ 307 308 for (i = 0; i < dp.nclnt; i++) 309 write(dp.lclnt[i][1], message, M_SIZE); 310 return 0; 311 312} 313 314void serverSendNet(void) 315{ 316 writeToAllClients(message); 317} 318 319int serverReceiveNet(void) 320{ 321 int i, c; 322 for (c = 0; c < maxClients; c++) { 323 for (i = 0; i < dp.nclnt; i++) { 324 serverReceiveClient(c); 325 } 326 } 327 return 0; 328} 329 330int serverReceiveLocal(void) 331{ 332 int i; 333 for (i = 0; i < dp.nclnt; i++) 334 read(masterReader, message, M_SIZE); 335 return 0; 336} 337 338int clientReceiveLocal(void) 339{ 340 read(slaveReader, message, M_SIZE); 341 return 0; 342} 343 344int clientSend(void) 345{ 346 write(slaveWriter, message, M_SIZE); 347 return 0; 348} 349 350int serverSend(void) 351{ 352 serverSendNet(); 353 serverSendLocal(); 354 return 0; 355} 356 357int serverReceive(void) 358{ 359 serverReceiveNet(); 360 serverReceiveLocal(); 361 return 0; 362} 363 364/* binary structure <-> ASCII functions used to ensure data will be correctly used over 365 * the network, especially when multiples clients do not use the same hardware architecture. 366 */ 367int serializeTLock(struct s_test *tLock) 368{ 369 memset(message, 0, M_SIZE); 370 sprintf(message, "T:%d:%d:%d::", tLock->test, tLock->type, 371 tLock->resAtt); 372 return 0; 373} 374 375void unSerializeTLock(struct s_test *tLock) 376{ 377 sscanf(message, "T:%d:%d:%d::", &(tLock->test), &(tLock->type), 378 &(tLock->resAtt)); 379 memset(message, 0, M_SIZE); 380 381} 382 383void serializeFLock(struct flock *request) 384{ 385 int len, pid, start; 386 memset(message, 0, M_SIZE); 387 len = (int)request->l_len; 388 pid = (int)request->l_pid; 389 start = (int)request->l_start; 390 /* Beware to length of integer conversions ... */ 391 sprintf(message, "L:%hd:%hd:%d:%d:%d::", 392 request->l_type, request->l_whence, start, len, pid); 393} 394 395void serializeResult(int result) 396{ 397 memset(message, 0, M_SIZE); 398 sprintf(message, "R:%d::", result); 399 400} 401 402void unSerializeResult(int *result) 403{ 404 sscanf(message, "R:%d::", result); 405} 406 407void unSerializeFLock(struct flock *request) 408{ 409 int len, pid, start; 410 sscanf(message, "L:%hd:%hd:%d:%d:%d::", 411 &(request->l_type), &(request->l_whence), &start, &len, &pid); 412 request->l_start = (off_t) start; 413 request->l_len = (off_t) len; 414 request->l_pid = (pid_t) pid; 415} 416 417int serverSendLockClient(struct flock *request, int client) 418{ 419 serializeFLock(request); 420 return serverSendClient(client); 421} 422 423int serverSendLockLocal(struct flock *request, int slave) 424{ 425 serializeFLock(request); 426 return write(dp.lclnt[slave][1], message, M_SIZE); 427} 428 429int getLockSection(struct flock *request) 430{ 431 memset(message, 0, M_SIZE); 432 clientReceiveLocal(); 433 unSerializeFLock(request); 434 return 0; 435} 436 437int sendLockTest(struct s_test *tLock) 438{ 439 serializeTLock(tLock); 440 serverSend(); 441 return 0; 442} 443 444int getLockTest(struct s_test *tLock) 445{ 446 clientReceiveLocal(); 447 unSerializeTLock(tLock); 448 return 0; 449} 450 451int sendResult(int result) 452{ 453 serializeResult(result); 454 clientSend(); 455 return 0; 456} 457 458int getResults(int ntest) 459{ 460 int i, c; 461 int result = 0; 462 /* Add remote test results */ 463 for (c = 0; c < maxClients; c++) { 464 for (i = 0; i < dp.nclnt; i++) { 465 serverReceiveClient(c); 466 unSerializeResult(&result); 467 counter(result, ntest); 468 469 } 470 } 471 /* Add local test results */ 472 for (i = 0; i < dp.nclnt; i++) { 473 read(masterReader, message, M_SIZE); 474 unSerializeResult(&result); 475 counter(result, ntest); 476 } 477 478 return 0; 479} 480 481#ifdef DEBUG 482#define P(a,b) memset(dbg,0,16);sprintf(dbg,a,b);write(0,dbg,16); 483#endif 484 485/* In the case of a network use, the master of the client application si only 486 * a 'repeater' of information. It resends server-master instructions to its own slaves. 487 */ 488void masterClient(void) 489{ 490 fd_set fdread; 491 struct timeval tv; 492 int n, i, r, m, start; 493#ifdef DEBUG 494 char dbg[16]; 495#endif 496 struct flock lock; 497 int t; 498 499 masterReader = dp.master[0]; 500 FD_ZERO(&fdread); 501 tv.tv_sec = 50; 502 tv.tv_usec = 0; 503 n = fdServer > masterReader ? fdServer : masterReader; 504 printf("Master Client - fdServer=%d\n", fdServer); 505 while (1) { 506 /* Add slave and server pipe file descriptors */ 507 FD_ZERO(&fdread); 508 FD_SET(fdServer, &fdread); 509 FD_SET(masterReader, &fdread); 510 r = select(n + 1, &fdread, NULL, NULL, &tv); 511 if (r < 0) { 512 perror("select:\n"); 513 continue; 514 } 515 if (r == 0) { 516 exit(0); 517 } 518 519 if (FD_ISSET(fdServer, &fdread)) { 520 /* We just have received information from the server. 521 * We repeat it to slaves. 522 */ 523 i = readFromServer(message); 524 t = message[0]; 525 switch (t) { 526 case 'L': 527 /* Lock instruction. We need to send a different section to lock to each process */ 528 unSerializeFLock(&lock); 529 start = lock.l_start; 530 for (i = 0; i < dp.nclnt; i++) { 531 lock.l_start = start + i; 532 serializeFLock(&lock); 533 write(dp.lclnt[i][1], message, M_SIZE); 534 } 535 printf("\n"); 536 continue; 537 case 'T': 538 /* Test instruction. Ensure server is not sending the END(ish) instruction to end tests */ 539 /* To be rewritten asap */ 540 m = atoi(&(message[2])); 541 if (m == END) 542 break; 543 if (m == CLEAN) 544 printf("\n"); 545 546 serverSendLocal(); 547 continue; 548 } 549 break; 550 } else { 551 /* Else, we read information from slaves and repeat them to the server */ 552 for (i = 0; i < dp.nclnt; i++) { 553 r = read(masterReader, message, M_SIZE); 554 r = write(fdServer, message, M_SIZE); 555 if (r < 0) 556 perror("write : "); 557 558 } 559 continue; 560 } 561 } 562 563 /* Receive the END(ish) instruction */ 564 565 /* Repeat it to the slaves */ 566 printf("Exitting...\n"); 567 serverSendLocal(); 568 569 /* Ok, we can quit */ 570 printf("Bye :)\n"); 571 572} 573 574int master(void) 575{ 576 int i, n, bl; 577 int clnt; 578 char tmp[MAXLEN], *buf; 579#ifdef DEBUG 580 char dbg[16]; 581#endif 582 struct flock request; 583 struct s_test tLock; 584 enum state_t state; 585 int offset; 586 /* A test sentence written in the file */ 587 char phraseTest[] = 588 "Ceci est une phrase test ecrite par le maitre dans le fichier"; 589 bl = -1; 590 clnt = dp.nclnt; 591 masterReader = dp.master[0]; 592 state = SELECT; 593 /* Start with the first test ;) */ 594 n = 0; 595 printf("\n--------------------------------------\n"); 596 while (1) { 597 switch (state) { 598 case SELECT: 599 /* Select the test to perform */ 600 printf("\n"); 601 E("Master: SELECT"); 602 selectTest(n, &tLock); 603 state = tLock.type; 604 bl = 0; 605 if (n < MAXTEST) { 606 memset(tmp, 0, MAXLEN); 607 sprintf(tmp, "TEST : TRY TO %s:", 608 LIST_NAMES_TESTS[n]); 609 write(0, tmp, strlen(tmp)); 610 } else 611 state = END; 612 P("state=%d\n", state); 613 n += 1; 614 continue; 615 616 case RDONLY: 617 case WRONLY: 618 619 case READLOCK: 620 P("Read lock :%d\n", state); 621 request.l_type = F_RDLCK; 622 state = LOCK; 623 continue; 624 625 case WRITELOCK: 626 P("Write lock :%d\n", state); 627 request.l_type = F_WRLCK; 628 state = LOCK; 629 continue; 630 631 case LOCK: 632 /* Apply the wanted lock */ 633 E("Master: LOCK"); 634 write(dp.fd, phraseTest, strlen(phraseTest)); 635 lockWholeFile(&request); 636 if (fcntl(dp.fd, F_SETLK, &request) < 0) { 637 perror("Master: can't set lock\n"); 638 perror("Echec\n"); 639 exit(0); 640 } 641 E("Master"); 642 state = SYNC; 643 continue; 644 645 case BYTELOCK_READ: 646 bl = 1; 647 request.l_type = F_RDLCK; 648 state = SYNC; 649 continue; 650 651 case BYTELOCK_WRITE: 652 bl = 1; 653 request.l_type = F_WRLCK; 654 state = SYNC; 655 continue; 656 657 case BYTELOCK: 658 /* The main idea is to lock all the bytes in a file. Each slave process locks one byte. 659 * 660 * We need : 661 * - To create a file of a length equal to the total number of slave processes 662 * - send the exact section to lock to each slave 663 * - ensure locks have been correctly set 664 */ 665 666 /* Create a string to record in the test file. Length is exactly the number of sub process */ 667 P("Master: BYTELOCK: %d\n", state); 668 buf = malloc(clnt * (maxClients + 1)); 669 memset(buf, '*', clnt); 670 write(dp.fd, buf, clnt); 671 free(buf); 672 673 /* Each slave process re-writes its own field to lock */ 674 request.l_whence = SEEK_SET; 675 request.l_start = 0; 676 request.l_len = 1; 677 678 /* Start to send sections to lock to remote process (network clients) */ 679 for (i = 0; i < maxClients; i++) { 680 /* Set the correct byte to lock */ 681 offset = (i + 1) * clnt; 682 request.l_start = (off_t) offset; 683 serverSendLockClient(&request, i); 684 } 685 686 /* Now send sections to local processes */ 687 for (i = 0; i < clnt; i++) { 688 request.l_start = i; 689 serverSendLockLocal(&request, i); 690 } 691 state = RESULT; 692 continue; 693 694 case SYNC: 695 sendLockTest(&tLock); 696 if (bl) { 697 state = BYTELOCK; 698 continue; 699 } 700 701 if (n < MAXTEST + 1) 702 state = RESULT; 703 else 704 state = END; 705 continue; 706 707 case RESULT: 708 /* Read results by one */ 709 getResults(n - 1); 710 if (bl) 711 validationResults(n - 1); 712 state = CLEAN; 713 continue; 714 715 case CLEAN: 716 /* Ask the clients to stop testing ... */ 717 tLock.test = CLEAN; 718 serializeTLock(&tLock); 719 serverSend(); 720 /* ... and wait for an ack before closing */ 721 serverReceive(); 722 /* Ignore message content : that is only an ack */ 723 724 /* close and open file */ 725 close(dp.fd); 726 initTest(); 727 state = SELECT; 728 continue; 729 case END: 730 tLock.test = END; 731 serializeTLock(&tLock); 732 serverSend(); 733 sleep(2); 734 break; 735 736 printf("(end)\n"); 737 exit(0); 738 739 } 740 break; 741 } 742 743 return report(clnt); 744} 745 746/* Slave process/thread */ 747 748void *slave(void *data) 749{ 750 struct dataChild *df; 751 int i, a, result, ftest; 752 struct s_test tLock; 753 struct flock request; 754 char tmp[16]; 755#ifdef DEBUG 756 char dbg[16]; 757#endif 758 char *phraseTest = "L'ecriture a reussi"; 759 int len; 760 enum state_t state; 761 762 result = -1; 763 ftest = -1; 764 len = strlen(phraseTest); 765 df = (struct dataChild *)data; 766 i = df->dpr->whoami; 767 P("Slave n=%d\n", i); 768 slaveReader = dp.lclnt[i][0]; 769 slaveWriter = dp.master[1]; 770 state = SYNC; 771 errno = 0; 772 memset(tmp, 0, 16); 773 while (1) { 774 switch (state) { 775 case SELECT: 776 case SYNC: 777 getLockTest(&tLock); 778 state = tLock.test; 779 P("Slave State=%d\n", state); 780 781 continue; 782 case RDONLY: 783 /* Try to read a file */ 784 P("TEST READ ONLY %d\n", RDONLY); 785 if ((ftest = open(dp.fname, O_RDONLY | O_NONBLOCK)) < 0) { 786 result = ECHEC; 787 state = RESULT; 788 if (dp.verbose) 789 perror("Open:"); 790 continue; 791 } 792 P("fd=%d\n", ftest); 793 a = read(ftest, tmp, 16); 794 if (a < 16) 795 result = ECHEC; 796 else 797 result = SUCCES; 798 state = RESULT; 799 continue; 800 801 case WRONLY: 802 /* Try to write a file */ 803 P("TEST WRITE ONLY %d\n", WRONLY); 804 if ((ftest = open(dp.fname, O_WRONLY | O_NONBLOCK)) < 0) { 805 result = ECHEC; 806 state = RESULT; 807 if (dp.verbose) 808 perror("Open read only:"); 809 continue; 810 } 811 P("fd=%d\n", ftest); 812 if (write(ftest, phraseTest, len) < len) 813 result = ECHEC; 814 else 815 result = SUCCES; 816 state = RESULT; 817 continue; 818 819 case LOCK: 820 821 case READLOCK: 822 /* Try to read a read-locked section */ 823 P("READ LOCK %d\n", F_RDLCK); 824 if ((ftest = open(dp.fname, O_RDONLY | O_NONBLOCK)) < 0) { 825 result = ECHEC; 826 state = RESULT; 827 if (dp.verbose) 828 perror("Open read-write:"); 829 continue; 830 } 831 832 P("fd=%d\n", ftest); 833 /* Lock the whole file */ 834 request.l_type = F_RDLCK; 835 request.l_whence = SEEK_SET; 836 request.l_start = 0; 837 request.l_len = 0; 838 839 if (fcntl(ftest, F_SETLK, &request) < 0) { 840 if (dp.verbose || errno != EAGAIN) 841 perror("RDONLY: fcntl"); 842 result = ECHEC; 843 } else 844 result = SUCCES; 845 state = RESULT; 846 continue; 847 848 case WRITELOCK: 849 /* Try to write a file */ 850 P("WRITE LOCK %d\n", F_WRLCK); 851 if ((ftest = open(dp.fname, O_WRONLY | O_NONBLOCK)) < 0) { 852 result = ECHEC; 853 state = RESULT; 854 if (dp.verbose) 855 perror("\nOpen:"); 856 continue; 857 } 858 /* Lock the whole file */ 859 P("fd=%d\n", ftest); 860 request.l_type = F_WRLCK; 861 request.l_whence = SEEK_SET; 862 request.l_start = 0; 863 request.l_len = 0; 864 865 if (fcntl(ftest, F_SETLK, &request) < 0) { 866 if (dp.verbose || errno != EAGAIN) 867 perror("\nWRONLY: fcntl"); 868 result = ECHEC; 869 } else 870 result = SUCCES; 871 state = RESULT; 872 continue; 873 874 case BYTELOCK_READ: 875 P("BYTE LOCK READ: %d\n", state); 876 state = BYTELOCK; 877 continue; 878 879 case BYTELOCK_WRITE: 880 P("BYTE LOCK WRITE: %d\n", state); 881 state = BYTELOCK; 882 continue; 883 884 case BYTELOCK: 885 /* Wait for the exact section to lock. The whole file is sent by the master */ 886 P("BYTE LOCK %d\n", state); 887 getLockSection(&request); 888 if ((ftest = open(dp.fname, O_RDWR | O_NONBLOCK)) < 0) { 889 result = ECHEC; 890 state = RESULT; 891 if (dp.verbose) 892 perror("\nOpen:"); 893 continue; 894 } 895 896 if (fcntl(ftest, F_SETLK, &request) < 0) { 897 if (dp.verbose || errno != EAGAIN) 898 perror("\nBTLOCK: fcntl"); 899 result = ECHEC; 900 state = RESULT; 901 continue; 902 } 903 /* Change the character at the given position for an easier verification */ 904 a = lseek(ftest, request.l_start, SEEK_SET); 905 write(ftest, "=", 1); 906 result = SUCCES; 907 state = RESULT; 908 continue; 909 910 case RESULT: 911 if (result == SUCCES) 912 write(0, "=", 1); 913 else 914 write(0, "x", 1); 915 P("RESULT: %d\n", result); 916 sendResult(result); 917 state = SYNC; 918 continue; 919 920 case CLEAN: 921 close(ftest); 922 /* Send CLEAN Ack */ 923 sendResult(result); 924 state = SYNC; 925 continue; 926 927 case END: 928 E("(End)\n"); 929 finish(0); 930 printf("Unknown command\n"); 931 finish(1); 932 933 } 934 } 935 936} 937 938char *nextArg(int argc, char **argv, int *i) 939{ 940 if (((*i) + 1) < argc) { 941 (*i) += 1; 942 return argv[(*i)]; 943 } 944 return NULL; 945} 946 947int usage(void) 948{ 949 printf("locktest -n <number of process> -f <test file> [-T]\n"); 950 printf("Number of child process must be higher than 1\n"); 951 exit(0); 952 return 0; 953} 954 955int main(int argc, char **argv) 956{ 957 int rc = 0; 958 int i, nThread = 0; 959 char *tmp; 960 int type = 0; 961 int clients; 962 type = PROCESS; 963 dp.fname = NULL; 964 dp.verbose = 0; 965 int server = 1; 966 char *host; 967 968 host = NULL; 969 clients = 0; 970 971 for (i = 1; i < argc; i++) { 972 973 if (!strcmp("-n", argv[i])) { 974 if (!(tmp = nextArg(argc, argv, &i))) 975 usage(); 976 nThread = atoi(tmp); 977 continue; 978 } 979 980 if (!strcmp("-f", argv[i])) { 981 if (!(dp.fname = nextArg(argc, argv, &i))) 982 usage(); 983 continue; 984 } 985 if (!strcmp("-v", argv[i])) { 986 dp.verbose = TRUE; 987 continue; 988 } 989 if (!strcmp("-c", argv[i])) { 990 if (!(clients = atoi(nextArg(argc, argv, &i)))) 991 usage(); 992 continue; 993 } 994 995 if (!strcmp("--server", argv[i])) { 996 if (!(host = nextArg(argc, argv, &i))) 997 usage(); 998 server = 0; 999 continue; 1000 } 1001 printf("Ignoring unknown option: %s\n", argv[i]); 1002 } 1003 1004 if (server) { 1005 if (!(dp.fname && nThread)) 1006 usage(); 1007 if (clients > 0) { 1008 configureServer(clients); 1009 setupClients(type, dp.fname, nThread); 1010 } 1011 } else { 1012 configureClient(host); 1013 dp.fname = malloc(512); 1014 memset(dp.fname, 0, 512); 1015 getConfiguration(&type, dp.fname, &nThread); 1016 } 1017 1018 if (dp.verbose) 1019 printf("By process.\n"); 1020 load = loadProcess; 1021 eType = "process"; 1022 finish = finishProcess; 1023 LIST_RESULTS = LIST_RESULTS_PROCESS; 1024 initialize(nThread); 1025 if (server) { 1026 rc = master(); 1027 } else { 1028 masterClient(); 1029 free(dp.fname); 1030 } 1031 clean(); 1032 1033 return rc; 1034} 1035