2010-11-09 22 views
14

Abbiamo un'applicazione C++ con JVM (Sun) incorporata. Poiché registriamo i nostri gestori di segnale, è consigliabile farlo prima di inizializzare la JVM poiché installa i propri gestori (see here).Concatenamento del segnale JVM SIGPIPE

Da quello che ho capito, la JVM sa internamente se il segnale proviene dal proprio codice e se non lo passa lungo la catena - ai nostri gestori.

quello che abbiamo iniziato a vedere è che stiamo ottenendo SIGPIPEs, con uno stack di chiamate che si presenta più o meno come questo (l'entrata in alto è il nostro gestore di segnale):

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

Sembra che la JVM è decidere che il SIGPIPE che è stato sollevato da send deve essere passato insieme al nostro segnale di blocco. È giusto quando lo fai?

Inoltre, perché lo stack di chiamate è incompleto? Voglio dire ovviamente non può mostrarmi il codice java prima del socketWrite0 ma perché non riesco a vedere lo stack prima del codice java?

+0

Avete installato un gestore di segnale per SIGPIPE? (se sì, sì - è comune ottenere SIGPIPE dalle chiamate send() quando qualcuno scrive su un socket rotto) – nos

+0

So che 'send' può generare SIGPIPE. Sto solo mettendo in discussione la decisione della JVM di trasmetterli a me, perché non solleva un'eccezione? –

+0

Ma non hai installato un gestore per questo? – nos

risposta

7

La JVM non può sapere se SIGPIPE proviene dal proprio codice o dal proprio codice. Questa informazione non è data dal segnale. Perché non vuole che ti perdi tutti gli eventi a cui potresti essere interessato, devi passare tutti SIGPIPE, anche quelli che risulta essere del suo stesso codice.

I segnali di Unix sono disponibili in due versioni: "sincrono" e "asincrono". Alcune condizioni eccezionali quando l'esecuzione del codice può causare trappole e generare segnali "sincroni". Queste sono cose come l'accesso alla memoria non allineato (SIGBUS), l'accesso illegale alla memoria, spesso NULL (SIGSEGV), la divisione per zero e altri errori matematici (SIGFPE), istruzioni indecodificabili (SIGILL) e così via. Questi hanno un preciso contesto di esecuzione e vengono consegnati direttamente al thread che li ha causati. Il gestore del segnale può cercare lo stack e vedere "hey ho avuto un accesso illegale alla memoria che esegue codice java, e il puntatore era un NULL. Lasciami andare a sistemarlo."

Al contrario, i segnali che interagiscono con il mondo esterno sono la varietà "asincrona" e includono elementi come SIGTERM, SIGQUIT, SIGUSR1, ecc. Questi non hanno un contesto di esecuzione fisso. Per i programmi con thread vengono distribuiti in modo casuale a qualsiasi thread. Soprattutto, SIGPIPE è tra questi. Sì, in un certo senso, è normalmente associato a una chiamata di sistema. Ma è del tutto possibile (per esempio) avere due thread che ascoltano due connessioni separate, entrambe le quali si chiudono prima che sia programmato il thread. Il kernel si limita ad assicurarsi che ci sia un SIGPIPE in attesa (la solita implementazione è come una maschera di bit di segnali in attesa), e si occupa di ripianificare qualsiasi thread nel processo. Questo è solo uno dei casi più semplici possibili in cui la JVM potrebbe non avere abbastanza informazioni per escludere che il codice client sia interessato a questo segnale.

(quanto a ciò che accade alle chiamate di lettura, tornano "c'è stato un errore: EINTR". E proseguire sulla A questo punto, la JVM può trasformarla in un'eccezione, ma il ritorno accade dopo il segnale consegna e il gestore del segnale si accende.)

Il risultato è che dovrete solo gestire i falsi positivi. (E si occupano di ottenere solo un segnale in cui due potrebbero essere previsti.)

+0

allora come fa a sapere se tutti gli altri segnali registrati sono venuti dal suo codice? –

+0

Ho gestori di segnale per quasi tutti i segnali, questo è il primo a mostrare un comportamento apparentemente negativo. Inoltre, la JVM è registrata per gestire SIGPIPE, una prova di ciò è il 'JVM_handle_linux_signal' nel callstack - questo documento afferma anche che la JVM cattura SIGPIPE http://www.oracle.com/technetwork/java/javase/signals- 139944.html # gbzbl Esistono situazioni più complesse in cui la JVM semplicemente "sa" se un segnale proviene dal proprio codice, ad es. l'ottimizzazione del puntatore nullo, quindi continuo a non capire il tuo argomento. –

+0

Grazie, la tua spiegazione ha senso ed è più o meno come immaginavo che la JVM decidesse se concatenare o no il segnale. Tuttavia, se si guarda lo stack di chiamate che ho ricevuto nel gestore del segnale, è possibile che JVM esamini lo stack e si accorga che SIGPIPE è originato dal proprio codice, ad esempio vedendo l'indirizzo 'Java_java_net_SocketOutputStream_socketWrite0' nello stack di chiamate . –