20

I don't have much experience, just trying to get involved into the processes how do they interpret to hardware from user level.

So when a command is fired from a shell, fork() inherits a child process of it and exec() loads the child process to the memory and executes.

  1. If the child process contains all the attributes of the parent process (which is the original process), then what is the need of this child process? The original process also could have been loaded to the memory.
  2. Does this fork and exec concept apply to all the executable program in UNIX? Like for shell script also or only for commands? Does it also apply for shell builtin commands?
  3. When is the copy on write concept used if I'll execute a command/script?

Sorry for asking many questions at a time, but all these questions come to my mind at once when I think about any command execution.

1

4 Answers 4

23

So when a command is fired from a shell, fork() inherits a child process of it and exec() loads the child process to the memory and executes.

Not quite. fork() clones the current process, creating an identical child. exec() loads a new program into the current process, replacing the existing one.

My qs is:

If the child process contains all the attributes of the parent process(which is the original process), then what is the need of this child process? The original process also could have been loaded to the memory.

The need is because the parent process does not want to terminate yet; it wants a new process to go off and do something at the same time that it continues to execute as well.

Does this fork and exec concept apply to all the executable program in UNIX?Like for shell script also or only for commands? Does it also apply for shell builtin commands?

For external commands, the shell does a fork() so that the command runs in a new process. Builtins are just run by the shell directly. Another notable command is exec, which tells the shell to exec() the external program without first fork()ing. This means that the shell itself is replaced with the new program, and so is no longer there for that program to return to when it exits. If you say, exec true, then /bin/true will replace your shell, and immediately exit, leaving nothing running in your terminal anymore, so it will close.

when copy on write concept is used if I'll execute a command/script?

Back in the stone age, fork() actually had to copy all of the memory in the calling process to the new process. Copy on Write is an optimization where the page tables are set up so that the two processes start off sharing all of the same memory, and only the pages that are written to by either process are copied when needed.

1
  • 5
    "For almost every command, the shell does a fork() so that the command runs in a new process. If that command is a builtin, then the child does not need to exec() a separate program." Good answer, but this part should be edited. The shell does not fork when running builtins. It runs those directly in the active shell process. This is the only way builtins like cd or read could work. The lack of forking also makes builtins much faster than external commands. Jan 18, 2015 at 19:22
7
  1. For some programs, the child process does one thing (read from a serial port, write to the terminal), and the parent process goes on to do something else (read from terminal, write to serial port). Another classic example is the child process does a checkpoint of whatever long running calculation is taking place. Mostly, the child process does some setup, like changing directory, resetting signal handlers or resetting file descriptors, and then calls execve() to overlay itself with different code.
  2. fork() and exec() do apply to all executables - in fact, along with argc and argv, and pipes, fork and exec are what distinguish Unix from other operating systems. A few specializations or generalizations of fork() exist, like BSD's vfork(), Plan 9's rfork() and Linux' clone(), but the principal remains the same.
  3. "copy on write" doesn't really show up to the user, it's more of a technique to optimize creating a child process, and during it's execution. The call stack and the heap (memory allocated with malloc(), or even static or global scope variables) might be "copy on write". When a child process gets created with a fork() call, the kernel would set up the child process to have the exact same pages of memory as heap and stack as the parent process. If the hardware (memory management unit) detects a write of the heap or stack, the kernel would get a new physical page of memory, copy the parent's page into the new page, and map that new page in the child process's stack or heap. This constitutes an optimization as the kernel spends less time setting up page mappings than it would to copy stack and heap completely for the child process.
1
  • Thanks Bruce for your answer. But so many things you have said here which are going over my head. I don't have much knowledge with these things..I'll try to get these functions' working you have mentioned. Thank you so much..!!
    – PriB
    Jan 18, 2015 at 6:24
5
If the child process contains all the attributes of the parent process (which is the original process), then what is the need of this child process? The original process also could have been loaded to the memory.

This question is very illustratively answered by taking a look at the earliest Unix implementations which had to work under severe memory constraints and had only one executing process in memory/address space at a time.

Multitasking was achieved by swapping a process out to disk and swapping a different process in.

Now the fork system call was almost the same: it swapped a process out to disk, but instead of swapping another process in, it gave the in-memory copy another process id and returned to it. And that was an opportune point of time for this process to decide to just exec into another executable after all.

fork+exec thus did not actually incur noticeable overhead over spawning: you had to swap out your process to disk anyway, and you had the old process image in workable memory locations anyway.

With growing amounts of available memory and memory management units and multiple in-memory processes, the initially negligible cost of a fork became somewhat more of a nuisance for some architectures: thus vfork was born.

3

To make this as easy to understand as possible I will use an analogy. Let's bake a pie!

We grab the recipe book, and start reading and settle on a strawberry rhubarb pie (my favorite), with a handmade crust. Almost everything we need is in the kitchen except for the eggs and the fruit, but since we live on a farm and the fruit is in season, this is not a problem. the problem is the oven is broke and there is not enough time to do every thing. Wouldn't it be nice to have more than one of me?

fork() to the rescue. Now there is two of me. and we both head to the kitchen to start making the pie crust. oops. So we look at the return from fork. I got a big number he got zero, so I head to the kitchen while he heads out to the chicken coop and garden. As I walk past the oven I fork() again, look at the return value: bummer I got zero. He continues on to the flour as I stare at the broken oven. I open the door, No light, I close the door. Does anyone know how to fix an oven?

exec() to the rescue. I reach for the voltmeter on my tool-belt, the bulb could be diagnostic, so I check the power, Indeed tripped breaker, easy fix. as I walk to the breaker panel, I see a fellow picking rhubarb. Yuck! I prefer chocolate silk pie.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .