flock still buggy

Eric Blake ebb9@byu.net
Wed Jul 22 16:11:00 GMT 2009


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


More information about the Cygwin mailing list

AltStyle によって変換されたページ (->オリジナル) /