読者です 読者をやめる 読者になる 読者になる

kill_fasyncの引数のまぎらわしさ

tl;dr

  • kill_fasyncの第2引数は飛ばしたいシグナル番号を指定するわけではない
  • つまみ食いで勉強すると落とし穴にはまる危険があるので気をつける

詳細

kill_fasyncという関数をご存知だろうか。kill_fasyncとは、Linuxカーネルが提供する関数の1つで、 カーネルモジュールからユーザプロセスへシグナルを飛ばすものだ。

Kernel 4.8での実装はこんな感じ。至ってシンプルで、 正直これで何がわかるか、というところであるが、少なくとも何をいくつ引数に取るかわかる。

Linux/fs/fcntl.c - Linux Cross Reference - Free Electrons

724 void kill_fasync(struct fasync_struct **fp, int sig, int band)
725 {
726         /* First a quick test without locking: usually
727          * the list is empty.
728          */
729         if (*fp) {
730                 rcu_read_lock();
731                 kill_fasync_rcu(rcu_dereference(*fp), sig, band);
732                 rcu_read_unlock();
733         }
734 }
735 EXPORT_SYMBOL(kill_fasync);

さて、これを見て何を思うか。素直な心と有り余る読解力で読むと、第2引数のsigは飛ばすシグナルの番号だと思うのではないだろうか。 ところがこれは飛ばすシグナルの番号とは全く関係がない。

さて、kill_fasync_rcuを見てみよう。

699 static void kill_fasync_rcu(struct fasync_struct *fa, int sig, int band)
700 {
701         while (fa) {
702                 struct fown_struct *fown;
703                 unsigned long flags;
704 
705                 if (fa->magic != FASYNC_MAGIC) {
706                         printk(KERN_ERR "kill_fasync: bad magic number in "
707                                "fasync_struct!\n");
708                         return;
709                 }
710                 spin_lock_irqsave(&fa->fa_lock, flags);
711                 if (fa->fa_file) {
712                         fown = &fa->fa_file->f_owner;
713                         /* Don't send SIGURG to processes which have not set a
714                            queued signum: SIGURG has its own default signalling
715                            mechanism. */
716                         if (!(sig == SIGURG && fown->signum == 0))
717                                 send_sigio(fown, fa->fa_fd, band);
718                 }
719                 spin_unlock_irqrestore(&fa->fa_lock, flags);
720                 fa = rcu_dereference(fa->fa_next);
721         }
722 }

意外にもsigはSIGURGじゃなければOKで、実際にシグナルを飛ばしていると思しき send_sigioにはsigが全く入っていない。じゃあ一体sigって何なのか。 それに飛ばしたいシグナル番号ってどこに入ってるんだ。

順番が前後するが、飛ばしたいシグナル番号はsend_sigio関数を見ればわかるよね。 send_sigioはさらにsend_sigio_to_taskという関数を呼んでる。

491 void send_sigio(struct fown_struct *fown, int fd, int band)
492 {
493         struct task_struct *p;
494         enum pid_type type;
495         struct pid *pid;
496         int group = 1;
497         
498         read_lock(&fown->lock);
499 
500         type = fown->pid_type;
501         if (type == PIDTYPE_MAX) {
502                 group = 0;
503                 type = PIDTYPE_PID;
504         }
505 
506         pid = fown->pid;
507         if (!pid)
508                 goto out_unlock_fown;
509         
510         read_lock(&tasklist_lock);
511         do_each_pid_task(pid, type, p) {
512                 send_sigio_to_task(p, fown, fd, band, group);
513         } while_each_pid_task(pid, type, p);
514         read_unlock(&tasklist_lock);
515  out_unlock_fown:
516         read_unlock(&fown->lock);
517 }

あった。シグナル番号signumはfownに入ってる。

449 static void send_sigio_to_task(struct task_struct *p,
450                                struct fown_struct *fown,
451                                int fd, int reason, int group)
452 {
453         /*
454          * F_SETSIG can change ->signum lockless in parallel, make
455          * sure we read it once and use the same value throughout.
456          */
457         int signum = ACCESS_ONCE(fown->signum);
458 
459         if (!sigio_perm(p, fown, signum))
460                 return;
461 
462         switch (signum) {
463                 siginfo_t si;
464                 default:
465                         /* Queue a rt signal with the appropriate fd as its
466                            value.  We use SI_SIGIO as the source, not 
467                            SI_KERNEL, since kernel signals always get 
468                            delivered even if we can't queue.  Failure to
469                            queue in this case _should_ be reported; we fall
470                            back to SIGIO in that case. --sct */
471                         si.si_signo = signum;
472                         si.si_errno = 0;
473                         si.si_code  = reason;
474                         /* Make sure we are called with one of the POLL_*
475                            reasons, otherwise we could leak kernel stack into
476                            userspace.  */
477                         BUG_ON((reason & __SI_MASK) != __SI_POLL);
478                         if (reason - POLL_IN >= NSIGPOLL)
479                                 si.si_band  = ~0L;
480                         else
481                                 si.si_band = band_table[reason - POLL_IN];
482                         si.si_fd    = fd;
483                         if (!do_send_sig_info(signum, &si, p, group))
484                                 break;
485                 /* fall-through: fall back on the old plain SIGIO signal */
486                 case 0:
487                         do_send_sig_info(SIGIO, SEND_SIG_PRIV, p, group);
488         }
489 }

でもfown_structなんてどこで設定するんだ?と思ったあなたは鋭い。 実はkill_fasyncを使うには(当たり前だが)準備がいる。 具体的にはfcntlを使えばよい。以下のスライドを見てくれれば何となくわかると思う。 F_SETSIGとシグナル番号を与えてfcntlを撃ってやればOKだ。先に見るべきだった。

http://www.cs.usfca.edu/~cruse/cs635s05/lesson22.ppt

では、SIGIOは一体何なのか。 このへんを読むと、非同期のI/Oイベントを伝えるときにはSIGIOを使うらしいというのがわかる。 要はある種のお約束的なものですね。 まあ確かにカーネルモジュールというかドライバだから、ユーザプロセスに何か通知するのって、 外部デバイスの入出力イベント以外にないよなあ。

ところでSIGURGって何で特別扱いされてるの?と気になるけど、こちらもある種のお約束的なものらしい。 SIGIOよりも用途が限定されてるようなので特別扱いなのかも。

ソケットを使用したアプリケーションへの信号

SIGURG は、OOB データをサポートしているソケットでアウト・オブ・バンド (OOB) データを受信するときに送信される信号です。たとえば、AF_INET アドレス・ファミリーで SOCK_STREAM タイプのソケットは、 SIGURG 信号を送信するように条件付けることができます。
SIGIO は、あらゆるタイプのソケットで通常のデータ、OOB データ、エラー条件、その他が発生したときに送信される信号です。 

まとめ

kill_fasyncの第2引数はある種のおまじない的にSIGIOを指定すればよいっぽい。 使い方をちゃんと勉強しないと余計なことを調べなきゃいけなくなるので、 ショートカットせずに地道に調べた方がよい。