【Linux-時間管理和內核定時器】

Linux-時間管理和內核定時器

  • ■ 設置系統節拍率
  • ■ 高節拍率和低節拍率的優缺點:
  • ■ jiffies 系統節拍數
    • ■ get_jiffies_64 這個函數可以獲取 jiffies_64 的值
    • ■ 處理繞回
    • ■ 使用 jiffies 判斷超時
  • ■ jiffies 和 ms、 us、 ns 之間的轉換函數`在這里插入代碼片`
  • ■ 內核定時器
    • ■ 內核定時器API
    • ■ 內核短延時函數
    • ■ 示例一:使用范例
    • ■ 示例二:Linux內核定時器實驗 內核定時器周期性的點亮和熄滅開發板上的 LED燈

■ 設置系統節拍率

在這里插入圖片描述
在這里插入圖片描述
默認情況下選擇 100Hz。設置好以后打開 Linux 內核源碼根目錄下的.config 文件,
在這里插入圖片描述

打開文件 include/asm-generic/param.h,
在這里插入圖片描述

■ 高節拍率和低節拍率的優缺點:

①、高節拍率會提高系統時間精度,
如果采用 100Hz 的節拍率,時間精度就是 10ms,
采用1000Hz 的話時間精度就是 1ms,精度提高了 10 倍。
高精度時鐘的好處有很多,對于那些對時間要求嚴格的函數來說,能夠以更高的精度運行,時間測量也更加準確。

②、高節拍率會導致中斷的產生更加頻繁,頻繁的中斷會加劇系統的負擔,
1000Hz 和 100Hz的系統節拍率相比,系統要花費 10 倍的“精力”去處理中斷。
中斷服務函數占用處理器的時間增加,但是現在的處理器性能都很強大,所以采用 1000Hz 的系統節拍率并不會增加太大的負載壓力。
根據自己的實際情況,選擇合適的系統節拍率,本教程我們全部采用默認的 100Hz 系統節拍率。

■ jiffies 系統節拍數

Linux 內核使用全局變量 jiffies 來記錄系統從啟動以來的系統節拍數,系統啟動的時候會將 jiffies 初始化為 0, jiffies 定義在文件 include/linux/jiffies.h 中

extern u64 __jiffy_data jiffies_64;     //定義了一個 64 位的 jiffies_64。
extern unsigned long volatile __jiffy_data jiffies;    //定義了一個 unsigned long 類型的 32 位的 jiffies。

jiffies_64用于 64 位系統,而 jiffies 用于 32 位系統.
當我們訪問 jiffies 的時候其實訪問的是 jiffies_64 的低 32 位,

■ get_jiffies_64 這個函數可以獲取 jiffies_64 的值

HZ 表示每秒的節拍數, jiffies 表示系統運行的 jiffies 節拍數,所以 jiffies/HZ 就是系統運行時間,單位為秒。

■ 處理繞回

假如 HZ 為最大值 1000 的時候,
對于 32 位的 jiffies 只需要 49.7 天就發生了繞回,
對于 64 位的 jiffies 來說大概需要5.8 億年才能繞回,因此 jiffies_64 的繞回忽略不計。處理 32 位 jiffies 的繞回顯得尤為重要

函數描述
time_after(unkown, known)unkown 超過 known 的話, time_after 函數返回真,否則返回假
time_before(unkown, known)unkown 沒有超過 known 的話 time_before 函數返回真,否則返回假
time_after_eq(unkown, known)和 time_after 函數類似 只是多了判斷等于這個條件
time_before_eq(unkown, known)和 time_before函數類似 只是多了判斷等于這個條件

■ 使用 jiffies 判斷超時

timeout 就是超時時間點,比如我們要判斷代碼執行時間是不是超過了 2 秒
在這里插入圖片描述

■ jiffies 和 ms、 us、 ns 之間的轉換函數在這里插入代碼片

函數描述
int jiffies_to_msecs(const unsigned long j)將 jiffies 類型的參數 j 分別轉換為對應的毫秒
int jiffies_to_usecs(const unsigned long j)將 jiffies 類型的參數 j 分別轉換為對應的微秒
u64 jiffies_to_nsecs(const unsigned long j)將 jiffies 類型的參數 j 分別轉換為對應的納秒
long msecs_to_jiffies(const unsigned int m)將毫秒轉換為 jiffies 類型。
long usecs_to_jiffies(const unsigned int u)將微秒轉換為 jiffies 類型。
unsigned long nsecs_to_jiffies(u64 n)將納秒轉換為 jiffies 類型。

■ 內核定時器

Linux 內核定時器使用很簡單,只需要提供超時時間(相當于定時值)和定時處理函數即可。
Linux 內核使用 timer_list 結構體表示內核定時器, timer_list 定義在文件include/linux/timer.h 中

struct timer_list {struct list_head entry;unsigned long expires; /* 定時器超時時間,單位是節拍數 */struct tvec_base *base;void (*function)(unsigned long); /* 定時處理函數 */unsigned long data; /* 要傳遞給 function 函數的參數 */int slack;
};

■ 內核定時器API

函數描述
init_timer 函數初始化 timer_list 類型變量,
add_timer 函數向 Linux 內核注冊定時器,
del_timer 函數刪除一個定時器
del_timer_sync 函數del_timer_sync 函數是 del_timer 函數的同步版,會等待其他處理器使用完定時器再刪除,del_timer_sync 不能使用在中斷上下文中。
mod_timer 函數修改定時值

■ 內核短延時函數

Linux 內核提供了毫秒、微秒 、納秒 延時函數
在這里插入圖片描述

■ 示例一:使用范例

struct timer_list timer; /* 定義定時器 *//* 定時器回調函數 */
void function(unsigned long arg)
{/** 定時器處理代碼*//* 如果需要定時器周期性運行的話就使用 mod_timer* 函數重新設置超時值并且啟動定時器。*/mod_timer(&dev->timertest, jiffies + msecs_to_jiffies(2000));
}/* 初始化函數 */
void init(void)
{init_timer(&timer); /* 初始化定時器 */	timer.function = function; /* 設置定時處理函數 */timer.expires=jffies + msecs_to_jiffies(2000);/* 超時時間 2 秒 */timer.data = (unsigned long)&dev; /* 將設備結構體作為參數 */	add_timer(&timer); /* 啟動定時器 */
}/* 退出函數 */
void exit(void)
{del_timer(&timer); /* 刪除定時器 *//* 或者使用 */del_timer_sync(&timer);
}

■ 示例二:Linux內核定時器實驗 內核定時器周期性的點亮和熄滅開發板上的 LED燈

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>#define TIMER_CNT		1		/* 設備號個數 	*/
#define TIMER_NAME		"timer"	/* 名字 		*/
#define CLOSE_CMD 		(_IO(0XEF, 0x1))	/* 關閉定時器 */
#define OPEN_CMD		(_IO(0XEF, 0x2))	/* 打開定時器 */
#define SETPERIOD_CMD	(_IO(0XEF, 0x3))	/* 設置定時器周期命令 */
#define LEDON 			1		/* 開燈 */
#define LEDOFF 			0		/* 關燈 *//* timer設備結構體 */
struct timer_dev{dev_t devid;			/* 設備號 	 */struct cdev cdev;		/* cdev 	*/struct class *class;	/* 類 		*/struct device *device;	/* 設備 	 */int major;				/* 主設備號	  */int minor;				/* 次設備號   */struct device_node	*nd; /* 設備節點 */int led_gpio;			/* key所使用的GPIO編號		*/int timeperiod; 		/* 定時周期,單位為ms */struct timer_list timer;/* 定義一個定時器*/spinlock_t lock;		/* 定義自旋鎖 */
};struct timer_dev timerdev;	/* timer設備 *//** @description	: 初始化LED燈IO,open函數打開驅動的時候* 				  初始化LED燈所使用的GPIO引腳。* @param 		: 無* @return 		: 無*/
static int led_init(void)
{int ret = 0;timerdev.nd = of_find_node_by_path("/gpioled");if (timerdev.nd== NULL) {return -EINVAL;}timerdev.led_gpio = of_get_named_gpio(timerdev.nd ,"led-gpio", 0);if (timerdev.led_gpio < 0) {printk("can't get led\r\n");return -EINVAL;}/* 初始化led所使用的IO */gpio_request(timerdev.led_gpio, "led");		/* 請求IO 	*/ret = gpio_direction_output(timerdev.led_gpio, 1);if(ret < 0) {printk("can't set gpio!\r\n");}return 0;
}/** @description		: 打開設備* @param - inode 	: 傳遞給驅動的inode* @param - filp 	: 設備文件,file結構體有個叫做private_data的成員變量* 					  一般在open的時候將private_data指向設備結構體。* @return 			: 0 成功;其他 失敗*/
static int timer_open(struct inode *inode, struct file *filp)
{int ret = 0;filp->private_data = &timerdev;	/* 設置私有數據 */timerdev.timeperiod = 1000;		/* 默認周期為1s */ret = led_init();				/* 初始化LED IO */if (ret < 0) {return ret;}return 0;
}/** @description		: ioctl函數,* @param - filp 	: 要打開的設備文件(文件描述符)* @param - cmd 	: 應用程序發送過來的命令* @param - arg 	: 參數* @return 			: 0 成功;其他 失敗*/
static long timer_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{struct timer_dev *dev =  (struct timer_dev *)filp->private_data;int timerperiod;unsigned long flags;switch (cmd) {case CLOSE_CMD:		/* 關閉定時器 */del_timer_sync(&dev->timer);break;case OPEN_CMD:		/* 打開定時器 */spin_lock_irqsave(&dev->lock, flags);timerperiod = dev->timeperiod;spin_unlock_irqrestore(&dev->lock, flags);mod_timer(&dev->timer, jiffies + msecs_to_jiffies(timerperiod));break;case SETPERIOD_CMD: /* 設置定時器周期 */spin_lock_irqsave(&dev->lock, flags);dev->timeperiod = arg;spin_unlock_irqrestore(&dev->lock, flags);mod_timer(&dev->timer, jiffies + msecs_to_jiffies(arg));break;default:break;}return 0;
}/* 設備操作函數 */
static struct file_operations timer_fops = {.owner = THIS_MODULE,.open = timer_open,.unlocked_ioctl = timer_unlocked_ioctl,
};/* 定時器回調函數 */
void timer_function(unsigned long arg)
{struct timer_dev *dev = (struct timer_dev *)arg;static int sta = 1;int timerperiod;unsigned long flags;sta = !sta;		/* 每次都取反,實現LED燈反轉 */gpio_set_value(dev->led_gpio, sta);/* 重啟定時器 */spin_lock_irqsave(&dev->lock, flags);timerperiod = dev->timeperiod;spin_unlock_irqrestore(&dev->lock, flags);mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->timeperiod)); }/** @description	: 驅動入口函數* @param 		: 無* @return 		: 無*/
static int __init timer_init(void)
{/* 初始化自旋鎖 */spin_lock_init(&timerdev.lock);/* 注冊字符設備驅動 *//* 1、創建設備號 */if (timerdev.major) {		/*  定義了設備號 */timerdev.devid = MKDEV(timerdev.major, 0);register_chrdev_region(timerdev.devid, TIMER_CNT, TIMER_NAME);} else {						/* 沒有定義設備號 */alloc_chrdev_region(&timerdev.devid, 0, TIMER_CNT, TIMER_NAME);	/* 申請設備號 */timerdev.major = MAJOR(timerdev.devid);	/* 獲取分配號的主設備號 */timerdev.minor = MINOR(timerdev.devid);	/* 獲取分配號的次設備號 */}/* 2、初始化cdev */timerdev.cdev.owner = THIS_MODULE;cdev_init(&timerdev.cdev, &timer_fops);/* 3、添加一個cdev */cdev_add(&timerdev.cdev, timerdev.devid, TIMER_CNT);/* 4、創建類 */timerdev.class = class_create(THIS_MODULE, TIMER_NAME);if (IS_ERR(timerdev.class)) {return PTR_ERR(timerdev.class);}/* 5、創建設備 */timerdev.device = device_create(timerdev.class, NULL, timerdev.devid, NULL, TIMER_NAME);if (IS_ERR(timerdev.device)) {return PTR_ERR(timerdev.device);}/* 6、初始化timer,設置定時器處理函數,還未設置周期,所有不會激活定時器 */init_timer(&timerdev.timer);timerdev.timer.function = timer_function;timerdev.timer.data = (unsigned long)&timerdev;return 0;
}/** @description	: 驅動出口函數* @param 		: 無* @return 		: 無*/
static void __exit timer_exit(void)
{gpio_set_value(timerdev.led_gpio, 1);	/* 卸載驅動的時候關閉LED */del_timer_sync(&timerdev.timer);		/* 刪除timer */
#if 0del_timer(&timerdev.tiemr);
#endif/* 注銷字符設備驅動 */gpio_free(timerdev.led_gpio);		cdev_del(&timerdev.cdev);/*  刪除cdev */unregister_chrdev_region(timerdev.devid, TIMER_CNT); /* 注銷設備號 */device_destroy(timerdev.class, timerdev.devid);class_destroy(timerdev.class);
}module_init(timer_init);
module_exit(timer_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zuozhongkai");

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/16591.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/16591.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/16591.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

QT常量中有換行符

頭文件添加&#xff1a; #pragma execution_character_set("utf-8")

隨筆之職場:追求技術悲慘之路

技術與職場的反思 作為一名擁有十幾年技術開發經驗的專業人士&#xff0c;我曾堅信技術能力的提升是職場成功的關鍵。我專注于WebGIS開發&#xff0c;不斷學習新技術&#xff0c;追求技術的深度和廣度。然而&#xff0c;隨著時間的推移&#xff0c;我逐漸意識到&#xff0c;技…

Java中的類加載器

類加載器 1.什么是類加載器&#xff1f; 啟動類加載器&#xff08;Bootstrap ClassLoader&#xff09;&#xff1a;這是JVM自帶的類加載器&#xff0c;負責加載Java的核心類庫&#xff0c;如rt.jar等。由于安全原因&#xff0c;啟動類加載器加載的類不能被其他類加載器加載的類…

數據庫(8)——DML數據操作

增添數據 給指定字段添加數據 INSERT INTO 表名 (字段名1&#xff0c;字段名2,...)VALUES(值1,值2...); 沒有的添加的字段默認為NULL。 給全部字段添加數據 INSERT INTO 表名 VALUE (值1,值2,....值n); 此時值的順序對應表中字段的順序 批量添加數據 INSERT INTO 表名(字段1,…

ssm143校園一卡通系統軟件的設計與實現+jsp

校園一卡通系統設計與實現 摘 要 現代經濟快節奏發展以及不斷完善升級的信息化技術&#xff0c;讓傳統數據信息的管理升級為軟件存儲&#xff0c;歸納&#xff0c;集中處理數據信息的管理方式。本校園一卡通系統就是在這樣的大環境下誕生&#xff0c;其可以幫助管理者在短時間…

聊聊變異測試

軟件質量保障 所寫即所思&#xff5c;一個阿里質量人對測試的所感所悟。 1. 介紹 有句話說&#xff1a;證實容易&#xff0c;證偽難。正如測試一樣&#xff0c;證明缺陷存在容易&#xff0c;但證明不存在缺陷難。而變異測試顛覆了這一原則&#xff0c;如果我們知道存在缺陷&am…

2024-5-26

今日安排&#xff1a; 后面還是按照安排來了&#xff0c;CTF 真不是我能玩的… 重新開始審計 nf_tables 源碼&#xff0c;并在審計的過程中復現歷史漏洞【 && iptables 相關學習】?????實驗報告 ?????復現 CTF 相關題目????學習 winpwn????mount 的…

CAD二次開發(6)-用戶交互之選擇集

1. 簡單測試 測試讓選中的圖形描紅 [CommandMethod("SeleDemo")]public void SeleDemo(){Database db HostApplicationServices.WorkingDatabase;Editor ed Application.DocumentManager.MdiActiveDocument.Editor;PromptSelectionResult psr ed.GetSelection();…

如何學到數據庫從入門到入土(MySQL篇)

本篇會加入個人的所謂魚式瘋言 ??????魚式瘋言:??????此瘋言非彼瘋言 而是理解過并總結出來通俗易懂的大白話, 小編會盡可能的在每個概念后插入魚式瘋言,幫助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能說的不是那么嚴謹.但小編初心是能讓更多人能接…

mars3d的V2版本的Video2D與V3版本的Video2D實現數據快速遷移

場景&#xff1a; 目前是v2和v3的兩個相機視角的不同格式&#xff0c;在Mars3d的V2的舊數據想可以快速遷移到V3版本。 V2版本的數據&#xff1a; {"camera": {"fov": 1.0471975511965976,"dis": 20,"stRotation": 0,"showFrust…

基于小波分析和機器學習(SVM,KNN,NB,MLP)的癲癇腦電圖檢測(MATLAB環境)

癲癇是一種由大腦神經元突發性異常放電導致的大腦功能性障礙疾病。據世界衛生組織統計&#xff0c;全球約有7000萬人患有癲癇。癲癇患者在發病時呈現肌肉抽搐、呼吸困難、意識喪失等癥狀。由于癲癇發作的偶然性&#xff0c;患者極有可能在高空、駕駛、游泳等危險情況下發病并喪…

2024最新 Jenkins + Docker實戰教程(二) - Jenkins相關配置

&#x1f604; 19年之后由于某些原因斷更了三年&#xff0c;23年重新揚帆起航&#xff0c;推出更多優質博文&#xff0c;希望大家多多支持&#xff5e; &#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有堅忍不拔之志 &#x1f390; 個人CSND主頁——Mi…

異常有什么,異常類有什么

在Java中&#xff0c;異常&#xff08;Exception&#xff09;是一種在程序運行過程中出現的不正常情況。異常機制提供了一種從錯誤中恢復的途徑。異常分為兩大類&#xff1a;檢查異常&#xff08;Checked Exception&#xff09;和運行時異常&#xff08;Runtime Exception&…

C語言代碼錯誤(一)

今天在寫選擇排序代碼時&#xff0c;在測試數據發現不能顯示結果 1、代碼如下&#xff1a; #include <stdio.h>int main(void) {int i, j; // 循環變量int MinIndex; // 保存最小的值的下標int buf; // 互換數據時的臨時變量int n;printf("你想輸入多少個數據n:\n…

C++之lambda函數與std::bind區別及用法實例(二百八十)

簡介&#xff1a; CSDN博客專家&#xff0c;專注Android/Linux系統&#xff0c;分享多mic語音方案、音視頻、編解碼等技術&#xff0c;與大家一起成長&#xff01; 優質專欄&#xff1a;Audio工程師進階系列【原創干貨持續更新中……】&#x1f680; 優質專欄&#xff1a;多媒…

202212青少年軟件編程(Python)等級考試試卷(四級)

第 1 題 【單選題】 有n個按名稱排序的商品,使用對分查找法搜索任何一商品,最多查找次數為 5 次, 則 n 的值可能為?() A :5 B :15 C :30 D :35 正確答案:C 試題解析: 對分查找最多查找次數m與個數之間 n 的關系是: n 對 2 的對數的取整后加 1,現在最多查找次數是…

LabVIEW如何實現多張圖拼接

在LabVIEW中實現相機多次拍攝進行拼接的過程&#xff0c;可以分為以下幾個步驟&#xff1a;設置相機參數、控制相機拍攝、圖像處理與拼接、顯示和保存結果。以下是一個詳細的實現方案&#xff1a; 1. 設置相機參數 首先需要配置相機的參數&#xff0c;例如分辨率、曝光時間、…

Java Swing + MySQL圖書借閱管理系統

系列文章目錄 Java Swing MySQL 圖書管理系統 Java Swing MySQL 圖書借閱管理系統 文章目錄 系列文章目錄前言一、項目展示二、部分代碼1.Book2.BookDao3.DBUtil4.BookAddInternalFrame5.Login 三、配置 前言 項目是使用Java swing開發&#xff0c;界面設計比較簡潔、適合作…

Qt中信號和槽解決了什么問題

信號和槽解決了什么問題 Qt 中的信號和槽機制是一種用于處理對象之間通信的重要機制,它解決了以下幾個問題: 對象之間的解耦(Decoupling): 問題: 在一個系統中,如果對象之間直接調用彼此的方法,就會形成緊密耦合的結構。這樣的耦合使得對象難以獨立地變更和維護,而且…

react-d3-tree:React組件創建交互式D3樹形圖

在這里插入代碼片import React from "react"; import ReactDOM from "react-dom"; import Tree from "react-d3-tree";import "./styles.css";const myTreeData [{name: "Gaurang Torvekar",attributes: {keyA: "val …