gettimeofday引起的bug

1. BUG描述

使用网关来管理若干个子设备,子设备每隔15秒来给网关发送心跳包。当网关超过45秒没有收到子设备的心跳包时,则认为子设备异常,需要重启子设备。

观察日志,发现子设备频繁重启,不符合设计要求.

2. BUG分析

观察系统的日志,发现系统上电时比较容易出现重启子设备的现象。因为系统是使用ntp来同步时间的,遂怀疑是时间不对引起的。

ntp服务采用的是ntpdate作为客户端。每分钟由cron同步一次。为了降低bug复现的难度,将同步间隔改为5分钟一次,观察bug是否必现。

抓取日志如下图

由上图可知,在NTP同步的前后,确实发生了子设备重启的问题。

再结合代码分析,终于发现了问题,原来代码中使用了gettimeofday!

gettimeofday是获取本地时间的,其值会随着系统时间的改变而改变。应该采用clock_gettime!

3. gettimeofday介绍

gettimeofday原型如下:

#include <time.h>

int gettimeofday(struct timeval *tv, struct timezone *tz);

说明: tz可以为NULL

struct timeval {

    time_t      tv_sec;     /* seconds */

    suseconds_t tv_usec;    /* microseconds */

};

gettimeofday的功能是将自1970-01-01 00:00:00 +0000 (UTC)以来的秒数和微秒数放入tv 中,当返回值为0时表示成功,否则失败。

注意:获取到的时间会随着系统时间的改变而改变。

4. clock_gettime介绍

#include <time.h>

int clock_gettime( clockid_t clock_id,struct timespec * tp );

说明:

     clock_id: 表示获取时间的类型

struct timespec {

    time_t tv_sec;     // 秒

    long   tv_nsec;    // 纳秒

};

clock_gettime的功能是返回某种类型的时间--包括秒和纳秒,其类型与参数clock_id有关。

当返回值为0时表示成功,否则失败。

clock_id的取值以及意义:

CLOCK_REALTIME: 是指系统时间,随着系统时间的改变而改变。系统时钟会被用户而改变。

CLOCK_MONOTONIC: 指从系统启动时开始计时。不受系统影响,也不会被用户改变。

CLOCK_PROCESS_CPUTIME_ID: 指这个进程运行到当前代码时,系统花费的时间。

CLOCK_THREAD_CPUTIME_ID: 指这个线程运行到当前代码时,系统花费的时间。

### 触摸屏乱报警的原因分析 触摸屏乱报警的现象可能源于硬件设计缺陷、软件逻辑错误以及外部干扰等多种因素。以下是可能导致此现象的具体原因及其对应的解决方法: #### 1. **中断程序影响** 如果在 DS18B20 的读写过程中存在中断操作,则可能会破坏其严格的时序要求,从而导致温度数据异常跳变[^1]。这种情况下,即使实际温度变化不大,也可能因为通信失败而返回不合理的数值。 - 解决方案: 确保 DS18B20 温度传感器的初始化和数据采集过程不会被其他任务打断。可以通过关闭全局中断或者优先级调整来实现这一点。 --- #### 2. **信号噪声与电磁干扰** 外界环境中的高频信号或其他电子设备产生的电磁波会对触控电路造成干扰,进而引发误触发或虚假输入事件[^4]。 - 解决方案: 增加屏蔽措施以减少 EMI 影响;优化 PCB 布局使敏感线路远离强电流路径;选用抗噪性能更优的触摸芯片。 --- #### 3. **驱动层问题** 某些嵌入式平台使用的触摸屏驱动可能存在 bug ,特别是在处理多点触控或多区域扫描时容易发生冲突,最终表现为无故弹窗警告提示框出现。 对于基于 Linux 系统开发的产品来说,`tslib` 库提供了标准化接口供应用程序访问原始坐标信息,在自定义 `input_read()` 函数内部如果没有正确解析状态字节就很可能引起混乱. - 修改后的代码如下所示: ```c static int ts_input_read(struct tslib_module_info *inf, struct ts_sample *samp, int nr) { struct tsdev *ts = inf->dev; int ret; unsigned long ts_status; ret = read(ts->fd, &ts_status, sizeof(ts_status)); if (ret < 0 || ret != sizeof(ts_status)) { return 0; // 如果读取长度不符合预期则忽略本次采样 } samp->x = ((ts_status >> 16) & 0xFFFF); samp->y = (ts_status & 0xFFFF); samp->pressure = !!(ts_status & (1UL << 31)); // 将最高位转换成布尔值表示压力是否存在 gettimeofday(&(samp->tv), NULL); return 1; } ``` 通过严格校验每次 I/O 返回的结果可以有效降低因底层库不稳定而导致的意外行为概率。 --- #### 4. **算法判断失误** 假设系统采用简单的阈值比较方式判定是否越界告警,那么一旦测量误差较大便很容易超出预定范围从而频繁发出通知消息。另外考虑到人体接触面板表面会产生静电放电效应同样能够激活感应元件产生短时间内的剧烈波动。 因此建议引入滤波机制平滑瞬态突增部分,并设置合理的时间窗口防止连续多次重复提醒用户注意相同状况的发生。 --- ### 结论 综上所述,要彻底消除此类故障需从软硬两个方面入手进行全面排查整改。一方面改进固件源码使其更加健壮可靠;另一方面加强物理防护手段提升整体鲁棒性水平。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值