2010-11-09 14 views
14

Mamy aplikację C++ z wbudowanym JVM (Sun's). Ponieważ rejestrujemy własne procedury obsługi sygnałów, zaleca się, abyśmy to zrobili przed zainicjowaniem maszyny JVM, ponieważ instaluje ona własne procedury obsługi (see here).Łańcuch sygnałów JVM SIGPIPE

Z tego co zrozumiałem, JVM zna wewnętrznie, jeśli sygnał pochodzi z własnego kodu, a jeśli nie, przekazuje go wzdłuż łańcucha - naszym handlerom.

Co zaczęliśmy widząc, że jesteśmy coraz SIGPIPEs, ze stosu wywołań, który wygląda mniej więcej tak (górna pozycja jest nasz obsługi sygnału):

/.../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] 

Wydaje się, że JVM jest zdecydować, że SIGPIPE, który został podniesiony z send powinien zostać przekazany do naszego handsera sygnału. Czy to prawda, kiedy to robisz?

Ponadto, dlaczego stos wywołań jest niekompletny? Mam na myśli oczywiście to nie może pokazać mi kod Java przed socketWrite0, ale dlaczego nie widzę stos przed kod Java?

+0

Czy zainstalowałeś program obsługi sygnału dla SIGPIPE? (jeśli tak, to tak - często uzyskuje się SIGPIPE z wywołań send(), gdy ktoś pisze do uszkodzonego gniazda). – nos

+0

Wiem, że 'send' może wywołać SIGPIPE. Po prostu kwestionuję decyzję JVM, aby przekazać mi je, dlaczego nie stanowi wyjątku? –

+0

Ale nie zainstalowałeś dla niego programu obsługi? – nos

Odpowiedz

7

Maszyna JVM nie może stwierdzić, czy SIGPIPE pochodzi z własnego kodu, czy z kodu. Ta informacja nie jest podana przez sygnał. Ponieważ nie chcesz, abyś przegapił wszystkie możliwe wydarzenia, które mogłyby cię zainteresować, musi przekazać ci wszystkie SIGPIPE, nawet te, które okazują się być z własnego kodu.

Sygnały uniksowe występują w dwóch wersjach - "synchronicznej" i "asynchronicznej". Kilka wyjątkowych warunków, kiedy samo wykonywanie kodu może powodować pułapki i skutkować sygnałami "synchronicznymi". Są to takie rzeczy, jak niewydzielony dostęp do pamięci (SIGBUS), niedozwolony dostęp do pamięci, często NULL, (SIGSEGV), dzielenie przez zero i inne błędy matematyczne (SIGFPE), instrukcje nieodnotowalne (SIGILL) i tak dalej. Mają one precyzyjny kontekst wykonania i są dostarczane bezpośrednio do wątku, który je spowodował. Obsługujący sygnał może odszukać stos i zobaczyć "hej, mam niedozwolony dostęp do pamięci wykonujący kod java, a wskaźnik był NULL. Pozwól mi to naprawić."

Natomiast sygnały wchodzące w interakcję ze światem zewnętrznym są odmianą "asynchroniczną" i obejmują takie rzeczy jak SIGTERM, SIGQUIT, SIGUSR1 itd. Nie mają one stałego kontekstu wykonania. W przypadku programów gwintowanych są one dostarczane losowo do dowolnego wątku. Co ważne, wśród nich jest SIGPIPE. Tak, w pewnym sensie jest on zwykle związany z jednym wywołaniem systemowym. Ale jest całkiem możliwe, aby (na przykład) mieć dwa wątki nasłuchujące dwóch oddzielnych połączeń, które zamykają się przed zaplanowaniem wątku. Jądro tylko upewnia się, że SIGPIPE jest w toku (zwykle implementacja jest bitmaską oczekujących sygnałów) i zajmuje się nim przy zmianie harmonogramu dowolnego wątku w procesie. Jest to tylko jeden z prostszych przypadków, w których JVM może nie mieć wystarczającej ilości informacji, aby wykluczyć, że Twój kod klienta jest zainteresowany tym sygnałem.

(Odnosząc się do tego, co dzieje się z wywołaniami odczytu, zwracają "wystąpił błąd: EINTR" i kontynuują, w tym momencie JVM może zmienić to w wyjątek, ale powrót następuje po sygnał dostawa i obsługa nośnika sygnału.)

Skutek polega na tym, że będziesz musiał radzić sobie z fałszywymi pozytywami. (Zajmij się otrzymywaniem tylko jednego sygnału, w którym można oczekiwać dwóch.)

+0

, to skąd wiadomo, czy wszystkie inne sygnały, które zostały zarejestrowane, pochodzą z jej kodu? –

+0

Mam obsługi sygnałów dla prawie każdego sygnału, jest to pierwszy, który pokazuje pozornie złe zachowanie. Ponadto JVM jest zarejestrowana do obsługi SIGPIPE, czego dowodem jest "JVM_handle_linux_signal" w staci wywoławczej - ten dokument również stwierdza, że ​​JVM przechwytuje SIGPIPE http://www.oracle.com/technetwork/java/javase/signals- 139944.html # gbzbl Istnieją bardziej złożone sytuacje, w których JVM po prostu "wie", czy sygnał pochodzi z własnego kodu, np. optymalizacja wskaźnika pustego, więc nadal nie rozumiem twojej argumentacji. –

+0

Dzięki, twoje wyjaśnienie ma sens i jest mniej więcej tym, w jaki sposób wyobrażałem sobie, że JVM podejmuje decyzję o łańcuchu sygnału, czy nie. Ale nadal, jeśli spojrzysz na stos wywołań, który dostałem do mojego programu obsługi sygnału, JVM może w ogóle sprawdzić stos i zdać sobie sprawę, że SIGPIPE pochodzi z własnego kodu, na przykład widząc 'Java_java_net_SocketOutputStream_socketWrite0' adres w stosie wywołań . –