Mail Archives: cygwin/2009/07/22/10:42:32
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
- Raw text -