21

私の理解では、一般に、シグナルハンドラーから非非同期シグナルセーフ関数を呼び出すと、動作は未定義ですが、Linux ではシステムコールを安全に呼び出すことができると聞きました。これは本当ですか?また、SIGSEGV ハンドラーの唯一の移植可能な動作は中止または終了ですが、Linux が実際に戻った場合に実行を再開することは理解しています。

4

3 に答える 3

7

はいといいえ

はい:

シグナル ハンドラー内で任意の実際の/生のシステム コールを呼び出すことができます。カーネルには、(カーネルの観点から)安全であることを保証する責任があります。

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 を呼び出すことができます。 () ...など

于 2012-07-27T08:19:09.200 に答える
6

実際のシステム コールは、シグナル ハンドラから呼び出すことができると思います。真の syscall には<asm/unistd.h>(または<asm/unistd_64.h>) に番号が含まれます。

マニュアルページのセクション 2 の一部の posix 関数は、「多重化」システムコールを介して実装されているため、私の感覚では「真のシステムコール」ではありません。

システム コールは、アプリケーションの観点からはアトミック操作です。これは、(アプリケーション内からの) 1 つの機械語命令のようなものです。この回答を参照してください。

あなたの質問が次の場合:ハンドラーは、または を使用して、エラーのあるアドレス マッピングを変更できますか? SIGSEGVmprotectmmap次に、あなたが引用した質問でここで述べたように、答えはイエスだと思います(少なくともx86-64およびx86-32アーキテクチャでは)が、私は試しませんでした。私はそれを行うことは非常に非効率的であることを読みました(処理はあまり速くなく、または少し遅いです). 特に、この方法を模倣するHurd/Mach 外部ページャーは非効率的である可能性があります。SIGSEGVmprotectmmap

于 2012-07-27T04:38:42.277 に答える