Цепочка сигналов JVM SIGPIPE - PullRequest
       0

Цепочка сигналов JVM SIGPIPE

14 голосов
/ 09 ноября 2010

У нас есть приложение на C ++ со встроенной JVM (Sun). Поскольку мы регистрируем наши собственные обработчики сигналов, рекомендуется сделать это перед инициализацией JVM, поскольку она устанавливает свои собственные обработчики ( см. Здесь ).

Из того, что я понял, JVM внутренне знает, произошел ли сигнал из его собственного кода и, если нет, он передает его по цепочке - нашим обработчикам.

То, что мы начали видеть, это то, что мы получаем SIGPIPE с стеком вызовов, который выглядит примерно так (верхняя запись - наш обработчик сигнала):

/.../libos_independent_utilities.so(_ZN2os32smart_synchronous_signal_handlerEiP7siginfoPv+0x9) [0x2b124f7a3989]
/.../jvm/jre/lib/amd64/server/libjvm.so [0x2aaaab05dc6c]
/.../jvm/jre/lib/amd64/server/libjvm.so [0x2aaaab05bffb]
/.../jvm/jre/lib/amd64/server/libjvm.so(JVM_handle_linux_signal+0x718) [0x2aaaab05e878]
/.../jvm/jre/lib/amd64/server/libjvm.so [0x2aaaab05bf0e]
/lib64/libpthread.so.0 [0x3c2140e4c0]
/lib64/libpthread.so.0(send+0x91) [0x3c2140d841]
/.../jvm/jre/lib/amd64/libnet.so [0x2aaabd360269]
/.../jvm/jre/lib/amd64/libnet.so(Java_java_net_SocketOutputStream_socketWrite0+0xee) [0x2aaabd35cf4e]
[0x2aaaaeb3bf7f]

Кажется, что JVM решает, что SIGPIPE, который был поднят с send, должен быть передан нашему обработчику сигналов. Правильно ли это при этом?

Кроме того, почему стек вызовов неполон? Я имею в виду, очевидно, что он не может показать мне код Java до socketWrite0, но почему я не могу увидеть стек до кода Java?

1 Ответ

7 голосов
/ 10 ноября 2010

JVM не может определить, был ли SIGPIPE взят из собственного кода или вашего кода.Эта информация просто не дается сигналом.Поскольку он не хочет, чтобы вы упускали какие-либо возможные события, которые могут вас заинтересовать, он должен передать вам все SIGPIPE, даже те, которые, как оказалось, были из его собственного кода.

Сигналы Unixбывают двух видов - «синхронный» и «асинхронный».Несколько исключительных условий, когда просто выполнение кода может вызвать ловушки и привести к «синхронным» сигналам.Это такие вещи, как доступ к памяти без выравнивания (SIGBUS), недопустимый доступ к памяти, часто NULL, (SIGSEGV), деление на ноль и другие математические ошибки (SIGFPE), некодируемые инструкции (SIGILL) и так далее.Они имеют точный контекст выполнения и доставляются непосредственно в поток, который их вызвал.Обработчик сигнала может посмотреть в стеке и увидеть: «эй, я получил недопустимый доступ к памяти, выполняя код Java, и указатель был NULL. Позвольте мне исправить это».

В отличие от сигналов, которые взаимодействуютк внешнему миру относятся «асинхронные» разновидности, включающие такие вещи, как SIGTERM, SIGQUIT, SIGUSR1 и т. д. Они не имеют фиксированного контекста выполнения.Для многопоточных программ они доставляются практически произвольно в любой поток.Важно отметить, что SIGPIPE является одним из них.Да, в некотором смысле это обычно связано с одним системным вызовом.Но вполне возможно (например) иметь два потока, слушающих два отдельных соединения, оба из которых закрываются до того, как запланирован какой-либо поток.Ядро просто проверяет наличие ожидающего SIGPIPE (обычная реализация представляет собой битовую маску ожидающих сигналов) и решает эту проблему при перепланировании любого из потоков в процессе.Это только один из более простых случаев, когда JVM может не иметь достаточно информации, чтобы исключить интерес вашего кода клиента к этому сигналу.

(Что касается того, что происходит с вызовами чтения, они возвращают «произошла ошибка: EINTR» и продолжают работу. На этом этапе JVM может превратить это в исключение, но возврат происходит после срабатывает доставка сигнала и обработчик сигнала.)

В результате вам просто придется иметь дело с ложными срабатываниями.(И иметь дело с получением только одного сигнала, где можно было бы ожидать два.)

...