localtime方法会加锁,当TZ环境变量为空或者变更时,还会读取文件,还有个问题就是这个方法返回的指针是一个全局变量,可以使用redis无锁的localtime方法来优化这个性能。
localtime方法调用链:localtime -> __localtime64 -> __tz_convert(加锁、调用tzset_internal方法解释TZ环境变量,如果为空或者改变,则会尝试读取TZ文件)
/* The C Standard says that localtime and gmtime return the same pointer. */
struct tm _tmbuf;
/* Return the `struct tm' representation of *T in local time,
using *TP to store the result. */
struct tm *
__localtime64_r (const __time64_t *t, struct tm *tp)
{
return __tz_convert (*t, 1, tp);
}
/* Provide a 32-bit variant if needed. */
#if __TIMESIZE != 64
struct tm *
__localtime_r (const time_t *t, struct tm *tp)
{
__time64_t t64 = *t;
return __localtime64_r (&t64, tp);
}
libc_hidden_def (__localtime64_r)
#endif
weak_alias (__localtime_r, localtime_r)
/* Return the `struct tm' representation of *T in local time. */
struct tm *
__localtime64 (const __time64_t *t)
{
/* 使用全局变量tmbuf,但是__tz_convert方法里面会加锁 */
return __tz_convert (*t, 1, &_tmbuf);
}
libc_hidden_def (__localtime64)
/* Provide a 32-bit variant if needed. */
#if __TIMESIZE != 64
struct tm *
localtime (const time_t *t)
{
__time64_t t64 = *t;
return __localtime64 (&t64);
}
libc_hidden_def (localtime)
#endif
struct tm *
__tz_convert (__time64_t timer, int use_localtime, struct tm *tp)
{
long int leap_correction;
int leap_extra_secs;
__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); /* 方法内部会读取TZ环境变量,并更根据需要读取TZ文件 */
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;
}
__libc_lock_unlock (tzset_lock);
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;
}
return tp;
}
redis版无锁localtime
static int is_leap_year(time_t year) {
if (year % 4) return 0; /* A year not divisible by 4 is not leap. */
else if (year % 100) return 1; /* If div by 4 and not 100 is surely leap. */
else if (year % 400) return 0; /* If div by 100 *and* 400 is not leap. */
else return 1; /* If div by 100 and not by 400 is leap. */
}
void nolocks_localtime(struct tm *tmp, time_t t, time_t tz, int dst) {
const time_t secs_min = 60;
const time_t secs_hour = 3600;
const time_t secs_day = 3600*24;
t -= tz; /* Adjust for timezone. */
t += 3600*dst; /* Adjust for daylight time. */
time_t days = t / secs_day; /* Days passed since epoch. */
time_t seconds = t % secs_day; /* Remaining seconds. */
tmp->tm_isdst = dst;
tmp->tm_hour = seconds / secs_hour;
tmp->tm_min = (seconds % secs_hour) / secs_min;
tmp->tm_sec = (seconds % secs_hour) % secs_min;
/* 1/1/1970 was a Thursday, that is, day 4 from the POV of the tm structure
* where sunday = 0, so to calculate the day of the week we have to add 4
* and take the modulo by 7. */
tmp->tm_wday = (days+4)%7;
/* Calculate the current year. */
tmp->tm_year = 1970;
while(1) {
/* Leap years have one day more. */
time_t days_this_year = 365 + is_leap_year(tmp->tm_year);
if (days_this_year > days) break;
days -= days_this_year;
tmp->tm_year++;
}
tmp->tm_yday = days; /* Number of day of the current year. */
/* We need to calculate in which month and day of the month we are. To do
* so we need to skip days according to how many days there are in each
* month, and adjust for the leap year that has one more day in February. */
int mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
mdays[1] += is_leap_year(tmp->tm_year);
tmp->tm_mon = 0;
while(days >= mdays[tmp->tm_mon]) {
days -= mdays[tmp->tm_mon];
tmp->tm_mon++;
}
tmp->tm_mday = days+1; /* Add 1 since our 'days' is zero-based. */
tmp->tm_year -= 1900; /* Surprisingly tm_year is year-1900. */
}
标签:__,tmp,glibc,tp,tm,year,源码,localtime
From: https://www.cnblogs.com/Lht1/p/18239885