Skip to main content

IAR Embedded Workbench for RH850 3.20.x

Setting up thread-local storage (TLS)

In this section:

Thread-local storage (TLS) is supported in both C (via the _Thread_local type specifier introduced in C11) and C++ (via the thread_local type specifier introduced in C++11). TLS variables reside in the thread-local storage area, a memory area that must be set up when the thread is created. Any resources used must be returned when the thread is destroyed. In a C++ environment, any TLS object must be created after the thread-local storage area has been set up, and destroyed before the thread-local storage area is destroyed.

If you are using an operating system, refer to the relevant TLS documentation. Additional information can be found in the IAR library header file DLib_Threads.h. Information from such specific sources takes precedence over this general overview.

The main thread

If the linker option ‑‑threaded_lib has been specified, TLS is active. The regular system startup handles the initialization of the main thread’s thread-local storage area. The initialized TLS variables in the main thread are placed in the linker section.tdata and the zero-initialized TLS variables are placed in the section .tbss. All other threads must set up their thread-local storage area when they are created. If ‑‑threaded_lib was not specified, content in the .tdata and .tbss sections is handled as if they were .data and .bss. However, accesses to such variables are still TLS accesses.

Acquiring memory for TLS

TLS variables must be placed in memory. Exactly how this is handled does not matter as long as the memory remains available for the duration of the thread’s lifetime. The size of the thread-local storage area can be obtained by calling the function __iar_tls_size (declared in DLib_Threads.h).

Some options for acquiring memory for TLS are:

  • Acquire memory from the OS

  • Allocate heap memory

  • Use space on the stack of a function that does not return until the thread is done

  • Use space in a dedicated section.

Initializing TLS memory

To initialize the TLS memory, call the function __iar_tls_init (declared in DLib_Threads.h) with a pointer to the memory area.

The initialization function copies the contents of the linker section__iar_tls$$INIT_DATA to the memory, and then zero-initializes the remaining memory up to the size of the section__iar_tls$$DATA. In a C++ environment, the function __iar_call_tls_ctors is also called—it executes all constructors in the section __iar_tls$$PREINIT_ARRAY. When the initialization has been performed, the thread-local storage area is ready to use, all TLS variables have their initial values, and in a C++ environment all thread-local objects have been constructed.

Deallocating TLS memory

When it is time to destroy the thread, the thread-local storage area must also be handled. In a C++ environment, the thread-local objects must be destroyed before the memory itself is processed. This is achieved by calling the function __call_thread_dtors (declared in DLib_Threads.h). If the memory was acquired from a handler (like the heap or the OS), that memory must be returned.

As an example, this code snippet allocates the thread-local storage area on the heap. tp is a pointer to a thread-control object:

/* creating a new thread */
  ...
  /* initialize TLS */
  void * tls_mem = malloc(__iar_tls_size()); /* get memory */
  __iar_tls_init(tls_mem);                 /* init TLS in the */
                                           /* new memory */
  tp->tls_area = tls_mem;                  /* set the thread’s */
                                 /* TLS area to the new memory */
  ...
  /* destroying a thread */
  ...
  /* destroy the TLS area */
  __call_thread_dtors();                /* only if C++ is used */
  free(tp->tls_area);                   /* return memory */
  ...