Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

localtime not thread safe, but okay to call in only one thread?

Am integrating another users code into mine. They have library that calls localtime function which is not thread safe.

I have noticed some strange problems. If their code is restricted to one thread only can localtime still cause a problem? Note in other threads of my code I call localtime_r ( the thread safe version ).

Thanks.

like image 922
steviekm3 Avatar asked May 15 '13 21:05

steviekm3


1 Answers

The reason localtime is not threadsafe is that it stores the result (struct tm *) in a static variable. So as long as you only call this function from a single thread, it shouldn't cause problems.

In other words, localtime looks something like this:

struct tm *localtime(time_t *timer)
{
   static struct tm tt;
   ... many lines that sets tt member variables ... 
   return &tt;
}

Obviously, if two threads call this function, then the value in returned pointer will change "randomly" based on which thread last called localtime() and what the value in timer is.

The function localtime_r is safe because it takes a struct tm * as an argument, and returns a pointer to that variable. And in fact, the above is how localtime USED to be implemented. So, if the code for localtime_r looks a bit like this:

struct tm *localtime_r(time_t *timer, struct tm *result)
{
   ... many lines that sets result member variables ... 
   return result;
}

and now, of course, we can make a much shorter version of localtime:

struct tm *localtime(time_t *timer)
{
   static struct tm tt;
   return localtime_r(timer, &tt); 
}

Edit2: It is of course CRITICAL that the result argument of localtime_r is unique to the thread calling it. Having a static or global variable for this argument will make it very much the same problem as before.

Edit3: Of course there is another way to make it go wrong:

struct tm *a, *b;
... 
a = localtime(something);
... 
b = localtime(someother);

if (a->tm_sec != b->tm_sec) 
{
   ... this never happens ... 
}

In this case, a and b will point to exactly the same place. The same applies if the same variable is used for localtime_r and different pointers are used to receive the data and the expectation is that the pointers are pointing at different things.

like image 92
Mats Petersson Avatar answered Oct 30 '22 20:10

Mats Petersson