У меня есть приложение, которое поддерживает список структур, связанных вместе 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, есть ли способ заблокировать обработчик сигнала, пока другой поток не завершит обновление списка?
Наконец, последний вопрос - при определенных обстоятельствах может потребоваться изменить список (добавить или удалить запись) в обработчике сигналов. Есть ли безопасный способ сделать это?