Threads
*******

This chapter describes functions used for managing threads. Theglibc provides two threading implementations: ISO C threads and POSIX threads.

ISO C Threads
=============

This section describes the glibcadj ISO C threads implementation. To have a deeper understanding of this API, it is strongly recommended to read ISO/IEC 9899:2011, section 7.26, in which ISO C threads were originally specified.  All types and function prototypes are declared in the header file threads.h.

Return Values
-------------

The ISO C thread specification provides the following enumeration constants for return values from functions in the API:

thrd_timedout
     C11, threads.h A specified time was reached without acquiring the requested resource, usually a mutex or condition variable.

thrd_success
     C11, threads.h The requested operation succeeded.

thrd_busy
     C11, threads.h The requested operation failed because a requested resource is already in use.

thrd_error
     C11, threads.h The requested operation failed.

thrd_nomem
     C11, threads.h The requested operation failed because it was unable to allocate enough memory.

Creation and Control
--------------------

Theglibc implements a set of functions that allow the user to easily create and use threads.  Additional functionality is provided to control the behavior of threads.

The following data types are defined for managing threads:

 -- Data Type: thrd_t
     C11, threads.h A unique object that identifies a thread.

 -- Data Type: thrd_start_t
     C11, threads.h This data type is an int (*) (void *) typedef that is passed to thrd_create when creating a new thread.  It should point to the first function that thread will run.

The following functions are used for working with threads:

 -- Function: int thrd_create (thrd_t *THR, thrd_start_t FUNC, void *ARG)
     C11, threads.h thrd_create creates a new thread that will execute the function FUNC.  The object pointed to by ARG will be used as the argument to FUNC.  If successful, THR is set to the new thread identifier.

     This function may return thrd_success, thrd_nomem, or thrd_error.

 -- Function: thrd_t thrd_current (void)
     C11, threads.h This function returns the identifier of the calling thread.

 -- Function: int thrd_equal (thrd_t LHS, thrd_t RHS)
     C11, threads.h thrd_equal checks whether LHS and RHS refer to the same thread.  If LHS and RHS are different threads, this function returns 0; otherwise, the return value is non-zero.

 -- Function: int thrd_sleep (const struct timespec *TIME_POINT, struct timespec *REMAINING)
     C11, threads.h thrd_sleep blocks the execution of the current thread for at least until the elapsed time pointed to by TIME_POINT has been reached.  This function does not take an absolute time, but a duration that the thread is required to be blocked.  See Time Basics, and Time Types.

     The thread may wake early if a signal that is not ignored is received. In such a case, if remaining is not NULL, the remaining time duration is stored in the object pointed to by REMAINING.

     thrd_sleep returns 0 if it blocked for at least the amount of time in time_point, -1 if it was interrupted by a signal, or a negative number on failure.

 -- Function: void thrd_yield (void)
     C11, threads.h thrd_yield provides a hint to the implementation to reschedule the execution of the current thread, allowing other threads to run.

 -- Function: _Noreturn void thrd_exit (int RES)
     C11, threads.h thrd_exit terminates execution of the calling thread and sets its result code to RES.

     If this function is called from a single-threaded process, the call is equivalent to calling exit with EXIT_SUCCESS (see Normal Termination).  Also note that returning from a function that started a thread is equivalent to calling thrd_exit.

 -- Function: int thrd_detach (thrd_t THR)
     C11, threads.h thrd_detach detaches the thread identified by thr from the current control thread.  The resources held by the detached thread will be freed automatically once the thread exits.  The parent thread will never be notified by any THR signal.

     Calling thrd_detach on a thread that was previously detached or joined by another thread results in undefined behavior.

     This function returns either thrd_success or thrd_error.

 -- Function: int thrd_join (thrd_t THR, int *RES)
     C11, threads.h thrd_join blocks the current thread until the thread identified by thr finishes execution.  If res is not NULL, the result code of the thread is put into the location pointed to by RES.  The termination of the thread synchronizes-with the completion of this function, meaning both threads have arrived at a common point in their execution.

     Calling thrd_join on a thread that was previously detached or joined by another thread results in undefined behavior.

     This function returns either thrd_success or thrd_error.

Call Once
---------

In order to guarantee single access to a function, theglibc implements a call once function to ensure a function is only called once in the presence of multiple, potentially calling threads.

 -- Data Type: once_flag
     C11, threads.h A complete object type capable of holding a flag used by call_once.

 -- Macro: ONCE_FLAG_INIT
     C11, threads.h This value is used to initialize an object of type once_flag.

 -- Function: void call_once (once_flag *FLAG, void (*FUNC) (void))
     C11, threads.h call_once calls function FUNC exactly once, even if invoked from several threads.  The completion of the function FUNC synchronizes-with all previous or subsequent calls to call_once with the same flag variable.

Mutexes
-------

To have better control of resources and how threads access them, theglibc implements a mutex object, which can help avoid race conditions and other concurrency issues.  The term ``mutex'' refers to mutual exclusion.

The fundamental data type for a mutex is the mtx_t:

 -- Data Type: mtx_t
     C11, threads.h The mtx_t data type uniquely identifies a mutex object.

The ISO C standard defines several types of mutexes.  They are represented by the following symbolic constants:

mtx_plain
     C11, threads.h A mutex that does not support timeout, or test and return.

mtx_recursive
     C11, threads.h A mutex that supports recursive locking, which means that the owning thread can lock it more than once without causing deadlock.

mtx_timed
     C11, threads.h A mutex that supports timeout.

The following functions are used for working with mutexes:

 -- Function: int mtx_init (mtx_t *MUTEX, int TYPE)
     C11, threads.h mtx_init creates a new mutex object with type TYPE.  The object pointed to by MUTEX is set to the identifier of the newly created mutex.

     Not all combinations of mutex types are valid for the type argument.  Valid uses of mutex types for the type argument are:

     mtx_plain
          A non-recursive mutex that does not support timeout.

     mtx_timed
          A non-recursive mutex that does support timeout.

     mtx_plain | mtx_recursive
          A recursive mutex that does not support timeout.

     mtx_timed | mtx_recursive
          A recursive mutex that does support timeout.

     This function returns either thrd_success or thrd_error.

 -- Function: int mtx_lock (mtx_t *MUTEX)
     C11, threads.h mtx_lock blocks the current thread until the mutex pointed to by MUTEX is locked.  The behavior is undefined if the current thread has already locked the mutex and the mutex is not recursive.

     Prior calls to mtx_unlock on the same mutex synchronize-with this operation (if this operation succeeds), and all lock/unlock operations on any given mutex form a single total order (similar to the modification order of an atomic).

     This function returns either thrd_success or thrd_error.

 -- Function: int mtx_timedlock (mtx_t *restrict MUTEX, const struct timespec *restrict TIME_POINT)
     C11, threads.h mtx_timedlock blocks the current thread until the mutex pointed to by MUTEX is locked or until the calendar time pointed to by TIME_POINT has been reached.  Since this function takes an absolute time, if a duration is required, the calendar time must be calculated manually.  See Time Basics, and Calendar Time.

     If the current thread has already locked the mutex and the mutex is not recursive, or if the mutex does not support timeout, the behavior of this function is undefined.

     Prior calls to mtx_unlock on the same mutex synchronize-with this operation (if this operation succeeds), and all lock/unlock operations on any given mutex form a single total order (similar to the modification order of an atomic).

     This function returns either thrd_success or thrd_error.

 -- Function: int mtx_trylock (mtx_t *MUTEX)
     C11, threads.h mtx_trylock tries to lock the mutex pointed to by MUTEX without blocking.  It returns immediately if the mutex is already locked.

     Prior calls to mtx_unlock on the same mutex synchronize-with this operation (if this operation succeeds), and all lock/unlock operations on any given mutex form a single total order (similar to the modification order of an atomic).

     This function returns thrd_success if the lock was obtained, thrd_busy if the mutex is already locked, and thrd_error on failure.

 -- Function: int mtx_unlock (mtx_t *MUTEX)
     C11, threads.h mtx_unlock unlocks the mutex pointed to by MUTEX.  The behavior is undefined if the mutex is not locked by the calling thread.

     This function synchronizes-with subsequent mtx_lock, mtx_trylock, and mtx_timedlock calls on the same mutex. All lock/unlock operations on any given mutex form a single total order (similar to the modification order of an atomic).

     This function returns either thrd_success or thrd_error.

 -- Function: void mtx_destroy (mtx_t *MUTEX)
     C11, threads.h mtx_destroy destroys the mutex pointed to by MUTEX.  If there are any threads waiting on the mutex, the behavior is undefined.

Condition Variables
-------------------

Mutexes are not the only synchronization mechanisms available.  For some more complex tasks, theglibc also implements condition variables, which allow the programmer to think at a higher level when solving complex synchronization problems.  They are used to synchronize threads waiting on a certain condition to happen.

The fundamental data type for condition variables is the cnd_t:

 -- Data Type: cnd_t
     C11, threads.h The cnd_t uniquely identifies a condition variable object.

The following functions are used for working with condition variables:

 -- Function: int cnd_init (cnd_t *COND)
     C11, threads.h cnd_init initializes a new condition variable, identified by COND.

     This function may return thrd_success, thrd_nomem, or thrd_error.

 -- Function: int cnd_signal (cnd_t *COND)
     C11, threads.h cnd_signal unblocks one thread that is currently waiting on the condition variable pointed to by COND.  If a thread is successfully unblocked, this function returns thrd_success.  If no threads are blocked, this function does nothing and returns thrd_success.  Otherwise, this function returns thrd_error.

 -- Function: int cnd_broadcast (cnd_t *COND)
     C11, threads.h cnd_broadcast unblocks all the threads that are currently waiting on the condition variable pointed to by COND.  This function returns thrd_success on success.  If no threads are blocked, this function does nothing and returns thrd_success. Otherwise, this function returns thrd_error.

 -- Function: int cnd_wait (cnd_t *COND, mtx_t *MUTEX)
     C11, threads.h cnd_wait atomically unlocks the mutex pointed to by MUTEX and blocks on the condition variable pointed to by COND until the thread is signaled by cnd_signal or cnd_broadcast. The mutex is locked again before the function returns.

     This function returns either thrd_success or thrd_error.

 -- Function: int cnd_timedwait (cnd_t *restrict COND, mtx_t *restrict MUTEX, const struct timespec *restrict TIME_POINT)
     C11, threads.h cnd_timedwait atomically unlocks the mutex pointed to by MUTEX and blocks on the condition variable pointed to by COND until the thread is signaled by cnd_signal or cnd_broadcast, or until the calendar time pointed to by TIME_POINT has been reached.  The mutex is locked again before the function returns.

     As for mtx_timedlock, since this function takes an absolute time, if a duration is required, the calendar time must be calculated manually.  See Time Basics, and Calendar Time.

     This function may return thrd_success, thrd_nomem, or thrd_error.

 -- Function: void cnd_destroy (cnd_t *COND)
     C11, threads.h cnd_destroy destroys the condition variable pointed to by COND.  If there are threads waiting on COND, the behavior is undefined.

Thread-local Storage
--------------------

Theglibc implements functions to provide thread-local storage, a mechanism by which variables can be defined to have unique per-thread storage, lifetimes that match the thread lifetime, and destructors that cleanup the unique per-thread storage.

Several data types and macros exist for working with thread-local storage:

 -- Data Type: tss_t
     C11, threads.h The tss_t data type identifies a thread-specific storage object.  Even if shared, every thread will have its own instance of the variable, with different values.

 -- Data Type: tss_dtor_t
     C11, threads.h The tss_dtor_t is a function pointer of type void (*) (void *), to be used as a thread-specific storage destructor.  The function will be called when the current thread calls thrd_exit (but never when calling tss_delete or exit).

 -- Macro: thread_local
     C11, threads.h thread_local is used to mark a variable with thread storage duration, which means it is created when the thread starts and cleaned up when the thread ends.

     Note: For C++, C++11 or later is required to use the thread_local keyword.

 -- Macro: TSS_DTOR_ITERATIONS
     C11, threads.h TSS_DTOR_ITERATIONS is an integer constant expression representing the maximum number of iterations over all thread-local destructors at the time of thread termination.  This value provides a bounded limit to the destruction of thread-local storage; e.g., consider a destructor that creates more thread-local storage.

The following functions are used to manage thread-local storage:

 -- Function: int tss_create (tss_t *TSS_KEY, tss_dtor_t DESTRUCTOR)
     C11, threads.h tss_create creates a new thread-specific storage key and stores it in the object pointed to by TSS_KEY.  Although the same key value may be used by different threads, the values bound to the key by tss_set are maintained on a per-thread basis and persist for the life of the calling thread.

     If destructor is not NULL, a destructor function will be set, and called when the thread finishes its execution by calling thrd_exit.

     This function returns thrd_success if tss_key is successfully set to a unique value for the thread; otherwise, thrd_error is returned and the value of tss_key is undefined.

 -- Function: int tss_set (tss_t TSS_KEY, void *VAL)
     C11, threads.h tss_set sets the value of the thread-specific storage identified by TSS_KEY for the current thread to VAL. Different threads may set different values to the same key.

     This function returns either thrd_success or thrd_error.

 -- Function: void * tss_get (tss_t TSS_KEY)
     C11, threads.h tss_get returns the value identified by TSS_KEY held in thread-specific storage for the current thread.  Different threads may get different values identified by the same key.  On failure, tss_get returns zero.

 -- Function: void tss_delete (tss_t TSS_KEY)
     C11, threads.h tss_delete destroys the thread-specific storage identified by TSS_KEY.

POSIX Threads
=============

This section describes the glibcadj POSIX Threads implementation.

Thread-specific Data
--------------------

The glibcadj implements functions to allow users to create and manage data specific to a thread.  Such data may be destroyed at thread exit, if a destructor is provided.  The following functions are defined:

 -- Function: int pthread_key_create (pthread_key_t *KEY, void (*DESTRUCTOR)(void*))
     POSIX, pthread.h Create a thread-specific data key for the calling thread, referenced by KEY.

     Objects declared with the C++11 thread_local keyword are destroyed before thread-specific data, so they should not be used in thread-specific data destructors or even as members of the thread-specific data, since the latter is passed as an argument to the destructor function.

 -- Function: int pthread_key_delete (pthread_key_t KEY)
     POSIX, pthread.h Destroy the thread-specific data KEY in the calling thread.  The destructor for the thread-specific data is not called during destruction, nor is it called during thread exit.

 -- Function: void *pthread_getspecific (pthread_key_t KEY)
     POSIX, pthread.h Return the thread-specific data associated with KEY in the calling thread.

 -- Function: int pthread_setspecific (pthread_key_t KEY, const void *VALUE)
     POSIX, pthread.h Associate the thread-specific VALUE with KEY in the calling thread.

Non-POSIX Extensions
--------------------

In addition to implementing the POSIX API for threads, theglibc provides additional functions and interfaces to provide functionality not specified in the standard.

Setting Process-wide defaults for thread attributes
...................................................

Theglibc provides non-standard API functions to set and get the default attributes used in the creation of threads in a process.

 -- Function: int pthread_getattr_default_np (pthread_attr_t *ATTR)
     GNU, pthread.h Get the default attribute values and set ATTR to match.  This function returns 0 on success and a non-zero error code on failure.

 -- Function: int pthread_setattr_default_np (pthread_attr_t *ATTR)
     GNU, pthread.h Set the default attribute values to match the values in ATTR.  The function returns 0 on success and a non-zero error code on failure. The following error codes are defined for this function:

     EINVAL
          At least one of the values in ATTR does not qualify as valid for the attributes or the stack address is set in the attribute.

     ENOMEM
          The system does not have sufficient memory.

Controlling the Initial Signal Mask of a New Thread
...................................................

Theglibc provides a way to specify the initial signal mask of a thread created using pthread_create, passing a thread attribute object configured for this purpose.

 -- Function: int pthread_attr_setsigmask_np (pthread_attr_t *ATTR, const sigset_t *SIGMASK)
     GNU, pthread.h Change the initial signal mask specified by ATTR.  If SIGMASK is not NULL, the initial signal mask for new threads created with ATTR is set to *SIGMASK.  If SIGMASK is NULL, ATTR will no longer specify an explicit signal mask, so that the initial signal mask of the new thread is inherited from the thread that calls pthread_create.

     This function returns zero on success, and ENOMEM on memory allocation failure.

 -- Function: int pthread_attr_getsigmask_np (const pthread_attr_t *ATTR, sigset_t *SIGMASK)
     GNU, pthread.h Retrieve the signal mask stored in ATTR and copy it to *SIGMASK.  If the signal mask has not been set, return the special constant PTHREAD_ATTR_NO_SIGMASK_NP, otherwise return zero.

     Obtaining the signal mask only works if it has been previously stored by pthread_attr_setsigmask_np.  For example, the pthread_getattr_np function does not obtain the current signal mask of the specified thread, and pthread_attr_getsigmask_np will subsequently report the signal mask as unset.

 -- Macro: int PTHREAD_ATTR_NO_SIGMASK_NP
     The special value returned by pthread_attr_setsigmask_np to indicate that no signal mask has been set for the attribute.

It is possible to create a new thread with a specific signal mask without using these functions.  On the thread that calls pthread_create, the required steps for the general case are:

 1. Mask all signals, and save the old signal mask, using pthread_sigmask.  This ensures that the new thread will be created with all signals masked, so that no signals can be delivered to the thread until the desired signal mask is set.

 2. Call pthread_create to create the new thread, passing the desired signal mask to the thread start routine (which could be a wrapper function for the actual thread start routine).  It may be necessary to make a copy of the desired signal mask on the heap, so that the life-time of the copy extends to the point when the start routine needs to access the signal mask.

 3. Restore the thread's signal mask, to the set that was saved in the first step.

The start routine for the created thread needs to locate the desired signal mask and use pthread_sigmask to apply it to the thread. If the signal mask was copied to a heap allocation, the copy should be freed.

Functions for Waiting According to a Specific Clock
...................................................

Theglibc provides several waiting functions that expect an explicit clockid_t argument.

 -- Function: int sem_clockwait (sem_t *SEM, clockid_t CLOCKID,
     const struct timespec *ABSTIME) Behaves like sem_timedwait except the time ABSTIME is measured against the clock specified by CLOCKID rather than CLOCK_REALTIME.  Currently, CLOCKID must be either CLOCK_MONOTONIC or CLOCK_REALTIME.

 -- Function: int pthread_cond_clockwait (pthread_cond_t *COND, pthread_mutex_t *MUTEX,
     clockid_t CLOCKID, const struct timespec *ABSTIME) Behaves like pthread_cond_timedwait except the time ABSTIME is measured against the clock specified by CLOCKID rather than the clock specified or defaulted when pthread_cond_init was called.  Currently, CLOCKID must be either CLOCK_MONOTONIC or CLOCK_REALTIME.

 -- Function: int pthread_rwlock_clockrdlock (pthread_rwlock_t *RWLOCK,
     clockid_t CLOCKID, const struct timespec *ABSTIME)

     Behaves like pthread_rwlock_timedrdlock except the time ABSTIME is measured against the clock specified by CLOCKID rather than CLOCK_REALTIME.  Currently, CLOCKID must be either CLOCK_MONOTONIC or CLOCK_REALTIME, otherwise EINVAL is returned.

 -- Function: int pthread_rwlock_clockwrlock (pthread_rwlock_t *RWLOCK,
     clockid_t CLOCKID, const struct timespec *ABSTIME)

     Behaves like pthread_rwlock_timedwrlock except the time ABSTIME is measured against the clock specified by CLOCKID rather than CLOCK_REALTIME.  Currently, CLOCKID must be either CLOCK_MONOTONIC or CLOCK_REALTIME, otherwise EINVAL is returned.

 -- Function: int pthread_tryjoin_np (pthread_t *THREAD,
     void **THREAD_RETURN) GNU, pthread.h Behaves like pthread_join except that it will return EBUSY immediately if the thread specified by THREAD has not yet terminated.

 -- Function: int pthread_timedjoin_np (pthread_t *THREAD,
     void **THREAD_RETURN, const struct timespec *ABSTIME) GNU, pthread.h Behaves like pthread_tryjoin_np except that it will block until the absolute time ABSTIME measured against CLOCK_REALTIME is reached if the thread has not terminated by that time and return EBUSY. If ABSTIME is equal to NULL then the function will wait forever in the same way as pthread_join.

 -- Function: int pthread_clockjoin_np (pthread_t *THREAD,
     void **THREAD_RETURN, clockid_t CLOCKID, const struct timespec *ABSTIME) GNU, pthread.h Behaves like pthread_timedjoin_np except that the absolute time in ABSTIME is measured against the clock specified by CLOCKID. Currently, CLOCKID must be either CLOCK_MONOTONIC or CLOCK_REALTIME.

Detecting Single-Threaded Execution
...................................

Multi-threaded programs require synchronization among threads.  This synchronization can be costly even if there is just a single thread and no data is shared between multiple processors.  Theglibc offers an interface to detect whether the process is in single-threaded mode. Applications can use this information to avoid synchronization, for example by using regular instructions to load and store memory instead of atomic instructions, or using relaxed memory ordering instead of stronger memory ordering.

 -- Variable: char __libc_single_threaded
     GNU, sys/single_threaded.h This variable is non-zero if the current process is definitely single-threaded.  If it is zero, the process may be multi-threaded, or theglibc cannot determine at this point of the program execution whether the process is single-threaded or not.

     Applications must never write to this variable.

Most applications should perform the same actions whether or not __libc_single_threaded is true, except with less synchronization.  If this rule is followed, a process that subsequently becomes multi-threaded is already in a consistent state. For example, in order to increment a reference count, the following code can be used:

     if (__libc_single_threaded)
       atomic_fetch_add (&reference_count, 1, memory_order_relaxed);
     else
       atomic_fetch_add (&reference_count, 1, memory_order_acq_rel);

This still requires some form of synchronization on the single-threaded branch, so it can be beneficial not to declare the reference count as _Atomic, and use the GCC __atomic built-ins.  See Built-in Functions for Memory Model Aware Atomic Operations (Using the GNU Compiler Collection (GCC)).  Then the code to increment a reference count looks like this:

     if (__libc_single_threaded)
       ++reference_count;
     else
       __atomic_fetch_add (&reference_count, 1, __ATOMIC_ACQ_REL);

(Depending on the data associated with the reference count, it may be possible to use the weaker __ATOMIC_RELAXED memory ordering on the multi-threaded branch.)

Several functions in theglibc can change the value of the __libc_single_threaded variable.  For example, creating new threads using the pthread_create or thrd_create function sets the variable to false.  This can also happen indirectly, say via a call to dlopen.  Therefore, applications need to make a copy of the value of __libc_single_threaded if after such a function call, behavior must match the value as it was before the call, like this:

     bool single_threaded = __libc_single_threaded;
     if (single_threaded)
       prepare_single_threaded ();
     else
       prepare_multi_thread ();

     void *handle = dlopen (shared_library_name, RTLD_NOW);
     lookup_symbols (handle);

     if (single_threaded)
       cleanup_single_threaded ();
     else
       cleanup_multi_thread ();

Since the value of __libc_single_threaded can change from true to false during the execution of the program, it is not useful for selecting optimized function implementations in IFUNC resolvers.

Atomic operations can also be used on mappings shared among single-threaded processes.  This means that a compiler must not use __libc_single_threaded to optimize atomic operations, unless it is able to prove that the memory is not shared.

Implementation Note: The __libc_single_threaded variable is not declared as volatile because it is expected that compilers optimize a sequence of single-threaded checks into one check, for example if several reference counts are updated.  The current implementation in theglibc does not set the __libc_single_threaded variable to a true value if a process turns single-threaded again.  Future versions of theglibc may do this, but only as the result of function calls which imply an acquire (compiler) barrier.  (Some compilers assume that well-known functions such as malloc do not write to global variables, and setting __libc_single_threaded would introduce a data race and undefined behavior.)  In any case, an application must not write to __libc_single_threaded even if it has joined the last application-created thread because future versions of theglibc may create background threads after the first thread has been created, and the application has no way of knowning that these threads are present.

Restartable Sequences
.....................

This section describes restartable sequences integration for theglibc.  This functionality is only available on Linux.

 -- Data Type: struct rseq
     Linux, sys/rseq.h The type of the restartable sequences area.  Future versions of Linux may add additional fields to the end of this structure.

     Users need to obtain the address of the restartable sequences area using the thread pointer and the __rseq_offset variable, described below.

     One use of the restartable sequences area is to read the current CPU number from its cpu_id field, as an inline version of sched_getcpu.  Theglibc sets the cpu_id field to RSEQ_CPU_ID_REGISTRATION_FAILED if registration failed or was explicitly disabled.

     Furthermore, users can store the address of a struct rseq_cs object into the rseq_cs field of struct rseq, thus informing the kernel that the thread enters a restartable sequence critical section.  This pointer and the code areas it itself points to must not be left pointing to memory areas which are freed or re-used. Several approaches can guarantee this.  If the application or library can guarantee that the memory used to hold the struct rseq_cs and the code areas it refers to are never freed or re-used, no special action must be taken.  Else, before that memory is re-used of freed, the application is responsible for setting the rseq_cs field to NULL in each thread's restartable sequence area to guarantee that it does not leak dangling references.  Because the application does not typically have knowledge of libraries' use of restartable sequences, it is recommended that libraries using restartable sequences which may end up freeing or re-using their memory set the rseq_cs field to NULL before returning from library functions which use restartable sequences.

     The manual for the rseq system call can be found at https://git.kernel.org/pub/scm/libs/librseq/librseq.git/tree/doc/man/rseq.2.

 -- Variable: int __rseq_offset
     Linux, sys/rseq.h This variable contains the offset between the thread pointer (as defined by __builtin_thread_pointer or the thread pointer register for the architecture) and the restartable sequences area.  This value is the same for all threads in the process.  If the restartable sequences area is located at a lower address than the location to which the thread pointer points, the value is negative.

 -- Variable: unsigned int __rseq_size
     Linux, sys/rseq.h This variable is either zero (if restartable sequence registration failed or has been disabled) or the size of the restartable sequence registration.  This can be different from the size of struct rseq if the kernel has extended the size of the registration.  If registration is successful, __rseq_size is at least 32 (the initial size of struct rseq).

 -- Variable: unsigned int __rseq_flags
     Linux, sys/rseq.h The flags used during restartable sequence registration with the kernel. Currently zero.

 -- Macro: int RSEQ_SIG
     Linux, sys/rseq.h Each supported architecture provides a RSEQ_SIG macro in sys/rseq.h which contains a signature.  That signature is expected to be present in the code before each restartable sequences abort handler.  Failure to provide the expected signature may terminate the process with a segmentation fault.