On 2/16/2012 8:04 AM, Corinna Vinschen wrote:
> On Feb 16 07:56, David Rothenberger wrote:
>> On 2/16/2012 6:09 AM, Corinna Vinschen wrote:
>>> I read the Linux man page again (http://linux.die.net/man/2/flock)
>>> and I just hacked the following testcase, based on your flock STC.
>>
>> That sounds pretty close to what the APR test case is doing, as far as I
>> understand.
>>
>>> The testcase is attached.  I'm pretty curious what your test is actually
>>> testing.
>>
>> I got to work at my real job all last night, so couldn't extract the STC
>> from the APR test suite. But, here's the test in APR-ese in case you're
>> interested. I'll remove the APRisms as soon as I can to get you another
>> test case.

I've extracted the test case, which is attached.

I must humbly apologize. The test case was actually using fcntl() for
file locking, not flock(). I got thrown off by the name of the test:
"testflock". It seems APR prefers fcntl() for file locking if available.

The attached test works fine for me on Linux, but fails on Cygwin
starting with the 20120215 snapshot.


-- 
David Rothenberger  ----  daver...@acm.org

"So why don't you make like a tree, and get outta here."
                -- Biff in "Back to the Future"
/***********************************************************************
 * This is a STC to show a process can get an exclusive lock on a file using
 * fcntl, even though another process has an exclusive lock.
 *
 * A parent process uses fcntl to get an exclusive lock. It then
 * uses fork/exec to spawn a child of itself, which also tries to get an
 * exclusive lock on the file.
 *
 * If all works correctly, the child should not be able to get the
 * lock. However, the child is able to get the lock.
 *
 * This test was extracted from the APR test suite.
 *
 * Compile: gcc -Wall -o stc-fcntl-forkexec stc-fcntl-forkexec.c
 ***********************************************************************/
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/file.h>
#include <sys/wait.h>

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

#define TESTFILE "testfile.lock"

error_t
lock_file (int fd, int cmd)
{
  int rc;
  struct flock l = { 0 };
  int fc;

  l.l_whence = SEEK_SET;  /* lock from current point */
  l.l_start = 0;          /* begin lock at this offset */
  l.l_len = 0;            /* lock to end of file */
  l.l_type = F_WRLCK;
  fc = cmd;

  /* keep trying if fcntl() gets interrupted (by a signal) */
  while ((rc = fcntl(fd, fc, &l)) < 0 && errno == EINTR)
    continue;

  if (rc == -1) {
    /* on some Unix boxes (e.g., Tru64), we get EACCES instead
     * of EAGAIN; we don't want APR_STATUS_IS_EAGAIN() matching EACCES
     * since that breaks other things, so fix up the retcode here
     */
    if (errno == EACCES) {
      return EAGAIN;
    }
    return errno;
  }
  return 0;
}

/* The child */
void
tryread ()
{
  int fd;
  error_t status;
  
  fd = open (TESTFILE, O_WRONLY, 0666);
  if (fd < 0)
    {
      perror ("child open failed");
      exit (2);
    }

  status = lock_file (fd, F_SETLK);
  if (status == 0)
    exit(0);
  if (status == EAGAIN)
    exit(1);
  exit(2);
}

int
main (int argc, const char *const *argv)
{
  int fd;
  const char *args[3];
  pid_t pid;
  pid_t pstatus;
  int exit_int;

  if (argc > 1)
    {
      /* Called to run the child. */
      tryread ();
      fprintf (stderr, "Should not get here!\n");
      return 2;
    }  

  /* Create the lock file. */
  fd = open (TESTFILE, O_WRONLY|O_CREAT, 0666);
  if (fd < 0)
    {
      perror ("open failed");
      return 1;
    }

  /* Lock the file. */
  if (lock_file (fd, F_SETLKW) != 0)
    {
      perror ("lock");
      return 1;
    }

  /* Spawn the child reader */
  if ((pid = fork ()) < 0)
    {
      perror ("fork");
      return 1;
    }
  else if (pid == 0) {
    /* child */
    args[0] = program_invocation_name;
    args[1] = "child";
    args[2] = NULL;
    execl (program_invocation_name, program_invocation_name, "child", NULL);
    fprintf (stderr, "execv failed\n");
    _exit (2);
  }

  /* Wait for the child. */
  do {
    pstatus = waitpid (pid, &exit_int, WUNTRACED);
  } while (pstatus < 0 && errno == EINTR);

  if (WIFEXITED (exit_int))
    {
      exit_int = WEXITSTATUS (exit_int);
      if (exit_int == 0)
        printf ("FAILED: Child was able to get a lock when it shouldn't.\n");
      else if (exit_int == 1)
        printf ("SUCCESS: Child was not able to get the lock.\n");
      else
        fprintf (stderr, "Unexpected error from child: %d\n", exit_int);
    }
  else
    fprintf (stderr, "Child did not terminate normally.\n");
  
  /* Close the file */
  close (fd);

  /* Clean up. */
  unlink (TESTFILE);

  return 0;
}

--
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

Reply via email to