Skip to content

v0.2.0-3

Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 10 Oct 14:01
16df759
fix: preserve Linux host exit after cooperative worker shutdown (#18)

* Keep the statics alive and end the process under a call at C exit on Linux

On Linux a C exit() destroyed the statics of libstable-diffusion.so while
other threads were still inside it, and those threads crashed: a generation
in ggml_cpu_extra_compute_forward, over the vector of ggml's CPU buffer
types, and a load in ggml_backend_reg_name, over ggml's backend registry
(leehack/llamadart#949).

On Linux, Android excepted:

- The hidden __cxa_atexit that Apple builds use is compiled in and registers
  the library's exit handler in the place of each static destructor, so no
  static of the library is ever destroyed.
- exit() frees nothing. Nothing on Linux needs the contexts freed, and a free
  during exit() would run among the exit handlers of a GPU driver.
- With no call in flight exit() goes on and takes no time in the library,
  also right after a call: there is no settle time.
- With a call in flight the process ends where the library's handler runs:
  stdio is flushed and _exit() is called with the status, which glibc's
  on_exit() provides. The rest of exit() would otherwise run under the call,
  and waiting for the call instead holds exit() up, which makes a Dart VM
  abort while another isolate runs Dart code (leehack/llamadart#977).
- No thread is blocked: a wrapper function called once the exit has begun
  returns at once with its failure value.
- The handler is registered again after whatever may have opened a driver:
  before the first load or device query, after the first device query and
  after every load.

Apple builds are unchanged: the macOS library built from this tree and from
its parent at one path is the same file. Android and Windows are untouched.

The stand-in test gains the Linux scenarios, and the runtime test, which only
reported on Linux, now has to pass there on the CPU.

Refs leehack/llamadart#949, leehack/llamadart#966, leehack/llamadart-native#105

* Fail a Linux library that registers static destructors with the C library

A Linux library that imports __cxa_atexit registers its static destructors
past the definition in src/sd_dart_exit.cpp, and exit() then destroys them
under the threads that are still inside the library. validate_artifacts.py
reads the imports with readelf and fails such a library, as it does a Mach-O
one.

It also fails a library that imports std::ios_base::Init::Init(). Before GCC
13 every source that includes <iostream> holds a stream initializer, whose
destructor would be dropped with the others, and a host that writes to an
unsynchronized std::cout would lose what it had not flushed.

Refs leehack/llamadart#949

* wip: initialise the refused flag of a statics call

The stand-in of tests/test_device_memory.py defines its own constructor and
left the Linux-only member unset, so a device query was refused at random.

Not rebuilt or re-measured after this change: the Linux and macOS libraries
measured in the pull request were built from the commit before it.

* fix: preserve Linux host callbacks after cooperative shutdown

* ci: require cooperative Linux Dart shutdown coverage

* test: initialize ASan for two-runtime shutdown probes