[comp.unix.ultrix] fcntl

fkittred@bbn.com (Fletcher Kittredge) (06/25/91)

Since upgrading to Ultrix 4.2, we have been having problems using 
POSIX file locking via fcntl().  It could be a configuration problem,
but it happens with local files as well as remote.  If anyone has any
insight into this issue, it would be most gratefully appreciated.


Below is a description of the problem and test code.

regards,
fletcher

------------------------------------------------------------------------
// Gordon and Rosen write:

We have found that a piece of code that worked in Ultrix 4.1
seems to no longer work with 4.2. This code uses the Unix
network locking feature of Ultrix (lockd/statd).

The following test demonstrates the problem:
 1.  Save the following program into a file :   tlock.c
 2.  compile :                                  cc -o tlock tlock.c
 3.  create a temporary file:                   touch testlock
 4.  execute tlock on this file twice in a row: tlock testlock

This program will attempt to get a  RW lock on the file; it will retry the
lock up to 10 times.  When it gets the lock it reports the result.  At
our site we find on Ultrix 4.2 we get the lock on the first attempt, but
when we release the lock and ask for it again we never successful.

We have found that this seems to happen with Ultrix 4.2 with files
on both LOCAL (ufs) and REMOTE (nfs) filesystems. This worked correctly
on Ultrix 4.1 files.

/**********************************************************************
* FILE tlock.c
* Unix network locking test program.
* Author: Bruce Rosen and Geoffrey Gordon
*
* compilation instructions: cc -o tlock tlock.c
*
* usage: tlock FILEPATH [timeout in seconds [retry count]]
*    by default it uses a timeout of 1 second with 10 retries
*
*    The program will print out the timeout and retry count is it
*    using, and then printout a message on each
*    request, followed by a beep on each timeout, and ultimately
*    a message of either success or failure.
*
* DESIGN and LOGIC:
* The program attempts to obtain a write lock on a file using the
* Unix fcntl(,F_WRLCK,) command. While in theory the correct way
* to use this service is to simply queue up for the lock and 
* wait the total amount of time you are willing, we have found that
* in networked situtations that if a lock is not available when you 
* queue up, it is either never granted until you close the file and 
* reassert the lock request or for 15 seconds after it is 
* released by the holder. Either of these cases is unacceptable for
* our purposes, so we break our total "patience period" into a set
* of smaller periods and retry several times.
*
* We use SIGALRM and the alarm() system call to implement the timeout
* since fcntl(,F_WRLCK,) does not have a built in timeout.
*
* For the purposes of this test we lock the entire file.
*
***********************************************************************/

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <sys/errno.h>

#define RETRY_COUNT (10)
#define TIMEOUT_VALUE ((unsigned int) 1)

int main(argc, argv)
    int argc;
    char **argv;
    {

    extern   char*  sys_errlist[];
    extern   void   timeout();
    extern   long   time();
    extern   char*  ctime();
    extern   int    errno;
    FILE*    fp;
    struct   flock  fl;
    int      fd, i;
    long     ts;
    int      saveno;
    int      count;
    int      success = 0;
    int retryCount = RETRY_COUNT;
    int timeoutValue = TIMEOUT_VALUE;
    
    if(argc < 2) 
	{
	fprintf(stderr,"usage %s file [[timeout retries]]\n",argv[0]);
	exit(0);
	}

    fp = fopen(argv[1], "r+");
    if (fp == (FILE *) NULL)
	{
	fprintf(stderr, "open failed: %s\n", sys_errlist[errno]);
	exit(1);
	}
    fclose(fp);
    

    if(argc >= 3)
	timeoutValue = atoi(argv[3]);
    if(argc >= 4)
	retryCount = atoi(argv[2]);

    
    printf("using a timeout of %d, with %d retries\n",
	   timeoutValue,retryCount);
	
    
    
    fl.l_type = F_WRLCK;
    fl.l_whence = SEEK_SET;
    fl.l_start = 0;
    fl.l_len = 0;
    
    signal(SIGALRM, timeout);

    for (count = 0 ; count < retryCount; count++)
	{
	fp = fopen(argv[1], "r+");
	if (fp == (FILE *) NULL)
	    {
	    fprintf(stderr, "open failed: %s\n", sys_errlist[errno]);
	    exit(1);
	    }
	fd = fileno(fp);
	time(&ts);
	printf("Requesting lock at %s", ctime(&ts));
	
	alarm(timeoutValue);
	if ((fcntl(fd, F_SETLKW, &fl)) == -1)
	    {
	    fclose(fp);
	    saveno = errno;
	    if ((saveno == EINTR) || (saveno == ENOLCK))
		continue;
	    fprintf(stderr, "write lock failed: %s\n", sys_errlist[errno]);
	    exit(2);
	    }
	success = 1;
	break;
	}
    
    alarm((unsigned int) 0);

    if (! success)
	{
	printf("\nNever got a lock\n");
	exit(3);
	}
    
    time(&ts);
    printf(
	   "Obtained lock at %s ... Holding lock, hit return to release ...", 
	   ctime(&ts));

    i = getchar();
    fclose(fp);
    }

void timeout()
    {
    signal(SIGALRM, timeout);
    fprintf(stderr, "\007");
    }
/* Fletcher Kittredge
 * BBN Software Products
 * 150 CambridgePark Dr,  Cambridge, MA. 02140
 * 617-873-3465  /  fkittred@bbn.com  /  fkittred@das.harvard.edu
 */