Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
4.  Input/Output Interfaces Using File and Record Locking Supported File Systems Setting a File Lock   Previous   Contents   Next 
   
 

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

struct flock lck;

 	lck.l_whence = 0;
 	lck.l_start = 0L;
 	lck.l_len = 0L;
 	do {
 		lck.l_type = F_WRLCK;
 		(void) fcntl(fd, F_GETLK, &lck);
 		if (lck.l_type != F_UNLCK) {
 			(void) printf("%d %d %c %8ld %8ld\n", lck.l_sysid, lck.l_pid,
            (lck.l_type == F_WRLCK) ? 'W' : 'R', lck.l_start, lck.l_len);
 			/* If this lock goes to the end of the address space, no
 			 * need to look further, so break out. */
 			if (lck.l_len == 0) {
 			/* else, look for new lock after the one just found. */
 					lck.l_start += lck.l_len;
 			}
 		}
 	} while (lck.l_type != F_UNLCK);

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

(void) lseek(fd, 0, 0L);
 /* set the size of the test region to zero (0). to test until the
    end of the file address space. */
 if (lockf(fd, (off_t)0, SEEK_SET) < 0) {
 	switch (errno) {
 		case EACCES:
 		case EAGAIN:
 			(void) printf("file is locked by another process\n");
 			break;
 		case EBADF:
 			/* bad argument passed to lockf */
 			perror("lockf");
 			break;
 		default:
 			(void) printf("lockf: unexpected error <%d>\n", errno);
 			break;
 	}
 

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).

 
 
 
  Previous   Contents   Next