public inbox for cygwin@cygwin.com
 help / color / mirror / Atom feed
From: David Rothenberger <daveroth@acm.org>
To: cygwin <cygwin@cygwin.com>
Subject: STC for libapr1 failure
Date: Tue, 14 Feb 2012 08:00:00 -0000	[thread overview]
Message-ID: <4F3A14A8.4090506@acm.org> (raw)

[-- Attachment #1: Type: text/plain, Size: 1398 bytes --]

The libapr1 test cases are failing again for flock locks. This same
test case failed with 1.7.9 with a fatal error[1], but that was
corrected. The test is no longer encountering the fatal error, but
it is producing the wrong result.

I extracted the attached STC to demonstrate the problem. It starts a
number of child processes, each of which repeatedly grab and release
a lock on a temporary file. While they have the lock, the increment
a counter in shared memory in a racy way.

If all goes well, the counter should end up having the value of
CHILDREN * ITERS_PER_CHILDREN. And it does, sometimes. Other times,
however, it's less than this value, indicating the lock did not
work.

(I'm using shmget for shared memory, so you have to have cygserver
running. APR has a number of shared memory methods, including mmap,
but this was the easiest for me to extract.)

As before, I haven't been doing C programming in a while, so I'm not
100% sure the test case is valid, but it does demonstrate the same
problem the APR test case is having.

I've tried this on my Win7-64 box running the 20120210 snapshot and
on a WinXP running stock 1.7.10. I get the same results in both
places.

Regards,
David

[1] http://cygwin.com/ml/cygwin/2011-08/msg00480.html

-- 
David Rothenberger  ----  daveroth@acm.org

I think we are in Rats' Alley where the dead men lost their bones.
                -- T.S. Eliot

[-- Attachment #2: stc-flock-fork.c --]
[-- Type: text/plain, Size: 4089 bytes --]

/***********************************************************************
 * This is a STC to show that flock occasionally does not work.
 *
 * It tries to use flock() for file locking. It creates a temporary
 * file, the uses fork to spawn a number of children. Each child opens
 * the file, then repeatedly uses flock to lock and unlock it.
 *
 * While each child has the lock, it increments a counter stored in
 * shared memory in a racy way, passing the current value to a function
 * which sleeps briefly, then returns the incremented counter.
 *
 * If all works correctly, the counter should end up be incremented
 * by each child iteration.
 *
 * However, this is failing for me occasionally. The counter ends up
 * being less than the expected value.
 *
 * This test was extracted from the APR test suite.
 *
 * Compile: gcc -Wall -o stc-flock-fork stc-flock-fork.c
 ***********************************************************************/

#include <sys/types.h>
#include <sys/file.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>

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

#define MAX_ITER 200
#define CHILDREN 6
#define MAX_COUNT (MAX_ITER * CHILDREN)

/* Counter stored in shared memory. */
static volatile int *x;

/* A temporary file used for flock. */
char tmpfilename[] = "/tmp/flocktstXXXXXX";

/* a slower more racy way to implement (*x)++ */
static int increment(int n)
{
    usleep(1);
    return n+1;
}

/* Fork and use flock to lock and unlock the file repeatedly in the child. */
void make_child(int trylock, pid_t *pid)
{
    if ((*pid = fork()) < 0) {
        perror("fork failed");
        exit(1);
    }
    else if (*pid == 0) {
        int fd2 = open(tmpfilename, O_RDONLY);
        if (fd2 < 0) {
            perror("child open");
            exit(1);
        }

        int rc;
        int i;
        for (i=0; i<MAX_ITER; ++i) {
            /* Get the lock. */
            do {
                rc = flock(fd2, LOCK_EX);
            } while (rc < 0 && errno == EINTR);
            if (rc < 0) {
                perror("lock");
                exit(1);
            }

            /* Have the lock. Increment the counter. */
            *x = increment(*x);

            /* Release the lock. */
            do {
                rc = flock(fd2, LOCK_UN);
            } while (rc < 0 && errno == EINTR);
            if (rc < 0) {
                perror("unlock");
                exit(1);
            }
        }
        exit(0);
    }
}

/* Wait for the child to finish. */
void await_child(pid_t pid)
{
    pid_t pstatus;
    int exit_int;

    do {
        pstatus = waitpid(pid, &exit_int, WUNTRACED);
    } while (pstatus < 0 && errno == EINTR);
}

/* Allocate and attach shared memory */
void init_shm ()
{
    int shmid;
    if ((shmid = shmget(IPC_PRIVATE, sizeof(int), S_IRUSR | S_IWUSR | IPC_CREAT)) < 0) {
        perror("shmget failed");
        exit(1);
    }
    if ((x = shmat(shmid, NULL, 0)) == (void *) -1) {
        perror("shmat failed");
        exit(1);
    }
}

int main(int argc, const char * const * argv, const char * const *env)
{
    pid_t child[CHILDREN];
    int i;
    int n;
    int fd;

    /* Create the temporary file. */
    fd = mkstemp(tmpfilename);
    if (fd < 0) {
        perror("open failed");
        exit(1);
    }
    close(fd);

    /* Initialize shared memory */
    init_shm();

    /* Perform the test multiple times, since this fails only intermittedly. */
    for (i = 0; i < 100; ++i) {
        /* Initialize counter */
        *x = 0;

        /* Create the children. */
        for (n = 0; n < CHILDREN; n++)
            make_child(0, &child[n]);

        /* Wait for them to finish. */
        for (n = 0; n < CHILDREN; n++)
            await_child(child[n]);

        /* Check counter */
        if (*x != MAX_COUNT) {
            printf("Iteration %d: FAILED: *x (%d) != MAX_COUNT (%d)\n", i, *x, MAX_COUNT);
            exit(1);
        }
    }

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

    return 0;
}


[-- Attachment #3: Type: text/plain, Size: 218 bytes --]

--
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	other threads:[~2012-02-14  8:00 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-02-14  8:00 David Rothenberger [this message]
2012-02-14  8:07 ` David Rothenberger
2012-02-14 14:03 ` Corinna Vinschen
2012-02-14 14:46   ` Corinna Vinschen
2012-02-14 17:58     ` David Rothenberger
2012-02-14 18:25       ` Corinna Vinschen
2012-02-14 21:43         ` David Rothenberger
2012-02-15 15:39           ` Corinna Vinschen
2012-02-15 19:39             ` David Rothenberger
2012-02-15 20:46               ` Corinna Vinschen
2012-02-15 21:16                 ` David Rothenberger
2012-02-15 21:20                   ` Corinna Vinschen
2012-02-15 22:14                     ` David Rothenberger
2012-02-16 14:11                       ` Corinna Vinschen
2012-02-16 15:57                         ` David Rothenberger
2012-02-16 16:06                           ` Corinna Vinschen
2012-02-18 21:52                             ` David Rothenberger
2012-02-20 14:19                               ` Corinna Vinschen
2012-02-20 20:15                                 ` David Rothenberger
2012-02-21  1:29                                 ` Yaakov (Cygwin/X)
2012-02-21  8:59                                   ` Corinna Vinschen
2012-02-21 17:10                                     ` Corinna Vinschen
2012-02-23 14:20                                       ` Corinna Vinschen
2012-02-23 18:43                                         ` Achim Gratz
2012-02-24  3:49                                         ` Yaakov (Cygwin/X)
2012-02-24  8:15                                           ` Corinna Vinschen
  -- strict thread matches above, loose matches on Subject: below --
2011-08-26  0:39 David Rothenberger
2011-08-26 11:16 ` Corinna Vinschen
2011-08-27 20:37   ` Corinna Vinschen
2011-08-27 22:27     ` David Rothenberger
2011-08-29 13:55       ` Corinna Vinschen
2011-08-29 17:09         ` David Rothenberger

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4F3A14A8.4090506@acm.org \
    --to=daveroth@acm.org \
    --cc=cygwin@cygwin.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).