wait and waitpid functions

    When a process terminates normally or abnormally, the kernel sends a SIGCHLD signal to its parent process, and the default action of the parent process for such a signal is to ignore it. You can use the wait and waitpid functions to get the termination status of the child process.
#include <sys/wait.h>
pid_t wait(int *statloc);
pid_t waitpid(pid_t pid, int *statloc, int options);
                  /* Two function return values: if successful, return the process ID; otherwise, return 0 or -1 */

    Usually when these two functions are called:
    * Blocks if all of its child processes are still running.
    * If a child process has terminated and is waiting for the parent process to obtain its termination status, return immediately after obtaining the termination status of the child process.
    * If it does not have any child processes, return immediately with an error.
    The difference between these two functions is as follows.
    (1) Wait causes its caller to block until a child process terminates, while waitpid has an option to not block the caller.
    (2) waitpid does not have to wait for the first terminated child process after its call, it has several options that can control the process it waits for.
    (3) For wait, the only error is that the calling process has no child process (the function call may also return another error when interrupted by a signal). But for waitpid, an error may occur if the specified process or process group does not exist, or if the process specified by pid is not a child of the calling process.
    If their parameter statloc is not a null pointer, the termination status of the child process is stored in the unit it points to. If you don't care about the termination status, you can specify it as a null pointer. Traditionally, the returned integer status word is implementation-defined, with some bits indicating the exit status (normal return), other bits indicating the signal number (abnormal return), one bit indicating whether a core file was generated, etc. The termination status can be viewed by the macros in <sys/wait.h>. The four mutually exclusive macros in the table below can be used to obtain the reason for the termination of the process. Based on which of these 4 macros is true, other macros can be used to get the exit status, signal number, etc. (many platforms support the WCOREDUMP macro, but some platforms hide the _POSIX_C_SOURCE constant if it is defined).

    The following program is to use these 4 macros to print the description of the process termination status.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

void pr_exit(int status){
	if(WIFEXITED(status))
		printf("normal terminaltion, exit status = %d\n",
				WEXITSTATUS(status) );
	else if(WIFSIGNALED(status))
		printf("abnormal termination, signal number = %d%s\n",
				WTERMSIG(status),
			#ifdef WCOREDUMP
				WCOREDUMP(status)?"(core file generated)": "");
			#else
				"");
			#endif
	else if(WIFSTOPPED(status))
		printf("child stopped, signal number = %d\n",
				WSTOPSIG(status));
}

int main(void){
	pid_t	pid;
	int		status;

	if((pid=fork()) < 0){
		printf("1st fork error\n");
		exit(2);
	}else if(pid == 0)		// child
		exit(7);
	if(wait(&status) != pid){	// wait for child
		printf("1st wait error\n");
		exit(2);
	}
	pr_exit(status);		// and print its status

	if((pid=fork()) < 0){
		printf("2nd fork error\n");
		exit(2);
	}else if(pid == 0)
		abort();		// generates SIGABRT, signal number is 6
	if(wait(&status) != pid){
		printf("2nd wait error\n");
		exit(2);
	}
	pr_exit(status);

	if((pid=fork()) < 0){
		printf("3rd fork error\n");
		exit(2);
	}else if(pid == 0)
		status /= 0;		// generates SIGFPE, signal number is 8
	if(wait(&status) != pid){
		printf("3rd wait error\n");
		exit(2);
	}
	pr_exit(status);

	exit(0);
}

    The running result is as follows.
$ ./exitStatusDemo.out
normal terminaltion, exit status = 7
abnormal termination, signal number = 6(core file generated)
abnormal termination, signal number = 8(core file generated)
$

    If a process has several subprocesses, wait returns as soon as one of the subprocesses terminates. The waitpid function comes in handy if you want to wait for a specified process to terminate. The role of the pid parameter in the waitpid function is explained as follows.
    * pid == -1: Wait for any child process, which is equivalent to wait.
    * pid > 0: wait for the child process whose process ID is pid.
    * pid == 0: Wait for any child process whose group ID is equal to the calling process's group ID.
    * pid < -1: Wait for any child process whose group ID is equal to the absolute value of pid.
    The parameter options can further control the operation of waitpid. This parameter can be 0 or the result of the bitwise OR of the constants in the following table (FreeBSD 8.0 and Solaris 10 support another nonstandard optional constant, WNOWAIT, which causes the system to hold a process whose termination status has been returned by waitpid in waiting. state so that it can be awaited again).

    If a process forks a child, but doesn't want it to wait for the child to terminate, and doesn't want the child to be in a zombie state until the parent terminates, the trick to accomplishing this is to call fork twice, as shown in the following program.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main(void){
	pid_t		pid;

	if((pid=fork()) < 0){
		printf("1st fork error\n");
		exit(2);
	}else if(pid == 0){		// first child
		if((pid=fork()) < 0){
			printf("2nd fork error\n");
			exit(2);
		}else if(pid > 0){
			exit(0);	// parent from second fork == first child
		}

		/* We're the second child; our parent becomes init as soon as
		 * our real parent calls exit() in the statement above. Here's
		 * where we'd continue executing, knowing that when we're
		 * done, init will reap our status.
		 */
		sleep(2);
		printf("second child, parent pid=%ld\n", (long)getppid());
		exit(0);
	}

	if(waitpid(pid, NULL, 0) != pid){	// wait for first child
		printf("waitpid error\n");
	}

	/* We're the parent(the original process); we continue executing,
	 * knowing that we're not the parent of the second child.
	 */
	exit(0);
}

    Results of the:
$ ./fork2timesDemo.out
$ second child, parent pid = 1

    Note that here the shell prints its prompt when the original process (that is, the one that execs this program) terminates, because this happens before the second child process prints its parent's process ID.
    In addition, the Single UNIX Specification includes another function to obtain the termination status of a process, waitid, which is similar to waitpid, but provides more flexibility.
#include <sys/wait.h>
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
                                   /* Return value: if successful, return 0; otherwise, return -1 */

    waitid also allows a process to specify the child process to wait on, but instead of combining this with the process ID or process group ID into one parameter, it uses two separate parameters for the type of process to wait for. The effect of the id parameter is related to the value of idtype. The function supports the idtype types in the table below.

    The options parameter is the bitwise OR of the flags in the following table that indicate which state changes the caller is concerned about.

    Note that one of the three constants WCONTINUED, WEXITED and WSTOPPED must be specified.
    The infop parameter is a pointer to a siginfo structure that contains detailed information about the signal that caused the child process to change state.
    Most UNIX system implementations also provide wait3 and wait4 functions, which provide one more functionality than several wait functions above, related to an additional parameter that allows the kernel to return the function used by the terminating process and all its children. resource situation. Resource statistics (different from resource limits) include total user CPU time, total system CPU time, number of page faults, number of received signals, etc. See the getrusage(2) man page for details.
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>

pid_t wait3(int *statloc, int options, struct rusage *rusage);
pid_t wait4(pid_t pid, int *statloc, int options, struct rusage *rusage);
                        /* Two function return values: if successful, return the process ID; otherwise, return -1 */

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326270052&siteId=291194637