Skip to content

Add constinit global string holder classes#1512

Open
yukawa wants to merge 1 commit into
google:masterfrom
ciceroaware:constinit_string2
Open

Add constinit global string holder classes#1512
yukawa wants to merge 1 commit into
google:masterfrom
ciceroaware:constinit_string2

Conversation

@yukawa
Copy link
Copy Markdown
Collaborator

@yukawa yukawa commented May 12, 2026

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 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 keeping all foreign code outside the publish lock and by being trivially destructible (unless
MOZC_NO_ATOMIC_FLAG_WAIT is specified).

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> g_program_files_x86(
    []() -> std::string { return ComputeProgramFilesX86Path(); });

absl::string_view path = g_program_files_x86.GetOrInit();

ConstInitMutableString is the set-many, snapshot-read variant. Set() atomically replaces the stored value; Get() returns a std::string snapshot under a lock-protected copy.

#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();
}

For platforms where std::atomic_flag::wait() is disallowed in favor of absl::Mutex, MOZC_NO_ATOMIC_FLAG_WAIT macro is provided to switch the implementation to the absl::Mutex-based one. This guarantees that std::atomic_flag::wait() is used only for client build flavors in mozc_select.

Issue IDs

N/A

Steps to test new behaviors (if any)

  • OS: All
  • Steps:
    1. bazelisk test //base/strings/... --build_tests_only

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 keeping all foreign code outside the publish
lock and by being trivially destructible (unless
MOZC_NO_ATOMIC_FLAG_WAIT is specified).

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> g_program_files_x86(
      []() -> std::string { return ComputeProgramFilesX86Path(); });

  absl::string_view path = g_program_files_x86.GetOrInit();

ConstInitMutableString is the set-many, snapshot-read variant. Set()
atomically replaces the stored value; Get() returns a std::string
snapshot under a lock-protected copy.

  #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(); }

For platforms where std::atomic_flag::wait() is disallowed in favor of
absl::Mutex, MOZC_NO_ATOMIC_FLAG_WAIT macro is provided to switch the
implementation to the absl::Mutex-based one. This guarantees that
std::atomic_flag::wait() is used only for "client" build flavors in
"mozc_select".
@yukawa yukawa force-pushed the constinit_string2 branch from 5c38653 to e111901 Compare May 12, 2026 18:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant