Reclaim kernel space resources wait function waitid function, waitwaitid
Abstract:This article describes how to reclaim the kernel space resources and how to use wait and waitid functions and their differences.
Reclaim kernel space resources wait and waitid Functions
The user space resources are released when the process exits, but the PCB of the process is not released. This is not done by yourself, but by the parent process of the current process.
When a process Exits normally or unexpectedly, the kernel sends a SIGCHLD signal to its parent process. because the termination of a sub-process is an asynchronous event, this signal is also an asynchronous notification sent by the kernel to the parent process. the parent process can choose to ignore this signal (if the parent process sets the SA_NOCLDWAIT flag bit (SA_NOCLDWAIT: causes the parent process to not receive the SIGCHLD signal when its child process exits ), or provide a function that is called when the signal occurs. The parent process can call the wait () and waitpid () functions explicitly.
1. The wait () and waitid () functions wait until the child process ends.
Function Definition:
# Include <sys/types. h>
# Include <sys/wait. h>
Pid_t wait (int * status );
Pid_t waitpid (pid_t pid, int * status, int options );
Function Description:
If you wait until any child process ends, the PID of the child process that is currently terminated is returned, and the status of the child process exited is stored in the "_ stat_loc" variable. if error-1 is returned, the error cause is stored in errno.
The parent process that calls the wait () function. If all its child processes are still running, the parent process will be blocked and wait until any child process ends, reclaim the kernel process resources of the sub-process. if the parent process does not have any child process, an error occurs.
If the process calls wait () because it receives the SIGCHLD signal, it is expected that wait () will return immediately. However, if wait () is called at any time, the process may be blocked.
Parameter status:
The status parameter is an integer pointer. if the status is not a null pointer, the termination state of the terminated process is placed in the memory unit to which it points. if you do not care about the Process Termination status, you can specify the parameter as a null pointer.
2. differences between wait () and waitid () functions (1) Before a sub-process is terminated, wait () blocks its callers, while waitpid () has an option, the caller is not blocked.
(2) waitpid () does not wait for the first end-to-end sub-process after it is called. It has several options to control the process it is waiting for (which will be detailed below ).
Example 1: demonstrate the basic usage of the wait () function
# Include <sys/types. h> # include <sys/wait. h> # include <unistd. h> # include <stdio. h> # include <stdlib. h> # include <sys/errno. h> int main () {pid_t pid, wait_pid; int status; pid = fork (); // call the fork function if (pid =-1) {printf ("fork errno: % m \ n");} if (pid = 0) {printf ("my pid is: % d \ n ", getpid (); sleep (5); exit (EXIT_SUCCESS); // exit normally} else {wait_pid = wait (& status ); // wait until the sub-process ends if (WIFEXITED (status) // call the WIFEXITED macro {printf ("wait on pid: % d, normal exit, return value is: % 4x \ n ", wait_pid, WEXITSTATUS (status);} else if (WIFSIGNALED (status) {printf (" wait on pid: % d, recive signal, return value is: % 4x \ n ", wait_pid, WIFSIGNALED (status) ;}} return 0 ;}
The program Exits normally. The output is as follows:
: My pid is: 2573
: Wait on pid: 2573, normal exit, return value is: 0
If a signal is sent to the sub-process after the program runs, the output is:
: My pid is: 2573
: Wait on pid: 2573, normal exit, return value is: 1
The WIFEXITED and WIFSIGNALED macros are also used in the program. The macro WIFEXITED is used to determine whether the process Exits normally. If yes, the macro value is 1. in this case, you can execute WEXITSTATUS (status) and send the sub-process to the Lower 8 bits of the parameter exit, _ exit or _ Exit.
The macro WIFSIGNALED is used to determine whether the process exits after receiving the signal. If yes, the macro value is 1. in this case, run WTERMSIG (status) to obtain the signal number that causes the sub-process to terminate.
There are also two macros related to the termination status returned by wait and waitpid. WIFSTOPPED and WIFCONTINUED.
3. the waitpid () function waits for the specified sub-process. If a process has several sub-processes, the wait () function returns the result as long as a sub-process ends and ends. but now we want to wait for a sub-process. We don't care about the completion of other sub-processes. What should we do? You can use the waitpid () function to wait for the specified sub-process to end.
Definition: pid_t waitpid (pid_t pid, int * status, int options );
Here, the first parameter is the process PID value, which is parsed as follows:
(1) pid =-1 wait for any sub-process to end. The waitpid () function is equivalent to the wait () function;
(2) pid> 0: Wait for the child process whose process ID is equal to the pid;
(3) pid = 0 wait for any sub-process whose group ID is equal to the call process group ID;
(4) pid <-1 waits for any sub-process whose group ID is equal to the absolute value of pid.
The second parameter is the variable address in the function that calls it. If the execution is successful, it is used to store the end state of the process.
The third parameter is the waiting option. It can be set to 0 or WNOHANG or WUNTRACED ). if options is set to WNOHANG and no sub-process exits at this time, 0 will be returned immediately and will not wait forever like wait. otherwise, the child process PID is returned and the status of the child process is obtained in the STAT_LOC parameter.
This is two constants. You can use the "|" operator to connect them. For example:
Ret = waitpid (-1, NULL, WNOHANG | WUNTRACED );
If you do not want to use them, you can set options to 0, for example:
Ret = waitpid (-1, NULL, 0 );
Waitpid Return Value
Due to the large number of waitpid function parameters, the returned values are also determined based on the parameters. A comprehensive analysis involves three situations:
(1) If the execution succeeds, the waitpid () returns the PID of the child process;
(2) If the option WNOHANG is set in options, and waitpid does not exit the child process during execution, 0 is returned;
(3) If an error occurs in a call,-1 is returned. errno is set to a value to indicate the error. When the specified process or process group does not exist, or if the process specified by the pid parameter is not a sub-process of the called process, an error occurs.
4. The waipid () function provides three functions that the wait () function does not have (1) waitpid can wait for a specific process, while wait returns the status of any final sub-process.
(2) waitpid provides a non-blocking version of wait. The user wants to obtain the sub-process status but does not want to block it.
(3) waitpid supports job control.
Example 2: Wait for the specified sub-process
# Include <sys/types. h> # include <sys/wait. h> # include <stdio. h> # include <unistd. h> # include <stdlib. h> int main () {pid_t chain_pid, wait_pid; chain_pid = fork (); if (chain_pid <0) printf ("Error occured on forking. \ n "); else if (chain_pid = 0) {sleep (5); exit (0) ;}do {wait_pid = waitpid (chain_pid, NULL, WNOHANG ); // if (wait_pid = 0) {printf ("No child exited \ n"); sleep (1 );}} while (wait_pid = 0); if (wait_pid = chlid_pid) printf ("successfully release child % d \ n", wait_pid ); else printf ("some error occured \ n"); return 0 ;}
Output:
: No child exited
: No child exited
: No child exited
: No child exited
: No child exited
: Successfully release child 2538.
Every second, the parent process checks whether a child process exits. in the first five seconds, because no sub-process exits, the parent process calls waitpid (chpai_pid, NULL, WNOHANG) to return directly. after the sub-process exits, it can handle the problem.
Author: my personal abilities are limited, just for reference. If the reader finds any errors in this article, please submit them.
--
Certificate ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Do not build a high station in the sand float, calm down and slowly accumulate -----------------------------------------Certificate ----------------------------------------------------------------------------------------------------------------------------------------------------------
How to check the kernel function corresponding to the R3-layer function
3.2 obtain actual data
In this chapter, we have been developing a filter program that can capture data on the serial port. Now that the virtual device has been bound to a real serial device, how can we get the data flowing through the serial port from the virtual device? The answer is based on the "request ". The operating system sends the request to a serial device. The request contains the data to be sent, and the response to the request contains the data to be received. The following analyzes these "requests" to obtain the actual serial data stream.
3.2.1 request Differentiation
Windows Kernel developers have determined a lot of data structures. In the previous content, we gradually met with DEVICE_OBJECT (device object), FILE_OBJECT (file object), and DRIVER_OBJECT (driver object. File objects have no application at the moment (but file objects are extremely important in file system filtering after this book ). Readers need to understand the following:
(1) Each driver has only one driver object.
(2) Each driver can generate several Device objects that belong to one driver. Can a driver generate a device object from a driver object of another driver? From the perspective of IoCreateDevice parameters, this is acceptable, but I have never tried such an application.
(3) Several devices (which may belong to different drivers) are bound in turn to form a device stack, and the top device always receives the request first.
Note: IRP is a common data structure for sending requests between upper-layer devices, but it is definitely not the only data structure. There are many other methods to send requests. Different devices may use different structures to send requests. However, in this book, 90% of requests and IRP are equivalent concepts.
All requests received by the serial port device are IRPs. Therefore, you only need to filter all IRPs to obtain all the data flowing through the serial port. When filtering through the serial port, you only need to consider two types of requests: Read requests and write requests. For the serial port, read refers to receiving data, while write refers to sending data. The serial port also has other requests, such as opening and closing, and setting the baud rate. However, our goal is to obtain the data flowing through the serial port, regardless of the opening or closing and the baud rate.
Requests can be differentiated by the main function number of IRP. The main function number of IRP is a byte stored in the IRP stack space. It is used to identify the main function category of this IRP. Correspondingly, there is also a feature number to identify the sub-category of this IRP function.
The primary function of a read request is IRP_MJ_READ, and the primary function of a write request is IRP_MJ_WRITE. The following method is used to obtain the primary function number from an IRP pointer (the variable irp here is a PIRP, that is, the IRP pointer ).
// The irpsp is called the IRP stack space. IoGetCurrentIrpStackLocation obtains the current stack space.
// Stack space is a very important data structure
PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation (irp );
If (irpsp-> MajorFunction = IRP_MJ_WRITE)
{
// If it is a write...
}
Else if (irpsp-> MajorFunction = IRP_MJ_READ)
{
// If reading...
}
3.2.2 request ending
There are three final results for filtering requests:
(1) The request is allowed to pass. Filter and do nothing, or simply obtain some information about the request. However, the request itself is not disturbed, so that the system behavior will not change.
(2) The request is rejected directly. If this request is blocked by filtering, an error is returned, and the underlying driver cannot receive the request. In this way, the system behavior changes, and the result is that the upper-layer application pop-up error box prompts information such as permission errors or failed File Reading.
(3) The filter completes the request. Sometimes there is such a requirement, such as a read request, we want to... the remaining full text>
Does the fork () function in linux belong to the kernel function or the C library function?
It is used to generate a new thread and should belong to the system function, not the C library function.
For more information, see
Baike.baidu.com/view/1952900.htm