class ThreadStorage

Defined at line 45 of file ../../sdk/lib/c/startup/../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 47 of file ../../sdk/lib/c/startup/../threads/thread-storage.h

void ThreadStorage (ThreadStorage && other)

Defined at line 48 of file ../../sdk/lib/c/startup/../threads/thread-storage.h

ThreadStorage & operator= (ThreadStorage && other)

Defined at line 50 of file ../../sdk/lib/c/startup/../threads/thread-storage.h

zx::result<Thread *> Allocate (zx::unowned_vmar 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 handle is saved and used for destruction, so it

must remain valid for the lifetime of the object (it's just the long-lived

primary allocation / root VMAR handle, except in tests).

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 297 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 16 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 30 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 77 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 121 of file ../../sdk/lib/c/startup/../threads/thread-storage.h

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 126 of file ../../sdk/lib/c/startup/../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 130 of file ../../sdk/lib/c/startup/../threads/thread-storage.h

PageRoundedSize stack_size ()

Defined at line 132 of file ../../sdk/lib/c/startup/../threads/thread-storage.h

PageRoundedSize guard_size ()

Defined at line 133 of file ../../sdk/lib/c/startup/../threads/thread-storage.h

const zx::vmar & vmar ()

A handy stash of the unowned AllocationVmar() value passed to Allocate().

Defined at line 136 of file ../../sdk/lib/c/startup/../threads/thread-storage.h

void ~ThreadStorage ()

The thread block is implicitly destroyed last. **NOTE:** The Thread

object itself resides inside the thread block, so the block must not be

reclaimed until the ThreadStorage has been moved out of the Thread!

FreeStacks() can be called first to free up most of the storage while the

Thread object needs to stay alive (until join or detached final-exit).

Defined at line 143 of file ../../sdk/lib/c/startup/../threads/thread-storage.h

template <typename T>
bool StackGrowsUp (T ThreadStorage::* stack)

This takes a pointer-to-data-member and all the members are private. It's

only used in implementation template code outside the class that's called

by method implementations.

Defined at line 150 of file ../../sdk/lib/c/startup/../threads/thread-storage.h