Corinna Vinschen <corinna-cygwin <at> cygwin.com> writes: > > Do you have a working C testcase to demonstrate this?
I still haven't gotten around to trying your patch, but here is the testcase I'm using (I guess it's not that simple, after all): $ cat foo.c #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/file.h> #include <unistd.h> int main (int argc, char** argv) { int mode, fd, pid; if (argc < 2) { printf ("usage: %s mode\n", argv[0]); printf (" grab flock, fork, then sleep in parent and child\n"); printf (" mode can be a bitwise-or of:\n"); printf (" 0 - no extra actions\n"); printf (" 1 - mark fd as close-on-exec\n"); printf (" 2 - close fd after fork\n"); printf (" 4 - unlock in child\n"); printf (" 8 - exec in child\n"); return 1; } mode = atoi (argv[1]); fd = open ("bar", O_RDWR | O_CREAT, 0660); pid = getpid (); if (fd < 0) { printf ("open failed %d\n", errno); return 1; } printf ("%s pid %d starting\n", argv[0], pid); if ((mode & 1) == 1) { if (fcntl (fd, F_SETFD, FD_CLOEXEC | fcntl (fd, F_GETFD)) == -1) { printf ("%s pid %d fcntl failed %d\n", argv[0], pid, errno); return 1; } printf ("%s pid %d protected fd\n", argv[0], pid); } if (flock (fd, LOCK_EX)) { printf ("%s pid %d failed to lock %d\n", argv[0], pid, errno); return 1; } printf ("%s pid %d got lock\n", argv[0], pid); if (fork ()) { /* parent */ if ((mode & 2) == 2) { if (close (fd)) { printf ("%s pid %d close failed %d\n", argv[0], pid, errno); return 1; } printf ("%s pid %d closed\n", argv[0], pid); } sleep (10); printf ("%s pid %d exiting\n", argv[0], pid); return 0; } /* child */ printf ("%s pid %d forked from %d\n", argv[0], (int) getpid (), pid); pid = getpid (); if ((mode & 4) == 4) { if (flock (fd, LOCK_UN)) { printf ("%s pid %d unlock failed %d\n", argv[0], pid, errno); return 1; } printf ("%s pid %d unlocked\n", argv[0], pid); } if ((mode & 8) == 8) { printf ("%s pid %d execing\n", argv[0], pid); execlp ("sh", argv[0], "-c", "sleep 8; echo $0 pid $$ exiting", NULL); printf ("%s pid %d exec failed %d\n", argv[0], pid, errno); return 1; } sleep (8); printf ("%s pid %d exiting\n", argv[0], pid); return 0; } For an example of some of the bugs (which I hope your latest patch attempt fixes): $ ./foo 4& sleep 2; ./foo 0 [1] 21692 ./foo pid 21692 starting ./foo pid 21692 got lock ./foo pid 21704 forked from 21692 ./foo pid 21704 unlocked ./foo pid 14060 starting ./foo pid 14060 got lock ./foo pid 21216 forked from 14060 ./foo pid 21704 exiting ./foo pid 21692 exiting ./foo pid 21216 exiting ./foo pid 14060 exiting [1]+ Done ./foo 4 Oops - process 14060 got the lock before 12692 and 21704 exited. $ ./foo 15 $ ./foo 15 ./foo pid 10932 starting ./foo pid 10932 protected fd ./foo pid 10932 got lock ./foo pid 10932 closed ./foo pid 26264 forked from 10932 ./foo pid 26264 unlocked ./foo pid 26264 execing ./foo pid 26264 exiting ./foo pid 10932 exiting Oops - process 26264 successfully unlocked fd, even though it was marked close- on-exec by 10932 before the fork. Now, on to try your patch... -- Eric Blake -- Problem reports: http://cygwin.com/problems.html FAQ: http://cygwin.com/faq/ Documentation: http://cygwin.com/docs.html Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple