ppoll


ppoll()はpoll()と本質的に変わりません。sigprocmask()で指定されるシグナルをマスクし(SIGKILL/SIGSTOPはマスクできません。)
、do_sys_poll()をコールします。マスクされていなシグナル/タイムアウト/ファイル状態変化でpollを脱します。タイムアウト/ファイル状態変化なら、sigprocmask()でシグナルマスクを復帰し、ユーザプロセス復帰時、そのシグナルが発生していたら、シグナルハンドラをコールする事になります。
SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, unsigned int, nfds,
               struct timespec __user *, tsp, const sigset_t __user *, sigmask,
               size_t, sigsetsize)
{
       sigset_t ksigmask, sigsaved;
       struct timespec ts, end_time, *to = NULL;
       int ret;

       if (tsp) {
               if (copy_from_user(&ts, tsp, sizeof(ts)))
                       return -EFAULT;

               to = &end_time;
               if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec))
                       return -EINVAL;
       }

       if (sigmask) {
               /* XXX: Don't preclude handling different sized sigset_t's.  */
               if (sigsetsize != sizeof(sigset_t))
                       return -EINVAL;
               if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask)))
                       return -EFAULT;

               sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
               sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
       }

       ret = do_sys_poll(ufds, nfds, to);

       if (ret == -EINTR) {
               if (sigmask) {
                       memcpy(&current->saved_sigmask, &sigsaved,
                                       sizeof(sigsaved));
                       set_restore_sigmask();
               }
               ret = -ERESTARTNOHAND;
       } else if (sigmask)
               sigprocmask(SIG_SETMASK, &sigsaved, NULL);

       ret = poll_select_copy_remaining(&end_time, tsp, 0, ret);

       return ret;
}
sigprocmask()をhow=SIG_SETMASKでコールすると、*oldset=current->blockedとし、current->blocked=*setとします。
int sigprocmask(int how, sigset_t *set, sigset_t *oldset)
{
       struct task_struct *tsk = current;
       sigset_t newset;

       if (oldset)
               *oldset = tsk->blocked;

       switch (how) {
       case SIG_BLOCK:
               sigorsets(&newset, &tsk->blocked, set);
               break;
       case SIG_UNBLOCK:
               sigandnsets(&newset, &tsk->blocked, set);
               break;
       case SIG_SETMASK:
               newset = *set;
               break;
       default:
               return -EINVAL;
       }

       set_current_blocked(&newset);
       return 0;
}

備考

タイムアウト引数のstruct timespecは、pollと異なりnsecの単位で設定できます。TASK_INTERRUPTIBLEでのpoll_schedule_timeout()を介しての処理故、poll中にシグナルハンドがコールされるケースもあり、シグナルマスクすることで、その負荷をなくすことで精度の高い時間管理ができる故と思います。

マスクしないシグナルは-EINTRで、ret = -ERESTARTNOHANDとしています。名称から察するに、ハンドラが無い場合システムコールの再実行と言う事でしょうか? だとしても、再実行コールバックが設定されてません・・・。

全シグナルをマスクし、タイムアウトしない設定で、ppollをコールすると、ファイル参照をシグナルで処理する。利用が可能かと思います。

なお、pollでもそうでppoll等システムコールでウエイトする機能は、シグナルの実装に行き着くということのようです。


最終更新 2015/05/26 18:12:32 - north
(2015/05/26 18:12:32 作成)


検索

アクセス数
3575886
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。