看了localtime/localtim_r的代码,里面确实有lock的操作,但有新发现。
在glibc的代码目录,time/localtime.c中,是localtime/localtime_r的实现:
struct tm _tmbuf;
/* Return the `struct tm' representation of *T in local time,
using *TP to store the result. */
struct tm *
__localtime_r (t, tp)
const time_t *t;
struct tm *tp;
{
return __tz_convert (t, 1, tp);
}
weak_alias (__localtime_r, localtime_r)
/* Return the `struct tm' representation of *T in local time. */
struct tm *
localtime (t)
const time_t *t;
{
return __tz_convert (t, 1, &_tmbuf);
}
从这几行代码看,是否reentrant,对比很明显。
接着再看time/tzset.c中__tz_convert函数的代码:
/* Return the `struct tm' representation of *TIMER in the local timezone.
Use local time if USE_LOCALTIME is nonzero, UTC otherwise. */
struct tm *
__tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
{
long int leap_correction;
int leap_extra_secs;
if (timer == NULL)
{
__set_errno (EINVAL);
return NULL;
}
__libc_lock_lock (tzset_lock);
/* Update internal database according to current TZ setting.
POSIX.1 8.3.7.2 says that localtime_r is not required to set tzname.
This is a good idea since this allows at least a bit more parallelism. */
tzset_internal (tp == &_tmbuf && use_localtime, 1);
if (__use_tzfile)
__tzfile_compute (*timer, use_localtime, &leap_correction,
&leap_extra_secs, tp);
else
{
if (! __offtime (timer, 0, tp))
tp = NULL;
else
__tz_compute (*timer, tp, use_localtime);
leap_correction = 0L;
leap_extra_secs = 0;
}
if (tp)
{
if (! use_localtime)
{
tp->tm_isdst = 0;
tp->tm_zone = "GMT";
tp->tm_gmtoff = 0L;
}
if (__offtime (timer, tp->tm_gmtoff - leap_correction, tp))
tp->tm_sec += leap_extra_secs;
else
tp = NULL;
}
__libc_lock_unlock (tzset_lock);
return tp;
}
其中进行了成对的加解锁操作,对tzset_lock这个变量。再看tzset_lock的声明和注释:
/* This locks all the state variables in tzfile.c and this file. */
__libc_lock_define_initialized (static, tzset_lock)
因为tzset_lock可以对两个文件中的变量都起作用,所以可以推出,需要tzset_lock保护的变量,肯定是或者包含于这两个文件的external变量中,同时,也可能包含这两个文件的文件局部变量(static)。
看一下,__tz_convert函数中,哪些操作需要锁住tzset_lock。__tz_convert函数中,从__libc_lock_lock (tzset_lock);语句之后看起。
首先,调用了tzset_internal函数,tzset_internal (tp == &_tmbuf && use_localtime, 1);,tzset_internal函数的实现如下:
/* Interpret the TZ envariable. */
static void
internal_function
tzset_internal (always, explicit)
int
在glibc的代码目录,time/localtime.c中,是localtime/localtime_r的实现:
struct tm _tmbuf;
/* Return the `struct tm' representation of *T in local time,
using *TP to store the result. */
struct tm *
__localtime_r (t, tp)
const time_t *t;
struct tm *tp;
{
return __tz_convert (t, 1, tp);
}
weak_alias (__localtime_r, localtime_r)
/* Return the `struct tm' representation of *T in local time. */
struct tm *
localtime (t)
const time_t *t;
{
return __tz_convert (t, 1, &_tmbuf);
}
从这几行代码看,是否reentrant,对比很明显。
接着再看time/tzset.c中__tz_convert函数的代码:
/* Return the `struct tm' representation of *TIMER in the local timezone.
Use local time if USE_LOCALTIME is nonzero, UTC otherwise. */
struct tm *
__tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
{
long int leap_correction;
int leap_extra_secs;
if (timer == NULL)
{
__set_errno (EINVAL);
return NULL;
}
__libc_lock_lock (tzset_lock);
/* Update internal database according to current TZ setting.
POSIX.1 8.3.7.2 says that localtime_r is not required to set tzname.
This is a good idea since this allows at least a bit more parallelism. */
tzset_internal (tp == &_tmbuf && use_localtime, 1);
if (__use_tzfile)
__tzfile_compute (*timer, use_localtime, &leap_correction,
&leap_extra_secs, tp);
else
{
if (! __offtime (timer, 0, tp))
tp = NULL;
else
__tz_compute (*timer, tp, use_localtime);
leap_correction = 0L;
leap_extra_secs = 0;
}
if (tp)
{
if (! use_localtime)
{
tp->tm_isdst = 0;
tp->tm_zone = "GMT";
tp->tm_gmtoff = 0L;
}
if (__offtime (timer, tp->tm_gmtoff - leap_correction, tp))
tp->tm_sec += leap_extra_secs;
else
tp = NULL;
}
__libc_lock_unlock (tzset_lock);
return tp;
}
其中进行了成对的加解锁操作,对tzset_lock这个变量。再看tzset_lock的声明和注释:
/* This locks all the state variables in tzfile.c and this file. */
__libc_lock_define_initialized (static, tzset_lock)
因为tzset_lock可以对两个文件中的变量都起作用,所以可以推出,需要tzset_lock保护的变量,肯定是或者包含于这两个文件的external变量中,同时,也可能包含这两个文件的文件局部变量(static)。
看一下,__tz_convert函数中,哪些操作需要锁住tzset_lock。__tz_convert函数中,从__libc_lock_lock (tzset_lock);语句之后看起。
首先,调用了tzset_internal函数,tzset_internal (tp == &_tmbuf && use_localtime, 1);,tzset_internal函数的实现如下:
/* Interpret the TZ envariable. */
static void
internal_function
tzset_internal (always, explicit)
int