ppoll
ppoll()はpoll()と本質的に変わりません。sigprocmask()で指定されるシグナルをマスクし(SIGKILL/SIGSTOPはマスクできません。)
、do_sys_poll()をコールします。マスクされていなシグナル/タイムアウト/ファイル状態変化でpollを脱します。タイムアウト/ファイル状態変化なら、sigprocmask()でシグナルマスクを復帰し、ユーザプロセス復帰時、そのシグナルが発生していたら、シグナルハンドラをコールする事になります。
マスクしないシグナルは-EINTRで、ret = -ERESTARTNOHANDとしています。名称から察するに、ハンドラが無い場合システムコールの再実行と言う事でしょうか? だとしても、再実行コールバックが設定されてません・・・。
全シグナルをマスクし、タイムアウトしない設定で、ppollをコールすると、ファイル参照をシグナルで処理する。利用が可能かと思います。
なお、pollでもそうでppoll等システムコールでウエイトする機能は、シグナルの実装に行き着くということのようです。
、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(¤t->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等システムコールでウエイトする機能は、シグナルの実装に行き着くということのようです。