無料Wikiサービス | デモページ
検索

アクセス数
最近のコメント
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
はじめ - ノース
はじめ - ノース
はじめ - 楽打連動ユーザー
はじめ - 楽打連動ユーザー
Adsense
広告情報が設定されていません。

O_ASYNC


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

備考

fasync_insert_entry()で登録済みFILEオブジェクトでの再登録は、ファイルIDのみを更新していました。これはsend_sigio()の引数となるのですが、シグナル処理その物でなく、ユーザプロセスが、シグナルがどのファイルからのシグナルであるかの判断とするため、単にsiginfoに設定されるだけのようです。実際シグナルの送信は、fa->fa_file->f_ownerに送信されます。

登録済みFILEオブジェクトでの再登録と言うのは、自プロセスないしマルチスレッドでファイルIDをデュプリケートしたケースで、従って、ファイルIDのみを更新で問題なさそうな気がします。なお、マルチスレッドの場合、子スレッドでデュプリケートしても、カーネル内部的には、親のプロセスにシグナルを送信する事になります。たぶん


最終更新 2012/11/03 19:51:58 - north
(2012/11/03 18:56:54 作成)