首页 > 编程语言 >glibc中的localtime方法源码分析

glibc中的localtime方法源码分析

时间:2024-06-09 19:10:55浏览次数:27  
标签:__ tmp glibc tp tm year 源码 localtime

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

相关文章

  • PHP“well”运动健身APP-计算机毕业设计源码87702
    【摘要】随着互联网的趋势的到来,各行各业都在考虑利用互联网将自己的信息推广出去,最好方式就是建立自己的平台信息,并对其进行管理,随着现在智能手机的普及,人们对于智能手机里面的应用“well”运动健身app也在不断的使用,本文首先分析了“well”运动健身app应用程序的需求,从系统......
  • SpringBoot社区配送服务系统小程序-计算机毕业设计源码88705
    摘要随着科学技术的飞速发展,社会的方方面面、各行各业都在努力与现代的先进技术接轨,通过科技手段来提高自身的优势,社区当然也不例外。社区配送服务系统小程序是以实际运用为开发背景,运用软件工程原理和开发方法,采用Java技术构建的一个管理系统。整个开发过程首先对软件系统进......
  • OpenCV与AI深度学习 | 实战 | OpenCV实现扫描文本矫正应用与实现详解(附源码)
    本文来源公众号“OpenCV与AI深度学习”,仅用于学术分享,侵权删,干货满满。原文链接:实战|OpenCV实现扫描文本矫正应用与实现详解(附源码)1导 读    本文主要介绍使用OpenCV对扫描文本矫正的应用实例及详细实现步骤。    2背景介绍  在使用打印机或扫描仪......
  • 基于微信小程序的网上鲜花店管理系统的设计与实现(期末大作业)+附源码+数据库
     摘要:本文旨在介绍设计与实现一款鲜花店小程序的过程。首先,分析目标用户群体的需求,确定了主要功能模块包括商品展示、购物车、订单管理等。接着,设计简洁直观的用户界面,采用了吸引人的图片效果,提升了用户体验。在功能模块方面,我们实现了用户注册、登录、商品浏览、下单购买等核......
  • Dubbo 3.x源码(21)—Dubbo服务引用源码(4)
    基于Dubbo3.1,详细介绍了Dubbo服务的发布与引用的源码。此前我们学习了createInvokerForRemote方法中的Wrapper有哪些以及作用,接下来我们将会的学习真正的本地、应用级别、接口级别的Protocol的引入逻辑,以及创建Proxy服务接口代理对象的逻辑。Dubbo3.x服务引用源码:Dub......
  • 基于协同过滤的在线通用旅游平台网站java ssm mysql|全套源码+文章lw+毕业设计+课程设
    基于协同过滤的在线通用旅游平台网站javassmmysql|全套源码+文章lw+毕业设计+课程设计+数据库+ppt摘要近几年来,计算机网络的发展得到了飞速的提升,由此展开的一系列行业大洗牌也由此开始。早些年只是人们只是对于计算机和互联网有了些基础的认识,现在它正在悄悄的改变着我......
  • 高校毕业设计管理系统java ssm mysql|全套源码+文章lw+毕业设计+课程设计+数据库+ppt
    高校毕业设计管理系统javassmmysql|全套源码+文章lw+毕业设计+课程设计+数据库+ppt摘要现代学校的教学规模逐渐增加,需要处理的信息量也在增加。每年毕业,将会有大量的毕业设计要处理。传统的毕业设计管理方法已不能满足师生的需求。教师和学生需要一个简单方便的系统来......
  • Java项目源码文案PPT讲解基于springboot框架的酒店管理
    !!!有需要的小伙伴可以通过文章末尾名片咨询我哦!!! ......
  • Java项目-基于springboot+vue的音乐网站与分享平台 (源码+数据库+文档)​
    如需完整项目,请私信博主基于SpringBoot+Vue的音乐网站与分享平台开发语言:Java数据库:MySQL技术:SpringBoot+MyBatis+Vue.js工具:IDEA/Ecilpse、Navicat、Maven音乐网站与分享平台的主要使用者分为管理员和用户,实现功能包括管理员:首页、个人中心、用户管理、音乐资讯管理、音乐......
  • Java项目-基于springboot+vue的影城管理系统 (源码+数据库+文档)​
    如需完整项目,请私信博主基于SpringBoot+Vue的影城管理系统开发语言:Java数据库:MySQL技术:SpringBoot+MyBatis+Vue.js工具:IDEA/Ecilpse、Navicat、Maven影城管理系统的主要使用者分为管理员和用户,实现功能包括管理员:首页、个人中心、用户管理、电影类型管理、放映厅管理、电影......