linux-wdt 原理和任意超時時間設定的解決方法
Watchdog Timer的縮寫字母,也就是看門狗,是一個定時器電路。這個電路的功能是維護系統的正常執行,如果遇到系統卡死的情況可以自動的從硬體上覆位系統。簡單來說是用軟體發現問題,用硬體操作解決問題。
可以看到整個模組是內部一個timer計數器,外部輸入一個timer 的復位訊號,輸出一箇中斷訊號和一個復位訊號。
流程是:
1.設定復位超時時間
2.內部計數器進行減數計時,減到0 輸出中斷,資料又更新到復位超時時間,然後再減數執行,再次減到0 輸出硬體的復位訊號,系統復位。也有不產生中斷直接第一次減數到0就輸出復位訊號,直接系統復位的。
3.軟體在復位時間內復位timer ,保證timer 內部的數不到0.
通過調整輸入時鐘可以改變reset 的時間,達到自動控制系統當機重啟的功能。
可以看到這個暫存器的設定檔位只有7:4,也就只能設定16個不同的時間週期,並且這個週期是以2的n次方的方式,並不是通常理解的線性時間設定,16個檔位肯定不能滿足需求,目標必須是任意時間都可以設定,硬體如此就只能通過軟體解決了。
解決辦法:
1.將硬體wdt 重啟時間設定成為0.5秒,這樣一般也就滿足了日常應用的最小時間設定。
在open 函式就啟動wdt,
···
static int fh_wdt_open(struct inode *inode, struct file *filp)
{
if (test_and_set_bit(0, &fh_wdt.in_use))
return -EBUSY;
/* Make sure we don't get unloaded. */
__module_get(THIS_MODULE);
spin_lock(&fh_wdt.lock);
if(fh_wdt.plat_data && fh_wdt.plat_data->resume)
fh_wdt.plat_data->resume();
fh_wdt_set_top(WDT_HW_TIMEOUT);///3000);
if (!fh_wdt_is_enabled())
{
/*
* The watchdog is not currently enabled. Set the timeout to
* the maximum and then start it.
*/
u32 value;
value = WDOG_CONTROL_REG_WDT_EN_MASK;
writel(value, fh_wdt.regs + WDOG_CONTROL_REG_OFFSET);//設定硬體最小的超時時間
fh_wdt_keepalive();
}
fh_wdt_set_next_heartbeat();
spin_unlock(&fh_wdt.lock);
return nonseekable_open(inode, filp);
}
···
2.驅動中起一個timer 定時器,定時時間小於硬體wdt重啟時間,進行軟體喂狗。放置硬體定時器重啟。
setup_timer(&fh_wdt.timer, fh_wdt_ping, 0);
mod_timer(&fh_wdt.timer, jiffies + WDT_TIMEOUT);
static void fh_wdt_ping(unsigned long data)
{
if (time_before(jiffies, fh_wdt.next_heartbeat) ||
(!nowayout && !fh_wdt.in_use)) {
fh_wdt_keepalive();
mod_timer(&fh_wdt.timer, jiffies + WDT_TIMEOUT);
} else
pr_crit("keepalive missed, machine will reset\n");
}
3.驅動解析應用設定的重啟時間,接收應用喂狗的資訊。
應用呼叫ioctl 配置一個全域性變數用來記錄軟體任意時間的超時時間heartbeat。
case WDIOC_SETTIMEOUT:
if (get_user(val, (int __user *)arg))
return -EFAULT;
pr_debug("[wdt] settime value %lu", val);
heartbeat = val;
fh_wdt_keepalive();
fh_wdt_set_next_heartbeat();
return put_user(val , (int __user *)arg);
驅動把超時時間記錄在fh_wdt.next_heartbeat中
static inline void fh_wdt_set_next_heartbeat(void)
{
fh_wdt.next_heartbeat = jiffies + heartbeat * HZ;
}
也可以通過write 來寫
ssize_t fh_wdt_write(struct file *filp, const char __user *buf, size_t len,
loff_t *offset)
{
if (!len)
return 0;
if (!nowayout) {
size_t i;
fh_wdt.expect_close = 0;
for (i = 0; i < len; ++i) {
char c;
if (get_user(c, buf + i))
return -EFAULT;
if (c == 'V') {
fh_wdt.expect_close = 1;
break;
}
}
}
fh_wdt_set_next_heartbeat();
mod_timer(&fh_wdt.timer, jiffies + WDT_TIMEOUT);//啟動下一次的超時時間
return len;
}
4.如若應用在自己設定的超時時間之內喂狗,則一直維護這個timer。如果應用在自己設定的超時時間內沒有喂狗,這個timer 呼叫的硬體喂狗停止,放任硬體wdt 重啟系統。
每0.5s timer迴圈進行呼叫fh_wdt_ping 進行時間比對,當前時間jffies 是否超過了應用預設時間fh_wdt_next_hearbeat,沒超過硬體喂狗,超過不喂狗。
static void fh_wdt_ping(unsigned long data)
{
if (time_before(jiffies, fh_wdt.next_heartbeat) ||
(!nowayout && !fh_wdt.in_use)) {
fh_wdt_keepalive();
mod_timer(&fh_wdt.timer, jiffies + WDT_TIMEOUT);繼續喂狗,設定0.5s重啟
} else
pr_crit("keepalive missed, machine will reset\n");停止喂狗
}
總結
用軟體方法解決硬體的侷限
相關文章
- session超時時間的設定Session
- weblogic設定超時時間Web
- 為jQuery的$.ajax設定超時時間jQuery
- HttpClient設定聯網超時時間HTTPclient
- C# UdpClient 設定超時時間C#UDPclient
- axios請求超時,設定重新請求的完美解決方法iOS
- SQL超時解決方案-有時並不是設定問題SQL
- 超時時間已過或伺服器未響應的解決方法伺服器
- Linux時間設定系統時間、硬體時間和時間服務Linux
- MyBatis自動設定建立時間和更新時間MyBatis
- 網站訪問狀態和超時時間監控報警設定網站
- 使用requests庫解決Session物件設定超時的問題Session物件
- win10 點選自動設定時間時間快1小時怎麼解決Win10
- Linux:設定時間與同步的方法Linux
- SSH 超時設定
- MongoDB 超時設定MongoDB
- oracleraccrs超時設定Oracle
- Linux設定和修改時間與時區Linux
- 【Linux-時間設定】-設定時區並調整時間Linux
- 優雅的快取解決方案--設定過期時間快取
- php 和 nginx 的幾個超時時間PHPNginx
- quartz定時任務時間設定quartz
- dubbo 超時設定和原始碼分析原始碼
- 解決代理超時問題的三種方法
- nginx限制上傳大小和超時時間設定說明/php限制上傳大小NginxPHP
- **java設定一段程式碼執行超時時間(轉)**Java
- 設定時間格式
- C++ 之Socket 程式設計 send rev 阻塞設定 阻塞超時時間C++程式設計
- Win10系統如何設定待機時間 win10設定待機時間的方法Win10
- ECS設定時區與時間
- CSocket設定超時(轉)
- HttpClient設定超時(轉)HTTPclient
- pip安裝selenium超時解決方法
- MySQL設定當前時間為預設值的方法MySql
- 臨時表空間過大的解決方法
- 臨時表空間已滿的解決方法
- python之為函式執行設定超時時間(允許函式執行的最大時間)Python函式
- PHP CURL 業務呼叫第三方介面設定超時時間PHP