in reply to Re^4: Standard way to convert timezone in multithreaded script
in thread Standard way to convert timezone in multithreaded script

XS code contains four calls to tzset()

Perl code running in main thread works pretty well without calling POSIX::tzset. I believe this is due to how tzset()/localtime() in libc works.

'man tzset' says "This function is automatically called by the other time conversion functions that depend on the time zone."

So, there is no wonder why this works in main thread. And in child threads tzset needs to be explicitly called for changing timezone, but really works only when called in XS code. I don't know why, I just managed to find this fact :)

Also, I did not tried it on other OSes or even on another linux distro or with different libc versions or versions of perl other than 5.10.0

My environment is CentOS 5.2, libc-2.5, perl-5.10.0

  • Comment on Re^5: Standard way to convert timezone in multithreaded script

Replies are listed 'Best First'.
Re^6: Standard way to convert timezone in multithreaded script
by whale2 (Novice) on Nov 25, 2009 at 11:00 UTC
    Oh-uh, my XS code is wrong. Just calling malloc() in threads is dangerous. I'll post corrected code as soon as it really will work :)
Re^6: Standard way to convert timezone in multithreaded script
by BrowserUk (Patriarch) on Nov 25, 2009 at 11:29 UTC
    My environment is CentOS 5.2, libc-2.5, perl-5.10.0

    I've been playing with 5.10.1 under Ubuntu 9.10:

    mehere@mehere-desktop:~/test$ gcc --version gcc (Ubuntu 4.4.1-4ubuntu8) 4.4.1 Copyright (C) 2009 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There i +s NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PUR +POSE.

    ...but, as a guest running within a VirtualBox on a Vista host.

    Ie. I have little faith that anything that works (or fails) here will produce the same results under any other circumstances :)

    (P.S.) You aren't the first to be bitten by the "malloc thing" in XS code. Truth beknown--if they'd all admit to it--we've all been there.

    Your discovery regarding not requiring tzset() in the main thread are interesting. It stimulates several possibilities. And when I am less sleep deprived, I may persue them to a (minorly) significant conclusion.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      this XS proved to work:
      #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" #include <time.h> #include <stdio.h> #include <stdlib.h> #include <string.h> MODULE = tztime PACKAGE = tztime long tz_mktime(sec, min, hour, mday, mon, year, tz_name) int sec int min int hour int mday int mon int year char *tz_name CODE: long epoch; struct tm tz_tm; char *old_tz; const char *tz_p; bool restore = FALSE; tz_tm.tm_sec = sec; tz_tm.tm_min = min; tz_tm.tm_hour = hour; tz_tm.tm_mday = mday; tz_tm.tm_mon = mon; tz_tm.tm_year = year; tz_tm.tm_wday = 0; tz_tm.tm_yday = 0; tz_tm.tm_isdst = -1; tz_p = getenv("TZ"); if(tz_p != NULL) { restore = TRUE; old_tz = malloc(strlen(tz_p) + 1); if(old_tz == NULL) { XSRETURN_UNDEF; } strncpy(old_tz,tz_p,strlen(tz_p) + 1); } setenv("TZ",tz_name,1); tzset(); epoch = (long)mktime(&tz_tm); if(restore) { putenv(old_tz); free(old_tz); } else { unsetenv("TZ"); } tzset(); RETVAL = epoch; OUTPUT: RETVAL void tz_gettime(epoch, tz_name) long epoch char *tz_name; PPCODE: struct tm tz_tm; char *old_tz; const char *tz_p; bool restore = FALSE; tz_p = getenv("TZ"); if(tz_p != NULL) { restore = TRUE; old_tz = malloc(strlen(tz_p) + 1); if(old_tz == NULL) { XPUSHs(sv_2mortal(newSVnv(errno))); } strncpy(old_tz,tz_p,strlen(tz_p) + 1); } setenv("TZ",tz_name,1); tzset(); localtime_r(&epoch,&tz_tm); if(restore) { putenv(old_tz); free(old_tz); } else { unsetenv("TZ"); } tzset(); XPUSHs(sv_2mortal(newSVnv(tz_tm.tm_sec))); XPUSHs(sv_2mortal(newSVnv(tz_tm.tm_min))); XPUSHs(sv_2mortal(newSVnv(tz_tm.tm_hour))); XPUSHs(sv_2mortal(newSVnv(tz_tm.tm_mday))); XPUSHs(sv_2mortal(newSVnv(tz_tm.tm_mon))); XPUSHs(sv_2mortal(newSVnv(tz_tm.tm_year))); XPUSHs(sv_2mortal(newSVnv(tz_tm.tm_wday))); XPUSHs(sv_2mortal(newSVnv(tz_tm.tm_yday))); XPUSHs(sv_2mortal(newSVnv(tz_tm.tm_isdst)));