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);

因为异步通知机制是分散的这节中就主要分析其实现机制,实现源码比较容易理解就没有列举出全部源码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值