Reprint: Process exit State--waitpid status significance

Source: Internet
Author: User
Tags signal handler

Recently encountered a process abruptly exiting the issue, because there is no registration signalhandler so no signal is captured.

However, from the log to see the status of Init Waitpid returned to 0x008b, before the status is not very understanding, the following article on the status of a more comprehensive introduction.

Go to http://tsecer.blog.163.com/blog/static/15018172012323975152/

one, and the child process synchronization
In a Linux system, the parent process usually needs to wait/get the child process state changes through waitpid, and this is mainly through the WAITXXX function family, such as the common init function implementation of the Respawn class configuration process (such as Getty), Gets the state of the child process in the debugger, the shell's monitoring and fetching of the synchronization process state, and the communication between the child process and the parent process typically used in our project.
We're under Linux man. Waitpid, you can see the following three more commonly used functions
#include <sys/types.h>
#include <sys/wait.h>
pid_t Wait (int *status);
pid_t waitpid (pid_t pid, int *status, int options);
int Waitid (idtype_t idtype, id_t ID, siginfo_t *infop, int options);
Their common feature is to provide a user-state pointer to the operating system, which is then populated by the kernel, where the return value of the subprocess is not determined by the return value of the Waitpid function itself, because Waitpid does not always return success, and if the incoming PID is illegal, a negative number may be returned. So the actual exit of the child process needs to be provided with additional parameters to complete.
As you can see, this return value is an int type of memory address, so all state interactions between parent and child processes are represented by this int, how this int is encoded is more important, and the same as the IP address, it is relatively compact, or rather crowded.
second, the child process through exit exit
This is generally equivalent to the normal exit, at least not because of an irresistible force caused by the exit, such as by Sigkill killed, received the sigpipe signal, its exit active exit, also considered a hospice. This type of error code passes through the kernel, and then the kernel relays in the return to the user state of the Waitpid, the road is still smooth, but the kernel is also simple processing, because the kernel is a minimum of 8bits is used for signal use, and the real exit return value recorded in the high 8bits, and can only occupy 8bits, This means that if the return value of exit is too large, waitpid is not able to see
Linux-2.6.37.1\kernel\exit.c
Syscall_define1 (exit_group, int, error_code)
{
Do_group_exit ((Error_code & 0xff) << 8);
/* notreached */
return 0;
}
Do_group_exit---. >>>do_exit
Tsk->exit_code = code;
For exiting a process through exit, it will first become a zombie process (tsk->state = task_dead and tsk->exit_state = Exit_zombie), waiting for the parent process to be reclaimed by waitxxx. The parent process is passed
Syscall_define3 (Waitpid, pid_t, PID, int __user *, stat_addr, int, options)---->>>syscall_define4 (WAIT4, pid_t , upid, int __user *, stat_addr, int, options, struct rusage __user *, ru)---->>>do_wait---->>>do_wait_t Hread--->>>wait_consider_task---->>>wait_task_zombie

Status = (P->signal->flags & signal_group_exit)? p->signal->group_exit_code:p->exit_code;
if (!retval && wo->wo_stat)
retval = Put_user (status, Wo->wo_stat);
So the return value of the child process is so deterministic, its low 8 bits is zero, the second lowest 8 bits is the true exit code.
[email protected] waitstat]$ cat exitcode.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main ()
{
pid_t Forker;
if (0 = = (Forker = fork ()))
{
Exit (0x12345678);
}else if ((pid_t) 0 > Forker)
{
Perror ("fork faile\n");
} else {
int status;
Waitpid (forker,&status,0);
printf ("Exit status is%x\n", status);
}
}

[Email protected] waitstat]$ gcc exitcode.c-o exitcode.exe
[Email protected] waitstat]$./exitcode.exe
Exit status is 7800 to see that the return value only has a minimum of 16bits in effect and the others are missing.

third, the signal causes the exit
This is also more common, should be next to exit after exit a task extinction method. If the signal processing function is not installed, the usual signal is fatal, such as segment error SIGSEGV, illegal instruction Sigill, pipeline fracture sigpipe, program abortion Sigabort, and so on, these parent processes also need to know the reason.
The low 7bits of status is used to save the signal at the end of the process, so the signal can have up to 127, such as MIPS systems.
Get_signal_to_deliver---->>>do_group_exit (Info->si_signo)--->>>do_exit (exit_code)
The next process is the same as the previous one. But when the signal exits, this place modifies the meaning of the return value.
Do_group_exit (int exit_code)
{
struct Signal_struct *sig = current->signal;

Bug_on (Exit_code & 0x80); /* Core dumps don ' t get here */

if (Signal_group_exit (SIG))
Exit_code = sig->group_exit_code;
else if (!thread_group_empty (current)) {
struct sighand_struct *const Sighand = current->sighand;
SPIN_LOCK_IRQ (&sighand->siglock);
if (Signal_group_exit (SIG))
/* Another thread got here before we took the lock. */
Exit_code = sig->group_exit_code;
else {
Sig->group_exit_code = Exit_code;
Sig->flags = Signal_group_exit; The two will affect the return value of the last status.
Zap_other_threads (current);
}
SPIN_UNLOCK_IRQ (&sighand->siglock);
}

Do_exit (Exit_code);
/* notreached */
}
Copy the assignment action from the previous section again
Status = (P->signal->flags & signal_group_exit)? p->signal->group_exit_code:p->exit_code; this satisfies the previous condition, the lower 7bits of the return value is the value that causes the process to exit the signal.
if (!retval && wo->wo_stat)
retval = Put_user (status, Wo->wo_stat);
The same is the code above, which creates an access exception in the child process
[email protected] waitstat]$ cat exitcode.fault.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main ()
{
pid_t Forker;
if (0 = = (Forker = fork ()))
{
* (int*) 0 = 0;
Exit (0x12345678);
}else if ((pid_t) 0 > Forker)
{
Perror ("fork faile\n");
} else {
int status;
Waitpid (forker,&status,0);
printf ("Exit status is%x\n", status);
}
}

[Email protected] waitstat]$ gcc exitcode.fault.c-o exitcode.fault.c.exe
[Email protected] waitstat]$./exitcode.fault.c.exe
Exit status is 8b a low of 7bits indicates the signal value that causes the task to exit, sigsegv=11, and the highest bit indicates whether the Coredump file is generated.

The location of the Coredump file is set to
int Get_signal_to_deliver (siginfo_t *info, struct k_sigaction *return_ka, struct pt_regs *regs, void *cookie)
if (Sig_kernel_coredump (SIGNR)) {
if (print_fatal_signals)
Print_fatal_signal (regs, Info->si_signo);
/*
* IF It is able to dump core, this kills all
* Other threads in the group and synchronizes with
* their demise. If we lost the race with another
* Thread getting here, it set Group_exit_code
* First and our do_group_exit call below would use
* That value and ignore the one we pass it.
*/
Do_coredump (Info->si_signo, Info->si_signo, regs);
}

Do_coredump
if (retval)
Current->signal->group_exit_code |= 0x80;
iv. process status changes
Typically, the process is converted to stopped or continued, and the parent process receives these signals by default, which can be masked when registering a signal handler, and by Sa_nocldstop when registering a sigchld to receive a signal when the process changes. , while the parent process does not wake up by default at stop and continue, the wuntraced and wcontinued flags need to be set separately in the last parameter of Waitpid.
Get_signal_to_deliver--->>>do_signal_stop
if (!sig->group_stop_count) {
struct Task_struct *t;

if (!likely (Sig->flags & signal_stop_dequeued) | |
Unlikely (Signal_group_exit (SIG)))
return 0;
/*
* There is no group stop already in progress.
* We must initiate one now.
*/
Sig->group_exit_code = Signr;
}
......
if (notify) {
Read_lock (&tasklist_lock);
Do_notify_parent_cldstop (current, notify);
Read_unlock (&tasklist_lock);
}
For waitpid system calls
static int wait_task_stopped (struct wait_opts *wo, int ptrace, struct task_struct *p)

P_code = Task_stopped_code (P, ptrace);///return &p->signal->group_exit_code; here returns the signal of the previous assignment.
......
if (!retval && wo->wo_stat)
retval = Put_user ( (Exit_code << 8) | 0x7f, Wo->wo_stat);
That is, the low 8bits is 0x7f, the second low 8bits to cause the task stop signal, this signal not only has sigstop, also has Sigtin and sigtout (everybody can look at sig_kernel_stop realization).

Test program
[email protected] waitstat]$ cat exitcode.stop.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>

int main ()
{
pid_t Forker;
if (0 = = (Forker = fork ()))
{
Setpgrp ();
Char buf[0x10];
while (1) {sleep (1); Read (0,buf,sizeof (BUF));}
Sleep (10000);
Exit (0x12345678);
}else if ((pid_t) 0 > Forker)
{
Perror ("fork faile\n");
} else {
int status;
while (1) {
Waitpid (forker,&status,wuntraced| wcontinued);
printf ("Exit status is%x\n", status);
}  }
}

[Email protected] waitstat]$ gcc exitcode.stop.c-o exitcode.stop.c.exe-static
[[email protected] waitstat]$./exitcode.stop.c.exe & Background, so the read trigger Sigttin signal for the child process, where Sigttin is 21=0x15 in the 386 system.
[6] 15452
[[Email protected] waitstat]$ exit status is 157f high byte for signal sigttin, low byte is 7f, this is an absolute value.

[[email protected] waitstat]$ Kill-sigcont 15453 This in the FC 31 kernel does not show continue corresponding 0xFFFF, in the 2.6.37 show, there is no reason to investigate.
[Email protected] waitstat]$ exit status is 157f
Where wuntraced and wcontinued are used under the 2.6.37 kernel:
static int wait_task_continued (struct wait_opts *wo, struct task_struct *p)
{
int retval;
pid_t pid;
uid_t uid;

if (!unlikely (Wo->wo_flags & wcontinued))
return 0;
......
}
static int wait_task_stopped (struct wait_opts *wo,
int ptrace, struct task_struct *p)
{
struct Siginfo __user *infop;
int retval, Exit_code, *p_code, why;
uid_t uid = 0; /* unneeded, required by compiler */
pid_t pid;

/*
* Traditionally we see Ptrace ' d stopped tasks regardless of options.
*/
if (!ptrace &&!) ( Wo->wo_flags & wuntraced))
return 0;
......
}
The encapsulation of the return value of the C library
In order to avoid the user directly judge the return value of Waitpid, C library defines a number of macros to determine the return value, interested students can be combined with the previous description of the corresponding.
Glibc-2.7\posix\sys\wait.h
# define Wexitstatus (status) __wexitstatus (__wait_int (status))
# define WTERMSIG (status) __wtermsig (__wait_int (status))
# define WSTOPSIG (status) __wstopsig (__wait_int (status))
# define wifexited (status) __wifexited (__wait_int (status))
# define WIFSIGNALED (status) __wifsignaled (__wait_int (status))
# define WIFSTOPPED (status) __wifstopped (__wait_int (status))
# ifdef __wifcontinued
# define WIFCONTINUED (status) __wifcontinued (__wait_int (status))
Glibc-2.7\bits\waitstatus.h
/* Everything extant so far uses these same bits. */


/* If wifexited (status), the Low-order 8 bits of the status. */
#define __WEXITSTATUS (status) ((status) & 0xff00) >> 8)

/* If wifsignaled (STATUS), the terminating signal. */
#define __WTERMSIG (status) & 0x7f

/* If wifstopped (STATUS), the signal that stopped the child. */
#define __WSTOPSIG (status) __wexitstatus (status)

/* Nonzero if STATUS indicates normal termination. */
#define __WIFEXITED (status) (__wtermsig (status) = = 0)

/* Nonzero if STATUS indicates termination by a signal. */
#define __WIFSIGNALED (status) \
(((Signed Char) (((status) & 0x7f) + 1) >> 1) > 0)

/* Nonzero if STATUS indicates the child is stopped. */
#define __WIFSTOPPED (Status) (& 0xff) = = 0x7f)

/* Nonzero if STATUS indicates the child continued after a stop. We only
Define this if <bits/waitflags.h> provides the wcontinued flag bit. */
#ifdef wcontinued
# define __wifcontinued (status) = = __w_continued)
#endif

/* Nonzero if STATUS indicates the child dumped core. */
#define __WCOREDUMP (status) & __wcoreflag

/* Macros for constructing status values. */
#define __W_EXITCODE (ret, SIG) (ret) << 8 | (SIG))
#define __w_stopcode (SIG) << 8 | 0x7f)
#define __W_CONTINUED 0xFFFF
#define __wcoreflag 0x80

Reprint: Process exit State--waitpid status significance

Related Article

E-Commerce Solutions

Leverage the same tools powering the Alibaba Ecosystem

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.