0

Imagine main() creates two threads. Each thread gets it errno (as a private function). There's a function in the program, which can be called by both of these two threads. It is made thread safe.

How compiler will arrange this function to ensure its same code calls appropriate errno function? How "thread environment" is being passed to the same piece of code?

Edit. The question is not about errno per se. Question is about how this common function knows which errno to call when it gets execution. From where the same piece of code gets different thread-specific info on errno function?

Edit: does it assume that if I pass 3 variables to the function, there're actually several more variables passed behind the scenes, and one of them is this FS processor register, which points to thread environment? If I used say errno in this common function, how this function knows that it must search for errno in its environment - is this mechanism embedded in errno definition?

Conclusion: due to declaration of errno as __thread compiler knows that this entity (variable or whatever) is thread-specific, and to access this compiler uses another "background" input to the function - for example, processor's FS register which always contains pointer to thread environment.

Anonymous
  • 561
  • 3
  • 7
  • 24

2 Answers2

3

errno is thread-local, meaning that it has a separate value maintained per-thread, in an implementation-dependent manner.

On my environment, it happens to be defined (macro) as *__errno_location (), where __errno_location() "shall return the address of the errno variable for the current thread." (ref).

Under the hood, this uses the __thread specifier in at least one case, but it can use any suitable mechanism for thread-local storage such as special support from the threading library/operating system.

On x86_64 Linux thread-local information can be reached through the fs register which points to thread-local data; on x86_64 Windows the gs register points to the Windows NT TIB which does the same. Here's a Linux example showing the generated code: https://godbolt.org/z/YeqEvdhnc

nanofarad
  • 40,330
  • 4
  • 86
  • 117
  • Does it assume that if I pass 3 variables to the function, there're actually several more variables passed behind the scenes, and one of them is this processor register, which points to thread environment? If I used say `errno` in this common function, how this function knows that it must search for `errno` in its environment - is this mechanism embedded in `errno` definition? – Anonymous Mar 05 '22 at 22:49
  • No, no hidden parameters need to be passed. A function that wants to read or write `errno` already has everything it needs. In fact, if you stop to think about it, how would the caller know to pass any hidden parameters anyway? If it can only see the function prototype (as opposed to the code itself), how can it know whether the function is going to access `errno` or not? – Paul Sanders Mar 05 '22 at 23:00
  • @Anonymous A processor register isn't a "parameter". It's always set as part of the ambient environment of the thread - the kernel is responsible for ensuring that it's properly set to a different value in each thread and saved/restored on context switches, just like any other register. The declaration with `__thread` tells the CPU to generate code that addresses via the `fs` (or `gs`, depending on operating system) register rather than simply with an address to a global. – nanofarad Mar 05 '22 at 23:05
  • @PaulSanders I do not get it. The function calls (for example) `errno`. This *same* function is called by different threads, thus both threads execute same code. How this same code get to know different address of `errno` for these two different threads? – Anonymous Mar 05 '22 at 23:07
  • 1
    Did you read nanofarad's answer and subsequent comment? I thought he laid it all out for you. – Paul Sanders Mar 05 '22 at 23:08
  • @nanofarad Do I understand properly that `errno` is the same common piece of code called by eveyone, but due to its `__thread` declaration this function uses `FS` register to fetch value from thread-specific location? – Anonymous Mar 05 '22 at 23:10
  • 3
    @Anonymous That's *almost* correct. The `__errno_location` function doesn't **fetch** errno; it returns a **pointer** to the thread-local `errno` (allowing e.g. setting with `errno = 0`). It does so by using the FS register (on x86 Linux, at least; other OSs may use different mechanisms) to obtain the correct address. Take a look at [this assembly](https://godbolt.org/z/YeqEvdhnc) and the differences between how x (thread-local) and y (global) are accessed. Also, the __thread declaration goes on the internal thread-local errno variable, *not* on the function. The function is just a function. – nanofarad Mar 05 '22 at 23:14
2

From the C Standard (7.5 Errors <errno.h>)

errno

which expands to a modifiable lvalue201) that has type int and thread local storage duration,

So each thread has its own errno.

The so-called common function is called in the thread environment where it is called.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335