C static variables and linux fork - c

Hi I created a server program that forks a new process after its accepts a socket connection.
There are several statically allocated global variables defined in the program. My question is are these static buffers allocated twice after the fork? Or does the fork only duplicate address space on the heap and the call stack?

The entire address space is duplicated, including all global variables and the program text.

The whole address space is "duplicated" during fork(2). It's often done with copy-on-write and there are more details about sharing program text and the libraries, but that is not relevant here. Both parent and child processes end up with their own copy of the static data.

fork() duplicates the entire process image. All of it. As such, are they allocated twice... no, they're allocated once per executable image of which there are now two, and no, if you refer to one in the parent, it will not hold the same content as that of the child unless you use shared memory.
On static, that keyword means this (from ISO C99):
An object whose identifier is declared
with external or internal linkage, or
with the storage-class specifier
static has static storage duration.
Its lifetime is the entire execution
of the program and its stored value is
initialized only once, prior to
program startup.
Which basically means your buffer will be initialised once as part of the CRT startup routine and that space only disappears when you exit. In this case, that storage disappears when each child exits.

Linux uses mechanism called copy-on-write. That basically means, that as long as variable is not modified parent and new process are sharing one variable. But before variable is modified it is copied and new process uses copy. It is done for performance reasons and technique is called lazy optimization. So you shouldn't worry that changing variable in one process will change it in another.

Related

Sharing dynamically-allocated char * between threads

My application has two threads (thread A and thread B) that read and write from/to a global structure like the following:
struct global_data_s {
pthread_mutex_t mutex;
uint8_t a;
char *string;
}
Thread A writes to global_data_s through a function:
set_global_data(struct global_data_s *in);
which sets the global structure according to the input global_data_s *in passed to the function (which manages the mutex lock/unlock mechanism).
Thread B reads from global_data_s with:
get_global_data(struct global_data_s *out);
This works as expected for static data (like uint8_t a), since the actual global data is only accessible by the get/set functions, and threads can freely work on a copy of the global data structure (the set function passes a local copy of the structure allocated in thread A and overwrites the global structure, while the get function returns a copy of the global data to a local struct in thread B. Everything is protected by mutex lock/unlock mechanism).
I found myself in a bit of a pickle, though, since string is allocated dynamically (via malloc) by thread A and contains a json-formatted string that is constantly updated (e.g. every second).
Thread B is actually a webserver, that needs to get string and send it as soon as a GET request is made (this action should be performed for every incoming GET request).
I fear the whole "work on a copy of the global shared structure" fails here, since dynamic memory is involved.
My point is, when and where should I free the allocated string? Freeing the local copy of string obviously frees the shared global structure too (since both pointers point to the same address).
I hope I made myself clear, but please, feel free to ask if anything is unclear.
Thank you in advance.
When architecturally feasible global variables and threading are not good bedfellows. But when forced to use them together, the global becomes a shared resource that can only be used by one thread at a time. It then becomes a simple matter of writing code that allows the threads to play nicely with each other, and share.
Enter mutex. (or some other thread safety device.)
In this case, you are using mutex. Each thread must wait for ownership of the mutex before it can execute the code that accesses the shared resource. With that in mind, each event that requires a thread to gain access to this global struct member, whether to read or to write, must first test the mutex to see if it is already being used by another thread. If not, take ownership, use the resource, release ownership. If it is already owned, it is the responsibility of the calling code to have a try-again method, that persists attempts to access until the mutex is free. When free, again, take ownership, use the resource, release ownership.

Clarifying how GNU C Library defines nonreentrant functions

Taken from: https://www.gnu.org/software/libc/manual/html_node/Nonreentrancy.html
For example, suppose that the signal handler uses gethostbyname. This function returns its value in a static object, reusing the same object each time. If the signal happens to arrive during a call to gethostbyname, or even after one (while the program is still using the value), it will clobber the value that the program asked for.
I fail to see how the above scenario is non-reentrant. It seems to me that gethostbyname is a (read-only) getter function that merely reads from memory (as opposed to modifying memory). Why is gethostbyname non-reentrant?
As the word says, reentrancy is the capability of a function to be able to be called again while it is being called in anothe thread. The scenario you propose is the exact place in which reentrancy is exercised. asume the function has some static or global variable (as the gethostbyname(3) function does) As the return buffer for the structure is being written by one, the other call can be overwriting it to completely destroy the first writing. When the in execution instance of the function (the interrupted one, not the interrumpting one) gets control again, all it's data has been overwritten by the interrupting one, and destroyed it.
A common solution to solve this problem with interruptions is to disable interrupts while the function is executing. This way it doesn't get interrupted by a new call to itself.
If two threads call the same piece of code, and all the parameters and local variables are stored in the stack, each thread has a copy of its own data, so there's no problem in calling both at the same time, as the data they touch is in different stacks. This will not happen with static variables, being those local scope, compilation unit scope or global scope (think that the problem comes when calling the same piece of code, so everywhere one call has access to, the other has also)
Static data, like buffers (look at stdio buffered packages) etc. means in general, the routines will not be reentrant.

What happens to the parameters to execv?

I was always a bit hazy on this little bit of C magic. When you call execv, you're "replacing the process image." What exactly does that mean? Just the DATA segment? Everything allocated to the process? The stack? The heap?
My question is about what happens to the storage used by the parameters that you pass to execv? If they were local variables to the function that called execv, then they're on the stack. But if you replace the process image, and call the new process's main() function, bad things would happen when main() returned, because the stack information that points to the return location from the main call was replaced by the new process image.
Same thing for variables, yes? And what if those variables were allocated on the heap?
Inquiring minds are inquiring to anybody who knows.
The exec family of functions replace the process wholesale - data, stack, text, heap, everything. Some file descriptors can stay open (those opened by the original process without FD_CLOEXEC set). But apart from that, you pretty much get a whole new process - see the link for all the details.
What happens to the parameters you passed in is the OS's problem - it has to make sure they're passed to the new process's main function in a way that complies with the standard, but I don't think POSIX dictates exactly how it does that.
For Linux, you can look at the fs/exec.c file to see the implementation. Jump near the end (line 1484 as I post this) to look at the do_execveat_common function which is the main part of the implementation. You'll see the arguments are copied into the new address space (calls to copy_strings near the end of the function).
Just the DATA segment?
No, all memory mappings are erased and re-create for the new executable
Everything allocated to the process? The stack? The heap?
Yes, all memory. Some kernel resources, documented here, are inherited from the parent process though, such as file descriptors. These resources are managed by the kernel, and are not part of the process memory. All of this is quite operating system specific though, it can accomplish this through various means as long as it complies with the mentioned exec() documentation.
what happens to the storage used by the parameters that you pass to execv?
Typically the kernel makes a copy of those arguments, and injects them into the memory of the new executable.
But if you replace the process image, and call the new process's main() function, bad things would happen when main() returned,
No, when main() returns, that process ends. The code and memory of the original process that called exec() doesn't exist any more, there's nothing to return to.

When a process forks, would the shared library .so still in the address space? And would the constructor be executed again?

When a process forks, would the child process have the customized shared library (.so file) in its address space?
If so, is the address of the shared library be same or different from its parent process (due to ASLR) ?
Would the function running before the main function __attribute__ ((constructor)) constructor be executed again in all the child process? What about thread?
Yes, the child will retain the parent's mappings. Ordinarily, Linux's virtual memory system will actually share the page between the two processes, up until either one tries to write new data. At that point, a copy will be made and each process will have its own unique version - at a different physical address but retaining the same virtual address. This is referred to as "copy on write" and is a substantial efficiency and resources advantage over systems which cannot support this, particularly running code which forks frequently.
Address Space Layout Randomization (ASLR) can't apply for libraries or objects which are already allocated virtual addresses, as to do so would break any pointers held anywhere in the code - something that a system running non-managed code can't know enough about to account for.
Since all previously constructed objects already exist in memory, constructors are not called again just because of the fork. Any objects which need to be duplicated because they are being uniquely modified have this done invisibly by the VM system behind the scenes - they don't really know that they are being cloned, and you could very well end up having a pair of objects where part of the implementation continues to share a physical page with identical contents while another part has been invisibly bifurcated into distinct physical pages with differing contents for each process.
You also asked about threads, and that is an area where things get complicated. Normally, only the thread which called fork() will exist in live form in the child (though data belonging to the others will exist in shared mappings, since it can't be known what might be shared with the forked thread). If you need to try to fork a multithreaded program, you will need to see the documentation of your threading implementation. For the common pthreads implementation on Linux, particularly pay attention to pthread_atfork()

Does local variable in thread function have separe copy according to thread?

I have declared some local variable in one function like this:
void* thread_function (void* parameter)
{
struct parameter * thread_data = (struct parameter *)parameter;
char buffer[20];
int temp;
}
Here if I have created two threads then in one thread if buffer & temp is updated so will it effect other thread ?
i mean if there are two thread then does there will be two copy of all local variable?
EDIT : then in which case i need to used thread specific data.? i mean pthread_setspecific & all such stuff
These variables are allocated on the stack, and each thread has its own stack: these variables are private to each thread (they are not shared). (See this answer for more details.)
If you assign thread_data to a global pointer, for example, other threads will be able to access thread_data via the global pointer.
Thread specific data (e.g. pthread_setspecific) is used to create variables that are global, but still specific to each thread (not shared): They are thread-specific global variables.
You need to use thread specific variables when you want global variables, but don't want to share them between threads.
It's not that each thread has its own copy, it's that each instance of a function invocation has its own copy of all automatic (i.e. local non-static) variables, regardless of whether the instances are in the same thread or different threads. This is true if the instances come into existence due to invocation in different threads, recursive invocation, mutual/indirect recursion, or even invocation from an asynchronous signal handler. Note that while the C standard does not specify threads, the relevant section in the standard is probably 5.2.3 Signals and interrupts:
Functions shall be implemented such that they may be interrupted at any time by a signal, or may be called by a signal handler, or both, with no alteration to earlier, but still active, invocations' control flow (after the interruption), function return values, or objects with automatic storage duration. All such objects shall be maintained outside the function image (the instructions that compose the executable representation of a function) on a per-invocation basis.
This makes it explicit that each invocation must have its own storage for automatic variables.
Local variables are stored in stack memory, which is private to a thread.
Therefore they are not shared between threads: there will be an independent copy of each variable in each thread
Update
Whether you would want to share data between threads really boils down to a design question; What are your threads doing? Are their effort co-ordinated or are they simply workers processing a queue.
The main thing to consider is synchronization of shared data. Variables that are shared between threads are variables that can change value unexpectedly (within a single thread) and so need to be treated as such. I would suggest that you err on the side of not sharing, unless you have a specific reason to do so.

Resources