---
name: "set_thread_area"
section: "2"
platform: "linux"
package: "man-pages"
version: "6.19-1"
release: "Arch Linux 2026-11-01"
platforms: ["linux"]
url: "https://new.carta.tech/set_thread_area"
---

# set\_thread\_area(2)

manipulate thread-local storage information

## NAME

get\_thread\_area, set\_thread\_area - manipulate thread-local storage information

## LIBRARY

Standard C library (*libc*, *-lc*)

## SYNOPSIS

```
#include <sys/syscall.h>     /* Definition of SYS_* constants */
#include <unistd.h>
```

**#if defined \_\_i386\_\_ \|\| defined \_\_x86\_64\_\_** **# include \<asm/ldt.h\>**        /\* Definition of **struct user\_desc** \*/

**int syscall(SYS\_get\_thread\_area, struct user\_desc \****u\_info***);** **int syscall(SYS\_set\_thread\_area, struct user\_desc \****u\_info***);**

**#elif defined \_\_m68k\_\_**

**int syscall(SYS\_get\_thread\_area);** **int syscall(SYS\_set\_thread\_area, unsigned long** *tp***);**

**#elif defined \_\_mips\_\_ \|\| defined \_\_csky\_\_**

**int syscall(SYS\_set\_thread\_area, unsigned long** *addr***);**

**#endif**

*Note*: glibc provides no wrappers for these system calls, necessitating the use of [**syscall**(2)](/syscall/2.md).

## DESCRIPTION

These calls provide architecture-specific support for a thread-local storage implementation. At the moment, **set\_thread\_area**() is available on m68k, MIPS, C-SKY, and x86 (both 32-bit and 64-bit variants); **get\_thread\_area**() is available on m68k and x86.

On m68k, MIPS and C-SKY, **set\_thread\_area**() allows storing an arbitrary pointer (provided in the **tp** argument on m68k and in the **addr** argument on MIPS and C-SKY) in the kernel data structure associated with the calling thread; this pointer can later be retrieved using **get\_thread\_area**() (see also NOTES for information regarding obtaining the thread pointer on MIPS).

On x86, Linux dedicates three global descriptor table (GDT) entries for thread-local storage. For more information about the GDT, see the Intel Software Developer's Manual or the AMD Architecture Programming Manual.

Both of these system calls take an argument that is a pointer to a structure of the following type:

```
struct user_desc {
    unsigned int  entry_number;
    unsigned int  base_addr;
    unsigned int  limit;
    unsigned int  seg_32bit:1;
    unsigned int  contents:2;
    unsigned int  read_exec_only:1;
    unsigned int  limit_in_pages:1;
    unsigned int  seg_not_present:1;
    unsigned int  useable:1;
#ifdef __x86_64__
    unsigned int  lm:1;
#endif
};
```

**get\_thread\_area**() reads the GDT entry indicated by *u\_info-\>entry\_number* and fills in the rest of the fields in *u\_info*.

**set\_thread\_area**() sets a TLS entry in the GDT.

The TLS array entry set by **set\_thread\_area**() corresponds to the value of *u\_info-\>entry\_number* passed in by the user. If this value is in bounds, **set\_thread\_area**() writes the TLS descriptor pointed to by *u\_info* into the thread's TLS array.

When **set\_thread\_area**() is passed an *entry\_number* of -1, it searches for a free TLS entry. If **set\_thread\_area**() finds a free TLS entry, the value of *u\_info-\>entry\_number* is set upon return to show which entry was changed.

A *user\_desc* is considered "empty" if *read\_exec\_only* and *seg\_not\_present* are set to 1 and all of the other fields are 0. If an "empty" descriptor is passed to **set\_thread\_area**(), the corresponding TLS entry will be cleared. See BUGS for additional details.

Since Linux 3.19, **set\_thread\_area**() cannot be used to write non-present segments, 16-bit segments, or code segments, although clearing a segment is still acceptable.

## RETURN VALUE

On x86, these system calls return 0 on success, and -1 on failure, with *errno* set to indicate the error.

On C-SKY, MIPS and m68k, **set\_thread\_area**() always returns 0. On m68k, **get\_thread\_area**() returns the thread area pointer value (previously set via **set\_thread\_area**()).

## ERRORS

- **EFAULT**

  *u\_info* is an invalid pointer.

- **EINVAL**

  *u\_info-\>entry\_number* is out of bounds.

- **ENOSYS**

  **get\_thread\_area**() or **set\_thread\_area**() was invoked as a 64-bit system call.

- **ESRCH**

  (**set\_thread\_area**()) A free TLS entry could not be located.

## STANDARDS

Linux.

## HISTORY

- **set\_thread\_area**()

  Linux 2.5.29.

- **get\_thread\_area**()

  Linux 2.5.32.

## NOTES

These system calls are generally intended for use only by threading libraries.

[**arch\_prctl**(2)](/arch_prctl/2.md) can interfere with **set\_thread\_area**() on x86. See [**arch\_prctl**(2)](/arch_prctl/2.md) for more details. This is not normally a problem, as [**arch\_prctl**(2)](/arch_prctl/2.md) is normally used only by 64-bit programs.

On MIPS, the current value of the thread area pointer can be obtained using the instruction:

```
rdhwr dest, $29
```

This instruction traps and is handled by kernel.

## BUGS

On 64-bit kernels before Linux 3.19, one of the padding bits in *user\_desc*, if set, would prevent the descriptor from being considered empty (see [**modify\_ldt**(2)](/modify_ldt/2.md)). As a result, the only reliable way to clear a TLS entry is to use [**memset**(3)](/memset/3.md) to zero the entire *user\_desc* structure, including padding bits, and then to set the *read\_exec\_only* and *seg\_not\_present* bits. On Linux 3.19, a *user\_desc* consisting entirely of zeros except for *entry\_number* will also be interpreted as a request to clear a TLS entry, but this behaved differently on older kernels.

Prior to Linux 3.19, the DS and ES segment registers must not reference TLS entries.

## SEE ALSO

[**arch\_prctl**(2)](/arch_prctl/2.md), [**modify\_ldt**(2)](/modify_ldt/2.md), [**ptrace**(2)](/ptrace/2.md) (**PTRACE\_GET\_THREAD\_AREA** and **PTRACE\_SET\_THREAD\_AREA**)
