O_ASYNC/FASYNC
FASYNCの設定は、キャラクタデバイスのファイルオペレーションの.fasyncがコールされます。ここではreadのpipeについて見てみました。
fcntlシステムコールでsetfl()が呼ばれるわけですが、そこでFASYNCの処理として.fasyncのpipe_read_fasync()がコールされます。
登録されていないなら、fasync_strucオブジェクトを設定し、fasync_structリストに登録します。この時filp->f_flags |= FASYNCとしています。これはrelaseロックの設定で本処理がコールされるからです。new->magic = FASYNC_MAGICはメッセージ送信において、new->magicにFASYNC_MAGICが設定されていない場合、メッセージが送信されないようになっています。たぶんこの辺りの処理は今後変更されるということで、LKMのマジックナンバーの様に、カーネル毎にこのマジックナンバーが異なって、同じカーネル下(FASYNC_MAGICが同じ)で作成したモジュールでないと、FASYNCでのシグナルを送信しないようにしているのではと推測しますが・・・。
if (!(sig == SIGURG && fown->signum == 0))で、sigがソケットのSIGURGで、fown->signum(fcntlのF_SETSIG)が設定されてないと送信されないようです。
fcntlシステムコールでsetfl()が呼ばれるわけですが、そこでFASYNCの処理として.fasyncのpipe_read_fasync()がコールされます。
const struct file_operations read_pipefifo_fops = {
.llseek = no_llseek,
.read = do_sync_read,
.aio_read = pipe_read,
.write = bad_pipe_w,
.poll = pipe_poll,
.unlocked_ioctl = pipe_ioctl,
.open = pipe_read_open,
.release = pipe_read_release,
.fasync = pipe_read_fasync,
};
pipe_read_fasync()では、inodeのかかるfasyncリストを4番目の引数として、fasync_helper()から、引数のonによって、fasyncの削除/追加の処理が行われます。
static int
pipe_read_fasync(int fd, struct file *filp, int on)
{
struct inode *inode = filp->f_path.dentry->d_inode;
int retval;
mutex_lock(&inode->i_mutex);
retval = fasync_helper(fd, filp, on, &inode->i_pipe->fasync_readers);
mutex_unlock(&inode->i_mutex);
return retval;
}
fasync_helper()をon=1でコールすると、fasynオブジェクトの追加処理でfasync_insert_entry()がコールされます。最初のforループは同じFILEオブジェクトがすでに登録されているかチェックします。登録されているならfa->fa_fd = fdでファイルIDを更新します。(send_sigio()の引数になるのですが・・・?具体的な意味合い今ひとつです。)登録されていないなら、fasync_strucオブジェクトを設定し、fasync_structリストに登録します。この時filp->f_flags |= FASYNCとしています。これはrelaseロックの設定で本処理がコールされるからです。new->magic = FASYNC_MAGICはメッセージ送信において、new->magicにFASYNC_MAGICが設定されていない場合、メッセージが送信されないようになっています。たぶんこの辺りの処理は今後変更されるということで、LKMのマジックナンバーの様に、カーネル毎にこのマジックナンバーが異なって、同じカーネル下(FASYNC_MAGICが同じ)で作成したモジュールでないと、FASYNCでのシグナルを送信しないようにしているのではと推測しますが・・・。
struct fasync_struct *fasync_insert_entry(int fd, struct file *filp, struct fasync_struct **fapp, struct fasync_struct *new)
{
struct fasync_struct *fa, **fp;
spin_lock(&filp->f_lock);
spin_lock(&fasync_lock);
for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) {
if (fa->fa_file != filp)
continue;
spin_lock_irq(&fa->fa_lock);
fa->fa_fd = fd;
spin_unlock_irq(&fa->fa_lock);
goto out;
}
spin_lock_init(&new->fa_lock);
new->magic = FASYNC_MAGIC;
new->fa_file = filp;
new->fa_fd = fd;
new->fa_next = *fapp;
rcu_assign_pointer(*fapp, new);
filp->f_flags |= FASYNC;
out:
spin_unlock(&fasync_lock);
spin_unlock(&filp->f_lock);
return fa;
}
pipe_write()はパイプの書き込み処理です。データを書き込んだ後、パイプでウエイトしているタスクがあればそれを起床させ、 kill_fasync()でSIGIOを送信します。kill_fasync()はfasync_structオブジェクトリストにオブジェクトがあるかどうかチェックして、kill_fasync_rcu()で、FASYNC_MAGICが設定されているfasync_structのリスト下のプロセスに、シグナル送信を行います。if (!(sig == SIGURG && fown->signum == 0))で、sigがソケットのSIGURGで、fown->signum(fcntlのF_SETSIG)が設定されてないと送信されないようです。
static ssize_t
pipe_write(struct kiocb *iocb, const struct iovec *_iov,
unsigned long nr_segs, loff_t ppos)
{
struct pipe_inode_info *pipe;
pipe = inode->i_pipe;
:
:
mutex_unlock(&inode->i_mutex);
if (do_wakeup) {
wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLRDNORM);
kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
}
if (ret > 0)
file_update_time(filp);
return ret;
}
static void kill_fasync_rcu(struct fasync_struct *fa, int sig, int band)
{
while (fa) {
struct fown_struct *fown;
unsigned long flags;
if (fa->magic != FASYNC_MAGIC) {
printk(KERN_ERR "kill_fasync: bad magic number in "
"fasync_struct!\n");
return;
}
spin_lock_irqsave(&fa->fa_lock, flags);
if (fa->fa_file) {
fown = &fa->fa_file->f_owner;
if (!(sig == SIGURG && fown->signum == 0))
send_sigio(fown, fa->fa_fd, band);
}
spin_unlock_irqrestore(&fa->fa_lock, flags);
fa = rcu_dereference(fa->fa_next);
}
}






