Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libpgiod.so 2.6.0 causes core dump on ARMv6 #361

Open
rdratlos opened this issue May 26, 2024 · 23 comments
Open

libpgiod.so 2.6.0 causes core dump on ARMv6 #361

rdratlos opened this issue May 26, 2024 · 23 comments
Assignees

Comments

@rdratlos
Copy link

rdratlos commented May 26, 2024

We wanted to migrate a project from a custom LinuxFS based GPIO digital output control implementation to the new Pi4J GpioD plugin. The reason was that LinuxFS native code uses deprecated kernel API functions. As all tests after update failed, we performed tests using the distributed Minimal Example and Pi4J v2.6.0 installed directly on Pi using Maven. All attempts failed with core dump (SIGILL fatal error) in native code and following error information:

[main] INFO com.pi4j.util.Console - ************************************************************
[main] INFO com.pi4j.util.Console - ************************************************************
[main] INFO com.pi4j.util.Console - 
[main] INFO com.pi4j.util.Console -                   <-- The Pi4J Project -->                   
[main] INFO com.pi4j.util.Console -                    Minimal Example project                   
[main] INFO com.pi4j.util.Console - 
[main] INFO com.pi4j.util.Console - ************************************************************
[main] INFO com.pi4j.util.Console - ************************************************************
[main] INFO com.pi4j.util.Console - 
[main] INFO com.pi4j.Pi4J - New auto context
[main] INFO com.pi4j.Pi4J - New context builder
[main] INFO com.pi4j.boardinfo.util.BoardInfoHelper - Detected OS: Name: Linux, version: 6.6.28+rpt-rpi-v6, architecture: arm
[main] INFO com.pi4j.boardinfo.util.BoardInfoHelper - Detected Java: Version: 11.0.23, runtime: 11.0.23+9-LTS, vendor: Azul Systems, Inc., vendor version: Zulu11.72+19-CA
[main] INFO com.pi4j.boardinfo.util.BoardInfoHelper - Detected board type ZERO_W by code: 9000c1
[main] INFO com.pi4j.context.impl.DefaultContext - Detected board model: Raspberry Pi Zero W
[main] INFO com.pi4j.context.impl.DefaultContext - Running on: Name: Linux, version: 6.6.28+rpt-rpi-v6, architecture: arm
[main] INFO com.pi4j.context.impl.DefaultContext - With Java version: Version: 11.0.23, runtime: 11.0.23+9-LTS, vendor: Azul Systems, Inc., vendor version: Zulu11.72+19-CA
[main] INFO com.pi4j.runtime.impl.DefaultRuntime - Initializing Pi4J context/runtime... 
[main] WARN com.pi4j.runtime.impl.DefaultRuntime - Ignoring provider DIGITAL_OUTPUT RaspberryPi Digital Output (GPIO) Provider with priority 0 as lower priority than GpioD Dig
ital Output (GPIO) Provider which has priority 150
[main] WARN com.pi4j.runtime.impl.DefaultRuntime - Ignoring provider DIGITAL_INPUT RaspberryPi Digital Input (GPIO) Provider with priority 0 as lower priority than GpioD Digit
al Input (GPIO) Provider which has priority 150
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGILL (0x4) at pc=0xac7121d8, pid=6664, tid=6665
#
# JRE version: OpenJDK Runtime Environment Zulu11.72+19-CA (11.0.23+9) (build 11.0.23+9-LTS)
# Java VM: OpenJDK Client VM Zulu11.72+19-CA (11.0.23+9-LTS, mixed mode, serial gc, linux-arm)
# Problematic frame:
# C  [libgpiod13311060481651781708.so+0x21d8]

Stack: [0xb64b9000,0xb6509000],  sp=0xb6505ef8,  free space=307k
Native frames: (J=compiled Java code, A=aot compiled Java code, j=interpreted, Vv=VM code, C=native code)
C  [libgpiod13311060481651781708.so+0x21d8]
V  [libjvm.so+0x60e5e0]  os::dll_load(char const*, char*, int)+0x78
V  [libjvm.so+0x48aa48]  JVM_LoadLibrary+0xa4

Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j  java.lang.ClassLoader$NativeLibrary.load0(Ljava/lang/String;ZZ)Z+0 [email protected]
j  java.lang.ClassLoader$NativeLibrary.load()Z+56 [email protected]
j  java.lang.ClassLoader$NativeLibrary.loadLibrary(Ljava/lang/Class;Ljava/lang/String;Z)Z+216 [email protected]
j  java.lang.ClassLoader.loadLibrary0(Ljava/lang/Class;Ljava/io/File;)Z+46 [email protected]
j  java.lang.ClassLoader.loadLibrary(Ljava/lang/Class;Ljava/lang/String;Z)V+70 [email protected]
j  java.lang.Runtime.load0(Ljava/lang/Class;Ljava/lang/String;)V+57 [email protected]
j  java.lang.System.load(Ljava/lang/String;)V+7 [email protected]
j  com.pi4j.library.gpiod.util.NativeLibraryLoader.loadLibraryFromClasspath(Ljava/lang/String;)V+229 [email protected]
j  com.pi4j.library.gpiod.util.NativeLibraryLoader.load(Ljava/lang/String;Ljava/lang/String;)V+605 [email protected]
j  com.pi4j.library.gpiod.internal.GpioD.<clinit>()V+6 [email protected]
v  ~StubRoutines::call_stub
j  com.pi4j.library.gpiod.internal.GpioDContext.initialize()V+8 [email protected]
j  com.pi4j.plugin.gpiod.provider.gpio.digital.GpioDDigitalInputProviderImpl.initialize(Lcom/pi4j/context/Context;)Lcom/pi4j/io/gpio/digital/DigitalInputProvider;+12 [email protected]
j  com.pi4j.plugin.gpiod.provider.gpio.digital.GpioDDigitalInputProviderImpl.initialize(Lcom/pi4j/context/Context;)Ljava/lang/Object;+2 [email protected]
j  com.pi4j.provider.impl.DefaultRuntimeProviders.initializeProvider(Lcom/pi4j/provider/Provider;)V+59 [email protected]
j  com.pi4j.provider.impl.DefaultRuntimeProviders.add(Ljava/util/Collection;)Lcom/pi4j/provider/Providers;+125 [email protected]
j  com.pi4j.provider.impl.DefaultRuntimeProviders.add([Lcom/pi4j/provider/Provider;)Lcom/pi4j/provider/Providers;+5 [email protected]
j  com.pi4j.provider.impl.DefaultRuntimeProviders.initialize(Ljava/util/Collection;)Lcom/pi4j/provider/impl/RuntimeProviders;+117 [email protected]
j  com.pi4j.runtime.impl.DefaultRuntime.initialize()Lcom/pi4j/runtime/Runtime;+375 [email protected]
j  com.pi4j.context.impl.DefaultContext.<init>(Lcom/pi4j/context/ContextConfig;)V+221 [email protected]
j  com.pi4j.context.impl.DefaultContext.newInstance(Lcom/pi4j/context/ContextConfig;)Lcom/pi4j/context/Context;+5 [email protected]
j  com.pi4j.context.impl.DefaultContextBuilder.build()Lcom/pi4j/context/Context;+15 [email protected]
j  com.pi4j.context.impl.DefaultContextBuilder.build()Ljava/lang/Object;+1 [email protected]
j  com.pi4j.Pi4J.newAutoContext()Lcom/pi4j/context/Context;+18 [email protected]
j  com.pi4j.example.MinimalExample.main([Ljava/lang/String;)V+27 [email protected]
v  ~StubRoutines::call_stub

siginfo: si_signo: 4 (SIGILL), si_code: 1 (ILL_ILLOPC), si_addr: 0xac7121d8

System information:

Hardware	: BCM2835
Revision	: 9000c1
Model		: Raspberry Pi Zero W Rev 1.1
model name	: ARMv6-compatible processor rev 7 (v6l)
Features	: half thumb fastmult vfp edsp java tls 

NAME="Raspbian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
uname:Linux 6.6.28+rpt-rpi-v6 #1 Raspbian 1:6.6.28-1+rpt1 (2024-04-22) armv6l
libc:glibc 2.36 NPTL 2.36 
rlimit (soft/hard): STACK 8192k/infinity , CORE 0k/infinity , NPROC 1292/1292 , NOFILE 1048576/1048576 , AS infinity/infinity , CPU infinity/infinity , DATA infinity/infinity , FSIZE infinity/infinity , MEMLOCK 65536k/65536k

Even though GpioD support was introduced with arrival of Raspberry Pi 5 we have not seen any information that other PIs are not supported.

Any help would be appreciated.

hs_err_pid6664.log

@rdratlos rdratlos changed the title libpgio 2.6.0 causes core dump libpgiod.so 2.6.0 causes core dump May 26, 2024
@FDelporte
Copy link
Member

FDelporte commented May 27, 2024

Thanks for the detailed info. V2.6 was tested on PIs with ARMv7/8 processors (4 and 5 for instance), not on ARMv6 (Pi Zero 1), as far as I know. I will need to set up a test to check if I can reproduce this...

@FDelporte FDelporte changed the title libpgiod.so 2.6.0 causes core dump libpgiod.so 2.6.0 causes core dump on ARMv6 May 27, 2024
@FDelporte
Copy link
Member

@rdratlos it would also be interesting to see what you get out of boardinfo logging, see https://www.pi4j.com/documentation/board-info/

console.println("Board model: " + pi4j.boardInfo().getBoardModel().getLabel());
console.println("Operating system: " + pi4j.boardInfo().getOperatingSystem());
console.println("Java versions: " + pi4j.boardInfo().getJavaInfo());

console.println("Board model: " + BoardInfoHelper.current().getBoardModel().getLabel());
console.println("Raspberry Pi model with RP1 chip (Raspberry Pi 5): " + BoardInfoHelper.usesRP1());
console.println("OS is 64-bit: " + BoardInfoHelper.is64bit());

@rdratlos
Copy link
Author

[main] INFO com.pi4j.boardinfo.util.BoardInfoHelper - Detected OS: Name: Linux, version: 6.6.28+rpt-rpi-v6, architecture: arm
[main] INFO com.pi4j.boardinfo.util.BoardInfoHelper - Detected Java: Version: 11.0.23, runtime: 11.0.23+9-LTS, vendor: Azul Systems, Inc., vendor version: Zulu11.72+19-CA
[main] INFO com.pi4j.boardinfo.util.BoardInfoHelper - Detected board type ZERO_W by code: 9000c1
[main] INFO com.pi4j.context.impl.DefaultContext - Detected board model: Raspberry Pi Zero W

@FDelporte
For BoardInfoHelper I need some more time to fix, as it tries to initialize an auto-context and crashes.

@rdratlos
Copy link
Author

@FDelporte
Sorry for being late. Please find the missing BoardInfo information in the following:

[main] INFO com.pi4j.util.Console - Board model: Raspberry Pi Zero W
[main] INFO com.pi4j.util.Console - Operating system: Name: Linux, version: 6.6.28+rpt-rpi-v6, architecture: arm
[main] INFO com.pi4j.util.Console - Java versions: Version: 11.0.23, runtime: 11.0.23+9-LTS, vendor: Azul Systems, Inc., vendor version: Zulu11.72+19-CA
[main] INFO com.pi4j.util.Console - Board model: Raspberry Pi Zero W
[main] INFO com.pi4j.util.Console - Raspberry Pi model with RP1 chip (Raspberry Pi 5): false
[main] INFO com.pi4j.util.Console - OS is 64-bit: false
[main] INFO com.pi4j.util.Console - JVM memory used (MB): 3.3950881958007812
[main] INFO com.pi4j.util.Console - Board temperature (°C): 47.1

This platform is still supported by Raspberry OS Bookworm as well as Zulu Java 11. Would be good to use a "modern" GPIO API and get rid of the deprecated Linux file system based access.

@rdratlos
Copy link
Author

rdratlos commented May 28, 2024

After native build of GpioD libraries on the Pi Zero 1 (ARMv6) itself with hacked POM and build scripts, which force 64 bit ARM arch, we got a working libpgiod.so. autoContext() and subsequent off/on of the digital output worked. Seems that something goes wrong, when building the libraries using cross-compiler on the 64 bit production machine.

Btw.: Native GPIO build on this slow PI has become inexpensive and works pretty fast. Nothing compared to the nightmare with LinuxFS native builds two years ago.

@FDelporte
Copy link
Member

Hi @rdratlos great to hear you could solve the problem and performance is a lot better!
Can you please share the changes that need to be done so we can try to get them into the build scripts?
Thanks a lot in advance!

@rdratlos
Copy link
Author

rdratlos commented May 28, 2024

Hi @FDelporte,
at least I could prove that GpioD library native build still works on 32-bit ARMv6. The more generic hack is now as follows:

diff --git a/libraries/pi4j-library-gpiod/src/main/native/build.sh b/libraries/pi4j-library-gpiod/src/main/native/build.sh
index 64ee5b0a..6011850d 100755
--- a/libraries/pi4j-library-gpiod/src/main/native/build.sh
+++ b/libraries/pi4j-library-gpiod/src/main/native/build.sh
@@ -51,9 +51,9 @@ fi
 
 # validate compatible CPU architecture
 ARCHITECTURE=$(uname -m)
-if [[ (("$ARCHITECTURE" != "aarch64") && ("$ARCHITECTURE" != "amd64") && ("$ARCHITECTURE" != "x86_64")) ]]; then
-    echo "This native build is only supported on Linux-based systems running on an Intel/AMD or ARM 64-bit platform."
-    echo "BUILD ABORTED; REASON: ARCHITECTURE='$ARCHITECTURE'; EXPECTED='aarch64|amd64|x86_64'"
+if [[ (("$ARCHITECTURE" != "aarch64") && ("$ARCHITECTURE" != "armv6l") && ("$ARCHITECTURE" != "amd64") && ("$ARCHITECTURE" != "x86_64")) ]]; then
+    echo "This native build is only supported on Linux-based systems running on an Intel/AMD or ARM platform."
+    echo "BUILD ABORTED; REASON: ARCHITECTURE='$ARCHITECTURE'; EXPECTED='aarch64|armv6l|amd64|x86_64'"
     exit 1
 fi
 
@@ -78,7 +78,7 @@ if [[ "${PI4J_BUILDER}" != "" ]]; then
    echo "Running inside a Pi4J Docker Builder image; [version=${PI4J_BUILDER}; arch=${PI4J_BUILDER_ARCH}]"
    echo "No need to check or install build environment prerequisites."
 else
-   # if this is a Linux-based system and a 64-bit Intel/AMD or ARM platform, then we can install the prerequisites
+   # if this is a Linux-based system and a Intel/AMD or ARM platform, then we can install the prerequisites
    # download and install development prerequisites
    ./build-prerequisites.sh
 fi

I fear that we have now working 32 bit libraries but broken 64bit libs. I have attached a zip with a 2.6.0 Maven cache, which contains all native libs build on the Pi Zero. Would be interesting to know, if the aarch64 libs work on later 64 bit Pi.

pi4j-library-gpiod-2.6.0_mvn.zip

@FDelporte
Copy link
Member

@eitch is this something you can look into regarding the build changes?

According to @taartspi could be related to #354, #217, #28

@eitch
Copy link
Member

eitch commented May 30, 2024

I currently don't have much time to look into this. If you could send a PR, then i can look into integrating it.
The issue that comes to my mind, is that the build of the 32-bit native libraries probably need a different docker container, this would make it a bit more complicated overall.
It would be great if we could enable this again on the Pi Zero.

@rdratlos
Copy link
Author

rdratlos commented May 31, 2024

@eitch:
It makes not much sense to re-enable ARMv6 native builds. These Pis are way to slow. I believe that there is an issue with the GPIO library POMs. When I download 2.6.0 and Maven build Pi4J I get the core dump. After rebuilding only the native GpioD library on a Pi Zero 1 (ARMv6) using

mvn clean install -Pnative

with hacked build script (see above) to enable ARMv6 builds everything works fine again.
But if I then rebuild the complete Pi4J suite using

mvn clean install

the minimal example app crashes again with java.lang.UnsatisfiedLinkError error:

[main] INFO com.pi4j.Pi4J - New auto context                                                                                                                                   
[main] INFO com.pi4j.Pi4J - New context builder                                                                                                                                
[main] TRACE com.pi4j.context.impl.DefaultContextBuilder - invoked 'build()'                                                                                                   
[main] TRACE com.pi4j.context.impl.DefaultContext - new Pi4J runtime context initialized [config=com.pi4j.context.impl.DefaultContextBuilder$1@173813a]                        
[main] DEBUG com.pi4j.runtime.impl.DefaultRuntime - Pi4J runtime context successfully created & initialized.'                                                                  
[main] INFO com.pi4j.boardinfo.util.BoardInfoHelper - Detected OS: Name: Linux, version: 6.6.28+rpt-rpi-v6, architecture: arm                                                  
[main] INFO com.pi4j.boardinfo.util.BoardInfoHelper - Detected Java: Version: 11.0.23, runtime: 11.0.23+9-LTS, vendor: Azul Systems, Inc., vendor version: Zulu11.72+19-CA     
[main] INFO com.pi4j.boardinfo.util.BoardInfoHelper - Detected board type ZERO_W by code: 9000c1                                                                               
[main] INFO com.pi4j.context.impl.DefaultContext - Detected board model: Raspberry Pi Zero W                                                                                   
[main] INFO com.pi4j.context.impl.DefaultContext - Running on: Name: Linux, version: 6.6.28+rpt-rpi-v6, architecture: arm                                                      
[main] INFO com.pi4j.context.impl.DefaultContext - With Java version: Version: 11.0.23, runtime: 11.0.23+9-LTS, vendor: Azul Systems, Inc., vendor version: Zulu11.72+19-CA    
[main] INFO com.pi4j.runtime.impl.DefaultRuntime - Initializing Pi4J context/runtime...                                                                                        
[main] TRACE com.pi4j.runtime.impl.DefaultRuntime - detected plugin: [com.pi4j.plugin.gpiod.GpioDPlugin] in classpath; calling 'initialize()'                                  
[main] TRACE com.pi4j.runtime.impl.DefaultRuntime - detected plugin: [com.pi4j.plugin.raspberrypi.RaspberryPiPlugin] in classpath; calling 'initialize()'                      
[main] WARN com.pi4j.runtime.impl.DefaultRuntime - Ignoring provider DIGITAL_INPUT RaspberryPi Digital Input (GPIO) Provider with priority 0 as lower priority than GpioD Digit
al Input (GPIO) Provider which has priority 150                                                                                                                                
[main] WARN com.pi4j.runtime.impl.DefaultRuntime - Ignoring provider DIGITAL_OUTPUT RaspberryPi Digital Output (GPIO) Provider with priority 0 as lower priority than GpioD Dig
ital Output (GPIO) Provider which has priority 150                                                                                                                             
[main] TRACE com.pi4j.provider.impl.DefaultRuntimeProviders - adding providers: [count=6]                                                                                      
[main] TRACE com.pi4j.provider.impl.DefaultRuntimeProviders - adding provider: [id=raspberrypi-serial; name=RaspberryPi Serial Provider; class=com.pi4j.plugin.raspberrypi.prov
ider.serial.RpiSerialProviderImpl]                                                                                                                                             
[main] TRACE com.pi4j.provider.impl.DefaultRuntimeProviders - invoked 'add()' provider [count=1]                                                                               
[main] TRACE com.pi4j.provider.impl.DefaultRuntimeProviders - adding provider to managed io map [id=raspberrypi-serial; name=RaspberryPi Serial Provider; class=com.pi4j.plugin
.raspberrypi.provider.serial.RpiSerialProviderImpl]                                                                                                                            
[main] TRACE com.pi4j.provider.impl.DefaultRuntimeProviders - initializing provider [id=raspberrypi-serial; name=RaspberryPi Serial Provider; class=com.pi4j.plugin.raspberrypi
.provider.serial.RpiSerialProviderImpl]                                                                                                                                        
[main] DEBUG com.pi4j.provider.impl.DefaultRuntimeProviders - added io to managed provider map [id=raspberrypi-serial; name=RaspberryPi Serial Provider; class=com.pi4j.plugin.
raspberrypi.provider.serial.RpiSerialProviderImpl]                                                                                                                             
[main] TRACE com.pi4j.provider.impl.DefaultRuntimeProviders - adding provider: [id=raspberrypi-spi; name=RaspberryPi SPI Provider; class=com.pi4j.plugin.raspberrypi.provider.s
pi.RpiSpiProviderImpl]                                                                                                                                                         
[main] TRACE com.pi4j.provider.impl.DefaultRuntimeProviders - invoked 'add()' provider [count=1]                                                                               
[main] TRACE com.pi4j.provider.impl.DefaultRuntimeProviders - adding provider to managed io map [id=raspberrypi-spi; name=RaspberryPi SPI Provider; class=com.pi4j.plugin.raspb
errypi.provider.spi.RpiSpiProviderImpl]                                                                                                                                        
[main] TRACE com.pi4j.provider.impl.DefaultRuntimeProviders - initializing provider [id=raspberrypi-spi; name=RaspberryPi SPI Provider; class=com.pi4j.plugin.raspberrypi.provi
der.spi.RpiSpiProviderImpl]                                                                                                                                                    
[main] DEBUG com.pi4j.provider.impl.DefaultRuntimeProviders - added io to managed provider map [id=raspberrypi-spi; name=RaspberryPi SPI Provider; class=com.pi4j.plugin.raspbe
rrypi.provider.spi.RpiSpiProviderImpl]                                                                                                                                         
[main] TRACE com.pi4j.provider.impl.DefaultRuntimeProviders - adding provider: [id=raspberrypi-pwm; name=RaspberryPi PWM Provider; class=com.pi4j.plugin.raspberrypi.provider.p
wm.RpiPwmProviderImpl]                                                                                                                                                         
[main] TRACE com.pi4j.provider.impl.DefaultRuntimeProviders - invoked 'add()' provider [count=1]                                                                               
[main] TRACE com.pi4j.provider.impl.DefaultRuntimeProviders - adding provider to managed io map [id=raspberrypi-pwm; name=RaspberryPi PWM Provider; class=com.pi4j.plugin.raspb
errypi.provider.pwm.RpiPwmProviderImpl]                                                                                                                                        
[main] TRACE com.pi4j.provider.impl.DefaultRuntimeProviders - initializing provider [id=raspberrypi-pwm; name=RaspberryPi PWM Provider; class=com.pi4j.plugin.raspberrypi.provi
[main] DEBUG com.pi4j.provider.impl.DefaultRuntimeProviders - added io to managed provider map [id=raspberrypi-pwm; name=RaspberryPi PWM Provider; class=com.pi4j.plugin.raspbe
rrypi.provider.pwm.RpiPwmProviderImpl]
[main] TRACE com.pi4j.provider.impl.DefaultRuntimeProviders - adding provider: [id=gpiod-digital-input; name=GpioD Digital Input (GPIO) Provider; class=com.pi4j.plugin.gpiod.p
rovider.gpio.digital.GpioDDigitalInputProviderImpl]
[main] TRACE com.pi4j.provider.impl.DefaultRuntimeProviders - invoked 'add()' provider [count=1]
[main] TRACE com.pi4j.provider.impl.DefaultRuntimeProviders - adding provider to managed io map [id=gpiod-digital-input; name=GpioD Digital Input (GPIO) Provider; class=com.pi
4j.plugin.gpiod.provider.gpio.digital.GpioDDigitalInputProviderImpl]
[main] TRACE com.pi4j.provider.impl.DefaultRuntimeProviders - initializing provider [id=gpiod-digital-input; name=GpioD Digital Input (GPIO) Provider; class=com.pi4j.plugin.gp
iod.provider.gpio.digital.GpioDDigitalInputProviderImpl]
[main] DEBUG com.pi4j.library.gpiod.util.NativeLibraryLoader - Attempting to load library [libgpiod.so] using path: [/lib/armhf/pi4j-gpiod/libgpiod.so]
[main] DEBUG com.pi4j.library.gpiod.util.NativeLibraryLoader - Library [libgpiod.so] loaded successfully using embedded resource file: [/lib/armhf/pi4j-gpiod/libgpiod.so]
[main] DEBUG com.pi4j.library.gpiod.util.NativeLibraryLoader - Attempting to load library [libpi4j-gpiod.so] using path: [/lib/armhf/pi4j-gpiod/libpi4j-gpiod.so]
[main] DEBUG com.pi4j.library.gpiod.util.NativeLibraryLoader - Library [libpi4j-gpiod.so] loaded successfully using embedded resource file: [/lib/armhf/pi4j-gpiod/libpi4j-gpio
d.so]
Exception in thread "main" java.lang.UnsatisfiedLinkError: 'java.lang.Long com.pi4j.library.gpiod.internal.GpioD.gpiod_chip_iter_new()'
        at [email protected]/com.pi4j.library.gpiod.internal.GpioD.gpiod_chip_iter_new(Native Method)
        at [email protected]/com.pi4j.library.gpiod.internal.GpioD.chipIterNew(GpioD.java:342)
        at [email protected]/com.pi4j.library.gpiod.internal.GpioDContext.initialize(GpioDContext.java:38)
        at [email protected]/com.pi4j.plugin.gpiod.provider.gpio.digital.GpioDDigitalInputProviderImpl.initialize(GpioDDigitalInputProviderImpl.java:49)
        at [email protected]/com.pi4j.plugin.gpiod.provider.gpio.digital.GpioDDigitalInputProviderImpl.initialize(GpioDDigitalInputProviderImpl.java:15)
        at [email protected]/com.pi4j.provider.impl.DefaultRuntimeProviders.initializeProvider(DefaultRuntimeProviders.java:275)
        at [email protected]/com.pi4j.provider.impl.DefaultRuntimeProviders.add(DefaultRuntimeProviders.java:251)
        at [email protected]/com.pi4j.provider.impl.DefaultRuntimeProviders.add(DefaultRuntimeProviders.java:231)
        at [email protected]/com.pi4j.provider.impl.DefaultRuntimeProviders.initialize(DefaultRuntimeProviders.java:356)
        at [email protected]/com.pi4j.runtime.impl.DefaultRuntime.initialize(DefaultRuntime.java:316)
        at [email protected]/com.pi4j.context.impl.DefaultContext.<init>(DefaultContext.java:113)
        at [email protected]/com.pi4j.context.impl.DefaultContext.newInstance(DefaultContext.java:76)
        at [email protected]/com.pi4j.context.impl.DefaultContextBuilder.build(DefaultContextBuilder.java:287)
        at [email protected]/com.pi4j.context.impl.DefaultContextBuilder.build(DefaultContextBuilder.java:48)
        at [email protected]/com.pi4j.Pi4J.newAutoContext(Pi4J.java:73)
        at [email protected]/com.pi4j.example.MinimalExample.main(MinimalExample.java:92)

If I rebuild the native library again or just overwrite the local Maven cache with the previous rebuild above, the minimal example works fine again. Downloading the native libraries from Maven repository and then uploading again seems to break things. Never experienced this with LinuxFS native libraries, which are too large to native build on a Pi Zero 1.

@hackerjimbo
Copy link

I can confirm that this is an issue. I use my original Pi 1s for a lot of IoT work as they're powerful enough to do so. I think this is something worth investigating. How can I help?

Perhaps the first thing to note is that the 32-bit Pi OS builds for v6 all the time, even on a Pi 4! Maybe that's our way forward. You don't need to build on a Pi 1 to be able to run on a Pi 1.

@FDelporte
Copy link
Member

Side info regarding supported JDK versions on ARMv6: a short time ago, I tried out all versions listed by SDKMAN, which "should" be compatible with ARMv6. Turns out only Azul Zulu 8 and 11 do really work. No newer versions, and no versions of Liberica. There are plans to re-introduce 32bit support in future versions of OpenJDK as these platforms are still used a lot and have some very specific use-cases.

@hackerjimbo
Copy link

I think the solution is simpler than we think. However, I'm struggling to find the build commands for the 32-bit binary libraries. I suspect a simple --with-arch=armv6 flag may resolve the problem.

Can someone point me to the location of the build image?

@eitch
Copy link
Member

eitch commented Aug 5, 2024

@hackerjimbo This is the image: https://github.com/Pi4J/pi4j-docker

@hackerjimbo
Copy link

I've got a suspicion that the solution is fairly simple, just horrible! The default architecture for the ubuntu 32-bit ARM seems to be v7. What I think it needs is to move it to v6, tell it that it has floating point and then tell it to not use the thumb instruction set! (That last took a long time to figure out).

Those flags are: -marm -march=armv6+fp

Without them compile code into assembler gives the first few lines as:

	.arch armv7-a
	.fpu vfpv3-d16

With those flags we get:

	.arch armv6
	.fpu vfp

So all that needs to be done is to add those flags in when cross compiling and we're done!

@hackerjimbo
Copy link

Well I'll be jiggered! It turns out that ubuntu on 32-bit ARM compiles to thumb mode by default! This happens to work on the v7+ Pies because the hardware supports it. However, that doesn't work on v6 because the thumb mode (1) doesn't have floating point.

All 32-bit Pies operate in ARM mode not thumb mode. Backwards compatibility, don't you know…

@hackerjimbo
Copy link

So, I hear you ask, how does the ARM processor know if it's in thumb or ARM mode?

Well, thumb instructions are 16-bit and 2 byte aligned. ARM instructions are 32-bit and 4 byte aligned. So those crafty chaps in Cambridge used the bottom bit of the PC to determine the processor mode: 0 → ARM and 1 → thumb. Clever, but nasty!

@hackerjimbo
Copy link

Status update: I successfully built the .o files with the correct architecture. However, when it links to form the .so somehow it wants to add some v7 code in as well. Most annoying!

@hackerjimbo
Copy link

Pondering this there may be another issue. I would hope that the java 11 from OpenJDK for v7 is compatible API-wise with the Azul JDK 11, but what if it's not?

I suspect we may need to supply a “patch” to modify the jar file so that it has v6/Azul .so files for Pi 0/1s.

I disagree with the comment above that Pi 0/1s don't have the CPU power. As I sit here now I have 2 Pi 1s and 2 Pi 0s in the room performing everything from CO₂ monitoring to a clock on a 128×64 LCD screen. The CPUs are barely used.

@karsteny
Copy link

Hey, I've got this exact issue after attempting to upgrade from an ancient version, 2.1.1, because that version that has issue #244 (can't open multiple serial/SPI), but it was only fixed in 2.6.0, which has the new Gpio provider that doesn't work on the Zero W.

I'm pretty inexperienced when it comes to hacking the original code, right now I just use the dependency with Maven and I am unaware of how to do the build script modification that is mentioned earlier. Can anyone give me some pointers on how to do that (or, patch the fix from #244 into the older version, if that's easier than modifying the build scripts)?

@hackerjimbo
Copy link

Sorry for the delay in responding, but I've been on holiday.

I think I'm going to have to provide a patch for the pi4j jar. The only non-difficult way to build the libraries for Pi 0/1s is to build it on a 32-bit Raspberry Pi OS (though that doesn't have to be on a 0/1, you could build it on a 5 — but it must be 32-bit). I'll see what I can do.

@hackerjimbo
Copy link

Well that was a long wait from me! However, I've just had Pi 2 die on me (odd fault, everything seems fine except that the USB appears to be dead) so I now need this is use a replacement 1B+ (which I have) rather than get a new 4/5 or reuse a needlessly power 3 that I want for something else.

I plan to initially just patch lib/armhf/libpi4j-pigpio.so in pi4j-library-pigpio.jar or should I also/alternatively patch pi4j-plugin-gpiod.jar? What's the default and what's the best chocie?

Looking at pi4j-v2/libraries/pi4j-library-pigpio/src/main/native/Makefile it seems we're building against Java 11. Is this correct?

@hackerjimbo
Copy link

So I tried building against the system version of libgpiod rather than the custom and old one pi4j uses. This seems to be a better idea as someone else maintains it. Is this a good idea?

It didn't work, I ended up with an Exception in thread "main" java.lang.UnsatisfiedLinkError: 'java.lang.Long com.pi4j.library.gpiod.internal.GpioD.gpiod_chip_iter_new()' error (which wasn't very helpful).

Thoughts?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants