Hi there,
According to FreeBSD / Darwin / Linux man page, the low level function localtime() is not thread safe and we should use locatime_r() instead to avoid that.
But the pike function localtime() use the low level localtime()
---/ from builtin_functions.c generated file - pike 7.4 /---
[...]
PMOD_EXPORT void f_localtime(INT32 args) { struct tm *tm; INT_TYPE tt; time_t t;
get_all_args("localtime", args, "%i", &tt);
t = tt; tm = localtime(&t); if (!tm) Pike_error ("localtime() on this system cannot handle " "the timestamp %ld.\n", (long) t); pop_n_elems(args); encode_struct_tm(tm);
[...]
---//--
Do you think it should be mutch better to - either use localtime_r() if OS support it and provide it - add a mutex or something to avoid threading problems.
Thanks,
/Xavier
There is already a mutex. f_localtime does not release the interpreter lock. Of course, it could still interfere with other threads running non-pike code, but that would not be fixed by adding another mutex.
/ Marcus Comstedt (ACROSS) (Hail Ilpalazzo!)
Previous text:
Nope. The only benefit would be protecting it from non pike threads (thus not holding the interpreter lock) using localtime at the same time. A rather questionable benefit though, since _those_ threads should really be using localtime_r anyway.
/ Marcus Comstedt (ACROSS) (Hail Ilpalazzo!)
Previous text:
And why can't they reason the same way? They might have their own mutex like the interpreter mutex. Is it perhaps because they are embedded while Pike is not? But we'd like to make Pike embeddable, so if this specific issue is solved beforehand there'll be one less worry.
I can see no harm using localtime_r if it exists; if Xavier wants to fix that then it's ok with me.
/ Martin Stjernholm, Roxen IS
Previous text:
Le mardi, 17 jun 2003, à 22:40 Europe/Paris, Martin Stjernholm, Roxen IS @ Pike developers forum a écrit :
Thanks Martin.
If we can use the _r function this can allow us more stablity and less cost. A mutex, AFAIK, cost a bit. If a function can have it's equivalent thread safe, then we should use it if possible instead of adding only a mutex...
My 0,02€
/Xavier
If we can use the _r function this can allow us more stablity and less cost. A mutex, AFAIK, cost a bit.
Which is why it's cheaper NOT to unlock than to unlock. Now, using localtime_r anyway is fine, but it's questionable whether the lock should be released or not. I say that it probably shouldn't.
/ David Hedbor
Previous text:
Le mardi, 17 jun 2003, à 22:40 Europe/Paris, Martin Stjernholm, Roxen IS @ Pike developers forum a écrit :
you are right... FreeBSD libc_r function sets a mutex... and try to getit a bit thread safe :
struct tm * localtime_r(timep, p_tm) const time_t * const timep; struct tm *p_tm; { #ifdef _THREAD_SAFE pthread_mutex_lock(&lcl_mutex); #endif tzset(); localsub(timep, 0L, p_tm); #ifdef _THREAD_SAFE pthread_mutex_unlock(&lcl_mutex); #endif return(p_tm); }
struct tm * localtime(timep) const time_t * const timep; { #ifdef _THREAD_SAFE static struct pthread_mutex _localtime_mutex = PTHREAD_MUTEX_STATIC_INITIALIZER; static pthread_mutex_t localtime_mutex = &_localtime_mutex; static pthread_key_t localtime_key = -1; struct tm *p_tm;
pthread_mutex_lock(&localtime_mutex); if (localtime_key < 0) { if (pthread_key_create(&localtime_key, free) < 0) { pthread_mutex_unlock(&localtime_mutex); return(NULL); } } pthread_mutex_unlock(&localtime_mutex); p_tm = pthread_getspecific(localtime_key); if (p_tm == NULL) { if ((p_tm = (struct tm *)malloc(sizeof(struct tm))) == NULL) return(NULL); pthread_setspecific(localtime_key, p_tm); } pthread_mutex_lock(&lcl_mutex); tzset(); localsub(timep, 0L, p_tm); pthread_mutex_unlock(&lcl_mutex); return p_tm; #else tzset(); localsub(timep, 0L, &tm); return &tm; #endif }
But it is not sure that some other OS has same protection options when calling localtime() in a threaded environment.
Note that this is not a criticism about pike, but I was just a bit surprises that low level pike didn't take advantage of some thread safe functions like is localtime_r()...
/Xavier
It's because there's no real need since Pike has its interpreter mutex. Nothing bad can happen by using the non-threadsafe variants unless you execute (or return to) pike code in the middle.
It's only, as Marcus pointed out, an issue if other non-pike threads are running, i.e. started by some library, that also uses the non-threadsafe functions. That's not very common, but it's of course better if we play safe anyway and use the threadsafe variants; we want to be able to interface Pike with other software without risking problems, e.g. making it embeddable.
Also, considering your example from FreeBSD, it looks like localtime_r would be more efficient than localtime, which has mutexes and stuff of its own.
/ Martin Stjernholm, Roxen IS
Previous text:
Le mardi, 17 jun 2003, à 23:20 Europe/Paris, David Hedbor @ Pike developers forum a écrit :
Thank you for this usefull information..
But is seems that is valid only in the core of Pike, since src/modules/Msql/*.c has such options THREADS_ALLOW and its friends THREADS_DISALLOW
/Xavier
Le mardi, 17 jun 2003, à 23:40 Europe/Paris, David Hedbor @ Pike developers forum a écrit :
Ok... So if I correctly understand, I can in a external module made in C (like for exemple a Pext) call a non thread-safe function without make a Mutex lock ?
If so... I just say wow !
and maybe the following code in src/modules/Msql/msqlmod.c is not really needed :
THREADS_ALLOW(); MSQL_LOCK(); status=msqlReloadAcls(socket); MSQL_UNLOCK(); THREADS_DISALLOW();
/Xavier
Correct.
It is. What happens here is:
1) Pike interpreter lock is released 2) msql lock is locked. 3) execution 4) release msql lock 5) try to regain interpreter lock
The msql lock, and similar locks in other modules, are used to avoid multiple calls using the same object instance, or in some cases, limit it to one call globally in the process. Why? Although not strictly needed (i.e remove both locks and it'd work perfectly fine), it's benefitial since Pike, during the possibly long query, can go on with other stuff. If you don't release the interpreter log, a 10 minute long database query would lock up ALL threads in the process, instead of only the calling thread and other threads wanting to use the same msql object.
/ David Hedbor
Previous text:
pike-devel@lists.lysator.liu.se