Ходьба TAILQ в обработчике сигналов - PullRequest
1 голос
/ 13 июня 2019

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

Наконец, последний вопрос - при определенных обстоятельствах может потребоваться изменить список (добавить или удалить запись) в обработчике сигналов. Есть ли безопасный способ сделать это?

1 Ответ

1 голос
/ 14 июня 2019

Я вижу 2 возможных решения:

1. signalfd (2)

Используйте signalfd(2) и считывайте из дескриптора файла signalfd из вашего основного потока.

Это решение позволит вам явно проверять и обрабатывать сигнал SEGV, чтобы вы могли быть уверены, что связанный список не изменяется одновременно.

2. Связанный список без блокировки

Измените свой связанный список на реализацию без блокировки, чтобы он был безопасен для сигналов. Связанные списки без блокировок и Пропуск списков описывает один из возможных подходов.

...