Home | History | Annotate | Download | only in locks
      1 /* *************************************************
      2  * *********** README ******************************
      3  * *************************************************
      4  *
      5  * COMPILE : make
      6  * RUN : ./locktests -n <number of concurent process> -f <test file> [-P]
      7  *
      8  * GOAL : This test tries to stress the fcntl locking functions.  A
      9  * master process sets a lock on a file region (this is called "byte
     10  * range locking").  Some slave processes try to perform operations on
     11  * this region, such as read, write, set a new lock ... The expected
     12  * results of these operations are known.  If the operation result is
     13  * the same as the expected one, the test suceeds, else it fails.
     14  *
     15  *
     16  *
     17  * Slaves are concurent processes or thread.
     18  * -n <num>  : Number of threads to use (mandatory).
     19  * -f <file> : Run the test on given test file defined by the -f option (mandatory).
     20  * -c <num>  : Number of clients to connect before starting the tests.
     21  *
     22  * HISTORY : This program was written to stress NFSv4 locks.
     23  * EXAMPLE : ./locktests -n 50 -f /file/system/to/test
     24  *
     25  *
     26  * Vincent ROQUETA 2005 - vincent.roqueta (at) ext.bull.net
     27  * BULL S.A.
     28  */
     29 
     30 #include "locktests.h"
     31 
     32 int MAXLEN = 64;
     33 int MAXTEST = 10;
     34 extern int maxClients;
     35 extern int fdServer;
     36 
     37 char message[M_SIZE];
     38 int slaveReader;
     39 int masterReader;
     40 int slaveWriter;
     41 
     42 /* Which lock will be applied by the master process on test startup */
     43 int 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 */
     51 int 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 */
     59 char *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 */
     72 int 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 */
     80 int LIST_RESULTS_THREADS[] = { SUCCES, SUCCES,
     81 	SUCCES, SUCCES,
     82 	SUCCES, SUCCES,
     83 	SUCCES, SUCCES,
     84 	ECHEC, ECHEC
     85 };
     86 
     87 int *LIST_RESULTS = NULL;
     88 char *eType = NULL;
     89 
     90 int TOTAL_RESULT_OK[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
     91 
     92 void *slave(void *data);
     93 int (*finish) (int a);
     94 
     95 int finishProcess(int a)
     96 {
     97 	exit(a);
     98 }
     99 
    100 int (*load) (void);
    101 
    102 struct dataPub dp;
    103 
    104 /* Functions to access tests/tests names/tests results*/
    105 int testSuiv(int n)
    106 {
    107 	return LIST_TESTS[n];
    108 }
    109 
    110 int resAttSuiv(int n)
    111 {
    112 	return LIST_RESULTS[n];
    113 }
    114 
    115 char *nomTestSuiv(int n)
    116 {
    117 	return LIST_NAMES_TESTS[n];
    118 }
    119 
    120 int lockSuiv(int n)
    121 {
    122 	return LIST_LOCKS[n];
    123 }
    124 
    125 /* Verify the test result is the expected one */
    126 int 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 */
    137 void 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  */
    145 void 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 
    175 int 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 
    188 struct 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 
    210 int 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 
    231 void 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 
    240 void clean(void)
    241 {
    242 	free(dp.lthreads);
    243 	free(dp.lclnt);
    244 }
    245 
    246 int 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 
    263 void 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 
    271 void 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 */
    281 int 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 
    302 int 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 
    314 void serverSendNet(void)
    315 {
    316 	writeToAllClients(message);
    317 }
    318 
    319 int 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 
    330 int 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 
    338 int clientReceiveLocal(void)
    339 {
    340 	read(slaveReader, message, M_SIZE);
    341 	return 0;
    342 }
    343 
    344 int clientSend(void)
    345 {
    346 	write(slaveWriter, message, M_SIZE);
    347 	return 0;
    348 }
    349 
    350 int serverSend(void)
    351 {
    352 	serverSendNet();
    353 	serverSendLocal();
    354 	return 0;
    355 }
    356 
    357 int 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  */
    367 int 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 
    375 void 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 
    383 void 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 
    395 void serializeResult(int result)
    396 {
    397 	memset(message, 0, M_SIZE);
    398 	sprintf(message, "R:%d::", result);
    399 
    400 }
    401 
    402 void unSerializeResult(int *result)
    403 {
    404 	sscanf(message, "R:%d::", result);
    405 }
    406 
    407 void 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 
    417 int serverSendLockClient(struct flock *request, int client)
    418 {
    419 	serializeFLock(request);
    420 	return serverSendClient(client);
    421 }
    422 
    423 int serverSendLockLocal(struct flock *request, int slave)
    424 {
    425 	serializeFLock(request);
    426 	return write(dp.lclnt[slave][1], message, M_SIZE);
    427 }
    428 
    429 int getLockSection(struct flock *request)
    430 {
    431 	memset(message, 0, M_SIZE);
    432 	clientReceiveLocal();
    433 	unSerializeFLock(request);
    434 	return 0;
    435 }
    436 
    437 int sendLockTest(struct s_test *tLock)
    438 {
    439 	serializeTLock(tLock);
    440 	serverSend();
    441 	return 0;
    442 }
    443 
    444 int getLockTest(struct s_test *tLock)
    445 {
    446 	clientReceiveLocal();
    447 	unSerializeTLock(tLock);
    448 	return 0;
    449 }
    450 
    451 int sendResult(int result)
    452 {
    453 	serializeResult(result);
    454 	clientSend();
    455 	return 0;
    456 }
    457 
    458 int 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  */
    488 void 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 
    574 int 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 
    748 void *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 
    938 char *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 
    947 int 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 
    955 int 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