简体   繁体   English

当我使用 sigaction 时,为什么我的程序会出现意外行为?

[英]Why do my program behave unexpectedly when I use sigaction?

I'm writing my own simple shell as an exercise.我正在编写自己的简单 shell 作为练习。 I need to register to the SIGCHLD signal in order to handle zombie-processes.我需要注册到SIGCHLD信号才能处理僵尸进程。 For some reason, when I add the handler using sigaction the program exits, and I don't understand why.出于某种原因,当我使用sigaction添加处理程序时,程序退出,我不明白为什么。

You can see in main() that we exit if process_arglist() returned 0 but I return 1 and I don't see how the signal handling could affect that.您可以在main()中看到,如果process_arglist()返回0 ,我们将退出,但我返回1 ,我看不到信号处理会如何影响它。

Here's my code.这是我的代码。 It should handle a command ending with an & (we fork() and use execvp in the child code).它应该处理以&结尾的命令(我们fork()并在子代码中使用execvp )。 For example: ping 127.0.0.1 -c 5 & .例如: ping 127.0.0.1 -c 5 &

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>

void sigchld_handler(int signal) {
  int my_errno = errno;
  while (waitpid(-1, 0, WNOHANG) > 0); // WNOHANG so handler will be non-blocking.
  errno = my_errno;
}

int handle_background_command(int count, char** arglist) {

  pid_t pid;
  arglist[count - 1] = NULL; // remove "&" from arglist

  //Handle SIGCHLD signal
  struct sigaction sa, sa_dft;
  sa.sa_handler = sigchld_handler;
  sa.sa_flags = SA_NOCLDSTOP;

  if (sigaction(SIGCHLD, &sa, &sa_dft) == -1) {
    perror("error when trying to set signal action");
    exit(-1);
  }

  if((pid = fork()) == -1) {
    perror("error when trying to fork() from handle_background_command()");
    exit(1);
  }

  if(pid == 0) {

    // Child code

    sigaction(SIGCHLD, &sa_dft, NULL);

    if(execvp(arglist[0], arglist) == -1) {
      perror("error when trying to execvp() from handle_background_command()");
      exit(1);
    }

  }

  // Parent code
  return 1;
}


int process_arglist(int count, char** arglist)
{
  return handle_background_command(count, arglist);
}

int main(void)
{
    while (1)
    {
        char** arglist = NULL;
        char* line = NULL;
        size_t size;
        int count = 0;

        if (getline(&line, &size, stdin) == -1) {
            printf("out!");
            break;
        }


        arglist = (char**) malloc(sizeof(char*));
        if (arglist == NULL) {
            printf("malloc failed: %s\n", strerror(errno));
            exit(-1);
        }
        arglist[0] = strtok(line, " \t\n");

        while (arglist[count] != NULL) {
            ++count;
            arglist = (char**) realloc(arglist, sizeof(char*) * (count + 1));
            if (arglist == NULL) {
                printf("realloc failed: %s\n", strerror(errno));
                exit(-1);
            }

            arglist[count] = strtok(NULL, " \t\n");
        }

        if (count != 0) {
            int result = process_arglist(count, arglist);
            printf("result = %d\n", result);
            if (!result) {
                free(line);
                free(arglist);
                printf("out\n");
                break;
            }
        }

        free(line);
        free(arglist);
    }
    pthread_exit(NULL);
    return 0;
}

Again, if I get rid of the signal handling code then it works.同样,如果我摆脱了信号处理代码,那么它就可以工作了。
What's the reason?什么原因?

EDIT Here's the output (last rows) of strace utility:编辑这是strace实用程序的输出(最后一行):

--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=2818, si_status=0, si_utime=0, si_stime=0} ---
wait4(-1, NULL, WNOHANG, NULL)          = 2818
wait4(-1, NULL, WNOHANG, NULL)          = -1 ECHILD (No child processes)
rt_sigreturn()                          = -1 EINTR (Interrupted system call)
write(1, "out!", 4out!)                     = 4
exit_group(0)                           = ?
+++ exited with 0 +++

Your program exits with EINTR (interrupted system call) from getline function (getline is interrupted by signal handler).您的程序从 getline 函数(getline 被信号处理程序中断)以 EINTR(中断的系统调用)退出。

Check this: How to handle EINTR (interrupted System Call)检查这个: 如何处理 EINTR(中断的系统调用)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用 sigaction()? 结构 sigaction 未定义 - How do I use sigaction()? struct sigaction is not defined 当我在无限循环中使用gettimeofday()时,程序意外停止 - Program stops unexpectedly when I use gettimeofday() in an infinite loop 为什么在使用floor和ceil以及取整函数时,我的C程序意外终止? - Why my C program unexpectedly terminates when using floor and ceil and rounding functions? 使用sigaction() - Use of sigaction() 我想使用 sigaction(),但我有问题 - I want to use sigaction(), but I've a problem 如果我在使用 SIGTERM 的 kill() 之后使用 waitpid() 我的程序不会按照它的预期运行。 但是如果我不使用waitpid()它会起作用吗? - if I use waitpid() after kill() with SIGTERM my program does not behave how its supposed. But it works if I dont use waitpid()? 为什么调试时程序崩溃? - Why is my program crashing when I debug? C - 为什么 puts 行为异常,而 printf 在使用 scanf 时却没有? - C - Why does puts behave unexpectedly, but printf does not when using scanf? 当我将它从OSX移动到Ubuntu机器时,为什么必须重新编译我的C程序? - Why do I have to recompile my C program when I move it from OSX to a Ubuntu machine? “kill -15”触发sigaction代码但不终止我的C程序 - “kill -15” triggers the sigaction code but does not terminate my C program
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM