3

ユーザーが任意のタイプの変数を検査できる新しいスレッドを起動するコマンドを定義する GDB python 拡張機能を開発しようとしています。私のpython拡張のスケルトンはこれです:

import gdb
import threading

def plot_thread():
    import time
    while True:
        print('Placeholder for a window event loop.')
        time.sleep(1)
        pass
    pass

class PlotterCommand(gdb.Command):
    def __init__(self):
        super(PlotterCommand, self).__init__("plot",
                                            gdb.COMMAND_DATA,
                                            gdb.COMPLETE_SYMBOL)
        self.dont_repeat()
        pass

    def invoke(self, arg, from_tty):
        plot_thread_instance=threading.Thread(target=plot_thread)
        plot_thread_instance.daemon=True
        plot_thread_instance.start()
        pass

    pass

PlotterCommand()

ご覧のとおり、ここでプロットコマンドを定義します。次のプログラムをデバッグしようとすると、次の場合に GDB がハングします。

  1. procedure() スレッド内の任意の場所にブレークポイントを配置します (たとえば、while ループ内の 9 行目)。
  2. gdb がブレークポイントに到達したら、コマンドplotを実行します。
  3. その後、実行を続けます。
#include <iostream>
#include <thread>

using namespace std;

void procedure() {
    cout << "before loop"<<endl;
    while(1) {
        cout << "loop iteration"<<endl;
    }
}

int main() {
    thread t(procedure);
    t.join();
    return 0;
}

最も奇妙なことは、このコードをスレッドを起動せずにprocedure()を呼び出すように変更すると、GDB が決してハングしないことです (そして、プレースホルダー メッセージは期待どおりに出力されます)。

これまでのところ、GDB バージョン 7.5.1 および 7.10 でこの手順を実行しようとしましたが、常に同じ動作が発生します。

私は何を間違っていますか?デーモン スレッドは GDB でサポートされていませんか? それは、ドキュメントのセクション 23.2.2.1が示唆していることと一致していないようです。

4

1 に答える 1

3

このブログ投稿から:

GDB は、この関数(sigsuspend、GDB がハングする関数)を使用して、アプリケーション実行からの新しいイベントを待ちます。デバッグ対象で何かが発生すると (デバッガーの動作を参照)、カーネルは SIGCHLD シグナルを送信して GDB に通知します。受信すると、GDB が起動し、何が起こったかを確認します。

ただし、シグナルは GDB プロセスに配信されますが、必ずしもそのメイン スレッドには配信されません。そして実際には、それを気にしない 2 番目のスレッドに配信され (これがデフォルトの動作です)、何も起こらなかったかのように存続することがよくあります。

解決策は、GDB メイン スレッドのみがこれらのシグナルによって通知されるように、スレッド シグナル処理動作を構成することです。

import gdb
import threading
import pysigset, signal # Import these packages!

def plot_thread():
    import time
    while True:
        print('Placeholder for a window event loop.')
        time.sleep(1)
        pass
    pass

class PlotterCommand(gdb.Command):
    def __init__(self):
        super(PlotterCommand, self).__init__("plot",
                                            gdb.COMMAND_DATA,
                                            gdb.COMPLETE_SYMBOL)
        self.dont_repeat()
        pass

    def invoke(self, arg, from_tty):
        with pysigset.suspended_signals(signal.SIGCHLD): # Disable signals here!
            plot_thread_instance=threading.Thread(target=plot_thread)
            plot_thread_instance.daemon=True
            plot_thread_instance.start()
            pass
        pass

    pass

PlotterCommand()

pysigsetパッケージが必要で、pip からインストールできます (sudo pip install pysigset)。

于 2015-11-02T19:27:29.433 に答える