Jerry D. Hedden wrote:
> [...]
> Under 1.5.24, this test always passes.  Under 1.5.25, it is
> now frequently failing.  If I add a debugging call in the
> central most loop:
>
>             print("got: $lt  exp: $localtime\n");
>
> I get the following as typical of the problem:
>
>     5 perl-current > ./perl -Ilib ext/threads/t/libc.t
>     1..11
>     ok 1 - use threads
>     got: Wed Dec 31 20:00:08 1969  exp: Wed Dec 31 19:00:08 1969
> [...]
> This shows a 1 hour difference between the expected and
> actual results - which looks like a timezone issue.
>
> As the changes for 1.5.25 include numerous references to
> timezone handling changes, I suspect there may be some
> re-entrancy bug in those changes.

Corinna Vinschen wrote:
> It would be more helpful if you would send self-contained code which
> doesn't have to be tweaked to do a test.  I'm not a perl developer, so
> it took me some time to get it running.  I'd also really prefer
> testcases in plain C which I can simply run under GDB.  Interpreter code
> just adds unnecessary complexity.

I was working on this when I got your email.  Attached.

> I assume the perl libs are using localtime_r, right?  Otherwise you
> can't rely on reentrency nor thread-safety.  Anyway, localtime is
> supposed to be thread-safe in Cygwin.

I believe this is correct.

> The only change in 1.5.25 related to localtime is the fact that the
> environment variable "TZ" is now left alone by Cygwin.  Up to 1.5.24 the
> function tzset() (called by localtime()) also sets the environment
> variable "TZ", which is apparently incorrect according to POSIX.  "TZ"
> is used in later calls to decide whether some other code has to be run
> or not.
>
> And exactly that's the problem.  Since TZ is now never set, that other
> code, which is not thread-safe, is called much more frequent than
> necessary.  Actually it should only be called once per process, now it's
> called once per invocation of tzset().  I've applied a patch to the 1.5.x
> branch and will release an updated 1.5.25 in the next couple of days.

Hope my test program helps to verify this.
/*****
 *
 * Test program that evokes 'localtime'+threads bug
 *
 * Build:  gcc -o loctim_bug loctim_bug.c
 * Run:    ./loctim_bug.exe
 *
 *****/

#include <time.h>
#include <pthread.h>

#define MAX_THR  25
#define MAX_LOOP 10000

/* Set this to 24 minus your non-DST timezone */
/* For example, EDT = -5, therefore use 19    */
#define EXPECTED 19


void *
time_loop(void* data)
{
    int arg = *((int *)data);
    time_t when = (time_t)arg;
    int ii;
    struct tm *tm;
    struct timespec sleep, remainder;

    sleep.tv_sec = 0;
    sleep.tv_nsec = 1000;

    for (ii=0; ii < MAX_LOOP; ii++) {
        tm = localtime(&when);
        if (tm->tm_hour != EXPECTED)
            printf("BUG in thread %2d: expected: %d   got: %d\n",
                        arg, EXPECTED, tm->tm_hour);

        nanosleep(&sleep, &remainder);
    }
}


int
main(int argc, char **argv)
{
    int ii;
    pthread_t p_thread[MAX_THR];
    int args[MAX_THR+2];

    /* Launch threads */
    for (ii=0; ii < 50; ii++) {
        args[ii] = ii;
        pthread_create(&p_thread[ii], NULL, time_loop, (void*)&args[ii]);
    }

    /* Make sure threads finish */
    args[MAX_THR] = MAX_THR;
    time_loop((void*)&args[MAX_THR]);
    args[MAX_THR+1] = MAX_THR+1;
    time_loop((void*)&args[MAX_THR+1]);

    printf("Done\n");
}

/* EOF */
--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Problem reports:       http://cygwin.com/problems.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/

Reply via email to