Reputation: 10073
I am trying to understand how stack allocation and alignment works with pthreads on a Linux x86_64 system with gcc and what data the system stores on the stack. I know that you can configure the stack memory using pthread_attr_setstack
. I've done this in a test program that does the following:
1) recursively calls itself and updates an uninitialized array that is allocated on the stack
2) prints out the value of the first array element, the last element, and rsp
From this I've been able to observe how rsp gets incremented (in my test program I noticed some of the recursive calls were inlined by the compiler). I've also been able to see that adding TLS memory (with __thread variables) causes the first value of rsp to be lower. So it looks like TLS variables are allocated on the top of the stack.
However, what I'm not sure about is what else is there. It looks to me like the first page of the stack is reserved for the system in some way because none of the stack variables that I allocate end up in that region. Even if I don't use any __thread variables the variables that I do instantiate do not appear to be allocated in the first page (I set the stack memory so that it is page aligned).
So my question is: what else, if anything, is on the stack for a pthread besides TLS data and stack variables?
Upvotes: 2
Views: 255
Reputation: 10579
how stack allocation and alignment works with pthreads on a Linux x86_64
"stacks" in the subthreads are really just a block of memory, usually malloc'd (which internally may be implemented by mmaping an anonymous area), though you can just as well use the original stack area itself provided it remains valid during the lifetime of the thread, e.g.
char foo[2<<20];
pthread_attr_t attr;
pthread_t tid;
pthread_attr_init(&attr);
pthread_attr_setstack(&attr, foo, sizeof(foo));
pthread_create(&tid, &attr, func, NULL);
pthread_join(tid, NULL);
Upvotes: 0
Reputation: 231373
On Linux NPTL:
The very top of the stack contains the TCB. This is also known as struct pthread
or pthread_t
. It's a bit hairy due to all the weird glibc system-specific defines, but basically it contains things like:
pthread_cleanup
and stack unwind informationpthread_setspecific
- if you exceed this number, the rest are allocated on the heappthread_join
This is mostly initialized in pthread_create
(__pthread_create_2_1
in nptl/pthread_create.c
if you're following along in the eglibc source), before the new thread actually starts running.
Below the TCB is statically allocated __thread
variables - or, at least, those the linker could identify at startup time. The dynamic linker initializes a l_tls_offset
field in the linker map to tell the NPTL code how much space to reserve. Note that libraries loaded after program startup won't be part of this - see the __thread
ABI spec for details.
Below the __thread
variables is the stack. The top of this stack is the start_thread()
code, so it'll still be a ways before it actually executes user code (but not too much further).
Upvotes: 4