A label is a pair of key and value, each of which is an arbitrary array of bytes.
A label set is a set of labels, where all the keys are unique.
This document describes a mechanism for threads to declare a particular label set to be active at a particular time, in such a way that an external program that is able to read the thread's memory while it is interrupted will be able to read the set.
The process must be running on Linux on an x86-64 or aarch64 system.
Two pieces of data must be exposed by the process; they are described in detail below. The component that defines this data must be an ELF binary loaded on startup by the process (that is, either the main executable or a dynamically linked library in the initial set loaded on startup).
If the binary is a dynamically linked library, its filename must match the following regular expression: libcustomlabels.*\.so
.
The binary must export a dynamic symbol called custom_labels_abi_version
. It must be have a size of 4 bytes and have the constant value 0
.
The binary must export a dynamic symbol called custom_labels_thread_local_data
.
If the binary is the main executable, the object must be accessible from the statically known offset from the thread pointer described in "ELF Handing For Thread-Local Storage" (variant I for aarch64; variant II for x86-64).
Note: This should be the default behavior; no special compiler flags are needed.
Otherwise, if the binary is a dynamically linked library, the data this symbol references must be accessible via a relocation of type R_X86_64_TLSDESC
or R_AARCH64_TLSDESC
, depending on the architecture.
Note: If the library is compiled using gcc, this can be achieved by annotating the
object's definition with __thread
and building it as follows on x86-64:
gcc -ftls-model=global-dynamic -mtls-dialect=gnu2 -fPIC -shared -o libcustomlabels.so customlabels.c
or as follows on aarch64:
gcc -ftls-model=global-dynamic -mtls-dialect=desc -fPIC -shared -o libcustomlabels.so customlabels.c
The object referenced by this symbol must have the layout of tls_t
, defined as follows:
typedef struct {
size_t len;
const unsigned char *buf;
} custom_labels_string_t;
typedef struct {
custom_labels_string_t key;
custom_labels_string_t value;
} custom_labels_label_t;
typedef struct {
custom_labels_label_t *storage;
size_t count;
} tls_t;
As already stated, custom_labels_abi_version
has the constant value 0
. If it has any other value, nothing in this document applies.
While a the thread is suspended, the external program may determine its active label set by reading the data at custom_labels_thread_local_data
according to the following principles.
custom_labels_string_t
: ifbuf
is null, this represents the absence of a value. Otherwise,buf
points to an array of bytes of sizelen
.custom_labels_label_t
: ifkey.buf
represents the absence of a value (that is, ifkey.buf
is null), this object is ignored.val.buf
must never be null. Otherwise, this represents a label whose key iskey
and whose value isvalue
.tls_t
:storage
points to an array of possible labels of lengthcount
. As described above, an element ofstorage
whose key is absent is ignored. An element is also ignored if its key is identical to an element that appears earlier in the array. Thustls_t
represents a label set where uniqueness of keys is guaranteed by taking the first label for any given key.
Note: Label sets are indeed mathematical sets; that is, they are unordered. Thus order of the objects in tls_t::storage
has no meaning except for disambiguation of keys as described above.