2015-02-06 40 views
5

Znalazłem problem polegający na tym, że biblioteka współdzielona, ​​która jest wywoływana z JNA pod pomostem, utknęła podczas drukowania na stderr.Współużytkowana biblioteka C (JNI) zawiesza się pod pomostem podczas pisania na stderr

Uprościliśmy problem, aby ułatwić jego odtworzenie, tworząc najpierw bardzo prostą bibliotekę współdzieloną C, która nie wywołuje niczego więcej niż wywołanie fprintf(stderr,"\n"); 100 razy, a następnie wraca.

Po stronie java mamy instrukcję synchronizacji na globalnej blokadzie, aby zapewnić, że tylko jeden wątek znajduje się w bibliotece współdzielonej na raz.

synchronized (lock) { 
    Foo.INSTANCE.shared_lib_function(); 
} 

wdrożyć to pod molo i uczynić stałe wnioski o dopuszczenie do molo zadzwonić do biblioteki współdzielonej ostatecznie (po mniej niż 100 wniosków) Uważam, że wspólna biblioteka utknie.

Korzystanie jstack widzimy nić które utknęło zaproszenia do wspólnej biblioteki (zajęcia zostały zmienione):

Thread 5991: (state = BLOCKED) 
- com.whats.going.on.connector.MyFooCaller.callIt() @bci=55, line=105 (Interpreted frame) 
- com.whats.going.on.Controller.callSharedLib() @bci=101, line=71 (Interpreted frame) 
- com.whats.going.on.Controller$$FastClassBySpringCGLIB$$d6a0f4b3.invoke(int, java.lang.Object, java.lang.Object[]) @bci=72 (Interpreted frame) 
- org.springframework.cglib.proxy.MethodProxy.invoke(java.lang.Object, java.lang.Object[]) @bci=19, line=204 (Interpreted frame) 
- org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint() @bci=19, line=717 (Interpreted frame) 
- org.springframework.aop.framework.ReflectiveMethodInvocation.proceed() @bci=19, line=157 (Interpreted frame) 
- org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(org.aopalliance.intercept.MethodInvocation) @bci=7, line=64 (Interpreted frame) 
- org.springframework.aop.framework.ReflectiveMethodInvocation.proceed() @bci=101, line=179 (Interpreted frame) 
- org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(java.lang.Object, java.lang.reflect.Method, java.lang.Object[], org.springframework.cglib.proxy.MethodProxy) @bci=112, line=653 (Interpreted frame) 

Korzystanie gdb jestem w stanie uzyskać ślad od wewnątrz mojego udostępnionej biblioteki:

#0 0x00007f1136ec153d in write() from /lib64/libc.so.6 
#1 0x00007f1136e57ad3 in _IO_new_file_write() from /lib64/libc.so.6 
#2 0x00007f1136e5799a in _IO_new_file_xsputn() from /lib64/libc.so.6 
#3 0x00007f1136e4da4d in fwrite() from /lib64/libc.so.6 
#4 0x00007f10ed2dc122 in shared_lib_function() at foo/bar.c:357 
#5 0x00007f10ed4d227c in ??() 
#6 0x000000000000000e in ??() 
#7 0x00007f110c2309c0 in ??() 
#8 0x00007f110c230700 in ??() 
#9 0x00007f10ed4d1ddf in ??() 
#10 0x0000000000000000 in ??() 

linia 357 to linia fprintf().

Obawiałem się, że być może problemem było coś, co utknęło tylko przy gotowaniu od stdouta i nigdy nie stderr. W java utworzyłem wątek, który kontynuuje drukowanie do stdout i stderr i widzę oba.

Próbowałem również zobaczyć, co się stanie, jeśli wykonamy 100 wywołań do System.err.println(""); w java i, jednak nie spowodowało to zablokowania wątku w java.

Początkowo podczas logowania to stderr i stdout został przekierowany z:

PrintStream errorLog = new PrintStream(new RolloverFileOutputStream(new Fil("yyyy_mm_dd.error.log").getCanonicalPath(), false, 90)); 
System.setErr(errorLog); 
System.setOut(errorLog); 

udało mi się zobaczyć, co wspólne lib było pisanie na stderr w pliku dziennika. Następnie usunąłem przekierowanie stderr i stdout i zauważyłem, że nie widzę już, co pisząca biblioteka współdzieliła na stderr, ale widziałem, że drukował się System.err.println().

Kiedy próbowałem wywoływać bibliotekę współdzieloną w ramach testu (bez pomostu), nie mogłem odtworzyć problemu. Przeprowadziłem mój test od zaćmienia i maven. Próbowałem też przekierować stderr i stdout jak wyżej, jednak odkryłem, że tylko zapisywanie do stderr i stdout w java zostało przekierowane (to jest fprintf(), aby stderr z wewnątrz wspólnej biblioteki nadal pojawiał się w czasie zaćmienia lub w konsoli).

wersja Java:

java version "1.8.0_25" 
Java(TM) SE Runtime Environment (build 1.8.0_25-b17) 
Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode) 

wersja Jetty: 9.2.6.v20141205

+0

JNA udostępnia ['Native.synchronizedLibrary()'] (http://twall.github.io/jna/4.1.0/com/sun/jna/Native.html#synchronizedLibrary (com.sun.jna.Library))) w celu ograniczenia dostępu do biblioteki natywnej do pojedynczego połączenia w danym momencie. – technomage

Odpowiedz

0

Problem miałem był YAJSW czytał tylko z System.out molo i System.err jeszcze nieczytanie ze standardowej biblioteki lub stderra, które mogłyby zostać wypełnione, gdyby wystąpił jakiś błąd.

Rozwiązaniem było ustawić wrapper.console.pipestreams = true, zobacz http://yajsw.sourceforge.net/YAJSW%20Configuration%20Parameters.html

Przekierowywanie stdout i stderr z freopen nie działa w tym czasie. Dzięki za pomoc.

0

pisanie na stderr z JNI, nie zagra miło z większością ram rejestrowania java.

Wariant nr 1: Java Side Fix

Co trzeba zrobić:

  • Nie używaj domyślnego modułu rejestrowania molo w
  • Nie używaj realizację molo w StdErrLog
  • Skonfiguruj alternatywny framework rejestrowania. zacznij od slf4j i skonfiguruj go tak, aby używał czegoś takiego jak logback lub log4j.
  • Skonfiguruj alternatywną strukturę logowania, aby NIE przechwytywać STDERR.
  • Skonfiguruj alternatywną strukturę logowania, aby NIE zapisywać do STDERR, tylko zapisuj w pliku dziennika.

Option # 2: JNI Side Fix

Innym rozwiązaniem jest napisanie kodu JNI aby nigdy wyjście do standardowego STDERR lub STDOUT strumieni. Ale zamiast tego uzyskaj odwołania do plików referencyjnych do Java System.err i System.out i napisz do nich.

Przykładem, który można znaleźć w grupie comp.lang.java.programmer na

https://groups.google.com/forum/#!msg/comp.lang.java.programmer/SUN7EEjk8AU/JWjGGaD0ey0J

+0

Joakim jest "Pisanie do STDERR z JNI, nie będzie grać z większością ram logowania Java" znany problem? Czy to zostało zgłoszone? – Luke