linux驅動開發學習二 建立乙個阻塞型的字元裝置

2022-05-30 20:24:11 字數 4831 閱讀 9021

在linux 驅動程式中,可以使用等待佇列來實現阻塞程序的喚醒。等待佇列的頭部定義如下,是乙個雙向列表。

struct list_head }

#define declare_waitqueue(name, tsk)                                      \

wait_queue_t name = __waitqueue_initializer(name, tsk)

其實就是兩個巨集定義,這個兩個巨集定義擴充套件開來其實就是

wait_queue_t name= }   #等待佇列

那麼回到**中的呼叫declare_waitqueue(wait, current)就是定義了乙個等待佇列元素wait。等待佇列的private就等於當前程序指標。

3 add_wait_queue/remove_wait_queue:新增移除等待佇列

4 等待事件

wait_event(queue,condition)

wait_event_interrupt(queue,condition)

wait_event_timeout(queue,condition,timeout)

wait_event_interruptible_timeout(queue,condition,timeout)

等待第1個引數queue作為等待佇列頭部的佇列被喚醒,而且第2個引數必須滿足,否則繼續阻塞,wait_event和wait_event_interrupt的區別在於後者可以被訊號中斷打斷。加上timeout後的巨集意味著阻塞等待的超時時間,在第三個引數timeout到達時,不論condition是否滿足,均返回。

來看下**的實現,首先是wait_event。 先判斷條件,如果條件,則立即退出,否則進入__wait_event

#define wait_event(wq, condition)                                         \

do while (0)

#define __wait_event(wq, condition)                                     \

do while (0)

(1)     define_wait(__wait) 中申明乙個當前進展的等待佇列

#define define_wait(name) define_wait_func(name, autoremove_wake_function)

#define define_wait_func(name, function)                                \

wait_queue_t name = while (0)

5 wake_up(wait_queue_head_t *queue) wake_up會喚醒作為等待佇列頭部的佇列中的所有程序。**按如下,遍歷佇列,然後依次執行喚醒**函式

static void __wake_up_common(wait_queue_head_t *q, unsigned int mode,

int nr_exclusive, int wake_flags, void *key)

wait_queue_t *curr, *next;

list_for_each_entry_safe(curr, next, &q->task_list, task_list) ;

struct globalmem_dev *globalmem_devp;

static

int globalmem_open(struct inode *inode,struct file *filp)

static

int globalmem_release(struct inode *inode,struct file *filp)

static

long globalmem_ioctl(struct file *filp,unsigned int cmd,unsigned long

arg)

return0;

}static ssize_t globalmem_read_queue(struct file *filp,char __user *buf,size_t size,loff_t *ppos)

__set_current_state(task_interruptible);

mutex_unlock(&dev->mutex);

schedule();

if(signal_pending(current))

mutex_lock(&dev->mutex);

}if(size > dev->current_len)

size=dev->current_len;

if(copy_to_user(buf,dev->mem,size))

else

out:

mutex_unlock(&dev->mutex);

out2:

remove_wait_queue(&dev->w_wait,&wait);

set_current_state(task_running);

return

ret;

}static ssize_t globalmem_write_queue(struct file *filp,const

char __user *buf,size_t size, loff_t *ppos)

__set_current_state(task_interruptible);

mutex_unlock(&dev->mutex);

schedule();

if(signal_pending(current))

mutex_lock(&dev->mutex);

} if(size > globalmem_size- dev->current_len)

size=globalmem_size - dev->current_len;

if(copy_from_user(dev->mem+dev->current_len,buf,size))

else

out:

mutex_unlock(&dev->mutex);

out2:

remove_wait_queue(&dev->w_wait,&wait);

set_current_state(task_running);

return

ret;

}static loff_t globalmem_llseek(struct file *filp,loff_t offset,int

orig)

filp->f_pos=(unsigned int

)offset;

ret=filp->f_pos;

break

;

case1:

if((filp->f_pos+offset) >globalmem_size)

if((filp->f_pos+offset) < 0

) filp->f_pos+=offset;

ret=filp->f_pos;

break

; }

return

ret;

}static

const

struct file_operations globalmem_fops=;

static

void globalmem_setup_dev(struct globalmem_dev *dev,int

index)

static

int __init globalmem_init(void

)

if(ret < 0

)

return

ret;

globalmem_devp=kzalloc(sizeof(struct

globalmem_dev),gfp_kernel);

if(!globalmem_devp)

mutex_init(&globalmem_devp->mutex);

globalmem_setup_dev(globalmem_devp,0);

printk(

"globalmem init success\n");

init_waitqueue_head(&globalmem_devp->r_wait);

init_waitqueue_head(&globalmem_devp->w_wait);

return0;

fail_malloc:

unregister_chrdev_region(devno,1);

return

ret;

}module_init(globalmem_init);

static

void __exit globalmem_exit(void

)module_exit(globalmem_exit);

module_author(

"zhf");

module_license(

"gpl

");**主要做了如下幾點改動:

1 在globalmem_dev中增加讀和寫的佇列r_wait以及w_wait

2 在globalmem_init中呼叫init_waitqueue_head初始化寫和讀佇列

3 在globalmem_read_queue中將當前程序加入讀的等待佇列,只有當讀佇列完成copy_to_user的操作後,才喚醒寫佇列的程序

4 在globalmem_write_queue中將當前程序加入寫的等待佇列,只有當寫佇列完成copy_from_user的操作後,才喚醒讀佇列的程序

Linux驅動開發學習(一)

1.軟體驅動 驅動硬體,使硬體處於某種工作模式,提供控制硬體方法 2.驅動的地位 驅動是連線核心與裝置的橋梁 1.字元裝置 字元裝置驅動 字元裝置檔案 2.網路裝置 網路裝置驅動 3.塊裝置 塊裝置驅動 塊裝置檔案 1.驅動編寫 2.驅動編譯 3.驅動使用 三要素 1.入口 載入 module in...

Linux驅動學習(二)

注 基於linux 2.6.38 還是 arch arm mach s3c64xx mach mini6410.c這個檔案,前面有篇文章已經說了裡面的mini6410 machine init 函式是什麼時候被呼叫的,因此在這裡不再重複,直接看這個函式裡面的內容 1 static void init...

Linux驅動開發學習筆記

一 linux裝置驅動基礎 基於linux2.6核心 參考 linux device drivers 3rd edition linux kernel有乙個很好的特性,可以支援在執行是進行擴充套件。這意味著系統啟動執行是,我們仍然可以向kernel新增功能。這種執行時可以被新增到kernel的 稱為...