我有一个维护结构列表的应用程序,由 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 关闭时检测到列表正在被修改,有没有办法阻止信号处理程序,直到另一个线程完成更新列表?
最后一个问题——在某些情况下,可能需要修改信号处理程序中的列表(添加或删除条目)。有没有安全的方法来做到这一点?