Understanding the principles of process control is very important for understanding and modifying Fio project . "Fio is an I/O tool meant to being used both for benchmark and stress/hardware verification."
Process
Unix provides a lot of system calls from the operating system in C programs ( Other languages should be there as well ).
Create a process
Each process has a positive ID, called pid. The getpid function returns the PIDof the calling process, andthegetppid function returns its parent process 's PID .
Fork
Exit
Parent and child processes are independent processes that run concurrently. The kernel can alternately execute instructions in their logical control flow in any way.
If you can pause both processes immediately after the fork function returns in the parent and child processes, we see that the address space for each process is the same. ( Each process has the same user stack, the same local variable value, the same heap, the same global variable value, and the same code.) However, they all have their own separate address space )
About this,Fio , the place where this program uses it is
while (TODO) { struct Thread_data *map[real_max_jobs]; struct Timeval this_start; int this_jobs = 0, left; FOR_EACH_TD (TD, I) { if (td->runstate! = td_not_created) Continue if (Td->o.start_delay) { spent = Utime_since_genesis (); if (Td->o.start_delay > spent) Continue } if (Td->o.stonewall && (nr_started | | nr_running)) { Dprint (fd_process, "%s:stonewall wait\n", Td->o.name); Break } Init_disk_util (TD); Td->rusage_sem = Fio_mutex_init (fio_mutex_locked); td->update_rusage = 0; /* * Set state to created. Thread would transition * To td_initialized when it's done setting up. */ Td_set_runstate (TD, Td_created); map[this_jobs++] = TD; nr_started++; ... if (td->o.use_thread) { int ret; Dprint (Fd_process, "would pthread_create\n"); ret = Pthread_create (&td->thread, NULL, Thread_main, TD); if (ret) { Log_err ("Pthread_create:%s\n", Strerror (ret)); nr_started--; Break } ret = Pthread_detach (td->thread); if (ret) Log_err ("Pthread_detach:%s", Strerror (ret)); } else { pid_t pid; Dprint (Fd_process, "would fork\n"); PID = fork (); if (!pid) { int ret = Fork_main (shm_id, i); _exit (ret); } else if (i = = fio_debug_jobno) *FIO_DEBUG_JOBP = pid; } |
|
This is equivalent to programming:
#include <stdio.h> Int main () { int i=1; int pid; while ((i--) >=0) { pid=fork ( ); if (pid==0) { i--; printf ("in the child process.\n "); } else printf ("in the parent process.\n "); } } |
Compile and execute the results of the above program:
[Email protected] ~]#./a.out In the parent process. In the child process. In the parent process. In the child process. |
Altogether two processes were created, except that the execution of the child processes in Fio is determined by another function fork_main and thread_main .
Note:thread main This function does a lot of things and will be analyzed again.
Reclaim Child processes
When a process terminates for some reason, the kernel does not immediately purge it from the system. Instead, the process is kept in a state that has been terminated until it is reapby its parent process. When the parent process recycles a child process that has already been terminated, the kernel passes the child process's exit status ( which is what kind of exit state, leaving a heart ) to the parent process, and then discards the terminated process, starting from that time, The process will not exist.
A process that has been terminated but not reclaimed is called a zombie zombie.
If the parent process does not recycle his zombie , then the kernel will schedule the init process to reclaim them. Long-running programs, such as the shell or the server, should always recycle their zombie ( always consuming the system's memory resources ).
A process can wait for its child process to terminate or stop by calling the Waitpid function.
Function Prototypes:
#include < Sys/types.h > #include <sys/wait.h> Define function pid_t waitpid (pid_t pid,int * status,int options); Waitpid-Function description Waitpid () will temporarily stop the execution of the current process until a signal arrives or a child process
end. If the child process has ended when calling Waitpid (), then Waitpid () will immediately
returns the child process end status value. The end state value of the child process is returned by the parameter status,
The process identification code of the child process is also returned together. If the end state value is not
The parameter status can be set to NULL. Parameter PID is to wait for the child process identification code,
other numerical meanings are as follows:
pid<-1 Wait for the process group identification code to be PIDAbsolute ValueAny of the child processes.
Pid=-1 waits for any child process, equivalent to wait ().
Pid=0 waits for the process group identifier to be the same as the current process for any child processes.
pid>0 waits for any child process identification code to be a child of PID.
The parameters options provide some additional options to control the Waitpid, which can be either 0 or "|". Operators to connect them together, such as:
Ret=waitpid ( -1,null,wnohang | wuntraced);
If we do not want to use them, we can also set options to 0, such as:
ret=waitpid ( -1,null,0);
Wnohang If the PID-specified child process does not end, the Waitpid () function returns 0, not waiting. If it ends, the ID of the child process is returned.
wuntraced The Kawai process enters a paused state, it returns immediately, but the end state of the child process is ignored. The wifstopped (status) macro determines whether the return value corresponds to a paused child process.
the end state of the child process is returned and stored in status, with a few macros at the bottom to determine the end condition:
wifexited (status) True if the status returned by the normal end of the child process, or wexitstatus (status), is passed to the lower 8 bits of exit or _eixt for this case.
wexitstatus (status) Gets the end code returned by the child process exit (), typically using wifexited to determine whether the macro ends properly before it can be used.
wifsignaled (status) is true if the status returned by the exception end child process, and in this case the Wtermsig (status) is executed, taking the signal number that causes the child process to end.
wtermsig (status) Gets the signal code that the child process aborts because of the signal, generally uses wifsignaled to judge before using this macro.
wifstopped (status) True if the status returned by the currently paused child process, or wstopsig (status) For this case, takes the signal number that causes the child process to pause.
wstopsig (status) Gets the signal code that causes the child process to pause, usually using wifstopped to judge before the macro is used.
returns the child process identifier (PID) if the execution succeeds, or returns if an error occurs
return value-1. The reason for failure is stored in errno. |
Examples of Fio using Waitpid
* Run over the job map and reap the threads that has exited, if any. */ static void reap_threads (unsigned int *nr_running, unsigned int *t_rate, unsigned int *m_rate) { ... Realthreads = pending = Cputhreads = 0; FOR_EACH_TD (TD, I) { int flags = 0; /* *->io_ops is NULL for a thread the has closed its * IO engine */ if (Td->io_ops &&!strcmp (td->io_ops->name, "Cpuio")) cputhreads++; Else realthreads++; ... Flags = Wnohang; if (td->runstate = = td_exited) Flags = 0; /* * Check if someone quit or got killed in an unusual */ ret = Waitpid (td->pid, &status, flags); if (Ret < 0) { if (errno = = Echild) { Log_err ("fio:pid=%d disappeared%d\n", (int) td->pid, td->runstate); Td->sig = Echild; Td_set_runstate (TD, Td_reaped); Goto reaped; } Perror ("Waitpid"); } else if (ret = = td->pid) { if (wifsignaled (status)) { int sig = Wtermsig (status); if (sig! = SIGTERM && sig! = SIGUSR2) Log_err ("fio:pid=%d, got signal=%d\n", (int) td->pid, SIG); Td->sig = sig; Td_set_runstate (TD, Td_reaped); Goto reaped; } if (wifexited (status)) { if (Wexitstatus (status) &&!td->error) Td->error = Wexitstatus (status); Td_set_runstate (TD, Td_reaped); Goto reaped; } } ... |
Let the process hibernate
The Sleep function suspends a process for a specified amount of time. The sleep function returns 0, otherwise returns the remaining number of seconds to sleep ( It is possible, because it may be prematurely returned by a signal interruption ) .
Another useful function is pause, which allows the calling function to hibernate until the process receives a signal.
Inter-process signal transmission Note: Due to the time relationship, there is space to replenish.
Reference documents
Caapp: In- depth understanding of computer systems
SOURCE fio-2.1.10
Linux process Management (C language)