1.內核定時器:
Linux 內核所提供的用于操作定時器的數據結構和函數如下:
(1) timer_list
在 Linux 內核中,timer_list 結構體的一個實例對應一個定時器
1 struct timer_list {
2 struct list_head entry; /* 定時器列表 */
3 unsigned long expires; /*定時器到期時間*/
4 void (*function)(unsigned long); /* 定時器處理函數 */
5 unsigned long data; /* 作為參數被傳入定時器處理函數 */
6 struct timer_base_s *base;
7 ...
8 };
當定時器期滿后,其中第 5 行的 function()成員將被執行,而第 4 行的 data 成員則是傳入其中的參數,第 3 行的 expires 則是定時器到期的時間(jiffies)。
如下代碼定義一個名為 my_timer 的定時器:
struct timer_list my_timer;
(2)初始化定時器
void init_timer(struct timer_list * timer);
上述 init_timer()函數初始化 timer_list 的 entry 的 next 為 NULL,并給 base 指針賦值
TIMER_INITIALIZER(_function, _expires, _data)宏用于賦值定時器結構體的function、expires、
data 和 base 成員
DEFINE_TIMER(_name, _function, _expires, _data)宏是定義并初始化定時器成員的“快捷方
式”。
此外,static inline void setup_timer(struct timer_list * timer, void (*function)(unsigned long),unsigned long data)
也可用于初始化定時器并賦值其成員
(3)增加定時器
void add_timer(struct timer_list* timer);
(4)刪除定時器
int del_timer(struct timer_list* timer);
del_timer_sync()是 del_timer()的同步版,在刪除一個定時器時需等待其被處理完,因此該函數的調用不能發生在中斷上下文。
(5).修改定時器的 expire
int mod_timer(struct timer_list *timer, unsigned long expires);
上述函數用于修改定時器的到期時間,在新的被傳入的 expires 到來后才會執行定時器函數。
2.內核中延時的工作delayed_work
注意,對于這種周期性的任務,Linux 內核還提供了一套封裝好的快捷機制,其本質利用工作隊列
和定時器實現,這套快捷機制是就是delayed_work,delayed_work結構體的定義如代碼清單10.11所示。
代碼清單 10.11 delayed_work 結構體
1 struct delayed_work {
2 struct work_struct work;
3 struct timer_list timer;
4 };
5 struct work_struct {
6 atomic_long_t data;
7 #define WORK_STRUCT_PENDING 0
8 #define WORK_STRUCT_FLAG_MASK (3UL)
9 #define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK)
10 struct list_head entry;
11 work_func_t func;
12 #ifdef CONFIG_LOCKDEP
13 struct lockdep_map lockdep_map;
14 #endif
15 };
我們可以通過如下函數調度一個 delayed_work 在指定的延時后執行:
int schedule_delayed_work(struct delayed_work *work, unsigned long delay);
當指定的 delay 到來時 delayed_work 結構體中 work 成員的 work_func_t 類型成員 func()會被
執行。work_func_t 類型定義為:
typedef void (*work_func_t)(struct work_struct *work);
其中 delay 參數的單位是 jiffies,因此一種常見的用法如下:
schedule_delayed_work(&work, msecs_to_jiffies(poll_interval));
其中的 msecs_to_jiffies()用于將毫秒轉化為 jiffies。
如果要周期性的執行任務,通常會在 delayed_work 的工作函數中再次調用 schedule_delayed_
work(),周而復始。
如下函數用來取消 delayed_work:
int cancel_delayed_work(struct delayed_work *work);
int cancel_delayed_work_sync(struct delayed_work *work);
3.內核延時
Linux 內核中提供了如下 3 個函數分別進行納秒、微秒和毫秒延遲:
void ndelay(unsigned long nsecs);
void udelay(unsigned long usecs);
void mdelay(unsigned long msecs);
上述延遲的實現原理本質上是忙等待,它根據 CPU 頻率進行一定次數的循環。
毫秒時延(以及更大的秒時延)已經比較大了,在內核中,最好不要直接使用 mdelay()函數,這將無謂地耗費 CPU 資源,對于毫秒級以上時延,內核提供了下述函數:
void msleep(unsigned int millisecs);
unsigned long msleep_interruptible(unsigned int millisecs);
void ssleep(unsigned int seconds);
上述函數將使得調用它的進程睡眠參數指定的時間,msleep()、ssleep()不能被打斷,而msleep_interruptible()則可以被打斷。
秒設備驅動程序:
#include #include #include #include #include #include #include #include #include #include #include #include #include static unsigned char timermajor = 0; #define TIMERNAME 'mytimer' static struct class *timer_class; static struct device *timer_device; struct timer_dev { struct cdev cdev; atomic_t counter; struct timer_list mytimer; }; struct timer_dev *my_timer_dev; static void my_timer_fun(unsigned int arg) { mod_timer(&my_timer_dev->mytimer, jiffies + HZ); atomic_inc(&my_timer_dev->counter); printk(KERN_NOTICE 'current jiffies is %ldn', jiffies); } static int my_timer_open(struct inode * inode, struct file * file) { init_timer( &my_timer_dev->mytimer); my_timer_dev->mytimer.expires = jiffies+ HZ; my_timer_dev->mytimer.function = & my_timer_fun; add_timer(&my_timer_dev->mytimer); atomic_set(&my_timer_dev->counter, 0); return 0; } static ssize_t my_timer_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) { int counter; counter = atomic_read(&my_timer_dev->counter); if(copy_to_user(buf, &counter, sizeof(int))) printk('copy_to_user errorn'); return 0; } static int my_timer_close(struct inode *inode, struct file *file) { del_timer( &my_timer_dev->mytimer); return 0; } struct file_operations timer_fops = { .owner = THIS_MODULE, .open = my_timer_open, .read = my_timer_read, .release = my_timer_close, }; static void timer_setup_cdev(struct timer_dev *dev, int minor ) { unsigned char err; dev_t deno; deno = MKDEV(timermajor, minor); cdev_init(&dev->cdev, &timer_fops); dev->cdev.owner = THIS_MODULE; dev->cdev.ops = &timer_fops; err = cdev_add(&dev->cdev, deno, 1); if(err) printk(KERN_ALERT'cdev_addd errorn'); } static int __init my_timer_init(void) { int err = 0; dev_t deno; if(timermajor) { register_chrdev_region(deno, 1, TIMERNAME); } else { err = alloc_chrdev_region(&deno, 0, 1, TIMERNAME); timermajor = MAJOR(deno); } if(err) printk(KERN_ALERT'alloc_chrdev_region errorn'); printk(KERN_ALERT'timermajor is %dn', timermajor); my_timer_dev = kmalloc(sizeof(struct timer_dev), GFP_KERNEL); if(!my_timer_dev) { printk(KERN_ALERT'kmalloc errorn'); return -ENOMEM; } memset(my_timer_dev, 0, sizeof(struct timer_dev) ); timer_setup_cdev(my_timer_dev, 0); timer_class = class_create(THIS_MODULE, TIMERNAME); if(IS_ERR(timer_class)) { printk(KERN_ALERT'class_create errorn'); return -EBUSY; } timer_device = device_create(timer_class, NULL, deno, NULL, TIMERNAME); if(IS_ERR(timer_device)) { printk(KERN_ALERT'device_create errorn'); return -EBUSY; } return 0; } static void __exit my_key_exit(void) { cdev_del(&my_timer_dev->cdev); unregister_chrdev_region(MKDEV(timermajor, 0), 1); kfree(my_timer_dev); } MODULE_LICENSE('GPL'); MODULE_AUTHOR('qigaohua'); module_init(my_timer_init); module_exit(my_key_exit); 測試程序: #include #include #include #include int main() { int fd; int counter = 0; int old_counter = 0; fd = open('/dev/mytimer', O_RDWR); if(fd < 0) { printf('open /dev/mytimer errorn'); return 0; } while(1) { read(fd, &counter, sizeof(int)); if(counter != old_counter) { old_counter = counter; printf('counter is %dn', counter); } } }
上一篇:Smart210學習記錄------paltform總線
下一篇:Smart210學習記錄-------linux驅動中斷
推薦閱讀最新更新時間:2025-04-16 19:36






設計資源 培訓 開發板 精華推薦
- STEVAL-IPFC12V1、2kW 2 通道交錯式 PFC 評估套件,基于具有數字浪涌電流控制的 STNRGPF12 數字控制器
- 用于離線電源的 NCP1253 電流模式 PWM 控制器的典型應用
- 使用 STMicroelectronics 的 R5973D 的參考設計
- NCS2002SN1T1G可變占空比脈沖發生器典型應用電路
- 使用 California Eastern Laboratories 的 ZICM2410 的參考設計
- 【物聯網】鴻蒙智能WIFI開關+4233031A
- 【訓練營】物聯網時鐘+955390A
- LTC2284IUP 演示板,DeMUX 雙路 ADC,+3.0V,105Msps 14 位 1MHz
- 三端固定穩壓器,具有輸出控制的低壓精密可調并聯穩壓器的典型應用
- AND8159/D,使用壓擴器NE570/SA571進行自動電平控制的應用電路