exitコード


[root@localhost c]# cat waitpid.c
#include <stdlib.h>
#include <stdio.h>

void    main(int argc, char *argv[])
{
   int pid, status;

    pid = fork();
    if (pid == 0) {
        if (argc == 1) {
            pause();
            printf("no show by call do_exit in pausing\n");
        }
        exit(atoi(argv[1]));

    } else {
        if (argc == 1) {
            printf("Child PID is %ld\n", pid);
        }
        waitpid(pid, &status, 0);

        printf("signal:%d  exit_code:%d\n", 
                                           status & 0xff,
                                           status >> 8);
    }
}

[root@localhost c]# ./waitpid.o 255
signal:0  exit_code:255
[root@localhost c]# ./waitpid.o 256
signal:0  exit_code:0
[root@localhost c]# ./waitpid.o 257
signal:0  exit_code:1

[root@localhost c]# ./waitpid.o &
[1] 2097
[root@localhost c]# Child PID is 2098
[root@localhost c]# kill -65 2098
-bash: kill: 65: 無効なシグナル指定です
[root@localhost c]# kill -64 2098
[root@localhost c]# signal:64  exit_code:0
[1]+  終了 23                 ./waitpid.o
signalコード/exitコードはdo_exit()でプロセスのtsk->exit_codeに設定され、wait待機中のtsk->childrenにリンクされているpidの子プロセスのtsk->exit_codeを返します。do_exit()でプロセスは終了する故、signalコード/exitコードが混在する事はありません。
list_for_each_entry(p, &tsk->children, sibling)

SYSCALL_DEFINE1(exit, int, error_code)
{
       do_exit((error_code&0xff)<<8);
}
子プロセスが待機中の親プロセスを起床させ、親プロセスにシグナリ送信時にコールされ、do_group_exit()でdo_exit(シグナルコード)とし、子プロセスをexitします。
int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka,
                         struct pt_regs *regs, void *cookie)
{
       struct sighand_struct *sighand = current->sighand;
       struct signal_struct *signal = current->signal;
       int signr;

relock:

       try_to_freeze();

       spin_lock_irq(&sighand->siglock);

       if (unlikely(signal->flags & SIGNAL_CLD_MASK)) {
               int why;

               if (signal->flags & SIGNAL_CLD_CONTINUED)
                       why = CLD_CONTINUED;
               else
                       why = CLD_STOPPED;

               signal->flags &= ~SIGNAL_CLD_MASK;

               spin_unlock_irq(&sighand->siglock);

               read_lock(&tasklist_lock);
               do_notify_parent_cldstop(current, false, why);

               if (ptrace_reparented(current->group_leader))
                       do_notify_parent_cldstop(current->group_leader,
                                               true, why);
               read_unlock(&tasklist_lock);

               goto relock;
       }

       for (;;) {
               struct k_sigaction *ka;

               if (unlikely(current->jobctl & JOBCTL_STOP_PENDING) &&
                   do_signal_stop(0))
                       goto relock;

               if (unlikely(current->jobctl & JOBCTL_TRAP_MASK)) {
                       do_jobctl_trap();
                       spin_unlock_irq(&sighand->siglock);
                       goto relock;
               }

               signr = dequeue_signal(current, &current->blocked, info);

               if (!signr)
                       break; /* will return 0 */

               if (unlikely(current->ptrace) && signr != SIGKILL) {
                       signr = ptrace_signal(signr, info,
                                             regs, cookie);
                       if (!signr)
                               continue;
               }

               ka = &sighand->action[signr-1];

               /* Trace actually delivered signals. */
               trace_signal_deliver(signr, info, ka);

               if (ka->sa.sa_handler == SIG_IGN) /* Do nothing.  */
                       continue;
               if (ka->sa.sa_handler != SIG_DFL) {
                       /* Run the handler.  */
                       *return_ka = *ka;

                       if (ka->sa.sa_flags & SA_ONESHOT)
                               ka->sa.sa_handler = SIG_DFL;

                       break; /* will return non-zero "signr" value */
               }

               if (sig_kernel_ignore(signr)) /* Default is nothing. */
                       continue;

               if (unlikely(signal->flags & SIGNAL_UNKILLABLE) &&
                               !sig_kernel_only(signr))
                       continue;

               if (sig_kernel_stop(signr)) {
                       if (signr != SIGSTOP) {
                               spin_unlock_irq(&sighand->siglock);

                               /* signals can be posted during this window */

                               if (is_current_pgrp_orphaned())
                                       goto relock;

                               spin_lock_irq(&sighand->siglock);
                       }

                       if (likely(do_signal_stop(info->si_signo))) {
                               /* It released the siglock.  */
                               goto relock;
                       }

                       continue;
               }

               spin_unlock_irq(&sighand->siglock);

               current->flags |= PF_SIGNALED;

               if (sig_kernel_coredump(signr)) {
                       if (print_fatal_signals)
                               print_fatal_signal(regs, info->si_signo);
                       do_coredump(info->si_signo, info->si_signo, regs);
               }

               do_group_exit(info->si_signo);
       }
       spin_unlock_irq(&sighand->siglock);
       return signr;
}

#define _NSIG           64

static inline int valid_signal(unsigned long sig)
{
       return sig <= _NSIG ? 1 : 0;
}

void  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))
                       exit_code = sig->group_exit_code;
               else {
                       sig->group_exit_code = exit_code;
                       sig->flags = SIGNAL_GROUP_EXIT;
                       zap_other_threads(current);
               }
               spin_unlock_irq(&sighand->siglock);
       }

       do_exit(exit_code);
}

追記

echo $?はechoによる実装でなく、コマンドの親となるシェルが取得した子プロセスのexit_codeをechoコマンド引数として実行させているかと。



最終更新 2017/01/11 14:11:50 - north
(2017/01/11 14:11:50 作成)


検索

アクセス数
3689400
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。