修复系统时间对于sem_timedwait的阻塞问题

316 篇文章 ¥29.90 ¥99.00
文章探讨了系统时间修改如何影响sem_timedwait函数,导致线程无限阻塞,并提出解决方案。在调用sem_timedwait前获取系统时间快照作为参考,比较与当前时间差异,若系统时间变化则调整等待时间,防止阻塞。

概述:
在编程中,我们经常会使用信号量(semaphore)来控制并发访问资源的情况。其中,sem_timedwait是一个常用的函数,它可以阻塞线程,直到给定的时间内等待信号量的计数器大于0。然而,有时候修改系统时间可能会导致sem_timedwait函数无限阻塞的问题。本文将讨论这个问题的原因,并提供解决方案和相应的源代码。

问题分析:
当我们修改系统时间时,涉及到的系统调用会受到影响,其中包括获取当前时间的系统调用。在一些操作系统中,这些系统调用可能会返回错误的时间戳,或者时间戳的顺序可能会被打乱。这可能会导致sem_timedwait函数无法正确计算剩余等待时间,从而导致线程永久阻塞。

解决方案:
为了解决由于修改系统时间导致的sem_timedwait函数阻塞的问题,我们可以采取以下步骤:

  1. 在调用sem_timedwait函数之前,获取系统时间的一个快照(snapshot)。这个快照将作为sem_timedwait函数的参考时间。

  2. 在调用sem_timedwait函数时,将参考时间传递给该函数作为参数。

  3. 在sem_timedwait函数内部,获取当前时间的快照,并计算等待时间。

  4. 比较等待时间与参考时间之间的差异。如果差异大于一个阈值(例如1秒),则可以假设系统时间已经发生了变化。

  5. 如果系统时间发生了变化,则可以将等待时间调整为正确的值。这可以通过将参考时间和等待时间的差异添加到当前时间的快照上来实现。

  6. 如果系统时间没有发生变化,则继续正常执行sem_timedwait函数。

我其实不想向你展示这些报错的,因为感觉会干扰你的设计思路,但是,你看看,你自创就会出现这种问题,给你之后,你有没有获取什么信息nasw.c: In function 'nasw_async_ping_check': nasw.c:185:29: error: storage size of 'diag_timer' isn't known static struct timer diag_timer; ^~~~~~~~~~ nasw.c:186:9: error: implicit declaration of function 'timer_set'; did you mean 'timer_settime'? [-Werror=implicit-function-declaration] timer_set(&diag_timer, diag_timer_callback, NULL, 100); ^~~~~~~~~ timer_settime nasw.c:187:9: error: implicit declaration of function 'timer_add'; did you mean 'inet_addr'? [-Werror=implicit-function-declaration] timer_add(&diag_timer, PERIODIC); ^~~~~~~~~ inet_addr nasw.c:187:32: error: 'PERIODIC' undeclared (first use in this function); did you mean 'EISDIR'? timer_add(&diag_timer, PERIODIC); ^~~~~~~~ EISDIR nasw.c:187:32: note: each undeclared identifier is reported only once for each function it appears in nasw.c:185:29: error: unused variable 'diag_timer' [-Werror=unused-variable] static struct timer diag_timer; ^~~~~~~~~~ nasw.c: At top level: nasw.c:204:24: error: conflicting types for 'nasw_do_ping_check' LOCAL NASW_PING_STATUS nasw_do_ping_check(void) ^~~~~~~~~~~~~~~~~~ nasw.c:63:10: note: previous declaration of 'nasw_do_ping_check' was here LOCAL S8 nasw_do_ping_check(void); ^~~~~~~~~~~~~~~~~~ nasw.c: In function 'nasw_do_ping_check': nasw.c:207:5: error: unknown type name 'sem_t'; did you mean 'key_t'? sem_t diag_sem; ^~~~~ key_t nasw.c:208:5: error: implicit declaration of function 'sem_init'; did you mean 'inet_init'? [-Werror=implicit-function-declaration] sem_init(&diag_sem, 0, 0); ^~~~~~~~ inet_init nasw.c: In function 'callback': nasw.c:213:9: error: implicit declaration of function 'sem_post'; did you mean 'fsetpos'? [-Werror=implicit-function-declaration] sem_post(&diag_sem); ^~~~~~~~ fsetpos nasw.c: In function 'nasw_do_ping_check': nasw.c:224:12: error: implicit declaration of function 'sem_timedwait' [-Werror=implicit-function-declaration] while (sem_timedwait(&diag_sem, &ts) == -1) { ^~~~~~~~~~~~~ nasw.c:230:5: error: implicit declaration of function 'sem_destroy' [-Werror=implicit-function-declaration] sem_destroy(&diag_sem); ^~~~~~~~~~~
10-22
解释以下以下代码是什么意思unsigned int g_ls_max_num = LS_PRELOAD_MAX_LS_NUM;   int g_ls_time_lsid = LS_TIME_LSID_INIT_VALUE;   unsigned int g_ls_time_debug = 0;   /* admin和ls同操作是否用锁隔离开 */   int g_ls_use_sem = 0;     offset_info_t *g_ls_time_offset[LS_PRELOAD_MAX_LS_NUM + 1] = {NULL};     static inline int gettimeofday_orig(struct timeval *tv, struct timezone *tz)   {       return g_pfn_ls_gettimeofday ? g_pfn_ls_gettimeofday(tv, tz) : DRV_ERROR; 16 Line113. g_pfn_ls_gettimeofday is true 17 Line113. Assume return here   }   static inline int settimeofday_orig(const struct timeval *tv, const struct timezone *tz)   {       return g_pfn_ls_settimeofday ? g_pfn_ls_settimeofday(tv, tz) : DRV_ERROR;   }   static inline int adjtimex_orig(struct timex *buf)   {       return g_pfn_ls_adjtimex ? g_pfn_ls_adjtimex(buf) : DRV_ERROR;   }   static inline int adjtime_orig(const struct timeval *delta, struct timeval *olddelta)   {       return g_pfn_ls_adjtime ? g_pfn_ls_adjtime(delta, olddelta) : DRV_ERROR;   }     static inline int sem_wait_timeout(sem_t *sem, int msec)   {       int ret;         while (msec > 0) { 12 Line132. msec > 0 is true           ret = sem_trywait(sem);           if (ret != -1) {               return LS_TIME_SEM_OK; 13 Line135. Assume return here           }           if (errno == EAGAIN) {               (void)usleep(USEC_IN_MSEC); /* sleep for 1ms */               msec--;           } else {               return LS_TIME_SEM_ERROR;           }       }         return LS_TIME_SEM_TIMEUP;           }       }         return (int)ret;   }     unsigned int ls_time_sem_wait_ls(int ls_id)   {       int ret = DRV_OK;         if (g_ls_use_sem == 0) { 8 Line215. g_ls_use_sem == 0 is false           return 0;       }         if (g_ls_time_offset[ls_id] && g_ls_time_offset[ls_id]->init_sem) { 9 Line219. g_ls_time_offset[ls_id] is true 10 Line219. g_ls_time_offset[ls_id] && g_ls_time_offset[ls_id]->init_sem is true           ret = sem_wait_timeout(&g_ls_time_offset[ls_id]->ls_sem, MSEC_SEMWAIT); 11 Line220. Function sem_wait_timeout is executed           if (ret == LS_TIME_SEM_OK) {               return DRV_OK; 14 Line222. Assume return here           } else if (ret == LS_TIME_SEM_TIMEUP) {               /* 如果超了,则说明LS之前异常复位,需要主动解锁并再加锁 */               if (sem_post(&g_ls_time_offset[ls_id]->ls_sem) == -1) {                   /* 一般不会进入此分支 */                   ret = errno;                   DEBUG("sem_post ls%d not success(%d), set init flag to 0.", ls_id, ret);               } else {                   /* 如果post后加锁还有问题,就直接返回 */                   return (sem_trywait(&g_ls_time_offset[ls_id]->ls_sem) == 0) ? DRV_OK : DRV_ERROR;               }   }     int settimeofday(const struct timeval *tv, const struct timezone *tz)   {       int ret;       unsigned int ls_id;       struct timeval tv_admin_old;       offset_info_t *info = NULL;       unsigned int sem_waited;         (void)memset_s(&tv_admin_old, sizeof(struct timeval), 0, sizeof(struct timeval)); 2 Line626. Function memset_s is executed         DEBUG_TRACE("setting ls[%d] time", g_ls_time_lsid);         if (g_ls_time_lsid < 0) { 4 Line630. g_ls_time_lsid < 0 is false           /* 如果lsid未初始化,使用原来的 */           return settimeofday_orig(tv, tz);       }         if (g_ls_time_lsid) { 5 Line635. g_ls_time_lsid is true           struct timeval tv_ls_old;           unsigned int sem_ret;             /* ls容器内修改时间 */           info = g_ls_time_offset[g_ls_time_lsid];           /* 获取偏移失败,为提高可靠性,认为不需要偏移并直接返回 */           if (info == NULL) { 6 Line642. info == NULL is false               DEBUG("settimeofday get ls%d offset not success.", g_ls_time_lsid);               return DRV_OK;           }             sem_ret = ls_time_sem_wait_ls(g_ls_time_lsid); 7 Line647. Function ls_time_sem_wait_ls is executed             ret = gettimeofday_orig(&tv_admin_old, NULL); 15 Line649. Function gettimeofday_orig is executed           if (ret) { 18 Line650. ret is false               if (sem_ret == 0) {                   (void)ls_time_sem_post_ls(g_ls_time_lsid);               }               DEBUG("gettimeofday_orig not success %d.", ret);               return ret;           }             /* 调用ls_time_calc更新下adjtime_delta,如果有的话 */           (void)ls_time_calc(&tv_ls_old, &tv_admin_old, info);           info->ls_start = TIME_TV2USEC(*tv); 19 Line660. Dereferencing of "tv" which can be null Dereferencing of "tv" which can be null 告警处理帮助           info->admin_start = TIME_TV2USEC(tv_admin_old);           info->offset = info->ls_start - info->admin_start;             /* 基于新的admin start设置了偏移,所以admin_start也重新设置一下, 否则需要计算出admin原来偏移的时间 */           ret = ls_time_offset_info_set(g_ls_time_lsid, info);             if (sem_ret == 0) {               (void)ls_time_sem_post_ls(g_ls_time_lsid);           }       } else {
05-15
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值