O_ASYNC
Rev.1を表示中。最新版はこちら。
FASYNCの設定は、キャラクタデバイスのファイルオペレーションの.fasyncがコールされます。ここではreadのpipeについて見てみました。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); } }