私の理解では、一般に、シグナルハンドラーから非非同期シグナルセーフ関数を呼び出すと、動作は未定義ですが、Linux ではシステムコールを安全に呼び出すことができると聞きました。これは本当ですか?また、SIGSEGV ハンドラーの唯一の移植可能な動作は中止または終了ですが、Linux が実際に戻った場合に実行を再開することは理解しています。
3 に答える
はいといいえ
はい:
シグナル ハンドラー内で任意の実際の/生のシステム コールを呼び出すことができます。カーネルには、(カーネルの観点から)安全であることを保証する責任があります。
1) カーネルはユーザー空間のコンテキストを認識していません。または、シグナルが配信されたときに状態をユーザー空間に保存した後、カーネルが意図的にそれを忘れていると言っています。(注: 実行の再開は、実際にはカーネルによってではなく、保存された状態の助けを借りて syscall を介してユーザーによって行われます。カーネルは既に忘れています)
2) 一部のスレッド lib はシングルを介して実装されているため、スレッドは既に「シグナル ハンドラー」にありますが、これらのスレッドは任意の syscall を呼び出すことができます。
いいえ:
しかし、ユーザー空間関数には独自の目的と副作用があります。一部は再入セーフではなく、これらの関数はシグナル ハンドラから呼び出すことができません。man 7 signal
どれが安全に再入場できるかを調べるのに役立ちます。
sys_futex()
たとえば、シグナル ハンドラを含む任意の場所を呼び出すことができますがsys_futex()
、ミューテックスを実装するために使用するとsys_futex()
、シグナルがミューテックスのクリティカル セクションに割り込むと、内部のシグナル ハンドラが永久にブロックされる可能性があります。
また、SIGSEGV ハンドラーの唯一の移植可能な動作は中止または終了ですが、Linux が実際に戻った場合に実行を再開することは理解しています。
はい、理由がわからない場合は。一部のユーザーは、独自の map-when-demand 目的で SIGSEGV を使用する場合があります (たとえば、JIT では、SIGSEGV シグナル ハンドラーでコードを変換し、変換されたコードをメモリに mmap してから返すことができます)、mmap() または mprotect を呼び出すことができます。 () ...など
実際のシステム コールは、シグナル ハンドラから呼び出すことができると思います。真の syscall には<asm/unistd.h>
(または<asm/unistd_64.h>
) に番号が含まれます。
マニュアルページのセクション 2 の一部の posix 関数は、「多重化」システムコールを介して実装されているため、私の感覚では「真のシステムコール」ではありません。
システム コールは、アプリケーションの観点からはアトミック操作です。これは、(アプリケーション内からの) 1 つの機械語命令のようなものです。この回答を参照してください。
あなたの質問が次の場合:ハンドラーは、または を使用して、エラーのあるアドレス マッピングを変更できますか? SIGSEGV
mprotect
mmap
次に、あなたが引用した質問でここで述べたように、答えはイエスだと思います(少なくともx86-64およびx86-32アーキテクチャでは)が、私は試しませんでした。私はそれを行うことは非常に非効率的であることを読みました(処理はあまり速くなく、または少し遅いです). 特に、この方法を模倣するHurd/Mach 外部ページャーは非効率的である可能性があります。SIGSEGV
mprotect
mmap