Уважаемые юникс-гуру! Слушайте, а как в этих ваших Линуксах обрабатывать нарушения обращения к памяти в мультитредной аппликации?
Ну, допустим, я переопределю обработчк сигнала SIGSEGV. Замечу, не для данного треда, а для всего процесса -- иного не дано.
Далее по идее, я где-то должен вызывать в тредах, которые могут навернуться, sigsetjmp. Чтоб туда откатиться, если мой тред подорвется на обращении к памяти. Проблема, однако, в том, что буфер, в который эта информация прописана должен быть ассоциирован с конкретным тредом. Ну ок, сделаю как нибудь. В thread local storage, да?
Теперь, значица, ко мне влетает сигнал, я ловлю его обработчиком, бегу в свой tls.... оп, а разве я могу обращаться к tls из-под обработчика сигнала? Да я даже свой собственный-то tls не напишу, поскольку даже ожидать на семафоре или мютексе не могу под сигналом. Ну и? Только не говорите мне, что в этом случае нужно писать lock-free имплементацию TLS, хорошо?
Спасите, не дайте разочароваться в Линуксах!
Ну, допустим, я переопределю обработчк сигнала SIGSEGV. Замечу, не для данного треда, а для всего процесса -- иного не дано.
Далее по идее, я где-то должен вызывать в тредах, которые могут навернуться, sigsetjmp. Чтоб туда откатиться, если мой тред подорвется на обращении к памяти. Проблема, однако, в том, что буфер, в который эта информация прописана должен быть ассоциирован с конкретным тредом. Ну ок, сделаю как нибудь. В thread local storage, да?
Теперь, значица, ко мне влетает сигнал, я ловлю его обработчиком, бегу в свой tls.... оп, а разве я могу обращаться к tls из-под обработчика сигнала? Да я даже свой собственный-то tls не напишу, поскольку даже ожидать на семафоре или мютексе не могу под сигналом. Ну и? Только не говорите мне, что в этом случае нужно писать lock-free имплементацию TLS, хорошо?
Спасите, не дайте разочароваться в Линуксах!
no subject
Date: 2012-07-20 09:01 pm (UTC)Если так уж хочется - читай man sigaction и man sigaltstack - там подробно расписано.
Но ты не можешь закладываться на сигналы в принципе - во-первых, тебе не гарантировано, что ты их получишь, во-вторых, они приходят в произвольном контексте.
no subject
Date: 2012-07-20 09:15 pm (UTC)ну у меня-то, очевидно, обратные совершенно резоны
* Если так уж хочется - читай man sigaction и man sigaltstack - там подробно расписано.
а чего там расписано-то? Так и так мне нужна какая-то структура обработки сигналов привязанная к треду. Или хотя бы структура tls-data. А с этим-то и затык.
Сигнал SIGSEGV я собираюсь получить ровно в том же контексте, что его и спровоцировал. Как же иначе-то?
no subject
Date: 2012-07-20 09:26 pm (UTC)Буду писать lock-free контейнер под обработчик сигнала.
Похоже, других вариантов в этом вашем линухе вообще НЕТУ!!!
А меж прочим, в мелкософте это делается самым обычным SEH-ом, доступным практически выпускнику ПТУ )))
no subject
Date: 2012-07-20 09:32 pm (UTC)http://www.linuxprogrammingblog.com/all-about-linux-signals?page=11
no subject
Date: 2012-07-20 09:44 pm (UTC)no subject
Date: 2012-07-20 09:53 pm (UTC)Я не понял, для защиты от кого нам нужно взаимное исключение, если можно просто обойтись массивом, индексируемым gettid().
no subject
Date: 2012-07-20 10:17 pm (UTC)Взаимное исключение нужно для того, чтобы не вышло, что один тред будет модифицировать наш контейнер, а другой в это время в нем что-то искать.
gettid(), кстати, как назло не signal-safe.
короче, it sucks, в смысле, Линух
no subject
Date: 2012-07-20 10:29 pm (UTC)gettid(), кстати, как назло не signal-safe.
А вот это, я б сказал, ни фига ж себе. Но как? Это ж просто системный вызов, который всегда успешен.
no subject
Date: 2012-07-20 10:34 pm (UTC)упс. а какую ж структуру данных подогнать, чтоб безопасно модифицировать?
Я-то лично уже остановился на идее сделать массив из 20 элементов и поставить семафор на 20, чтобы позволить не более 20 тредам одновременно делать опасные операции. Скромно и надёжно.
Но вот чтоб sparse array? Как это?
no subject
Date: 2012-07-20 10:51 pm (UTC)no subject
Date: 2012-07-20 11:12 pm (UTC)Я вообще осознал, что нельзя удалять куски подобной структуры данных, т.е. если какая-то ячейка не нужна, то нужно её обнулить, но никак не удалять.
Ну, в общем, получается, что можно это всё сделать, так или иначе.
no subject
Date: 2012-07-20 11:28 pm (UTC)no subject
Date: 2012-07-20 11:35 pm (UTC)я не совсем понимаю эту нотацию
Удалять неиспользуемые куски нельзя, поскольку в момент удаления по ним может бежать обработчик сигнала.
Расширять? Можно, наверное. Но так даже linked-list можно написать, в котором запретить удалять элементы, а позволить их только обнулять. И вроде, всё должно сработать.
no subject
Date: 2012-07-20 11:42 pm (UTC)массив указателей на массив
или
массив указателей на массив указателей на массив
и т.п.
Обработчик сигнала может бежать только по тем кускам, в которых есть данные для существующих на данный момент тредов. В тот момент, когда мы завершаем тред, который был на тот момент единственным в куске, этот кусок можно удалить, защитившись лишь от создания нового треда в этом же куске, потому что чтения этого куска обработчиком гарантированно не может быть.
no subject
Date: 2012-07-21 12:02 am (UTC)Если за это время тред нечаянно словит SIGSEGV (из-за ошибки в прикладном коде, а не из-за "осознанной" попытки прочитать проблемную память), то он таки полезет в эту структуру, и если в этот момент она будет модифицироваться, может случиться SIGSEGV уже в обработчике сигнала.
Получается, что в подобном дизайне нужно размещать подходящую запись в массив сразу же на старте любого треда а отписываться только при окончании треда. Тогда это будет работать, если пренебречь вероятностью того, что SIGSEGV проскочит всё же до того, как мы впишемся в таблицу.
no subject
Date: 2012-07-21 12:53 am (UTC)Да, конечно. Я так понимал, что и у Вас между моментом создания треда и sigsetjmp нет никакого прикладного кода.
no subject
Date: 2012-07-21 12:55 am (UTC)я предполагаю ставить sigsetjmp на тот краткий промежуток, когда я выполняю серию опасных операций. В остальных случаях он будет снят, а программа в случае SIGSEGV закрэшена.