Handling misbehaving libraries in binary products

It is a bit of an arcane artform, making a game that runs on all Linux versions. We do quite well at LGP but there is always room for improvement.

Recently, we came across an issue with PulseAudio (I will rant about Pulse in some other post). It became almost impossible, due to the architecture of alsa, and the combination of our build environment, and our higher level sound libraries, to make sound work – pretty much at all, in Linux games. Those of you with older games will know that for a while they all stopped having sound. Some of them we still haven’t released patches for yet (they will be forthcoming).

Now, one of the big problems was that sound libraries (such as OpenAL or SDL) go through their own motions of opening sound. We have no way of directly controlling what they do or how they do it. This is a common feature with many libraries, they will load their own dependencies in a way we cannot control.

The biggest problem is that OpenAL and SDL try to dlopen libasound, and on some machines, libasound doesn’t work with our binaries. On others, it can actually crash the whole game due to incompatibilities. This is a common issue when dealing with unknown system configurations when sending out a binary-only product into the world. You never know just what peoples systems will have installed, and just how they may confuse the situation. But you cannot just say ‘well, bad luck, it crashes on your machine’, people will be understandably upset.

We came up with a rather horrible system to make this work, and one that I hope may be of use to those of you who come here for our technical insights. This system is deliberately designed to work with libraries that have the potential to actually crash a program. As a simple example that many here will follow, I am using SDL’s audio system as the target, and using it to test whether ALSA works or crashes the program.

  static int system_asound_ok=-1;

  if (system_asound_ok==-1)
    {
      forkval=fork();
      switch (forkval)
        {
        case -1:
          //This is an error, we couldnt fork() so we just say no to
          //system openal working
          system_asound_ok=0;
        case 0:
          //This is the child, try and run the open, and then close and exit
          {
            //Your code here to remove whichever signal handlers you have set up
          }
          fail=SDL_InitSubSystem(SDL_INIT_AUDIO);
          if (!fail)
            SDL_QuitSubSystem(SDL_INIT_AUDIO);
          //MUST use _exit here not exit
          _exit(0);
          break;
        default:
          //This is the parent, wait for the child to exit somehow
          waitpid(forkval,&fail,0);

          //The child has now exited somehow, check how
          if (WIFEXITED(fail))
            {
              //The child exited ok, we can try and use the system library
              system_asound_ok=1;
            }
          else
            {
              //The child probably crashed, dont try and use the system library
              system_asound_ok=0;
            }
        }
    }

At this point you know whether the system asound (ALSA) library is safe to use.

This is a truly truly horrible system, when you actually have to allow an application to crash, you know something is wrong, but sometimes there is no option.

As a technical note, note the use of _exit() instead of exit(). This ensures that when the program ends, no atexit() functions are called. Using exit() could mean things like SDL’s cleanup being called, or who knows what else!

Signal handlers should be removed at the point in the code indicated. They interfere with the proper signaled exit of the program and will prevent WIFEXITED from detecting a crash properly. Bear in mind the signal removing only happens in the child process and will not affect signals in the parent.

So, what can you do knowing that the system works or doesn’t work?

Well, knowing that it works, you can simply run the initialisation as it stands and enjoy the working library.

If you know it fails, you can either skip this system altogether (in this case run without sound) or you can switch to another library. If you setenv an LD_LIBRARY_PATH this will influence the path that dlopen looks for libraries. LD_LIBRARY_PATH is searched before any other directories, and so will override the default location of the library. This means, in this instance, that SDL_InitSubSystem will dlopen the libasound.so in the location you have set the LD_LIBRARY_PATH to.

I hope this will relieve some headaches for some developers out there. It is always difficult making any application when you do not know what the target system will have installed on it. Of course, we can always say ’sorry, you need a specific version of this or that library’ but when you have just bought a game, that is the last thing you want to hear, and so – we have to jump through some hoops to stop that happening.

  • Share/Bookmark

Tags: , , , , , , , ,

11 Responses to “Handling misbehaving libraries in binary products”

  1. sakuramboo says:

    But, choice is good, right?

    Pulseaudio has it’s place, but for distributions to make it the default is a huge mistake. Even more of a mistake is Ubuntu packaging Pulseaudio in with the ubuntu-desktop package. No longer can we remove it without loosing the desktop.

    • Jury says:

      What you say is a nonsense. You can’t “lose a desktop”. ubuntu-desktop is a meta-package. Think of is as a list of default packages for desktop system. You can safely remove it.

      As for the pulseaudio, what do you have against it? It’s much easier to work with and much more reliable for desktop system.

      • sakuramboo says:

        The ubuntu-desktop package and pulseaudio are dependencies of each other. Remove one, the other goes with it. When Ubuntu first released pulseaudio, it was a stand along package and could be removed. Now, it is tied to the system and can’t be removed without removing the desktop. I’m sure you can probably uninstall everything and install it all back piece by piece, but why should I?

        Pulseaudio is easier to work with? Ever since it came out, I have been having problems that took weeks to fix. Granted, now it works, but I’m still seeing artifacts of the system hiccuping from time to time (that one, I don’t know if it was pulseaudio that did it or something else), once in a while, I will loose sound (to “fix” I have to wait around for a bit of time).

        But, the biggest reason I hate it, it is an added layer that is not needed in music production. Why must I now have to deal with the added system lag of having yet another audio sub system? Something where system latency means everything, by forcing another audio layer, this just makes things worse. I was forced reconfigure jackd for days, trying to find the right settings, all because Ubuntu wanted to force me to use pulseaudio.

  2. Hannes says:

    For you as an developer, what sound system is most nice to code for? Of course you are using OpenAL/SDL but I guess you still have an insight into the code. If you fear a flame war or feel uneasy, just ignore this question. :)

    I myself love OSS (v4 of course) because “it just works” for me.

    • Well, I’ll be going into more detail soon in itsown article, but we were really happy with things pre-pulse. Sound just worked.
      Things are actually getting better, our general target is ALSA, but OSS does seem to be coming back from the dead.

      • Nath says:

        The only thing about Pulse that I don’t like is that it doesn’t work well with Emu10k-based cards. Even though the developers claim that it is Creatives fault, those cards worked very well before Pulse.

  3. GBGames says:

    Thanks for posting this article! For a long time I held off on upgrading my Ubuntu system, but when I did, I found that the upgrade caused all manner of problems. Maybe a fresh install would work better, but the main issue is that every so often audio just completely dies. I have to restart because I don’t know what exactly has gone wrong.

    Another issue related to audio involves Flash or Java programs stealing control of audio, so if I try to run a game while Firefox is still running, I’ll find that my games or music players are silent and unstable.

    I’m told that all of these issues might be related to PulseAudio or at least Ubuntu’s implementation of it, so I can’t wait to hear more about LGP’s struggles with it.

  4. Audio on Linux is really a mess – look at that:

    http://blogs.adobe.com/penguin.swf/linuxaudio.png

    And stories from (my) real-life:
    1. Install openSUSE 11 – ok
    2. plugged in a second audio interface (USB) – ok
    3. change the order of the audio interface on my desktop (KDE4)
    3a) no effect on LGP games
    3b) no effect on skype
    3c) no effect on RealPlayer
    4) the correct effect on Amarok – YES – but no mp3 sound (d’ooh)
    5) an very old game (bridge builder) has not sound at all (broken openAL)
    6) sometimes the external interface crashes the whole system..

    YES – there are different reasons and probably many solutions for each problem, but who has the time to elaborate all the stuff?

    Above all Linux is a very good OS and many things on the desktop improved in the last time, but there is still “no light at the end of the sound tunnel”.

  5. Thanks for the interesting link which provides some new information for me.

    However, it seems that things will be more complicated with the new pulseaudio system which is totally new for me as an openSUSE user.

    The chance that all software components are bug-free is 0 – either some of them will dropped or we will never see good sound support on Linux.

Leave a Reply

To stop spam, please answer this simple question
What OS do we make games for

Please note: This site is fully moderated