OpenSSLStatic
A raw pthread (created by C code, outside Crystal) has no ::Thread
object in its thread-local storage. The stdlib fallback
Crystal::System::Thread.current_thread then lazily runs ::Thread.new,
whose #stack_address asks the Boehm GC for this thread's stack bottom —
and GC_get_my_stackbottom segfaults, because the thread was never
registered with GC_pthread_create.
Fiber.current reaches that path from everywhere (e.g. Crystal::FdLock
sets @closing = Fiber.current on every socket close), so a raw thread
gets a pre-created STAND-IN ::Thread instead.
The stand-in is built with allocate — NEVER Thread.new/Fiber.new:
the real initializers push the objects into the global Thread.threads
/ Fiber.fibers lists, and the GC before_collect hook walks those
lists calling GC_set_stackbottom for every entry. A list entry for a
thread that owns no real GC registration corrupts the mark phase
(SIGSEGV inside GC_mark_from). The allocated pair stays out of both
lists: it is an IDENTITY MARKER ONLY — nobody may resume the fiber or
join the thread.
The main thread itself ALSO has an empty TLS early at startup, and
there the stdlib lazy create-and-store must keep working — hence the
pthread_self check against the handle captured at require time.
Class methods
Once per thread: make sure the Boehm GC knows this pthread. Safe to
call from GC.malloc — allocates nothing.
Runs at the exit of a thread we registered (pthread TLS destructor). :nodoc:
poll(fd, events, timeout) → true when ready, false on timeout.
Called once at require time from the main thread. :nodoc:
Thread-safe SO_SNDTIMEO-free blocking read of one buffer; the
EINTR-safe syscall loop every method below repeats.