Setting and Removing Record Locks
You lock a record the same way as you lock a file, except that you do not set the starting point and length of the lock segment to zero.
Contention for data is why you use record locking. Therefore, you should lan a failure response for when you cannot obtain all the required locks. Possible strategies are:
Wait a certain amount of time, then try again
Abort the procedure and warn the user
Let the process sleep until signaled that the lock has been freed
Do some combination of the above
This example shows locking a record using fcntl(2).
{ 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 = here; lck.l_len = sizeof(struct record); /* lock "this" with write lock */ lck.l_start = this; if (fcntl(fd, F_SETLKW, &lck) < 0) { /* "this" lock failed. */ return (-1); ... } |
The next example shows the lockf(3C) interface.
#include <unistd.h> { ... /* lock "this" */ (void) lseek(fd, this, SEEK_SET); if (lockf(fd, F_LOCK, sizeof(struct record)) < 0) { /* Lock on "this" failed. Clear lock on "here". */ (void) lseek(fd, here, 0); (void) lockf(fd, F_ULOCK, sizeof(struct record)); return (-1); } |
You remove locks the same way you set them. Only the lock type is different (F_ULOCK). An unlock cannot be blocked by another process and affects only locks placed by the calling process. The unlock affects only the segment of the file specified in the preceding locking call.
Getting Lock Information
You can determine which process, if any, is holding a lock. Use this as a simple test or to find locks on a file. A lock is set, as in the previous examples, and F_GETLK is used in fcntl(2).
The next example finds and prints identifying data on all the locked segments of a file.
Example 4-2 Printing Locked Segments of a File
fcntl(2) with the F_GETLK command can sleep while waiting for a server to respond, and it can fail (returning ENOLCK) if there is a resource shortage on either the client or server.
Use lockf(3C) with the F_TEST command to test if a process is holding a lock. This interface does not return information about where the lock is and which process owns it.
Example 4-3 Testing a Process With lockf
Process Forking and Locks
When a process forks, the child receives a copy of the file descriptors that the parent opened. Locks are not inherited by the child because they are owned by a specific process. The parent and child share a common file pointer for each file. Both processes can try to set locks on the same location in the same file. This problem occurs with both lockf(3C) and fcntl(2). If a program holding a record lock forks, the child process should close the file and reopen it to set a new, separate file pointer.
Deadlock Handling
The UNIX locking facilities provide deadlock detection/avoidance. Deadlocks can occur only when the system is ready to put a record-locking interface to sleep. A search is made to determine whether process A will wait for a lock that B holds while B is waiting for a lock that A holds. If a potential deadlock is detected, the locking interface fails and sets errno to indicate deadlock. Processes setting locks that use F_SETLK do not cause a deadlock because they do not wait when the lock cannot be granted immediately.
Terminal I/O Functions
Terminal I/O interfaces deal with a general terminal interface for controlling asynchronous communications ports, as shown in the following table. For more information, see the termios(3C) and termio(7I) man pages.
Table 4-5 Terminal I/O Interfaces
Interface Name | Purpose |
---|---|
tcgetattr(3C), tcsetattr(3C) | Get and set terminal attributes |
tcsendbreak(3C), tcdrain(3C), tcflush(3C), tcflow(3C) | Perform line control interfaces |
cfgetospeed(3C), cfgetispeed(3C)cfsetispeed(3C), cfsetospeed(3C) | Get and set baud rate |
tcsetpgrp(3C) | Get and set terminal foreground process group ID |
tcgetsid(3C) | Get terminal session ID |
The following example shows how the server dissociates from the controlling terminal of its invoker in the non-DEBUG mode of operation.
Example 4-4 Dissociating From the Controlling Terminal
(void) close(0); (void) close(1); (void) close(2); (void) open("/", O_RDONLY); (void) dup2(0, 1); (void) dup2(0, 2); setsid(); |
This prevents the server from receiving signals from the process group of the controlling terminal. After a server has dissociated itself, it cannot send reports of errors to a terminal and must log errors with syslog(3C).