06-20-06 06:24 PM
Could anyone point what's wrong with following locking code? After
compiling program, symbolic links "writer" and "reader" should be
created to executable, and then program should be launched first trough
name "writer" and then, within 10 seconds, trough name "reader".
Program "writer" is creating file, then locking it as a whole for
writing, then writing 4 bytes in file, then releasing the lock and
finally sleeping for 10 seconds in order to make possible to launch
"reader" program. This program is in turn locking whole file for
reading, then reading 4 bytes from file and printing this value to
standard output, and finally releasing the lock. The problem is,
"reader" program is blocked while trying to get read lock, until
"writer" program exited (or more precisely, until file descriptor
"fdout" used within "writer" program closed implicitly or explicitly,
in which case of course all related locks are relased). Added code to
get offending lock is printing that first program is still holding
write lock for whole contents of file.
Note that numerous variations are tried, including fsync()-ing after
writing to file from "writer" program, then locking explicitly for 4
bytes from start of the file instead of locking of whole file contents
(of course, in that case file with 4 bytes was actually created before
launching programs) etc. Note also that described behavior is observed
on both GNU/Linux (2.6.15.7 kernel, Slackware 10.2 distribution), as
well as on NetBSD 3.0.
Thanks.
/* --- */
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#define FILENAME "test.txt"
int
main(int argc, char **argv)
{
if (strstr(argv[0], "writer") != NULL) {
int fdout;
struct flock lock;
int x;
fdout =
open(FILENAME, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
assert(fdout >= 0);
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 4;
fprintf(stderr, "writer: trying to acquire write lock\n");
assert(fcntl(fdout, F_SETLKW, &lock) == 0);
fprintf(stderr, "writer: acquired write lock\n");
x = 42;
write(fdout, &x, sizeof(int));
lock.l_type = F_UNLCK;
fprintf(stderr, "writer: trying to release write lock\n");
assert(fcntl(fdout, F_UNLCK, &lock) == 0);
fprintf(stderr, "writer: released write lock\n");
} else if (strstr(argv[0], "reader") != NULL) {
int fdin;
struct flock lock;
int x;
fdin = open(FILENAME, O_RDONLY);
assert(fdin >= 0);
lock.l_type = F_RDLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
assert(fcntl(fdin, F_GETLK, &lock) == 0);
if (lock.l_type != F_UNLCK) {
fprintf(stderr, "PROBLEM: %d %d %d %d %d\n",
lock.l_type, lock.l_whence, lock.l_start,
lock.l_len, lock.l_pid);
}
lock.l_type = F_RDLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
fprintf(stderr, "reader: trying to acquire read lock\n");
assert(fcntl(fdin, F_SETLKW, &lock) == 0);
fprintf(stderr, "reader: acquired read lock\n");
read(fdin, &x, sizeof(int));
fprintf(stderr, "%d\n", x);
lock.l_type = F_UNLCK;
fprintf(stderr, "reader: trying to release read lock\n");
assert(fcntl(fdin, F_UNLCK, &lock) == 0);
fprintf(stderr, "reader: released read lock\n");
}
sleep(10);
return 0;
}
[ Post a follow-up to this message ]
|