blob: 2825d074a4769f4d83760c5aebc7e31c9067e023 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
#include <zircon/types.h>
#include <ktl/atomic.h>
// Represents an internalized string that may be referenced in traces by id to
// improve the efficiency of labels and other strings. This type does not define
// constructors or a destructor and contains trivially constructible members so
// that it may be aggregate-initialized to avoid static initializers and guards.
struct StringRef {
static constexpr int kInvalidId = -1;
const char* string{nullptr};
ktl::atomic<int> id{kInvalidId};
StringRef* next{nullptr};
// Returns the numeric id for this string ref. If this is the first runtime
// encounter with this string ref a new id is generated and the string ref
// is added to the global linked list.
int GetId() {
const int ref_id = id.load(ktl::memory_order_relaxed);
return ref_id == kInvalidId ? Register(this) : ref_id;
// Returns the head of the global string ref linked list.
static StringRef* head() { return head_.load(ktl::memory_order_acquire); }
// TODO( Replace runtime lock-free linked list with comdat linker
// sections once the toolchain supports it.
static int Register(StringRef* string_ref);
static ktl::atomic<int> id_counter_;
static ktl::atomic<StringRef*> head_;
// String literal template operator that generates a unique StringRef instance
// for the given string literal. Every invocation for a given string literal
// value returns the same StringRef instance, such that the set of StringRef
// instances behaves as an internalized string table.
// This implementation uses the N3599 extension supported by Clang and GCC.
// C++20 ratified a slightly different syntax that is simple to switch to, once
// available, without affecting call sites.
// TODO( Update to C++20 syntax when available.
// References:
// Example:
// ktrace_probe("probe_name"_stringref, ...);
template <typename T, T... chars>
inline StringRef* operator""_stringref() {
static const char storage[] = {chars..., '\0'};
static StringRef string_ref{storage};
return &string_ref;