Headless run crashes due to XWindowSystem

Hi guys,

I’m currently developing a standalone application which is intended to run on a headless RPi4, attached to a HiFiBerry DAC+ADC Pro soundcard. The build works perfectly fine. However, when running the application I get a load of XWindowSystem assertions until the application finally crashes in juce::StandaloneFilterWindow. This does not happen in non-headless mode (i.e. when connected using ssh -X).

Here is a collection of the window system assertions. These 4 assertions seem to be triggered randomly and about 3-5 times each:

Program received signal SIGTRAP, Trace/breakpoint trap.
0xb6a9920c in kill () at ../sysdeps/unix/syscall-template.S:78
78      in ../sysdeps/unix/syscall-template.S
(gdb) continue
Continuing.
JUCE Assertion failure in juce_linux_XWindowSystem.cpp:1617

Program received signal SIGTRAP, Trace/breakpoint trap.
0xb6a9920c in kill () at ../sysdeps/unix/syscall-template.S:78
78      in ../sysdeps/unix/syscall-template.S
(gdb) continue
Continuing.
JUCE Assertion failure in juce_linux_XWindowSystem.cpp:1729

Program received signal SIGTRAP, Trace/breakpoint trap.
0xb6a9920c in kill () at ../sysdeps/unix/syscall-template.S:78
78      in ../sysdeps/unix/syscall-template.S
(gdb) continue
Continuing.
JUCE Assertion failure in juce_linux_XWindowSystem.cpp:1936

Program received signal SIGTRAP, Trace/breakpoint trap.
0xb6a9920c in kill () at ../sysdeps/unix/syscall-template.S:78
78      in ../sysdeps/unix/syscall-template.S
(gdb) continue
Continuing.
JUCE Assertion failure in juce_linux_XWindowSystem.cpp:1717

And here is the segfault, which happens a few seconds after the assertions:

Thread 1 "optimicer" received signal SIGSEGV, Segmentation fault.
0x00020028 in juce::StandaloneFilterWindow::StandaloneFilterWindow(juce::String const&, juce::Colour, juce::PropertySet*, bool, juce::String const&, juce::AudioDeviceManager::AudioDeviceSetup const*, juce::Array<juce::StandalonePluginHolder::PluginInOuts, juce::DummyCriticalSection, 0> const&, bool)::{lambda()#1}::operator()() const (__closure=0xbefff21c) at /home/pi/optimicer/Source/Externals/JUCE/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h:757
757                         const auto screenLimits = displays.getDisplayForRect ({ x, y, width, height })->userArea;

I’m using this kernel in combination with most recent JUCE on develop branch as of now:

Linux raspberrypi 5.4.79-v7l+ #1373 SMP Mon Nov 23 13:27:40 GMT 2020 armv7l GNU/Linux

I tracked down the JUCE versions and found out that my problem only occurs from JUCE >= 6.0.5 on, 6.0.4 is perfectly fine (at least there’s no segfault).

I think I already opened a similar, or even the same issue quite some time ago.

The original forum entry

Unfortunately it seems the fix did not solve my problem in the end …

Any help appreciated, thank you a lot!

1 Like

Hi there,

the issue still exists for me. I’ve just tried (again) with JUCE 8.0.2 and I still get a segfault.

Is there any possibility to fix this? I’d very much appreciate it, because the issue prevents me from updating from the (rather old) JUCE 6.0.4.

Thanks a bunch!

Best,
Lukas

Hi,
I am trying to run a standalone plug-in in headless mode on a Cortex-A53 and I am having the same problem. This is the gdb output at the segfault from my plug-in, built with JUCE 8.0.2:

I also observe the leading XWindowSystem assertions until I run into this segfault.
For me it also works fine for JUCE 6.0.4 but any version above crashes. I would greatly appreciate any help regarding this problem as I need to update the JUCE version I am working with.

Thanks for reporting. The issue seems to be caused by an attempted access to a non-existent Display structure, which should be fixed in this commit:

We’ve also pushed the following change, which should mean that you only see a single assertion, rather than several, when running on a headless system:

2 Likes

Thank you very much for fixing this!

Hi again,
I tested the first commit which successfully fixes the original issue. However the second commit you mentioned causes a new problem with which my application does not run properly. It seems to get stuck and throws a segfault when I terminate it manually. I also tested the latest commit (today) on the develop branch and the issue persists.

And while I’m at it, I was wondering if you could tell me what causes the following assertion and ALSA issue, coming with the JUCE upgrade of my application?
I think the assertion might be related to the new issue I described above as it only appears on later (not working) commits.


If I am correct, ALSA needs the missing file for MIDI support and so far this does not seem to cause a problem for my application (as I don’t need MIDI). I was just wondering if this is something that should be handled somehow.

It would be great if you could look into your assertion fix again so that I am not stuck with another JUCE version all over again :slight_smile:
If you need further information, I’m happy to help!

Please can you describe how you’re terminating the program? Does the app attempt to quit in response to some user input, or are you sending a signal to the app (e.g. pressing ctrl+c to send SIGINT)?

Do you see the same failure if you run the program under a debugger? If so, what is the stack trace at the point of the segfault?

It’d be interesting to know whether you see the same failure in any of the JUCE example projects. If not, the segfault may be caused by some aspect of your plugin code, rather than by the standalone wrapper code.

The assertion is triggered when no display is available. There’s a comment above the assertion explaining what went wrong. In this situation, we fall back to creating a StandalonePluginHolder without a StandaloneFilterWindow.

I think the ALSA output is harmless. That line is printed from inside the snd_seq_open call in the AlsaClient() constructor. In older versions of JUCE, the AlsaClient wasn’t created until a MIDI input/output was created, but in newer versions, the AudioDeviceManager constructs an AlsaClient instance so that it can receive notifications whenever a new MIDI device is added or removed.

I have to terminate the program with SIGINT because nothing is happening very early on after my application is started and I don’t get a response to anything.
It looks like it gets stuck in a poll:

Using the debugger, I don’t see the segfault anymore. Instead if I continue the execution in gdb it seems that it goes right back to polling. I would have expected that the app would be terminated after ctrl+c, bt, continue in gdb but I can do this endlessly.
Sorry for the lack of debugger information in my previous message.

Thanks for explainig the ALSA output!

What response are you expecting to get? Do you mean that the program isn’t processing audio? Are the audio inputs and outputs definitely being opened successfully?

SIGINT works differently under gdb - I think gdb intercepts it and pauses the debugged program, rather than passing the signal on. To send SIGINT to the debugged program you can enter signal 2 into the gdb prompt while the program is paused.

That ‘poll’ is what drives the message loop on Linux. It’s expected that the main thread would spend the majority of its time here in the message loop, waiting for new input events, so I don’t think this is unusual.

Please would you test one of the JUCE example plugin projects, e.g. the AudioPluginDemo_Standalone target, and check whether it also crashes when you interrupt it with SIGINT? For me, this works correctly, so I wonder whether the crash is caused by something in your AudioProcessor.

No nothing is processed at all and I am expecting a bunch of DBG outputs which do not come. Furthermore I have some GPIOs that are handled by my program which do not work either so the one thing I am certain of, is that my application does not run as it should and as it does when building from the first JUCE commit you made and in non-headless mode.
That it runs perfectly fine one commit earlier made me believe that maybe something went wrong in your second commit but if you can’t reproduce this issue, I will have to dig deeper and take a closer look at the changes.

At first glance I think it could be that the introduction of createPluginHolder() in juce_audio_plugin_client_Standalone.cpp:144 clashes with my manually handled StandalonePluginHolder.
I don’t think that the example projects would have this kind of issue so it would explain why you don’t have it.

I think I found my problem:
I am trying to assign a pluginHolder = StandalonePluginHolder::getInstance(); for further setup of my application within the createEditor() method of my processor. Am I correct that now there is no call to createEditor() anymore in headless mode? I tried setting a breakpoint there which is never reached.

This would mean that the plugin is running but is missing pretty much everything of my internal setup which is also triggered in createEditor().
I suppose I have to find a more logical place to initialize my plugin.

Yes, it doesn’t really make sense to create an editor that won’t be displayed. You may need to move your initialisation code into the AudioProcessor itself.

Yes that makes sense, it just worked that way for a long time apparently :slight_smile:
Thanks for your support!

1 Like

Hello yet again,
I am sorry that I have to get back to this topic once more but there is still something I am struggling with:

As I mentioned earlier, I am trying to get a hold of the StandalonePluginHolder instance, that is created in the JUCE sources, with StandalonePluginHolder::getInstance() to further configure my plugin and especially the AudioDeviceManager.
It seems however that StandalonePluginHolder::getInstance() can only return a nullptr if no editor was created or if no desktop/window is present.
I did not find a different method to get a hold of the StandalonePluginHolder so even if I e.g. create my own AudioDeviceManager it conflicts with the one in the already running StandalonePluginHolder instance which I can’t access.

Could you clarify if I am missing something here?

I tried getting a hold of the StandalonePluginHolder with StandalonePluginHolder::getInstance() at different points in my code as well as polling for it until its ready but it always stays a nullptr even though there definitely is a running instance (we clarified that earlier). It always works in non-headless mode but never on my headless system.

I’ve added a change here that allows StandalonePluginHolder::getInstance() to succeed even when there are no active desktop windows:

1 Like