13.17 Open File Description Locks

In contrast to process-associated record locks (see File Locks), open file description record locks are associated with an open file description rather than a process.

Using fcntl to apply an open file description lock on a region that already has an existing open file description lock that was created via the same file descriptor will never cause a lock conflict.

Open file description locks are also inherited by child processes across fork, or clone with CLONE_FILES set (see Creating a Process), along with the file descriptor.

It is important to distinguish between the open file description (an instance of an open file, usually created by a call to open) and an open file descriptor, which is a numeric value that refers to the open file description. The locks described here are associated with the open file description and not the open file descriptor.

Using dup (see Duplicating Descriptors) to copy a file descriptor does not give you a new open file description, but rather copies a reference to an existing open file description and assigns it to a new file descriptor. Thus, open file description locks set on a file descriptor cloned by dup will never conflict with open file description locks set on the original descriptor since they refer to the same open file description. Depending on the range and type of lock involved, the original lock may be modified by a F_OFD_SETLK or F_OFD_SETLKW command in this situation however.

Open file description locks always conflict with process-associated locks, even if acquired by the same process or on the same open file descriptor.

Open file description locks use the same struct flock as process-associated locks as an argument (see File Locks) and the macros for the command values are also declared in the header file fcntl.h. To use them, the macro _GNU_SOURCE must be defined prior to including any header file.

In contrast to process-associated locks, any struct flock used as an argument to open file description lock commands must have the l_pid value set to 0. Also, when returning information about an open file description lock in a F_GETLK or F_OFD_GETLK request, the l_pid field in struct flock will be set to -1 to indicate that the lock is not associated with a process.

When the same struct flock is reused as an argument to a F_OFD_SETLK or F_OFD_SETLKW request after being used for an F_OFD_GETLK request, it is necessary to inspect and reset the l_pid field to 0.

Macro: int F_OFD_GETLK

This macro is used as the command argument to fcntl, to specify that it should get information about a lock. This command requires a third argument of type struct flock * to be passed to fcntl, so that the form of the call is:

fcntl (filedes, F_OFD_GETLK, lockp)

If there is a lock already in place that would block the lock described by the lockp argument, information about that lock is written to *lockp. Existing locks are not reported if they are compatible with making a new lock as specified. Thus, you should specify a lock type of F_WRLCK if you want to find out about both read and write locks, or F_RDLCK if you want to find out about write locks only.

There might be more than one lock affecting the region specified by the lockp argument, but fcntl only returns information about one of them. Which lock is returned in this situation is undefined.

The l_whence member of the lockp structure are set to SEEK_SET and the l_start and l_len fields are set to identify the locked region.

If no conflicting lock exists, the only change to the lockp structure is to update the l_type field to the value F_UNLCK.

The normal return value from fcntl with this command is either 0 on success or -1, which indicates an error. The following errno error conditions are defined for this command:

EBADF

The filedes argument is invalid.

EINVAL

Either the lockp argument doesn’t specify valid lock information, the operating system kernel doesn’t support open file description locks, or the file associated with filedes doesn’t support locks.

Macro: int F_OFD_SETLK

This macro is used as the command argument to fcntl, to specify that it should set or clear a lock. This command requires a third argument of type struct flock * to be passed to fcntl, so that the form of the call is:

fcntl (filedes, F_OFD_SETLK, lockp)

If the open file already has a lock on any part of the region, the old lock on that part is replaced with the new lock. You can remove a lock by specifying a lock type of F_UNLCK.

If the lock cannot be set, fcntl returns immediately with a value of -1. This command does not wait for other tasks to release locks. If fcntl succeeds, it returns 0.

The following errno error conditions are defined for this command:

EAGAIN

The lock cannot be set because it is blocked by an existing lock on the file.

EBADF

Either: the filedes argument is invalid; you requested a read lock but the filedes is not open for read access; or, you requested a write lock but the filedes is not open for write access.

EINVAL

Either the lockp argument doesn’t specify valid lock information, the operating system kernel doesn’t support open file description locks, or the file associated with filedes doesn’t support locks.

ENOLCK

The system has run out of file lock resources; there are already too many file locks in place.

Well-designed file systems never report this error, because they have no limitation on the number of locks. However, you must still take account of the possibility of this error, as it could result from network access to a file system on another machine.

Macro: int F_OFD_SETLKW

This macro is used as the command argument to fcntl, to specify that it should set or clear a lock. It is just like the F_OFD_SETLK command, but causes the process to wait until the request can be completed.

This command requires a third argument of type struct flock *, as for the F_OFD_SETLK command.

The fcntl return values and errors are the same as for the F_OFD_SETLK command, but these additional errno error conditions are defined for this command:

EINTR

The function was interrupted by a signal while it was waiting. See Primitives Interrupted by Signals.

Open file description locks are useful in the same sorts of situations as process-associated locks. They can also be used to synchronize file access between threads within the same process by having each thread perform its own open of the file, to obtain its own open file description.

Because open file description locks are automatically freed only upon closing the last file descriptor that refers to the open file description, this locking mechanism avoids the possibility that locks are inadvertently released due to a library routine opening and closing a file without the application being aware.

As with process-associated locks, open file description locks are advisory.