Using File and Record Locking
You do not need to use traditional file I/O to lock file elements. Use the lighter weight synchronization mechanisms described in Multithreaded Programming Guide with mapped files. The threads library interfaces are more efficient than the old style file locking described in this section.
You lock files, or portions of files, to prevent errors that can occur when two or more users try to update a file at the same time.
File locking and record locking are really the same thing, except that file locking blocks access to the whole file, while record locking blocks access to only a specified segment of the file. In SunOS, all files are a sequence of bytes of data: a record is a concept of the programs that use the file.
Choosing a Lock Type
Mandatory locking suspends a process until the requested file segments are free. Advisory locking returns a result indicating whether the lock was obtained or not: processes can ignore the result and do the I/O anyway. You cannot use both mandatory and advisory file locking on the same file at the same time. The mode of a file at the time it is opened determines whether locks on a file are treated as mandatory or advisory.
Of the two basic locking calls, fcntl(2) is more portable, more powerful, and less easy to use than lockf(3C). fcntl(2) is specified in POSIX 1003.1 standard. lockf(3C) is provided to be compatible with older applications.
Selecting Advisory or Mandatory Locking
For mandatory locks, the file must be a regular file with the set-group-ID bit on and the group execute permission off. If either condition fails, all record locks are advisory.
Set a mandatory lock as follows.
#include <sys/types.h> #include <sys/stat.h> int mode; struct stat buf; ... if (stat(filename, &buf) < 0) { perror("program"); exit (2); } /* get currently set mode */ mode = buf.st_mode; /* remove group execute permission from mode */ mode &= ~(S_IEXEC>>3); /* set 'set group id bit' in mode */ mode |= S_ISGID; if (chmod(filename, mode) < 0) { perror("program"); exit(2); } ... |
Because the operating system ignores record locks when executing a file, files to be record locked should not have any execute permission set.
The chmod(1) command can also be used to set a file to permit mandatory locking. For example:
$ chmod +l file |
This command sets the O20n0 permission bit in the file mode, which indicates mandatory locking on the file. If n is even, the bit is interpreted as enabling mandatory locking. If n is odd, the bit is interpreted as "set group ID on execution."
The ls(1) command shows this setting when you ask for the long listing format with the -l option:
$ ls -l file |
This command displays the following information:
-rw---l--- 1 user group size mod_time file |
The letter "l" in the permissions indicates that the set-group-ID bit is on, so mandatory locking is enabled, along with the normal semantics of set group ID.
Cautions About Mandatory Locking
Keep in mind the following aspects of locking:
Mandatory locking works only for local files. It is not supported when accessing files through NFS.
Mandatory locking protects only the segments of a file that are locked. The remainder of the file can be accessed according to normal file permissions.
If multiple reads or writes are needed for an atomic transaction, the process should explicitly lock all such segments before any I/O begins. Advisory locks are sufficient for all programs that perform in this way.
Arbitrary programs should not have unrestricted access permission to files on which record locks are used.
Advisory locking is more efficient because a record lock check does not have to be performed for every I/O request.
Supported File Systems
Both advisory and mandatory locking are supported on the file systems listed in the following table.
Table 4-4 Supported File Systems
File System | Description |
---|---|
ufs | The default disk-based file system |
fifofs | A pseudo file system of named pipe files that give processes common access to data |
namefs | A pseudo file system used mostly by STREAMS for dynamic mounts of file descriptors on top of file |
specfs | A pseudo file system that provides access to special character and block devices |
Only advisory file locking is supported on NFS. File locking is not supported for the proc and fd file systems.
Opening a File for Locking
You can only request a lock for a file with a valid open descriptor. For read locks, the file must be open with at least read access. For write locks, the file must also be open with write access. In the following example, a file is opened for both read and write access.
... filename = argv[1]; fd = open (filename, O_RDWR); if (fd < 0) { perror(filename); exit(2); } ... |
Setting a File Lock
To lock an entire file, set the offset to zero and set the size to zero.
You can set a lock on a file in several ways. The choice of method depends on how the lock interacts with the rest of the program, performance, and portability. This example uses the POSIX standard-compatible fcntl(2) interface. The interface tries to lock a file until one of the following happens:
The file lock is set successfully.
An error occurs.
MAX_TRY is exceeded, and the program stops trying to lock the file.
#include <fcntl.h> ... struct flock lck; ... lck.l_type = F_WRLCK; /* setting a write lock */ lck.l_whence = 0; /* offset l_start from beginning of file */ lck.l_start = (off_t)0; lck.l_len = (off_t)0; /* until the end of the file */ if (fcntl(fd, F_SETLK, &lck) <0) { if (errno == EAGAIN || errno == EACCES) { (void) fprintf(stderr, "File busy try again later!\n"); return; } perror("fcntl"); exit (2); } ...
Using fcntl(2), you can set the type and start of the lock request by setting a few structure variables.
Note - You cannot lock mapped files with flock(3UCB). However, you can use the multithread-oriented synchronization mechanisms (in either POSIX or Solaris styles) with mapped files. See the mutex(3THR), condition(3THR), semaphore(3THR), mmap(2), and rwlock(3THR) man pages.