linux tty core code,linux tty core 源码分析(7)
套接字和終端通常都具有異步通知機制,即應用程序可以在數據可用的時候接收到一個信號SIGIO而不需要去輪詢關注的數據。但是當對于多個數據源時,應用不能區分SIGIO的來源。為了實現異步通知機制,應用程序需要為數據源設置一個屬主進程即用fcntl的F_SETOWN來設置屬主進程,以及用fcntl的F_SETFL設置FASYNC標志來開啟文件的異步通知機制。
終端設備是tty設備的一種,其異步通知機制的實現在驅動中是分布的:
1)首先在F_SETOWN被調用時對filp->owner賦值。
2)文件打開時默認FASYNC標志是清除的,當設置這個標志式調用fasync方法。fasync方法依賴于struct fasync_struct 結構和fasync_helper函數。下面具體分析該函數:
static DEFINE_RWLOCK(fasync_lock);
static struct kmem_cache *fasync_cache __read_mostly;
/*
* fasync_helper() is used by some character device drivers (mainly mice)
* to set up the fasync queue. It returns negative on error, 0 if it did
* no changes and positive if it added/deleted the entry.
*/
//fasync_helper從相關的進程列表中增加或刪除文件,on為0表示刪除,非0表示增加int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)
{
struct fasync_struct *fa, **fp;
struct fasync_struct *new = NULL;
int result = 0;
//若在進程列表中增加文件則從后備高速緩存中分配一個struct fasync_struct 結構
if (on) {
new = kmem_cache_alloc(fasync_cache, GFP_KERNEL);
if (!new)
return -ENOMEM;
}
write_lock_irq(&fasync_lock);
//遍歷進程的異步通知文件列表,若存在相關文件且為增加則刪除前面分配的fasync_struct 對象,若為刪除則刪除文件對應
//的fasync_struct對象 for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) {
if (fa->fa_file == filp) {
if(on) {
fa->fa_fd = fd;
kmem_cache_free(fasync_cache, new);
} else {
*fp = fa->fa_next;
kmem_cache_free(fasync_cache, fa);
result = 1;
}
goto out;
}
}
//列表中不存在相關文件則初始化faync_struct 對象并加入到列表頭
if (on) {
new->magic = FASYNC_MAGIC;
new->fa_file = filp;
new->fa_fd = fd;
new->fa_next = *fapp;
*fapp = new;
result = 1;
}
out:
write_unlock_irq(&fasync_lock);
return result;
}
//下面再來看看tty核心中fasync方法tty_fasync函數
static int tty_fasync(int fd, struct file *filp, int on)
{
struct tty_struct *tty;
unsigned long flags;
int retval = 0;
lock_kernel();
tty = (struct tty_struct *)filp->private_data;
if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_fasync"))
goto out;
retval = fasync_helper(fd, filp, on, &tty->fasync); //增加或刪除文件到進程列表 if (retval <= 0)
goto out;
if (on) {
enum pid_type type;
struct pid *pid;
if (!waitqueue_active(&tty->read_wait))
tty->minimum_to_wake = 1;
spin_lock_irqsave(&tty->ctrl_lock, flags);
if (tty->pgrp) {
pid = tty->pgrp;
type = PIDTYPE_PGID;
} else {
pid = task_pid(current);
type = PIDTYPE_PID;
}
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
retval = __f_setown(filp, pid, type, 0); //設置文件的屬主? if (retval)
goto out;
} else {
if (!tty->fasync && !waitqueue_active(&tty->read_wait))
tty->minimum_to_wake = N_TTY_BUF_SIZE;
}
retval = 0;
out:
unlock_kernel();
return retval;
}
3)上面的步驟完成后就是當數據到達時給應用程序發送SIGIO信號,這一步是一般分布在數據的讀寫操作中,我們具體分析內核中的輔助函數kill_fasync其作用是當數據到達時通知所有相關進程
//sig表示要發送的信號,band表示模式讀為POLL_IN 寫為POLL_OUT
void kill_fasync(struct fasync_struct **fp, int sig, int band)
{
/* First a quick test without locking: usually
* the list is empty.
*/
if (*fp) {
read_lock(&fasync_lock);
/* reread *fp after obtaining the lock */
__kill_fasync(*fp, sig, band);
read_unlock(&fasync_lock);
}
}
//遍歷struct fasync_struct 鏈表并對相關進程發送信號
void __kill_fasync(struct fasync_struct *fa, int sig, int band)
{
while (fa) {
struct fown_struct * fown;
if (fa->magic != FASYNC_MAGIC) {
printk(KERN_ERR "kill_fasync: bad magic number in "
"fasync_struct!/n");
return;
}
fown = &fa->fa_file->f_owner;
/* Don't send SIGURG to processes which have not set a
queued signum: SIGURG has its own default signalling
mechanism. */
if (!(sig == SIGURG && fown->signum == 0))
send_sigio(fown, fa->fa_fd, band);
fa = fa->fa_next;
}
}
4)最好在關閉進程時再把文件從進程列表中清除即tty_fysnc(-1,flip,0);
因為異步通知機制是分散的這節中就主要分析其實現機制,實現源碼比較容易理解就沒有列舉出全部源碼
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的linux tty core code,linux tty core 源码分析(7)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 来赚
- 下一篇: 【经验】短接 Flash 解决二次量产金