I'm playing with the Linux kernel, and one thing that I don't understand is the pid of the init_task task.
As far as I know, there are two special pids: pid 0 for the idle/swapper task, and pid 1 for the init task.
Every online resource (e.g. one, two) I could find say that the init_task task represents the swapper task, i.e. it should have pid 0.
But when I print all the pids using the for_each_process macro, which starts from init_task, I get pid 1 as the first process. I don't get pid 0 at all. Which means that init_task has pid 1, and that it's the init task (?!).
Please help me resolve this confusion.
P.S. the kernel version is 2.4.
The reason for my confusion was the tricky definition of the for_each_task macro:
#define for_each_task(p) \
for (p = &init_task ; (p = p->next_task) != &init_task ; )
Even though it seems that p starts from init_task, it actually starts from init_task.next_task because of the assignment in the condition.
So for_each_task(p) { /* ... */ } could be rewritten as:
p = init_task.next_task;
while(p != &init_task)
{
/* ... */
p = p->next_task;
}
As it can be seen, the swapper process is not part of the iteration.
Related
Information
I was reading the book of E. Tanenbaum about Modern operating systems and there was a code snippet that was introducing Petersons algorithm for process synchronization which is implemented with software.
Here's the snippet.
```
#define FALSE 0
#define TRUE 1
#define N 2 /* number of processes */
int turn; /* whose turn is it? */
int interested[N]; /* all values initially 0 (FALSE) */
void enter_region(int process) /* process is 0 or 1 */
{
int other; /* number of the other process */
other = 1 − process; /* the opposite of process */
interested[process] = TRUE; /* show that you are interested */
turn = process; /*set flag*/
while (turn == process && interested[other] == TRUE); /* null statement */
}
void leave_region(int process) { /* process: who is leaving */
interested[process] = FALSE; /* indicate departure from critical region */
}
```
The question is
Isn't there a mistake? [Edit] Must'nt it be turn = other or maybe there is another mistake.
This version of algorithm violates rules of mutual exclusion.
[Edit]
I think this version is violating the rules of mutual exclusion. As if first process sets the interested variable than stops and other process runs, second process can idle wait after setting his interested and turn variables without any need as there is no any process in critical section.
Any answer and help is appreciated. Thanks!
If process 0 sets interested[0], and then process 1 runs enter_region up until the loop, then process 0 will be able to exit the loop because turn == process is no longer true for it. turn, in this case, really means "turn to wait", and protects against exactly the situation you described. In contrast, if the code did turn = other then process 0 would not be able to exit the loop until process 1 started waiting.
How many processes are created when running the following program ? I can not solve. I would appreciate if you help
int main()
{
int i;
for (i=fork(); i<2; i++ )
fork();
}
fork() creates a child process, creating an another instance of the parent process. It returns 0 to the child and PID of the child to the parent.
In this case, when i = fork() is executed,
The parent gets i assigned as the PID of the child process, which is most likely greater than 1. The for loop in the parent will run not run even once as i < 2 will fail. At this point of time there are two processes P and C1 (Child)
After the fork is executed by parent, child gets a 0 as return value, i = 0. This means the condition i < 2 is successful. Child executes the fork() in the loop body, creating C2. Value of i in both C1 and C2 are 0. i gets incremented to 1.
C1 and C2 execute i < 2, This condition is successful. Fork is executed by both. C3 is spawned off by C1 and C4 by C2.
i's value gets incremented to 2. i < 2 fails. All of them get out of the loop
To summarise, there are 4 child processes created in this program. You can try this with the following program where you will see 5 PIDs getting printed.
#include <stdio.h>
main()
{
int i = 0;
for (i = fork(); i < 2; i++)
fork();
printf("Hello World i %d\n", getpid());
}
I'm a C programmer learning about fork(), exec(), and wait() for the first time. I'm also whiteboarding a Standard C program which will run on Linux and potentially need a lot of child processes. What I can't gauge is... how many child processes are too many for one parent to spawn and then wait upon?
Suppose my code looked like this:
pid_t status[ LARGENUMBER ];
status[0] = fork();
if( status[0] == 0 )
{
// I am the child
exec("./newCode01.c");
}
status[1] = fork();
if( status[1] == 0 )
{
// child
exec("./newCode02.c");
}
...etc...
wait(status[0]);
wait(status[1]);
...and so on....
Obviously, the larger LARGENUMBER is, the greater the chance that the parent is still fork() ing while children are segfaulting or becoming zombies or whatever.
So this implementation seems problematic to me. As I understand it, the parent can only wait() for one child at a time? What if LARGENUMBER is huge, and the time gap between running status[0] = fork(); and wait(status[0]); is substantial? What if the child has run, becomes a zombie, and been terminated by the OS somehow in that time? Will the parent then wait(status[0]) forever?
In the above example, there must be some standard or guideline to how big LARGENUMBER can be. Or is my approach all wrong?
#define LARGENUMBER 1
#define LARGENUMBER 10
#define LARGENUMBER 100
#define LARGENUMBER 1000
#define LARGENUMBER ???
I want to play with this, but my instinct is to ask for advice before I invest the development time into a program which may or may not turn out to be infeasible. Any advice/experience is appreciated.
If you read the documentation of wait, you would know that
If status information is available prior to the call to wait(), return will be immediate.
That means, if the child has already terminated, wait() will return immediately.
The OS will not remove the information from the process table until you have called wait¹ for the child process or your program exits:
If a parent process terminates without waiting for all of its child processes to terminate, the remaining child processes will be assigned a new parent process ID corresponding to an implementation-dependent system process.
Of course you still can't spawn an unlimited amount of children, for more detail on that see Maximum number of children processes on Linux (as far as Linux is concerned, other OS will impose other limits).
¹: https://en.wikipedia.org/wiki/Zombie_process
I will try my best to explain.
First a bad example: where you fork() one child process, then wait for it to finish before forking another child process. This kills the multiprocessing degree, bad CPU utilization.
pid = fork();
if (pid == -1) { ... } // handle error
else if (pid == 0) {execv(...);} // child
else (pid > 0) {
wait(NULL); // parent
pid = fork();
if (pid == -1) { ... } // handle error
else if (pid == 0) {execv(...);} // child
else (pid > 0) {wait(NULL); } // parent
}
How should it be done ?
In this approach, you first create the two child process, then wait. Increase CPU utilization and multiprocessing degree.
pid1 = fork();
if (pid1 == -1) { ... } // handle error
if (pid1 == 0) {execv(...);}
pid2 = fork();
if (pid2 == -1) { ... } // handle error
if (pid2 == 0) {execv(...);}
if (pid1 > 0) {wait(NULL); }
if (pid2 > 0) {wait(NULL); }
NOTE:
even though it seems as parent is waiting before the second wait is executed, the child is still running and is not waiting to execv or being spawned.
In your case, you are doing the second approach, first fork all processes and save return value of fork then wait.
the parent can only wait() for one child at a time?
The parent can wait for all its children one at a time!, whether they already finished and became zombie process or still running. For more explained details look here.
How many child processes can a parent spawn before becoming infeasible?
It might be OS dependent, but one acceptable approach is to split the time given to a process to run in 2, half for child process and half for parent process.
So that processes don't exhaust the system and cheat by creating child processes which will run more than the OS wanted to give the parent process in first place.
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include<stdlib.h>
int main(void)
{
pid_t pids[10];
int i;
for (i = 9; i >= 0; --i) {
pids[i] = fork();
if (pids[i] == 0) {
printf("Child%d\n",i);
sleep(i+1);
_exit(0);
}
}
for (i = 9; i >= 0; --i){
printf("parent%d\n",i);
waitpid(pids[i], NULL, 0);
}
return 0;
}
What is happening here? How is sleep() getting executed in the for loop? When is it getting called? Here is the output:
parent9
Child3
Child4
Child2
Child5
Child1
Child6
Child0
Child7
Child8
Child9 //there is a pause here
parent8
parent7
parent6
parent5
parent4
parent3
parent2
parent1
parent0
Please explain this output. I am not able to understand how it's working.
Step by step analysis would be great.
In the first loop, the original (parent) process forks 10 copies of itself. Each of these child processes (detected by the fact that fork() returned zero) prints a message, sleeps, and exits. All of the children are created at essentially the same time (since the parent is doing very little in the loop), so it's somewhat random when each of them gets scheduled for the first time - thus the scrambled order of their messages.
During the loop, an array of child process IDs is built. There is a copy of the pids[] array in all 11 processes, but only in the parent is it complete - the copy in each child will be missing the lower-numbered child PIDs, and have zero for its own PID. (Not that this really matters, as only the parent process actually uses this array.)
The second loop executes only in the parent process (because all of the children have exited before this point), and waits for each child to exit. It waits for the child that slept 10 seconds first; all the others have long since exited, so all of the messages (except the first) appear in quick succession. There is no possibility of random ordering here, since it's driven by a loop in a single process. Note that the first parent message actually appeared before any of the children messages - the parent was able to continue into the second loop before any of the child processes were able to start. This again is just the random behavior of the process scheduler - the "parent9" message could have appeared anywhere in the sequence prior to "parent8".
I see that you've tagged this question with "zombie-processes". Child0 thru Child8 spend one or more seconds in this state, between the time they exited and the time the parent did a waitpid() on them. The parent was already waiting on Child9 before it exited, so that one process spent essentially no time as a zombie.
This example code might be a bit more illuminating if there were two messages in each loop - one before and one after the sleep/waitpid. It would also be instructive to reverse the order of the second loop (or equivalently, to change the first loop to sleep(10-i)).
When you run top and see all running processes, I've always wanted to know just what everything actually means. e.g. all the various single-letter state codes for a running process (R = Running, S = Sleeping, etc...)
Where can I find this?
The man page says what the state codes are mapped to, but not what they actually mean. From the top man page:
'D' = uninterruptible sleep
'R' = running
'S' = sleeping
'T' = traced or stopped
'Z' = zombie
'R' is the easiest; the process is ready to run, and will run whenever its turn to use the CPU comes.
'S' and 'D' are two sleep states, where the process is waiting for something to happen. The difference is that 'S' can be interrupted by a signal, while 'D' cannot (it is usually seen when the process is waiting for the disk).
'T' is a state where the process is stopped, usually via SIGSTOP or SIGTSTP. It can also be stopped by a debugger (ptrace). When you see that state, it usually is because you used Ctrl+ Z to put a command on the background.
'Z' is a state where the process is dead (it has finished its execution), and the only thing left is the structure describing it on the kernel. It is waiting for its parent process to retrieve its exit code, and not much more. After its parent process is finished with it, it will disappear.
You can use the command man top to look up the states:
D = uninterruptible sleep
I = idle
R = running
S = sleeping
T = stopped by job control signal
t = stopped by debugger during trace
Z = zombie
Programs like top and ps takes these values from the kernel itself. You can find its definitions in the source code here:
https://github.com/torvalds/linux/blob/3950e975431bc914f7e81b8f2a2dbdf2064acb0f/fs/proc/array.c#L129-L143
static const char * const task_state_array[] = {
/* states in TASK_REPORT: */
"R (running)", /* 0x00 */
"S (sleeping)", /* 0x01 */
"D (disk sleep)", /* 0x02 */
"T (stopped)", /* 0x04 */
"t (tracing stop)", /* 0x08 */
"X (dead)", /* 0x10 */
"Z (zombie)", /* 0x20 */
"P (parked)", /* 0x40 */
/* states beyond TASK_REPORT: */
"I (idle)", /* 0x80 */
};
For more info see this question: https://unix.stackexchange.com/q/462098/79648