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/