A second basic communication technique, similar in spirit to using lock files, can be implemented by using some of the standard file protection routines found in UNIX. UNIX allows the locking of records. As there is no real record structure imposed on a file, a record (which is sometimes called a segment or section) is considered to be a specified number of contiguous bytes of storage starting at an indicated location. If the starting location for the record is the beginning of a file, and the number of bytes equals the number found in the file, then the entire file is
At a system level the chmod command can be used to specify a file support mandatory locking. For example, in Figure 4.5, the permissions on the data file x.dat are set to support mandatory file locking. The ls command will display the letter S in the group execution bit field of a file that supports a mandatory lock. Notice that in the example absolute mode was used with the chmod command to establish locking. The first digit of the mode value should be a 2 and the third digit a 6, 4, 2, or 0 (but not a 1).
linux$ echo hello > x.dat <-- 1 linux$ ls -l x.dat -rw-r--r-- 1 gray faculty 6 Jan 30 12:06 x.dat <-- 2 linux$ chmod 2644 x.dat <-- 3 $ ls -l x.dat -rw-r-Sr-- 1 gray faculty 6 Jan 30 12:06 x.dat
(1) Create a small text file.
(2) Default
protections .(3) Set the execution bit for the group.
The topic of record locking is expansive. We focus on one small aspect of it. We use file locking routines to place and remove an advisory lock on an entire file as a communication technique with cooperating processes.
There are several ways to set a lock. The two most common approaches are presented: the fcntl system call and the lockf library function. We begin with fcntl (Table 4.6).
|
Include File(s) |
<unistd.h> <fcntl.h> |
Manual Section |
2 |
|
|
Summary |
int fcntl(int fd, int cmd /* , struct flock *lock */); |
|||
|
Return |
Success |
Failure |
Sets errno |
|
|
Value returned depends upon the cmd argument passed. |
-1 |
Yes |
||
As its first argument the
fcntl
system call is passed a valid integer file descriptor of an
|
Defined Constant |
Action Taken by fcntl |
|---|---|
|
F_SETLK |
Set or remove a lock. Specific action is based on the contents of the flock structure that is passed as a third argument to fcntl . |
|
F_SETLKW |
Same as F_SETLK, but block (wait) if the indicated record/segment is not availablethe default is not to block. |
|
F_GETLK |
Return lock status information via the flock structure that is passed as the third argument to fcntl . |
The third argument for fcntl is optional for some invocations (as indicated by it being gcommented out in the function prototype). However, when working with locks, the third argument is specified and references a flock structure, which is defined as
struct flock {
short int l_type; /* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK. */
short int l_whence; /* Where 'l_start' is relative to. */
#ifndef __USE_FILE_OFFSET64
__off_t l_start; /* Offset where the lock begins. */
__off_t l_len; /* Size of the locked area; (0 == EOF). */
#else
__off64_t l_start; /* For systems with 64 bit offset. */
__off64_t l_len;
#endif
__pid_t l_pid; /* PID of process holding the lock. */
};
The flock structure is used to pass information to and return information from the fcntl call. The type of lock, l_type , is indicated by using one of the defined constants shown in Table 4.8.
The
l_whence
,
l_start
, and
l_len flock
|
Defined Constant |
Lock Specification |
|---|---|
|
F_RDLCK |
Read lock |
|
F_WRLCK |
Write lock |
|
F_UNLCK |
Remove lock |
When dealing with locks, if fcntl fails to carry out an indicated command, it will return a value of -1 and set errno . Error messages associated with locking are shown in Table 4.9.
|
# |
Constant |
perror Message |
Explanation |
|---|---|---|---|
|
4 |
EINTR |
Interrupted system call |
A signal was caught during the system call. |
|
9 |
EBADF |
Bad file number |
fd does not reference a valid open file descriptor. |
|
11 |
EAGAIN |
Resource temporarily unavailable |
Lock operation is
|
|
13 |
EACCES |
Permission
|
Lock operation prohibited by a lock held by another process. |
|
14 |
EFAULT |
Bad address |
*lock references an illegal address space. |
|
22 |
EINVAL |
Invalid argument |
|
|
35 |
EDEADLK |
Resource deadlock avoided |
cmd
is
F_SETLKW
and
|
|
37 |
ENOLCK |
No locks available |
System has reached the maximum number of record locks. |
Program 4.2
File : p4.2.cxx
/* Locking a file with fcntl
*/
#include <iostream>
+ #include <cstdio>
#include <cerrno>
#include <fcntl.h>
#include <unistd.h>
using namespace std;
const int MAX = 5;
10 int
main(int argc, char *argv[ ]) {
int f_des, pass = 0;
pid_t pid = getpid();
struct flock lock; // for fcntl info
+ if (argc < 2) { // name of file to lock missing
cerr << "Usage " << *argv << " lock_file_name" << endl;
return 1;
}
sleep(1); // don't start immediately
20 if ((f_des = open(argv[1], O_RDWR)) < 0){
perror(argv[1]); // could not access file
return 2;
}
lock.l_type = F_WRLCK; // set a write lock
+ lock.l_whence = 0; // start at beginning
lock.l_start = 0; // with a 0 offset
lock.l_len = 0; // whole file
while (fcntl(f_des, F_SETLK, &lock) < 0) {
switch (errno) {
30 case EAGAIN:
case EACCES:
if (++pass < MAX)
sleep(1);
else { // run out of tries
+ fcntl(f_des, F_GETLK, &lock);
cerr << "Process " << pid << " found file "
<< argv[1] << " locked by " << lock.l_pid << endl;
return 3;
}
40 continue;
}
perror("fcntl");
return 4;
}
+ cerr << endl << "Process " << pid << " has the file" << endl;
sleep(3); // fake processing
cerr << "Process " << pid << " is done with the file" << endl;
return 0;
}
In this program the name of the file to be locked is passed on the command line. A call to
sleep
is placed at the start of the program to slow down the processing (for demonstration purposes only). The designated file is opened for reading and writing. In lines 24 through 27 the
lock
structure is assigned values that indicate a
write
lock is to be applied to the entire file. In the
while
loop that
If we run three copies of Program 4.2 in rapid succession, using the file x.dat as the lock file, their output will be similar to that shown in Figure 4.6.
linux$ p4.2 x.dat & p4.2 x.dat & p4.2 x.dat &
<-- 1
[1] 28392
[2] 28393
[3] 28394
$
Process 28392 has the file
Process 28392 is done with the file
Process 28393 has the file
Process 28394 found file x.dat locked by 28393
Process 28393 is done with the file
[3] Exit 3 p4.2 x.dat
[2] Done p4.2 x.dat
[1] + Done p4.2 x.dat
(1) All three processes will use the same file :
Notice that the last process, PID 28394 in this example, is unable to place a lock on the file and returns the process ID of the process that currently has the lock on the file. The second process, PID 28393, through repeated retries (with
4-4 EXERCISEChange the F_SETLK constant in Program 4.2 to F_SETLKW. Recompile the program and rerun it as shown in Figure 4.6. What sequence of messages are produced now? Why? |
The lockf library function may also be used to apply, test, or remove a lock on an open file. Beneath the covers this library function is an alternate interface for the fcntl system call. The lockf library function is summarized in Table 4.10.
|
Include File(s) |
<sys/file.h> <unistd.h> |
Manual Section |
3 |
|
|
Summary |
int lockf(int fd, int cmd, off_t len); |
|||
|
Return |
Success |
Failure |
Sets errno |
|
|
-1 |
Yes |
|||
The fd argument is a file descriptor of a file that has been opened for either writing (O_WRONLY) or for reading and writing (O_RDWR). The cmd argument for lockf is similar to the cmd argument used with fcntl . The cmd value indicates the action to be taken. The action that lockf will take for each cmd value (as specified in the include file <unistd.h> ) is summarized in Table 4.11.
|
Defined Constant |
Lock Specification |
|---|---|
|
F_ULOCK |
Unlock a previously locked file. |
|
F_LOCK |
Lock a file (or a section of a file) for exclusive use if it is available. If unavailable, the lockf function will block. |
|
F_TLOCK |
Test and, if successful, lock a file (or section of a file) for exclusive use. An error is returned if no lock can be applied; with this option the lockf function will not block if the lock cannot be applied. |
|
F_TEST |
Test a file for the presence of a lock. A 0 is returned if the file is unlocked or locked by the current process. If locked by another process, -1 is returned and errno is set to EACCES. |
The len argument of lockf indicates the number of contiguous bytes to lock or unlock. A value of zero indicates the section should be from the present location to the end of the file.
If the lockf call is successful, it returns a value of 0. If the call fails, it sets errno and returns the value -1 (Table 4.12).
|
# |
Constant |
perror Message |
Explanation |
|---|---|---|---|
|
9 |
EBADF |
Bad file number |
fd is not a valid open file descriptor. |
|
11 |
EAGAIN |
Resource temporarily unavailable |
|
|
13 |
EACCES |
Permission denied |
Lock operation prohibited by a lock held by another process. |
|
22 |
EINVAL |
Invalid argument |
Invalid operation specified for fd . |
|
35 |
EDEADLK |
File locking deadlock |
Requested lock operation would cause a deadlock. |
|
37 |
ENLOCK |
No locks available |
Maximum number of system locks has been reached. |
Of the two techniques,
lockf
is simpler but less flexible than using
fcntl
. Note that when using the
lockf
call, the
A final noteLinux supports a shlock command that can be used in shell scripts. The shlock command creates a lock file that contains an identifying PID.
4-5 EXERCISEWrite Exercise 4.3 using the lockf system call. Verify that your solution works. |
|
|
| Top |