Introduce ConstInitImmutableString and ConstInitMutableString#1493
Open
yukawa wants to merge 1 commit into
Open
Introduce ConstInitImmutableString and ConstInitMutableString#1493yukawa wants to merge 1 commit into
ConstInitImmutableString and ConstInitMutableString#1493yukawa wants to merge 1 commit into
Conversation
Collaborator
hiroyuki-komatsu
left a comment
There was a problem hiding this comment.
Thank you for the PR!
Collaborator
Author
|
Done. Let me know if you prefer |
These are utility classes for global strings whose value is known only
at runtime. They are motivated by the on-going effort to remove
Singleton<T>, which has surfaced several places in system_util.cc
(directory caches, user-SID lookup, program-invocation-name holder)
where the singleton wraps a string lookup that must run *after* the
surrounding modules are ready.
A function-local "static std::string" would be the obvious replacement,
but reintroduces two issues that Singleton<T> callers have learnt to
avoid:
* On Windows, function-local static initialization is not safe to
invoke from DllMain because the compiler-generated guard can take
locks that interact badly with the Loader Lock.
* The resulting destructor runs at process exit in unspecified order
relative to other globals.
Both classes address these by being trivially destructible (values that
don't fit inline live in an intentionally-leaked heap buffer) and by
keeping all foreign code outside the publish lock.
ConstInitImmutableString is the publish-once, read-many variant. It
takes an IdempotentInitializer function pointer that is invoked
lock-free on the first GetOrInit(), so the class is safe to use from
DllMain even when the initializer itself acquires the Loader Lock.
Subsequent reads return a string_view over stable, NUL-terminated
storage on a lock-free fast path:
#include "base/strings/const_init_immutable_string.h"
constinit mozc::ConstInitImmutableString<256> kProgramFilesX86(
[]() -> std::string { return ComputeProgramFilesX86Path(); });
absl::string_view path = kProgramFilesX86.GetOrInit();
ConstInitMutableString is the set-many, snapshot-read variant. Set
atomically replaces the stored value; Get returns a std::string
snapshot under a spinlock-protected copy. Empty doubles as the "never
set" sentinel; callers that want a lazy default observe empty and
Set it themselves:
#include "base/strings/const_init_mutable_string.h"
constinit mozc::ConstInitMutableString<256> g_invocation_name;
void Init(absl::string_view name) { g_invocation_name.Set(name); }
std::string GetName() { return g_invocation_name.Get(); }
Implementation notes:
* Only the publish step is serialized, by a small atomic_flag
spinlock with PAUSE / YIELD hints. Heap allocation for the
fallback buffer is staged before the spinlock is taken, so the
critical section is bounded by fixed_array_size and a throwing
bad_alloc cannot leave the spinlock latched.
* Constructors are consteval, so instances must be
constant-initialized.
* Common helpers (spin hint, RAII spinlock guard, heap-fallback
staging and commit) live in
base/strings/internal/const_init_string_helpers.{h,cc}.
Templates that operate on CharT data are explicitly instantiated
for char and wchar_t so they live in one TU.
Collaborator
Author
|
I've uploaded another variant of the implementation that relies on |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
These are utility classes for global strings whose value is known only at runtime. They are motivated by the on-going effort to remove
Singleton<T>, which has surfaced several places insystem_util.cc(directory caches, user-SID lookup, program-invocation-name holder) where the singleton wraps a string lookup that must run after the surrounding modules are ready.A function-local
static std::stringwould be the obvious replacement, but reintroduces two issues thatSingleton<T>callers have learnt to avoid:DllMainbecause the compiler-generated guard can take locks that interact badly with the Loader Lock.Both classes address these by being trivially destructible (values that don't fit inline live in an intentionally-leaked heap buffer) and by keeping all foreign code outside the publish lock.
ConstInitImmutableStringis the publish-once, read-many variant. It takes anIdempotentInitializerfunction pointer that is invoked lock-free on the firstGetOrInit(), so the class is safe to use fromDllMaineven when the initializer itself acquires the Loader Lock. Subsequent reads return astring_viewover stable, NUL-terminated storage on a lock-free fast path:ConstInitMutableStringis the set-many, snapshot-read variant. Set atomically replaces the stored value; Get returns astd::stringsnapshot under a spinlock-protected copy. Empty doubles as the "never set" sentinel; callers that want a lazy default observe empty and Set it themselves:Implementation notes:
atomic_flagspinlock with PAUSE / YIELD hints. Heap allocation for the fallback buffer is staged before the spinlock is taken, so the critical section is bounded byfixed_array_sizeand a throwingbad_alloccannot leave the spinlock latched.consteval, so instances must be constant-initialized.base/strings/internal/const_init_string_helpers.{h,cc}. Templates that operate onCharTdata are explicitly instantiated forcharandwchar_tso they live in one TU.Issue IDs
N/A
Steps to test new behaviors (if any)
bazelisk test //base/strings/... --build_tests_onlyAdditional context
Add any other context about the pull request here.