class ThreadStorage
Defined at line 47 of file ../../sdk/lib/c/threads/thread-storage.h
ThreadStorage handles the memory allocation and ownership for Thread. It's
responsible for allocating all the various kinds of stacks, and the thread
area that underlies both the implementation's private Thread Control Block
(TCB) as well as the public Fuchsia Compiler ABI and ELF TLS. ThreadStorage
initializes only the parts of the TCB that are part of the public ABI
(including all of ELF Initial Exec TLS) and then leaves the rest of the TCB
zero-initialized for later use by libc internals.
Initially it's used at process startup and thread creation. It owns those
allocations and cleans them up on destruction e.g. if thread creation fails.
During the thread's lifetime, the ThreadStorage is moved into its Thread.
This is a bit tricky, as the Thread object's own memory resides in one of
the blocks that ThreadStorage owns. So to destroy Thread, its ThreadStorage
must be moved back out before explicitly calling ~Thread().
ThreadStorage can only be default-constructed or moved. Before Allocate()
has returned successfully (or after it fails), it should only be destroyed
and no other methods used (except for moves).
Public Methods
void ~ThreadStorage ()
Defined at line 36 of file ../../sdk/lib/c/threads/thread-storage.cc
void ThreadStorage ()
Defined at line 49 of file ../../sdk/lib/c/threads/thread-storage.h
void ThreadStorage (ThreadStorage && other)
Defined at line 50 of file ../../sdk/lib/c/threads/thread-storage.h
ThreadStorage & operator= (ThreadStorage && other)
Defined at line 52 of file ../../sdk/lib/c/threads/thread-storage.h
zx::result<Thread *> Allocate (thrd_zx_create_handles_t allocate_from, std::string_view vmo_name, PageRoundedSize stack, PageRoundedSize guard)
This allocates everything and holds ownership in this object. If it
returns an error, some resources may now be owned but nothing more should
be done with the object but to destroy it (and thus reclaim them).
When this returns success, the remaining methods return useful values.
The machine stack, unsafe stack (for the SafeStack ABI, enabled on all
machines), and shadow call stack (enabled on some machines), are all
allocated with guard pages and all-zeroes contents. In the thread area:
* The unsafe stack pointer at $tp + ZX_TLS_UNSAFE_SP_OFFSET is set to
the top of the unsafe stack.
* If the machine's TLS ABI has *$tp = $tp (like x86), that is set.
* The ZX_TLS_STACK_GUARD_OFFSET word still must be set. For the initial
thread, the caller will choose random bits; for new threads, the caller
will copy the value found via its own $tp.
* All the ELF Initial Exec TLS data (static TLS) is initialized.
* The DTV for the dynamic TLS implementation is allocated and filled in.
TODO(https://fxbug.dev/397084454): The new //sdk/lib/dl TLS runtime
does not require a bespoke ABI contract for a DTV.
The name string will become the ZX_PROP_NAME used for the VMO, and must
not be empty. The VMAR handles are saved and used for destruction, so
they must remain valid for the lifetime of the object.
The returned Thread* points somewhere inside the thread area block owned
by this ThreadStorage object, which also contains the static TLS area
already initialized with all the Initial Exec TLS data. The ABI rules
govern where that is in relation to the thread pointer ($tp) and thereby,
indirectly, where the TCB lies relative to $tp. (Note that here we
consider the Fuchsia Compiler ABI
<zircon
/tls.h> fixed slots, as well as
the $tp->self pointer on x86, to be part of the TCB--at one end of it or
the other--though nothing else about the TCB is part of any public ABI.)
Defined at line 314 of file ../../sdk/lib/c/threads/thread-storage-allocate.cc
void FreeStacks ()
This frees just the blocks for all the stacks, leaving the thread block
(where the Thread object itself resides) intact until destruction.
Defined at line 29 of file ../../sdk/lib/c/threads/thread-storage.cc
ThreadStorage FromThread (Thread & thread, bool take_thread_block)
This moves ownership of the ThreadStorage out of the Thread, making it
possible to destroy the Thread before destroying the ThreadStorage makes
its memory inaccessible. (When Thread becomes a true C++ type, this will
be replaced with plain move-construction from its ThreadStorage member.)
If take_thread_block is false, leave the thread block intact.
Defined at line 50 of file ../../sdk/lib/c/threads/thread-storage.cc
void ToThread (Thread & thread)
This moves ownership from this ThreadStorage into the Thread. (When
Thread becomes a true C++ type, this will be replaced with plain
move-assignment to its ThreadStorage member.)
Defined at line 90 of file ../../sdk/lib/c/threads/thread-storage.cc
void AssertLive ()
Assert that this ThreadStorage looks like the result of a successful
Allocate(), possibly after FreeStacks() has been called.
Defined at line 109 of file ../../sdk/lib/c/threads/thread-storage.h
std::span<uint64_t> ThreadMachineStack (const Thread & thread)
These recover those spans from a Thread without modifying it. (When
Thread becomes a true C++ type, these can be removed in favor of just
using the methods above on the ThreadStorage member in Thread.)
Defined at line 112 of file ../../sdk/lib/c/threads/thread-storage.cc
std::span<uint64_t> ThreadUnsafeStack (const Thread & thread)
Defined at line 117 of file ../../sdk/lib/c/threads/thread-storage.cc
std::span<uint64_t> ThreadShadowCallstack (const Thread & thread)
Defined at line 125 of file ../../sdk/lib/c/threads/thread-storage.cc
uint64_t * machine_sp ()
This returns the initial value for the machine SP. This is always the
limit of the stack, where a push (`*--sp = ...`) will be the first thing
done. This makes it appropriate for a call site, and on most machines for
the entry to a C function. But on x86 it needs a return address pushed
before it can be used at a C function's entry point.
Defined at line 131 of file ../../sdk/lib/c/threads/thread-storage.h
std::span<std::byte> ThreadThreadBlock (const Thread & thread)
Defined at line 133 of file ../../sdk/lib/c/threads/thread-storage.cc
uint64_t * unsafe_sp ()
This returns the initial value for the unsafe SP. This is always the
limit of the stack, which is always the protocol for function entry.
(This is already stored at $tp + ZX_TLS_UNSAFE_SP_OFFSET, too.)
Defined at line 136 of file ../../sdk/lib/c/threads/thread-storage.h
uint64_t * shadow_call_sp ()
This returns the initial value for the shadow call stack pointer.
That stack grows up, so the next operation will be `*sp++ = ...`.
Defined at line 140 of file ../../sdk/lib/c/threads/thread-storage.h
std::span<uint64_t> machine_stack ()
These return each entire stack as a span.
Defined at line 144 of file ../../sdk/lib/c/threads/thread-storage.h
std::span<uint64_t> unsafe_stack ()
Defined at line 148 of file ../../sdk/lib/c/threads/thread-storage.h
std::span<uint64_t> shadow_call_stack ()
Defined at line 152 of file ../../sdk/lib/c/threads/thread-storage.h
std::span<std::byte> thread_block ()
Defined at line 156 of file ../../sdk/lib/c/threads/thread-storage.h
PageRoundedSize stack_size ()
Defined at line 172 of file ../../sdk/lib/c/threads/thread-storage.h
PageRoundedSize guard_size ()
Defined at line 173 of file ../../sdk/lib/c/threads/thread-storage.h
template <auto&& block>
void CommitBlock (auto && block)
This is only used inside the Allocate() implementation, but it's public so
it can be used in a concept.
Defined at line 177 of file ../../sdk/lib/c/threads/thread-storage.h