yigal_s: (Default)
[personal profile] yigal_s
Уважаемые юникс-гуру! Слушайте, а как в этих ваших Линуксах обрабатывать нарушения обращения к памяти в мультитредной аппликации?

Ну, допустим, я переопределю обработчк сигнала SIGSEGV. Замечу, не для данного треда, а для всего процесса -- иного не дано.

Далее по идее, я где-то должен вызывать в тредах, которые могут навернуться, sigsetjmp. Чтоб туда откатиться, если мой тред подорвется на обращении к памяти. Проблема, однако, в том, что буфер, в который эта информация прописана должен быть ассоциирован с конкретным тредом. Ну ок, сделаю как нибудь. В thread local storage, да?

Теперь, значица, ко мне влетает сигнал, я ловлю его обработчиком, бегу в свой tls.... оп, а разве я могу обращаться к tls из-под обработчика сигнала? Да я даже свой собственный-то tls не напишу, поскольку даже ожидать на семафоре или мютексе не могу под сигналом. Ну и? Только не говорите мне, что в этом случае нужно писать lock-free имплементацию TLS, хорошо?

Спасите, не дайте разочароваться в Линуксах!

Date: 2012-07-20 09:01 pm (UTC)
From: [identity profile] kot-begemot.livejournal.com
Не надо такого писать. Вообще. Если программа лезет в чужую память - она должна умереть.
Если так уж хочется - читай man sigaction и man sigaltstack - там подробно расписано.
Но ты не можешь закладываться на сигналы в принципе - во-первых, тебе не гарантировано, что ты их получишь, во-вторых, они приходят в произвольном контексте.

Date: 2012-07-20 09:32 pm (UTC)
spamsink: (Default)
From: [personal profile] spamsink
Пишут, что SIGSEGV - thread-directed.
http://www.linuxprogrammingblog.com/all-about-linux-signals?page=11

Date: 2012-07-20 09:53 pm (UTC)
spamsink: (Default)
From: [personal profile] spamsink
Из текста это никак не следует ни в какую сторону.

Я не понял, для защиты от кого нам нужно взаимное исключение, если можно просто обойтись массивом, индексируемым gettid().

Date: 2012-07-20 10:29 pm (UTC)
spamsink: (Default)
From: [personal profile] spamsink
Ну массив-то можно и sparse сделать, который модифицируется безопасно. А зачем одному треду лезть в jmp_buf другого, мне невдомек.

gettid(), кстати, как назло не signal-safe.

А вот это, я б сказал, ни фига ж себе. Но как? Это ж просто системный вызов, который всегда успешен.

Date: 2012-07-20 10:51 pm (UTC)
spamsink: (Default)
From: [personal profile] spamsink
Модификация в sparse array безопасна относительно чтения, поскольку мы знаем, что читать можно хотеть только ранее добавленные элементы, а однажды добавленный кусок никогда не перемещается. Опасна лишь одновременная попытка добавления куска, что может случиться при создании тредов, но обработчику сигналов это всё равно.

Date: 2012-07-20 11:28 pm (UTC)
spamsink: (Default)
From: [personal profile] spamsink
Я имею в виду традиционную реализацию "массив {указателей на массив}+". В ней можно даже удалять неиспользуемые куски, страхуясь только от записи.

Date: 2012-07-20 11:42 pm (UTC)
spamsink: (Default)
From: [personal profile] spamsink
"массив {указателей на массив}+" - это регулярное выражение, означающее
массив указателей на массив
или
массив указателей на массив указателей на массив
и т.п.

Обработчик сигнала может бежать только по тем кускам, в которых есть данные для существующих на данный момент тредов. В тот момент, когда мы завершаем тред, который был на тот момент единственным в куске, этот кусок можно удалить, защитившись лишь от создания нового треда в этом же куске, потому что чтения этого куска обработчиком гарантированно не может быть.

Date: 2012-07-21 12:53 am (UTC)
spamsink: (Default)
From: [personal profile] spamsink
Получается, что в подобном дизайне нужно размещать подходящую запись в массив сразу же на старте любого треда

Да, конечно. Я так понимал, что и у Вас между моментом создания треда и sigsetjmp нет никакого прикладного кода.