#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <assert.h>
#define NUMPROCS 20
#define NUMITERS 1000
#define WIDTH 5
static int trylock(int fd, int ofs)
{
int rv;
struct flock f;
memset(&f, 0, sizeof(f));
f.l_type = F_WRLCK;
f.l_start = ofs;
f.l_len = 1;
rv = fcntl(fd, F_SETLK, &f);
if (rv)
{
if (errno == EAGAIN || errno == EACCES)
return 0; perror("trylock");
abort();
}
return 1; }
static void unlock(int fd, int ofs)
{
int rv;
struct flock f;
memset(&f, 0, sizeof(f));
f.l_type = F_UNLCK;
f.l_start = ofs;
f.l_len = 1;
rv = fcntl(fd, F_SETLK, &f);
if (rv)
{
perror("unlock");
abort();
}
}
static int check(int fd, int ofs)
{
pid_t pid, wantpid;
int rv;
struct flock f;
memset(&f, 0, sizeof(f));
f.l_type = F_WRLCK;
f.l_start = ofs;
f.l_len = 1;
wantpid = getpid();
pid = fork();
if (pid == 0) {
rv = fcntl(fd, F_GETLK, &f);
if (rv)
{
perror("getlock");
abort();
}
if (f.l_type == F_UNLCK)
_exit(0); else
{
if (f.l_pid == wantpid)
_exit(1); else
_exit(0); }
}
else if (pid > 0) {
int status = 0;
wait(&status);
assert(WIFEXITED(status));
return WEXITSTATUS(status);
}
else
{
perror("fork");
abort();
}
}
static int submain(int procnum, int fd)
{
static char owned[WIDTH];
int i, ofs;
memset(owned, 0, sizeof(owned));
srandom(procnum);
for (i = 0; i < NUMITERS; i++)
{
ofs = random() % WIDTH;
if (check(fd, ofs) != owned[ofs])
{
fprintf(stderr, "proc=%-5d ofs=%-5d iter=%-5d - expected %d\n",
procnum, ofs, i, owned[ofs]);
abort();
}
if (owned[ofs])
{
unlock(fd, ofs);
owned[ofs] = 0;
}
else
owned[ofs] = trylock(fd, ofs);
assert(check(fd, ofs) == owned[ofs]);
}
return 0;
}
int main()
{
int fd, i, err;
pid_t pid;
unlink("mylock"); fd = open("mylock", O_RDWR|O_CREAT|O_EXCL, 0600);
for (i = 0; i < NUMPROCS; i++)
{
pid = fork();
if (pid == 0) _exit(submain(i, fd));
else if (pid < 0) {
perror("fork");
exit(1);
}
}
err = 0;
for (i = 0; i < NUMPROCS; i++)
{
int status = 0;
pid = wait(&status);
if (status != 0)
{
fprintf(stderr, "pid %ld returned %04x\n", (long)pid, status);
err++;
}
}
fprintf(stderr, "Errors: %d of %d\n", err, NUMPROCS);
return err != 0;
}