23

この質問の内容と同様の点がhereおよびhereの前に提起されており、Google コアダンプ ライブラリを認識しています (これは評価して不足していることがわかりましたが、問題をよりよく理解していればそれに取り組むことができるかもしれません) )。

プロセスを中断することなく、実行中の Linux プロセスのコア ダンプを取得したいと考えています。自然なアプローチは、次のように言うことです。

if (!fork()) { abort(); }

フォークされたプロセスは元のプロセスのメモリの固定スナップショット コピーを取得するため、完全なコア ダンプを取得する必要があります。また、コピーはコピー オン ライトを使用するため、通常はコストがかかりません。ただし、このアプローチの重大な欠点はfork()、現在のスレッドのみをフォークし、元のプロセスの他のすべてのスレッドがフォークされたコピーに存在しないことです。

私の質問は、他の元のスレッドの関連データを何らかの方法で取得できるかどうかです。この問題へのアプローチ方法は完全にはわかりませんが、思いついたいくつかのサブ質問を次に示します。

  1. すべてのスレッドのスタックを含むメモリは、フォークされたプロセスで引き続き使用可能であり、アクセス可能ですか?

  2. 元のプロセスで実行中のすべてのスレッドを (すばやく) 列挙し、それらのスタックのベースのアドレスを保存することは可能ですか? 私が理解しているように、Linux のスレッド スタックのベースには、カーネルのスレッド ブックキーピング データへのポインターが含まれているため、...

  3. 保存されたスレッド ベース アドレスを使用して、フォークされたプロセスの元のスレッドのそれぞれに関連するデータを読み取ることができますか?

それが可能であれば、コア ダンプに他のスレッドのデータを追加するだけでよいでしょう。ただし、そのデータがフォークの時点ですでに失われている場合、このアプローチに希望はないようです。

4

4 に答える 4

13

プロセス checkpoint-restart に精通していますか? 特に、CRIU ? それはあなたにとって簡単なオプションを提供するかもしれないと私には思えます.

プロセスを中断することなく、実行中の Linux プロセスのコア ダンプを取得したいと考えています。

プロセスを中断しないことを忘れてください。考えてみれば、コア ダンプダンプの間、プロセスを中断する必要があります。したがって、あなたの真の目標は、この中断の期間を最小限に抑えることでなければなりません。使用するという最初のアイデアはfork()プロセスを中断しますが、それは非常に短い時間だけです。

  1. すべてのスレッドのスタックを含むメモリは、フォークされたプロセスで引き続き使用可能であり、アクセス可能ですか?

いいえ。fork()実際の呼び出しを行うスレッドのみが保持され、残りのスレッドのスタックは失われます。

CRIUが不適切であると仮定して、私が使用する手順は次のとおりです。

  • 子プロセスが停止するたびに子プロセスのコア ダンプを生成する親プロセスを用意します。(複数の連続した停止イベントが生成される可能性があることに注意してください。次の継続イベントまで、最初の停止イベントのみを処理する必要があります。)

    を使用して停止/継続イベントを検出できますwaitpid(child,,WUNTRACED|WCONTINUED)

  • オプション:sched_setaffinity()プロセスを単一の CPU に制限するために使用し、sched_setscheduler()(おそらくsched_setparam()) プロセスの優先度を に落としますIDLE

    これは、有効なセットと許可されたセットの両方で、機能のみを必要とする親プロセスから実行できます (現在のほとんどの Linux ディストリビューションのようにファイルシステム機能が有効になっている場合は、親バイナリCAP_SYS_NICEを使用して付与できます)。setcap 'cap_sys_nice=pe' parent-binary

    その目的は、スレッドがスナップショット/ダンプが必要であると判断した瞬間から、すべてのスレッドが停止した瞬間までの他のスレッドの進行を最小限に抑えることです。変更が有効になるまでにかかる時間はテストしていません。確かに、変更は現在のタイムスライスの最後にのみ発生します。したがって、このステップはおそらく少し前に行う必要があります。

    個人的には気になりません。私の 4 コア マシンでは、次のSIGSTOP方法だけでもスレッド間でミューテックスやセマフォと同様のレイテンシが得られるため、同期をさらに改善する必要はないと思います。

  • 子プロセス内のスレッドが自身のスナップショットを取得することを決定すると、SIGSTOP( 経由でkill(getpid(), SIGSTOP)) を自身に送信します。これにより、プロセス内のすべてのスレッドが停止します。

    親プロセスは、子プロセスが停止したという通知を受け取ります。最初/proc/PID/task/に、子プロセスの各スレッドの TID (およびおそらく/proc/PID/task/TID/他の情報の疑似ファイル) を取得するために調べ、次に を使用して各 TID にアタッチしptrace(PTRACE_ATTACH, TID)ます。明らかに、スレッドごとのレジスタ状態を取得します。これは、スレッドごとのスタック トレースとptrace(PTRACE_GETREGS, TID, ...)組み合わせて使用​​することで、関心のあるその他の情報を取得できます。 (たとえば、デバッガー互換のコアを作成できます。各スレッドのファイル)。/proc/PID/task/TID/smaps/proc/PID/task/TID/mem

    親プロセスがダンプの取得を完了すると、子プロセスが続行されます。SIGCONTに依存するのではなく、子プロセス全体を継続させるために別のシグナルを送信する必要があると思いますがptrace(PTRACE_CONT, TID)、これを確認していません。これを確認してください。

上記により、プロセスが停止するスレッド間のウォールクロック時間の遅延が最小限になると思います。Xubuntu 上の AMD Athlon II X4 640 と 3.8.0-29-generic カーネルでの簡単なテストでは、他のスレッドで揮発性変数をインクリメントするタイトなループが、スレッドの数に応じてカウンターを数千だけ進めることを示しています (より具体的なことを言うために私が行ったいくつかのテストでのノイズ)。

プロセスを単一の CPU に制限し、さらに IDLE 優先度に制限すると、その遅延がさらに大幅に短縮されます。CAP_SYS_NICEこの機能により、親は子プロセスの優先度を下げるだけでなく、優先度を元のレベルに戻すこともできます。ファイルシステム機能は、親プロセスを setuid にする必要さえなく、それCAP_SYS_NICEだけで十分であることを意味します。(私は、親プログラムでいくつかの適切なチェックがあれば、学生がインストールされたプログラムを悪用する興味深い方法を非常に積極的に見つけている大学のコンピューターなどにインストールしても、十分に安全だと思います。)

ブーストを提供するカーネル パッチ (またはモジュール) を作成してkill(getpid(), SIGSTOP)、実行中の CPU から他のスレッドを開始させようとすることも可能です。これにより、スレッドが停止する間の遅延をさらに小さくしようとします。個人的には、私は気にしません。CPU/優先度の操作がなくても、十分な同期が得られます (スレッドが停止する間の十分な遅延)。

上記の私のアイデアを説明するためのサンプルコードが必要ですか?

于 2013-09-02T21:59:36.970 に答える
2

fork実行中のプロセス メモリの完全なコピーを取得したとき。これには、すべてのスレッドのスタックが含まれます (結局のところ、それらへの有効なポインターを持つことができます)。ただし、呼び出し元のスレッドのみが子で実行を続けます。

これは簡単にテストできます。マルチスレッド プログラムを作成して実行します。

pid_t parent_pid = getpid();

if (!fork()) {
    kill(parent_pid, SIGSTOP);

    char buffer[0x1000];

    pid_t child_pid = getpid();
    sprintf(buffer, "diff /proc/%d/maps /proc/%d/maps", parent_pid, child_pid);

    system(buffer);

    kill(parent_pid, SIGTERM);

    return 0;
} else for (;;);

したがって、すべてのメモリがそこにあり、コア ダンプを作成すると、他のすべてのスレッド スタックが含まれます (コア ファイルの最大サイズが許す限り)。欠落する唯一の部分は、レジスタ セットです。それらが必要な場合はptrace、親に入手してもらう必要があります。

ただし、コア ダンプは複数のスレッド (コア ダンプの原因となったスレッド) の実行時情報を含むようには設計されていないことに注意してください。

他のいくつかの質問に答えるには:

を通じてスレッドを列挙することはでき/proc/[pid]/tasksますが、それらのスタック ベースを特定するまでは識別できませんptrace

はい、フォークされたプロセスから他のスレッド スタック スナップショット (上記を参照) に完全にアクセスできます。それらを特定するのは簡単ではありませんが、コア ファイルのサイズが許せばコア ダンプに入れられます。最善の策は、作成時に可能であれば、それらをグローバルにアクセス可能な構造に保存することです。

于 2013-09-02T17:13:13.770 に答える
1

非特定の場所でコア ファイルを取得するつもりで、強制終了せずに実行中のプロセスのコア イメージを取得する場合は、gcoreを使用できます。

特定の場所 (条件) でコア ファイルを取得し、プロセスの実行を継続する場合、その場所からgcoreをプログラムで実行するのが大雑把な方法です。

より古典的でクリーンなアプローチは、gcore が使用する API をチェックしてそれをアプリケーションに組み込むことですが、ほとんどの場合、その必要性に比べて労力がかかりすぎます。

チッ!

于 2013-08-28T13:28:04.310 に答える