Re: flock deadlock
Nahor via Cygwin <[email protected]>
| Newsgroups | gmane.os.cygwin |
|---|---|
| Message-ID | <CA+1R0Vju3VQYaz-s00vCroEV3pH7vBeUhoMGqtUxi0x5k56vpQ@mail.gmail.com> |
Attached is a reproducible example. The example just calls `fork()` then open/flock/close a directory and repeats (fork/open/flock/close). The forks optionally sleep then open/flock/close the same directory and exit. There is no issue if either the parent or the children don't call `flock()`. Without sleeping, the example deadlocks immediately on my system 100% of the time. Killing the child allow the parent to proceed, fork the next child, which triggers the next deadlock. When sleeping, _sometimes_ one child will deadlock with the parent. Killing that child allows the parent and remaining children to proceed (and potentially trigger another deadlock). Killing the parent also unblocks all the children. Regards, Nahor. -- Problem reports: https://cygwin.com/problems.html FAQ: https://cygwin.com/faq/ Documentation: https://cygwin.com/docs.html Unsubscribe info: https://cygwin.com/ml/#unsubscribe-simple
main.c
(text/plain, 1.7 KB)
// #define SLEEP
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/file.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
const int FORK_COUNT = 10;
typedef struct {
int id;
} call_args;
static void *flock_call(void *arg) {
call_args *args = (call_args *)arg;
#ifdef SLEEP
if (args->id != -1) {
struct timespec duration;
duration.tv_sec = 0;
duration.tv_nsec = 1;
nanosleep(&duration, NULL);
}
#endif
// open and lock dir
int dir_fd = open("/cygdrive/c/cygwin64/etc", O_RDONLY, 0);
if (dir_fd < 0) {
printf("open dir error: %d - %s\n", errno, strerror(errno));
}
assert(dir_fd >= 0);
// lock
int lock_res = flock(dir_fd, LOCK_SH);
if (lock_res != 0) {
printf("lock error: %d - %s\n", errno, strerror(errno));
}
assert(lock_res == 0);
// close
assert(close(dir_fd) == 0);
printf("done[%i]\n", args->id);
return NULL;
}
int main() {
call_args main_args;
main_args.id = -1;
// spawn children
pid_t children[FORK_COUNT];
for (int i = 0; i < FORK_COUNT; ++i) {
call_args args;
args.id = i;
children[i] = fork();
if (children[i] == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (children[i] == 0) {
flock_call(&args);
return 0;
}
flock_call(&main_args);
}
// wait children
for (int i = 0; i < FORK_COUNT; ++i) {
int wstatus;
pid_t w;
do {
w = waitpid(children[i], &wstatus, WUNTRACED | WCONTINUED);
if (w == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
} while (!WIFEXITED(wstatus) && !WIFSIGNALED(wstatus));
}
printf("done[main]\n");
return 0;
}