TAILQ によってリンクされた構造のリストを維持するアプリケーションがあります。各構造体には、ダーティ ビットと、メモリ内の専用の特別なページへのポインターがあります。誰かがこれらのページのいずれかに書き込みを行っているかどうかを知る必要があるためmprotect
、PROT_READ
SEGV が検出されたときにオフになるシグナル ハンドラーをインストールします。
ハンドラーが呼び出されると、アドレスを取得し、リストを調べて、ページのいずれかで segv が発生したかどうかを確認します。発生した場合は、そのページをダーティとしてマークし、mprotect
書き込み可能にします。したがって、次のようになります。
typedef struct _record_t {
void * start_addr;
int dirty;
TAILQ_ENTRY(_record_t)
tailq_entry;
} record_t;
segv_handler(int sig, siginfo_t *si, void *p1) {
void * addr = si->si_addr;
void * addr_page = ROUND_DOWN(addr, page_size);
record_t rec;
TAILQ_FOREACH(rec, g_reclist, tailq_entry) {
if (rec->start_addr == addr_page) {
rec->dirty = 1;
mprotect(addr_btm, page_size, PROT_READ|PROT_WRITE);
return;
}
}
// otherwise call default page handler...
}
シグナル ハンドラ内でリストを安全に処理できるか心配です。別のスレッドが SEGV を生成しているときに、あるスレッドがリストを変更している場合、未定義の動作が発生するのではないかと懸念しています。
スレッドがリストを変更するときにスレッドを徹底的に調べることができ、それが SEGV を生成しないことがわかっている場合、シグナル ハンドラでこのリストをトラバースする安全な方法はありますか? つまり、SEGV がオフになったときにリストが変更されていることを検出した場合、他のスレッドがリストの更新を完了するまでシグナル ハンドラをブロックする方法はありますか?
最後に、最後の質問です。状況によっては、シグナル ハンドラでリストを変更 (エントリの追加または削除) する必要がある場合があります。これを行う安全な方法はありますか?