#define _GNU_SOURCE #define _LARGEFILE_SOURCE #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include #include #include #define FNAME "kill-locks.tmp" #define BUFSIZE 16384 #define DEATHSIG SIGINT #define LOCKTRIES 10 #define STRINGIFY_(x) #x #define STRINGIFY(x) STRINGIFY_(x) #define LOCKTRIESSTR STRINGIFY(LOCKTRIES) #define LOCKSLEEPSECS 1 void parent_try_lock(int mfd, int successcount, int status) { int i; struct flock lck; for (i=0; 1 /* always true */; ++i) { lck.l_type = F_WRLCK; lck.l_whence = SEEK_SET; lck.l_start = (off_t)0; lck.l_len = (off_t)0; if (fcntl(mfd, F_SETLK, &lck) == -1) { if (errno == EAGAIN) { if ( i == LOCKTRIES ) { fprintf(stderr, "unexpected status from child %08X\n" "successful locking attempts: %d\n", status, successcount); exit(1); } else { sleep(LOCKSLEEPSECS); } } else perror("[parent] fcntl(F_SETLK)"), exit(1); } else { lck.l_type = F_UNLCK; lck.l_whence = SEEK_SET; lck.l_start = (off_t)0; lck.l_len = (off_t)0; if (fcntl(mfd, F_SETLK, &lck) == -1) perror("[parent] fcntl(F_SETLK) UNLCK"), exit(1); if (status) fprintf(stderr, "[parent] transient error, going on...\n"); break; } } } int main() { int successcount = 0; int mfd; /**/ mfd = open(FNAME, O_RDWR|O_CREAT, 0666); if (mfd == -1) perror("open()"), exit(1); parent_try_lock(mfd, successcount, 0); while (1) { pid_t childpid; int status; /**/ childpid = fork(); if (childpid == (pid_t) -1) perror("fork()"), exit(1); if (childpid == 0) { /* Child */ int fd; struct flock lck; char buf[BUFSIZE]; /**/ fd = open(FNAME, O_RDWR|O_CREAT, 0666); if (fd == -1) perror("[child] open()"), exit(1); lck.l_type = F_WRLCK; lck.l_whence = SEEK_SET; lck.l_start = (off_t)0; lck.l_len = (off_t)0; if (fcntl(fd, F_SETLK, &lck) == -1) perror("[child] fcntl(F_SETLK)"), exit(1); memset(buf, 0, sizeof(buf)); while(1) write(fd, buf, sizeof(buf)); } usleep(rand()%1000); kill(childpid, DEATHSIG); if (waitpid(childpid, &status, 0) != childpid) perror("waitpid"), exit(1); if ( ! (WIFSIGNALED(status) && WTERMSIG(status) == DEATHSIG)) parent_try_lock(mfd, successcount, status); ++successcount; } }