Spin-wait often involves active sleep (better known as "pause"). x86
has a direct assembly instruction named "PAUSE" which has two roles:
one is to hint at the operating systme that it might be ready to be
swapped out, and the other is to create a small delay. That delay is
useful as backoff from attempting to capture spinlocks, which improves
the behavior of the system and allows more efficient lock acquisition.
However, the "yield" instruction is not a good fit because it is
effectively a nop on most Arm cores and does not cause enough delay to
help backoff. The "isb" instruction is a barrier that, especially
inside a loop, creates a small delay without consuming ALU resources.
Android's Bionic libc stores the thread ID in TLS slot 1 instead of 0
on 32-bit ARM and AArch64. Slot 0 contains a pointer to the ELF DTV
(Dynamic Thread Vector) instead, which is constant for each loaded DSO.
Because mimalloc uses the thread ID to determine whether operations are
thread-local or cross-thread (atomic), all threads having the same ID
causes internal data structures to get corrupted quickly when multiple
threads are using the allocator:
mimalloc: assertion failed: at "external/mimalloc/src/page.c":563, mi_page_extend_free
assertion: "page->local_free == NULL"
mimalloc: assertion failed: at "external/mimalloc/src/page.c":74, mi_page_is_valid_init
assertion: "page->used <= page->capacity"
mimalloc: assertion failed: at "external/mimalloc/src/page.c":100, mi_page_is_valid_init
assertion: "page->used + free_count == page->capacity"
mimalloc: assertion failed: at "external/mimalloc/src/page.c":74, mi_page_is_valid_init
assertion: "page->used <= page->capacity"
Add support for Android's alternate TLS layout to fix the crashes in
multi-threaded use cases.
Fixes#376.