Skip to content

LWJGL2 Deadlock when initialization fails #1576

@MeFisto94

Description

@MeFisto94

How to reproduce this?
Try to run jme3-testing tests in a headless environment (e.g. ci-runner.sh, which uses a docker container) and attach a debugger:
For some reason org.lwjgl.Sys cannot be found there, causing an issue during context creation.

Since Context Creation on LWJGL2 happens on the "render" thread, the main thread goes into waitFor, which essentially waits on the createdLock object.

The default uncaught exception handler that I installed then fires [which also means the thread local handler from LwjglAbstractDisplay#initInThread does not; ClassNotFound is also an Error not an Exception], which calls into handleError(), where I call stop(false), which is roughly what the local handler also would do: call destroy.
The problem is, since the context isn't properly running, there is no-one notifying createdLock().

In theory LwjglContext#internalDestroy should notify the main thread waiting in start(true), BUT since destroy sets created = false, start will wait even further.

Basically there are two things here:

  • Why does waitFor() await a specific created state? It waits on a lock and that lock is notified as soon as something happened, be it the context being successfully created or destroy being called by the context creation, it can't be otherwise.
  • Why not notify twice then, once faking created = true and then = false? That would allow for start(true); stop(true); chains to successfully unblock
  • LwjglContext#internalCreate would set created/free the lock before the initialization even happened, but since this is called after LwjglAbstractDisplay#initInThread, the context is created and created=true anyway.

Edit: It may be worth noting that this is a special case, because it runs when the jvm is about to load the LwjglAbstractDisplay/LwjglContext class, which it can't because of the import on Sys.
Actually LwjglAbstractDisplay#initInThread catches all exceptions and notifies the lock, for the very purpose of avoiding this issue.
BUT: it doesn't guarantee created is true there.

Still this issue is otherwise a bit misleading, as this is a very special condition, there isn't much the code can do when it's not even propery loaded/executed.

It happens in LwjglAbstractDisplay#run (L220)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    tracked

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions