void tp_base<task_type>::thread_body(unsigned thread_id) { while(keep_going) { auto t = get_task(thread_id); task_action(thread_id, t); done_task(t); } stopped(thread_id); }
static void handle_signal (int signum) { W_DEBUG ("handle signal $i ($s)\n", signum, signal_to_name (signum)); /* Receiving INT/TERM signal will stop gracefully */ if (signum == SIGINT || signum == SIGTERM) { running = 0; return; } /* Handle CHLD: check children */ if (signum == SIGCHLD) { check_child = 1; return; } /* * If we have a maximum time to run the process, and we receive SIGALRM, * then the timeout was reached. As per signal(7) it is safe to kill(2) * the process from a signal handler, so we do that and then mark it for * respawning. */ if (cmd_timeout && signum == SIGALRM) { write_status ("cmd timeout $L\n", (unsigned long) cmd_task.pid); task_action (&cmd_task, A_STOP); task_action_queue (&cmd_task, A_START); alarm (cmd_timeout); return; } unsigned i = 0; while (forward_signals[i].code != NO_SIGNAL) { if (signum == forward_signals[i++].code) break; } if (signum != NO_SIGNAL) { /* Try to forward signals */ if (cmd_signals) { W_DEBUGC (" delayed signal $i for cmd process\n", signum); task_action_queue (&cmd_task, A_SIGNAL); task_signal_queue (&cmd_task, signum); } if (log_signals && log_enabled) { W_DEBUGC (" delayed signal $i for log process\n", signum); task_action_queue (&log_task, A_SIGNAL); task_signal_queue (&log_task, signum); } } }
int dmon_main (int argc, char **argv) { w_io_t *pidfile_io = NULL; char *opts_env = NULL; bool success; unsigned i, consumed; /* Check for "-C configfile" given in the command line. */ if (argc > 2 && ((argv[1][0] == '-' && argv[1][1] == 'C' && argv[1][2] == '\0') || !strcmp ("--config", argv[1]))) { w_lobj w_io_t *cfg_io = NULL; char *err_msg = NULL; if ((cfg_io = w_io_unix_open (argv[2], O_RDONLY, 0)) == NULL) w_die ("$s: Could not open file '$s', $E\n", argv[0], argv[2]); success = w_opt_parse_io (dmon_options, cfg_io, &err_msg); if (!success || err_msg) w_die ("$s: Error parsing '$s' at line $s\n", argv[0], argv[2], err_msg); replace_args_shift (2, &argc, &argv); } if ((opts_env = getenv ("DMON_OPTIONS")) != NULL) replace_args_string (opts_env, &argc, &argv); i = consumed = w_opt_parse (dmon_options, NULL, NULL, "cmd [cmd-options] [ -- " "log-cmd [log-cmd-options]]", argc, argv); W_DEBUG ("w_opt_parse consumed $I arguments\n", consumed); if (workdir_path) { if (chdir (workdir_path) != 0) w_die ("$s: Cannot use '$s' as work directory, $E\n", argv[0], workdir_path); } if (status_path) { status_io = w_io_unix_open (status_path, O_WRONLY | O_CREAT | O_APPEND, 0666); if (!status_io) w_die ("$s: Cannot open '$s' for writing, $E\n", argv[0], status_path); } if (cmd_interval && success_exit) w_die ("$s: Options '-i' and '-1' cannot be used together.\n", argv[0]); if (load_enabled && almost_zerof (load_low)) load_low = load_high / 2.0f; cmd_task.argv = argv + consumed; /* Skip over until "--" is found */ while (i < (unsigned) argc && strcmp (argv[i], "--") != 0) { cmd_task.argc++; i++; } /* There is a log command */ if (i < (unsigned) argc && strcmp (argv[i], "--") == 0) { log_task.argc = argc - cmd_task.argc - consumed - 1; log_task.argv = argv + argc - log_task.argc; log_task.argv[log_task.argc] = NULL; } cmd_task.argv[cmd_task.argc] = NULL; if (log_task.argc > 0) { if (pipe (log_fds) != 0) { w_die ("$s: Cannot create pipe: $E\n", argv[0]); } W_DEBUG ("pipe_read = $i, pipe_write = $i\n", log_fds[0], log_fds[1]); fd_cloexec (log_fds[0]); fd_cloexec (log_fds[1]); } #ifdef _DEBUG_PRINT { char **xxargv = cmd_task.argv; w_io_format (w_stderr, "cmd:"); while (*xxargv) w_io_format (w_stderr, " $s", *xxargv++); w_io_format (w_stderr, "\n"); if (log_enabled) { char **xxargv = log_task.argv; w_io_format (w_stderr, "log:"); while (*xxargv) w_io_format (w_stderr, " $c", *xxargv++); w_io_format (w_stderr, "\n"); } } #endif /* _DEBUG_PRINT */ if (cmd_task.argc == 0) w_die ("$s: No command to run given.\n", argv[0]); if (pidfile_path) { pidfile_io = w_io_unix_open (pidfile_path, O_TRUNC | O_CREAT | O_WRONLY, 0666); if (!pidfile_io) { w_die ("$s: cannot open '$s' for writing: $E\n", argv[0], pidfile_path); } } if (!nodaemon) become_daemon (); /* We have a valid file descriptor: write PID */ if (pidfile_io) { w_io_result_t r = w_io_format (pidfile_io, "$L\n", (unsigned long) getpid ()); if (w_io_failed (r)) W_WARN ("I/O error writing to PID file: $E\n"); w_obj_unref (pidfile_io); } setup_signals (); alarm (cmd_timeout); cmd_task.write_fd = log_fds[1]; log_task.read_fd = log_fds[0]; while (running) { W_DEBUG (">>> loop iteration\n"); if (check_child) { int retcode = reap_and_check (); /* * Wait the specified timeout but DO NOT use safe_sleep(): here * we want an interruptible sleep-wait so reaction to signals is * quick, which we definitely want for SIGINT/SIGTERM. */ if (cmd_interval && !success_exit && retcode == 0) { int retval; struct timespec ts; ts.tv_sec = cmd_interval; ts.tv_nsec = 0; do { retval = nanosleep (&ts, &ts); W_DEBUGC (" nanosleep -> $i\n", retval); } while (retval == -1 && errno == EINTR && running); } /* * Either handling signals which interrupt the previous loop, * or reap_and_check() may request stopping on successful exit */ if (!running) { task_action_queue (&cmd_task, A_NONE); break; } } task_action_dispatch_and_write_status ("cmd", &cmd_task); if (log_enabled) task_action_dispatch_and_write_status ("log", &log_task); if (load_enabled) { double load_cur; W_DEBUGC (" checking load after sleeping 1s\n"); interruptible_sleep (1); if (getloadavg (&load_cur, 1) == -1) W_WARN ("getloadavg() failed: $E\n"); if (paused) { /* If the current load dropped below load_low -> resume */ if (load_cur <= load_low) { W_DEBUGC (" resuming...\n"); task_signal (&cmd_task, SIGCONT); write_status ("cmd resume $L\n", (unsigned long) cmd_task.pid); paused = 0; } } else { /* If the load went above load_high -> pause */ if (load_cur > load_high) { W_DEBUGC (" pausing...\n"); task_signal (&cmd_task, SIGSTOP); write_status ("cmd pause $L\n", (unsigned long) cmd_task.pid); paused = 1; } } } else { /* Wait for signals to arrive. */ W_DEBUGC (" waiting for signals to come...\n"); pause (); } } W_DEBUG ("exiting gracefully...\n"); if (cmd_task.pid != NO_PID) { write_status ("cmd stop $L\n", (unsigned long) cmd_task.pid); task_action (&cmd_task, A_STOP); } if (log_enabled && log_task.pid != NO_PID) { write_status ("log stop $L\n", (unsigned long) log_task.pid); task_action (&log_task, A_STOP); } if (status_io) { w_obj_unref (status_io); status_io = NULL; } exit (EXIT_SUCCESS); }