For a normal function call, stack frame is created and stored in stack. But
How memory is allocated for two thread within one process and how stack frame is handled when thread call other function.
Either thread stack memory is allocated by the operating system as part of the system call that creates a thread, or the process creating the thread has to provide memory from the application heap to be used as thread stack.
We know that when a process is created,one stack is allocated for this process.
Stack Allocation: The allocation happens on contiguous blocks of memory. We call it a stack memory allocation because the allocation happens in the function call stack. The size of memory to be allocated is known to the compiler and whenever a function is called, its variables get memory allocated on the stack.
Thread-local storage is a memory location, which is allocated and freed by a single thread. Therefore, there is no need to synchronize allocation and deallocation of thread-local storage. Specifically, we enhance the memory management functions with two new functions, tls malloc and tls free.
The current 'thread' concept in Linux is the NPTL one. NPTL uses clone()
, which wraps sys_clone()
. Allocating a stack for a new 'thread' is handled in the user space (ie. libc), not in kernel (ie. Linux). A library can allocate a stack using the allocation of choice (eg. malloc) and then call clone() passing this address as the stack (of course, needs to pass the top of the allocated region, since stacks grow downwards on most platforms):
Unlike fork(2), clone() allows the child process to share parts of its execution context with the calling process, such as the memory space, the table of file descriptors, and the table of signal handlers. ...
The main use of clone() is to implement threads: multiple threads of control in a program that run concurrently in a shared memory space.
When the child process is created with clone(), it executes the function fn(arg) ...
The child_stack argument specifies the location of the stack used by the child process ...
If you want to learn more specific details, open the source of your distro pthread_create
implementation and get reading.
For example pthread_create.c
:
int
__pthread_create_2_1 (newthread, attr, start_routine, arg)
...
struct pthread *pd = NULL;
int err = ALLOCATE_STACK (iattr, &pd);
...
and allocatestack.c:
# define ALLOCATE_STACK(attr, pd) allocate_stack (attr, pd, &stackaddr)
static int
allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
ALLOCATE_STACK_PARMS)
...
You'll see that stack allocation has some whistles and bells, like caching and reusing stack regions, guard pages, but in the end is just a memory region allocated in user space.
As someone commented each thread have it's own stack. When function gets called from that thread new stack frame is created in that stack.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With