2016-08-24 24 views
6

Próbuję połączyć się z kamerą Basler USB3 z aplikacji Haskell, ale mam pewne trudności. Aparat jest wyposażony w bibliotekę C++, która sprawia, że ​​jest dość prosta. Poniższy kod może być użyty do nabycia źródło kamery:Wywołanie współdzielonej biblioteki z Haskell za pośrednictwem bloków FFI, podczas gdy nie jest, gdy jest połączony z programem C

extern "C" { 
    void basler_init() { 
    PylonAutoInitTerm pylon; 
    CInstantCamera camera(CTlFactory::GetInstance().CreateFirstDevice()); 
    camera.RegisterConfiguration((CConfigurationEventHandler*) NULL, RegistrationMode_ReplaceAll, Cleanup_None); 
    cout << "Using device " << camera.GetDeviceInfo().GetModelName() << endl; 
    } 
} 

Mam używany ten kod źródłowy do budowy biblioteki współdzielonej - libbasler.so. Aby potwierdzić, że działa, tutaj jest podstawowy program C, która łączy przeciwko niemu i potwierdza wszystko działa:

void basler_init(); 

int main() { 
    basler_init(); 
} 

skompilować i uruchomić to jako:

$ gcc Test2.c -lbasler -Llib -Wl,--enable-new-dtags -Wl,-rpath,pylon5/lib64 -Wl,-E -lpylonbase -o Test2-c 

$ PYLON_CAMEMU=1 LD_LIBRARY_PATH=lib ./Test2-c 
Using device Emulation 

Jest to oczekiwany wynik.

Jednak gdy spróbuję użyć tego z Haskellem, zachowanie się zmienia i program blokuje się w nieskończoność. Oto kod źródłowy Haskell:

{-# LANGUAGE ForeignFunctionInterface #-} 

foreign import ccall "basler_init" baslerInit :: IO() 

main :: IO() 
main = baslerInit 

skompilować i uruchomić to jako:

$ ghc --make Test2.hs -o Test2-haskell -Llib -lbasler -optl-Wl,--enable-new-dtags -optl-Wl,-rpath,pylon5/lib64 -optl-Wl,-E -lpylonbase 

$ PYLON_CAMEMU=1 LD_LIBRARY_PATH=lib ./Test2-haskell 

Aplikacja teraz wisi w nieskończoność.

Przebiegłem przez strace, aby spróbować zorientować się, co się dzieje, ale nie jestem w stanie tego zrozumieć. Wyjście jest zbyt długi, aby dodać tutaj, ale proszę zobaczyć te dwie pasty:

na szczycie to, użyłem gdb, aby spróbować ustalić, gdzie aplikacja Haskell utknęła:

$ PYLON_CAMEMU=1 LD_LIBRARY_PATH=lib gdb Test2-haskell 
GNU gdb (GDB) 7.11 
Copyright (C) 2016 Free Software Foundation, Inc. 
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> 
This is free software: you are free to change and redistribute it. 
There is NO WARRANTY, to the extent permitted by law. Type "show copying" 
and "show warranty" for details. 
This GDB was configured as "x86_64-pc-linux-gnu". 
Type "show configuration" for configuration details. 
For bug reporting instructions, please see: 
<http://www.gnu.org/software/gdb/bugs/>. 
Find the GDB manual and other documentation resources online at: 
<http://www.gnu.org/software/gdb/documentation/>. 
For help, type "help". 
Type "apropos word" to search for commands related to "word"... 
Reading symbols from Test2-haskell...done. 
(gdb) run 
Starting program: /home/ollie/work/circuithub/receiving-station/Test2-haskell 
warning: File "/nix/store/9ljgbhb26ca0j9shwh8bwsa77h42izr2-gcc-5.4.0-lib/lib/libstdc++.so.6.0.21-gdb.py" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load". 
To enable execution of this file add 
     add-auto-load-safe-path /nix/store/9ljgbhb26ca0j9shwh8bwsa77h42izr2-gcc-5.4.0-lib/lib/libstdc++.so.6.0.21-gdb.py 
line to your configuration file "/home/ollie/.gdbinit". 
To completely disable this security protection add 
     set auto-load safe-path/
line to your configuration file "/home/ollie/.gdbinit". 
For more information about this security protection see the 
"Auto-loading safe path" section in the GDB manual. E.g., run from the shell: 
     info "(gdb)Auto-loading safe path" 
[Thread debugging using libthread_db enabled] 
Using host libthread_db library "/nix/store/bb32xf954imhdrzn7j8h82xs1bx7p3fr-glibc-2.23/lib/libthread_db.so.1". 
^C 
Program received signal SIGINT, Interrupt. 
0x00007ffff6c6fb33 in __recvfrom_nocancel() from /nix/store/98s2znxww6x7h2ch7cj1w5givahxmdna-glibc-2.23/lib/libc.so.6 
(gdb) bt 
#0 0x00007ffff6c6fb33 in __recvfrom_nocancel() from /nix/store/98s2znxww6x7h2ch7cj1w5givahxmdna-glibc-2.23/lib/libc.so.6 
#1 0x00007fffedb885c2 in GxImp::CEnumCollector::OnReady(unsigned int, _GX_SOCKET_INTERFACE_INFO const*)() from /home/ollie/work/circuithub/receiving-station/pylon5/lib64/libgxapi-5.0.1.so 
#2 0x00007fffedb8d54d in CCollector::Collect(GxImp::CSocket*, unsigned int, unsigned int, _GX_SOCKET_INTERFACE_INFO const*)() from /home/ollie/work/circuithub/receiving-station/pylon5/lib64/libgxapi-5.0.1.so 
#3 0x00007fffedb8817b in CBroadcastSocketCollection::Collect(CCollector&, unsigned int)() from /home/ollie/work/circuithub/receiving-station/pylon5/lib64/libgxapi-5.0.1.so 
#4 0x00007fffedb889ab in Gx::Enumerator::Discover(Gx::Enumerator::Callee*, unsigned int, unsigned int, sockaddr const*)() from /home/ollie/work/circuithub/receiving-station/pylon5/lib64/libgxapi-5.0.1.so 
#5 0x00007fffeddeaca0 in Pylon::CBaslerGigETl::DoDeviceEnumeration(Pylon::DeviceInfoList&, bool, sockaddr const*)() from pylon5/lib64/libpylon_TL_gige-5.0.1.so 
#6 0x00007fffeddeaebc in Pylon::CBaslerGigETl::InternalEnumerateDevices(Pylon::DeviceInfoList&)() from pylon5/lib64/libpylon_TL_gige-5.0.1.so 
#7 0x00007fffeddf3c99 in Pylon::CTransportLayerBase<Pylon::IGigETransportLayer>::EnumerateDevices(Pylon::DeviceInfoList&, Pylon::DeviceInfoList const&, bool)() from pylon5/lib64/libpylon_TL_gige-5.0.1.so 
#8 0x00007ffff7949669 in Pylon::CTlFactory::EnumerateDevices(Pylon::DeviceInfoList&, Pylon::DeviceInfoList const&, bool)() from pylon5/lib64/libpylonbase-5.0.1.so 
#9 0x00007ffff7949c8f in Pylon::CTlFactory::InternalCreateDevice(Pylon::CDeviceInfo const&, GenICam_3_0_Basler_pylon_v5_0::gcstring_vector const&, bool)() from pylon5/lib64/libpylonbase-5.0.1.so 
#10 0x00007ffff794a655 in Pylon::CTlFactory::CreateFirstDevice(Pylon::CDeviceInfo const&)() from pylon5/lib64/libpylonbase-5.0.1.so 
#11 0x00007ffff7bd7dc5 in basler_init() from lib/libbasler.so 
#12 0x0000000000438415 in rFl_info() 
#13 0x0000000000000000 in ??() 

Dla programu C:

Reading symbols from Test2-c...done. 
(gdb) run 
Starting program: /home/ollie/work/circuithub/receiving-station/Test2-c 
warning: File "/nix/store/9ljgbhb26ca0j9shwh8bwsa77h42izr2-gcc-5.4.0-lib/lib/libstdc++.so.6.0.21-gdb.py" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load". 
To enable execution of this file add 
     add-auto-load-safe-path /nix/store/9ljgbhb26ca0j9shwh8bwsa77h42izr2-gcc-5.4.0-lib/lib/libstdc++.so.6.0.21-gdb.py 
line to your configuration file "/home/ollie/.gdbinit". 
To completely disable this security protection add 
     set auto-load safe-path/
line to your configuration file "/home/ollie/.gdbinit". 
For more information about this security protection see the 
"Auto-loading safe path" section in the GDB manual. E.g., run from the shell: 
     info "(gdb)Auto-loading safe path" 
[Thread debugging using libthread_db enabled] 
Using host libthread_db library "/nix/store/bb32xf954imhdrzn7j8h82xs1bx7p3fr-glibc-2.23/lib/libthread_db.so.1". 
[New Thread 0x7fffed4ae700 (LWP 13792)] 
[New Thread 0x7fffeccad700 (LWP 13793)] 
Using device Emulation 
[Thread 0x7fffeccad700 (LWP 13793) exited] 
[Thread 0x7fffed4ae700 (LWP 13792) exited] 
[Inferior 1 (process 13788) exited normally] 

Domyślam się Runtime GHC jest robienie czegoś, co powoduje pthreads mieć różne zachowania, ale nie jestem pewien, co to może być.

+0

@ J.J.Hakala że nie robi różnicy. Mogę też bezproblemowo używać 'cout' wcześniej w' basler_init'. – ocharles

Odpowiedz

8

Wierzę, że to jest istotne TRAC Komentarz:

https://ghc.haskell.org/trac/ghc/wiki/Commentary/Rts/Signals

Różnica występuje zaczynając linię 437 w C strace wyjście vs. linii 495 na wyjściu strace Haskell.

W tym momencie biblioteka tworzy dwa gniazda UDP i wysyła dwa datagramy UDP (linie 448-449 C/linie 506-507 Haskell). Pakiety są transmitowane do dwóch sieci lokalnych: 192.168.1.0/24 i 192.168.56/2/2.

Następnie oczekuje na odpowiedź na każdym z tych gniazd z limitem czasu (podobno) 25 mikrosekund (linia 450 C/linia Haskell 508). W przypadku C wybrane limit czasu wynosi . W przypadku Haskell połączenie wybierające jest wielokrotnie przerywane sygnałem SIGVTALRM używanym przez GHC RTS. Jest to ten sam wzór, który jest pokazany w powyższym komentarzu TRAC.

dla potencjalnego fix, rzucić okiem na to, jak narzędziami pakietu mysql i wykorzystuje makra block_rts_signals() i unblock_rts_signals():

+3

Wow, na miejscu! Użyłem "hacka" z http://www.serpentine.com/blog/2010/09/04/dealing-with-fragile-c-libraries-e-g-mysql-from-haskell/ i wszystko jest teraz dobre. Dziękuję Ci! – ocharles