Device Driver : select() in user space and device driver's poll()
這兩個東西之前有稍微的了解一下,今天因為在trace之前寫的code才又想起來,原本是在研究waitqueue做整理的。這部分也可以參考LDD3 Ch 6.3。
在Linux系統上,Device Driver的poll()函數是select()這個system call的支柱,以下截取網路上的一段話,來自http://www.xxlinux.com/linux/article/development/kernel/20061023/5307.html
接著用例子來說明:
struct file_operations xxx_fops = {
.owner = THIS_MODULE,
.read = xxx_read,
.write = xxx_write,
.ioctl = xxx_ioctl,
.open = xxx_open,
.release = xxx_release,
.poll = xxx_poll
};
若上層程式碼呼叫select()的時候,通用的核心poll機制就會串到紅字顯示的API: xxx_poll
在此API中有兩個參數,struct file *filp 和 poll_table *wait,其中flip是file pointer,wait則是
則是一個poll_table的pointer,poll_table是個struct長得像下面這樣子:
typedef struct poll_table_struct {
poll_queue_proc qproc;
unsigned long key;
} poll_table;
poll_queue_proc是個function pointer,key則是個單純的變數而已。
至於該function pointer是如何assign可以參考poll.h以及select.c這兩個檔案,至少在我的code base是從這兩個地方找到的。Assign給qproc的API即是poll_wait函數被呼叫時所連結到函式。
以下是我之前porting driver中使用到的poll函式,由於上層要配合middleware來串起來,所以驅動程式的行為部分還是由廠商的協助完成。
unsigned int xxx_poll(struct file *filp, poll_table *wait)
{
struct xxx_device * p_device = filp->private_data; //將filp->private_data撈出來放在區域變數內
unsigned int mask = 0;
//使用poll_wait將read_queue和write_queue兩個wait queue加入給kernel的poll table後進入sleep的狀態,這些wait queue會一直處在block的狀態,直到所偵測的資料有變化的時候為止。這些資料狀態的變化通常是由ISR來做監控。
poll_wait(filp, &p_device->read_queue, wait);
poll_wait(filp, &p_device->write_queue, wait);
/*=================================================================
poll_wait函式原型
void poll_wait(struct file *flip, wait_queue_head_t *sync, poll_table *pt)
此API讓驅動程式將每一個會喚醒process的wait queue(第二個參數也就是sync引數)填入所指向的poll_table pt.
若目前無法讀出或寫入,那麼在sys_poll->do_poll中當前process就會睡眠在wait queue上,此wiat queue是由驅動程序所提供,也就是 poll_wait中傳入的p_device->read_queue和p_device->write_queue。進入wait_queue之後,就會return mask回到呼叫的函式,此時該函式可能就會放掉cpu讓cpu schedule下一個process
當可以讀寫的時候,可能是driver中的ISR改變了flag(p_device->reset_pending和p_device->nb_available_bytes)的值,此時會wake up在wait queue上的process,也就是之前睡眠的那個,當該process被喚醒後sys_poll->do_poll會再次的呼叫driver的poll函數,此時user application就知道可以讀寫了。
在poll_wait API中並未block住user application,block是由select and poll完成,這部分還必須要了解一下,目前並未深入到select and poll將user application block的部分
小結:1. select/poll 和 poll_wait要區分清楚,block是由不同的sys call來決定,並非poll_wait。
2. select會一直等到可以讀或是寫才return,poll則會在check完之後馬上return。
==================================================================*/
mutex_lock(&p_device->mutex);
if (p_device->reset_pending == 0)
{
mask = POLLOUT | POLLWRNORM;
}
if (p_device->nb_available_bytes)
{
mask |= POLLIN | POLLRDNORM;
}
mutex_unlock(&p_device->mutex);
return mask;
}
在我的Driver Code中是因為中斷發生(表示有N個Bytes可以從裝置上讀取)時會做wake_up read_queue的動作,才致使 if (p_device->nb_available_bytes) 的情況成立而改變mask的值。
另外有用到類似這樣的架構的,還有android中camera的架構,其中取得frame的方法,同樣是透過 select() and poll() 的方式來監控 frame buffer的 fd。
在Linux系統上,Device Driver的poll()函數是select()這個system call的支柱,以下截取網路上的一段話,來自http://www.xxlinux.com/linux/article/development/kernel/20061023/5307.html
select/poll會在一個循環中對每個需要監聽的device呼叫它們自己的poll函數(如下面的程式碼所示)以使得當前process被加入各個device的wait queue。若當前沒有任何被監聽的device就緒,則kernel進行process scheduleing讓出cpu進入block狀態(這個block並不是poll的函式xxx_poll去完成,是由user space完成),schedule返回時將再次循環檢測是否有操作可以進行,如此反覆
struct file_operations xxx_fops = {
.owner = THIS_MODULE,
.read = xxx_read,
.write = xxx_write,
.ioctl = xxx_ioctl,
.open = xxx_open,
.release = xxx_release,
.poll = xxx_poll
};
若上層程式碼呼叫select()的時候,通用的核心poll機制就會串到紅字顯示的API: xxx_poll
在此API中有兩個參數,struct file *filp 和 poll_table *wait,其中flip是file pointer,wait則是
則是一個poll_table的pointer,poll_table是個struct長得像下面這樣子:
typedef struct poll_table_struct {
poll_queue_proc qproc;
unsigned long key;
} poll_table;
poll_queue_proc是個function pointer,key則是個單純的變數而已。
至於該function pointer是如何assign可以參考poll.h以及select.c這兩個檔案,至少在我的code base是從這兩個地方找到的。Assign給qproc的API即是poll_wait函數被呼叫時所連結到函式。
以下是我之前porting driver中使用到的poll函式,由於上層要配合middleware來串起來,所以驅動程式的行為部分還是由廠商的協助完成。
unsigned int xxx_poll(struct file *filp, poll_table *wait)
{
struct xxx_device * p_device = filp->private_data; //將filp->private_data撈出來放在區域變數內
unsigned int mask = 0;
//
poll_wait(filp, &p_device->read_queue, wait);
poll_wait(filp, &p_device->write_queue, wait);
/*=================================================================
poll_wait函式原型
void poll_wait(struct file *flip, wait_queue_head_t *sync, poll_table *pt)
此API讓驅動程式將每一個會喚醒process的wait queue(第二個參數也就是sync引數)填入所指向的poll_table pt.
若目前無法讀出或寫入,那麼在sys_poll->do_poll中當前process就會睡眠在wait queue上,此wiat queue是由驅動程序所提供,也就是 poll_wait中傳入的p_device->read_queue和p_device->write_queue。進入wait_queue之後,就會return mask回到呼叫的函式,此時該函式可能就會放掉cpu讓cpu schedule下一個process
當可以讀寫的時候,可能是driver中的ISR改變了flag(p_device->reset_pending和p_device->nb_available_bytes)的值,此時會wake up在wait queue上的process,也就是之前睡眠的那個,當該process被喚醒後sys_poll->do_poll會再次的呼叫driver的poll函數,此時user application就知道可以讀寫了。
在poll_wait API中並未block住user application,block是由select and poll完成,這部分還必須要了解一下,目前並未深入到select and poll將user application block的部分
小結:1. select/poll 和 poll_wait要區分清楚,block是由不同的sys call來決定,並非poll_wait。
2. select會一直等到可以讀或是寫才return,poll則會在check完之後馬上return。
==================================================================*/
mutex_lock(&p_device->mutex);
if (p_device->reset_pending == 0)
{
mask = POLLOUT | POLLWRNORM;
}
if (p_device->nb_available_bytes)
{
mask |= POLLIN | POLLRDNORM;
}
mutex_unlock(&p_device->mutex);
return mask;
}
在我的Driver Code中是因為中斷發生(表示有N個Bytes可以從裝置上讀取)時會做wake_up read_queue的動作,才致使 if (p_device->nb_available_bytes) 的情況成立而改變mask的值。
另外有用到類似這樣的架構的,還有android中camera的架構,其中取得frame的方法,同樣是透過 select() and poll() 的方式來監控 frame buffer的 fd。
留言
張貼留言