シグナルハンドラから非同期シグナルセーフ関数を呼び出すと、一般的にその動作は定義されていませんが、linuxがシステムコールを安全に呼び出すことができると聞きました。これは本当ですか?また、SIGSEGVハンドラの唯一の移植可能な振る舞いは、中止または終了することですが、あなたが本当に戻るとlinuxが実際に実行を再開することは分かりますか? section 2 signal
manualによるとlinuxはシグナルハンドラからのシステムコールを許可していますか?
答えて
実際のシステムコールはシグナルハンドラから呼び出すことができます。真のシステムコールの番号は<asm/unistd.h>
(または<asm/unistd_64.h>
)です。
システムコールは、の点からアトミック操作でmanページのセクション2から
いくつかのPOSIXの機能は、「多重化」システムコールスルー実装されているので、彼らは私の意味での「真のシステムコール」ではありませんアプリケーションのビュー。それは(アプリケーションの内部から)単一の機械命令に似ています。 this answerを参照してください。
あなたの質問の場合:SIGSEGV
ハンドラがmprotect
またはmmap
スルー不良アドレスのマッピングを変更できますか?私は答えがはい(少なくともx86-64 & x86-32のアーキテクチャで)、あなたが引用した質問のsaid hereと信じていますが、私は試していませんでした。私はそれが非常に非効率的であることを読んだ(SIGSEGV
処理は非常に高速ではなく、mprotect
またはmmap
も少し遅いです)。特に、この方法を模倣すると、Hurd/Mach external pagersが非効率的になることがあります。
システムコールは、一種のアトミックですが、呼び出された場所またはシグナルハンドラにユーザーコードに制御を戻すことができます。通常の振る舞いは、シグナルハンドラが何かをしてから復帰した後、中断されたシステムコールがEINTRを返します。 (そして、glibcはそれを再び呼び出すことができると思います。)シグナルハンドラの内部からシステムコールを行うと、OSはあなたが完了するまで信号を待ちます。あるいは、保証された安全なリストにないシステムコールを呼び出すと、何か変なことがあります。 –
Linus自身が書いたツリー内の文書を見ると、私はそれを信じます! :-) –
:
は 安全にシグナルハンドラ内から呼び出すことができる非同期シグナルセーフ機能のリストについては、(7)信号を参照してください。私はこの情報がより信頼できると信じてい
非同期シグナル安全機能
A signal handler function must be very careful, since processing elsewhere may be interrupted at some arbitrary point in the execution of the program. POSIX has the concept of "safe function". If a signal interrupts the execution of an unsafe function, and handler calls an unsafe function, then the behavior of the program is undefined. POSIX.1-2004 (also known as POSIX.1-2001 Technical Corrigendum 2) requires an implementation to guarantee that the following functions can be safely called inside a signal handler: _Exit() _exit() abort() accept() access() aio_error() aio_return() aio_suspend() alarm() bind() cfgetispeed() cfgetospeed() cfsetispeed() cfsetospeed() chdir() chmod() chown() clock_gettime() close() connect() creat() dup() dup2() execle() execve() fchmod() fchown() fcntl() fdatasync() fork() fpathconf() fstat() fsync() ftruncate() getegid() geteuid() getgid() getgroups() getpeername() getpgrp() getpid() getppid() getsockname() getsockopt() getuid() kill() link() listen() lseek() lstat() mkdir() mkfifo() open() pathconf() pause() pipe() poll() posix_trace_event() pselect() raise() read() readlink() recv() recvfrom() recvmsg() rename() rmdir() select() sem_post() send() sendmsg() sendto() setgid() setpgid() setsid() setsockopt() setuid() shutdown() sigaction() sigaddset() sigdelset() sigemptyset() sigfillset() sigismember() signal() sigpause() sigpending() sigprocmask() sigqueue() sigset() sigsuspend() sleep() sockatmark() socket() socketpair() stat() symlink() sysconf() tcdrain() tcflow() tcflush() tcgetattr() tcgetpgrp() tcsendbreak() tcsetattr() tcsetpgrp() time() timer_getoverrun() timer_gettime() timer_settime() times() umask() uname() unlink() utime() wait() waitpid() write() POSIX.1-2008 removes fpathconf(), pathconf(), and sysconf() from the above list, and adds the following functions: execl() execv() faccessat() fchmodat() fchownat() fexecve() fstatat() futimens() linkat() mkdirat() mkfifoat() mknod() mknodat() openat() readlinkat() renameat() symlinkat() unlinkat() utimensat() utimes()
:以下の機能および/またはシステムはかなり明確な説明と一緒に呼び出します
とsection 7 signals
manualリストどこかで時々聞くもの。したがって、Linuxではシステムコールの一部しか許可されませんが、それらのすべてが許可されるわけではありません。あなたの質問に対する答えは単純に - いいえです。
これは、Linuxではなくposixと思われるでしょう。私はlinuxがposixに準拠していることを知っていますので、少なくともそれらの関数が安全であることを意味するようにしました。これ以上のもの(特にmprotect)があるかどうかを理解したいと思います。 –
@gct:これはLinux固有のマニュアルページです。これは、ソースコードを見てから得られる最も正確なものです。ソースコードを調べてより良い分析をしたいと思ったら... –
@gct:BTW、この制限のないシグナルを扱うより良い方法があります - あなたは 'epoll'を'signalfd'です。その後、ハンドラで何でもできます。http://www.kernel.org/doc/man-pages/online/pages/man2/signalfd.2.html –
はいおよびNO
はい:
あなたはシグナルハンドラ内の任意の生/本物のシステムコールを呼び出すことができます。カーネルは、(カーネルの観点から)安全であることを保証する責任があります。
1)カーネルは、ユーザー空間のコンテキストを知らない、またはシグナルを配信するときに状態をユーザー空間に保存した後、カーネルが故意にそれを忘れると言う。 (注:実行再開は、保存された状態の助けを借りて、実際にはカーネルではなく、カーネルが忘れてしまった状態で、システムコール経由で実行されます)2)スレッドlibはシングルスレッドで実装されています。すでに "シグナルハンドラ"にありますが、これらのスレッドはすべてのシステムコールを呼び出すことができます。
いいえ:
しかし、ユーザースペース関数には独自の目的と副作用があります。一部はre-entrance safeではないため、これらの関数はシグナルハンドラから呼び出すことはできません。 man 7 signal
は、再入場が安全なものを見つけるのに役立ちます。
は例を見てください、あなたは、シグナルハンドラを含むsys_futex()
どこでも呼び出すことができますが、ミューテックスを実装するためにsys_futex()
を使用する場合、信号は、ミューテックスのクリティカルセクションを中断したときに、シグナルハンドラ内sys_futex()
は永遠にブロックされたことがあります。
また、SIGSEGVハンドラのための唯一のポータブル動作が終了を中止または することですが、私はあなた リターン場合、Linuxは実際に本当、実行を再開します理解できますか?
はい、理由がわからない場合は、あるユーザがSIGSEGVを独自のマップ・オン・デマンドの目的で使うことができます(例えば、JITではSIGSEGVシグナル・ハンドラのコードを翻訳し、翻訳されたコードをメモリにmmapして戻すことができます)、mmap()やmprotect ()...など。
"シグナルハンドラ内で実際の/未処理のシステムコールを呼び出すことができます。"その要求をサポートするためのリソース(カーネルのドキュメント、コメントなど)がありますか? –
あなたはそれについて聞いたことがありますか? – moooeeeep
具体的には、この質問への答え:http://stackoverflow.com/questions/2663456/write-a-signal-handler-to-catch-sigsegv –
タイトルに「生システムコール」という言葉を付け加えてください。 - ) –