话说产品的大哥转过来一个定时器失效的问题,当时还以为是内核的定时器,到手一看,居然是产品代码中的一个自写的定时器没有生效,被告知是调用的系统接口,看着令人头痛的CPP代码,咨询之后才知道是ACE(Adaptive Communication Environment)框架,然后再次被人用小学学到的对比法把问题丢给了自己,苦命的搞了内核还要了解CPP各种框架。

先大致说一下问题:产品用ACE的框架,使用对象cond_timedwait等待设定时间超时,进程运行中,将系统的时间提前一天,cond_timedwait就失效了,1s的超时跑了3小时也没有动静。

可以确定的是cond_timedwait挂住了,通过gdb attach到进程看bt数据,可以看到cond_timedwait其实是封装glibc的pthread_cond_timedwait函数实现的,这个样子就直接跳过了ACE框架的代码(节省了不少脑细胞),根据产品大哥反馈,问题是在某日代码持续集成后出的问题,于是遍历相关修改,发现当时更新了glibc的rpm包,即从glibc-2.11.3-17.39.1更新到glibc-2.11.3-17.43.1,于是将glibc强制回退,OK,问题木有了。

翻看SUSE glibc的更新记录看

  • Fix pthread_cond_timedwait stack unwinding (bnc#750741, bnc#777233)

只好找李义童鞋要bugzilla看,说的是为了和posix保持一致,将pthread_cond_timedwait的相对时间改为了绝对时间,同时自己写了段代码验证glibc问题,发现只要提前1min pthread_cond_timedwait就会失效,代码参见如下:

#include <stdio.h>
#include <stdlib.h>

#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <sys/time.h>

pthread_t thread;
pthread_cond_t cond;
pthread_mutex_t mutex;
int flag = 1;

void *timewait(void *argv)
{
   int pthread_times = 0;
   struct timeval now;
   struct timespec timeout;

   pthread_mutex_lock(&mutex);

   while(flag)
   {
     printf("%dn",pthread_times);

     gettimeofday(&now, NULL);
     printf("now is %ldn", now.tv_sec);

     timeout.tv_sec = now.tv_sec + 5;
     timeout.tv_nsec = now.tv_usec * 1000;

     printf("timeout is %ldn", timeout.tv_sec);

     pthread_cond_timedwait(&cond, &mutex, &timeout);

   }

   pthread_mutex_unlock(&mutex);
   printf("thread exitn");
}

int main()
{
   pthread_mutex_init(&mutex, NULL);
   pthread_cond_init(&cond, NULL);

   if(0 != pthread_create(&thread, NULL, timewait, NULL))
   {
      printf("create pthread errorn");
      return 1;
   }

   char C;
   while((c = getchar()) != 'q');

   flag = 0;

   pthread_mutex_lock(&mutex);
   pthread_cond_signal(&cond);
   pthread_mutex_unlock(&mutex);

   printf("Wait for thread to exitn");
   pthread_join(thread, NULL);
   return 0;
}

将如上代码编译,然后线程每5s打印一次,通过date -s "hh:mm"将系统时间提前1min,就发现线程卡死在pthread_cond_timedwait,也就是超时函数失效了。

从SUSE bugzilla上搞到了patch文件,全是汇编......

先跟着问题,具体原因后续再发。

后续:NOVELL根据GNU的posix标志将相对时间改成了绝对时间,这个酱紫就会在timewait等待时间的时候对系统时间产生依赖,改动系统时间就会导致失效。

NOVELL的意见是:这是posix标准,就不支持改时间......

目前看glibc这个问题不会改过来啦,想办法在用户态规避,不建议手工改正,这个样子便脱离了主分支,成为版本控制的蛀虫。


Glibc更新导致pthread_cond_timedwait失效来自于OenHan

链接为:https://oenhan.com/glibc_pthread_cond_timedwait_disable

发表回复