"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.10.00/stress-wait.c" (8 Jul 2019, 5336 Bytes) of package /linux/privat/stress-ng-0.10.00.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "stress-wait.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.09.57_vs_0.09.58.

    1 /*
    2  * Copyright (C) 2013-2019 Canonical, Ltd.
    3  *
    4  * This program is free software; you can redistribute it and/or
    5  * modify it under the terms of the GNU General Public License
    6  * as published by the Free Software Foundation; either version 2
    7  * of the License, or (at your option) any later version.
    8  *
    9  * This program is distributed in the hope that it will be useful,
   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12  * GNU General Public License for more details.
   13  *
   14  * You should have received a copy of the GNU General Public License
   15  * along with this program; if not, write to the Free Software
   16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
   17  *
   18  * This code is a complete clean re-write of the stress tool by
   19  * Colin Ian King <colin.king@canonical.com> and attempts to be
   20  * backwardly compatible with the stress tool by Amos Waterland
   21  * <apw@rossby.metr.ou.edu> but has more stress tests and more
   22  * functionality.
   23  *
   24  */
   25 #include "stress-ng.h"
   26 
   27 static const help_t help[] = {
   28     { NULL, "wait N",   "start N workers waiting on child being stop/resumed" },
   29     { NULL, "wait-ops N",   "stop after N bogo wait operations" },
   30     { NULL, NULL,       NULL }
   31 };
   32 
   33 /*
   34  *  Disabled for GNU/Hurd because it this stressor breaks with
   35  *  the error:
   36  *    intr-msg.c:387: _hurd_intr_rpc_mach_msg: Assertion
   37  *    `m->header.msgh_id == msgid + 100'
   38  */
   39 #if !defined(__gnu_hurd__)
   40 
   41 #define ABORT_TIMEOUT   (1.0)
   42 
   43 static void MLOCKED_TEXT stress_usr1_handler(int signum)
   44 {
   45     (void)signum;
   46 }
   47 
   48 /*
   49  *  spawn()
   50  *  spawn a process
   51  */
   52 static pid_t spawn(
   53     const args_t *args,
   54     void (*func)(const args_t *args, const pid_t pid),
   55     pid_t pid_arg)
   56 {
   57     pid_t pid;
   58 
   59 again:
   60     pid = fork();
   61     if (pid < 0) {
   62         if (g_keep_stressing_flag && (errno == EAGAIN))
   63             goto again;
   64         return -1;
   65     }
   66     if (pid == 0) {
   67         stress_parent_died_alarm();
   68 
   69         func(args, pid_arg);
   70         _exit(EXIT_SUCCESS);
   71     }
   72     (void)setpgid(pid, g_pgrp);
   73     return pid;
   74 }
   75 
   76 /*
   77  *  runner()
   78  *  this process pauses, but is continually being
   79  *  stopped and continued by the killer process
   80  */
   81 static void runner(
   82     const args_t *args,
   83     const pid_t pid)
   84 {
   85     (void)pid;
   86 
   87     pr_dbg("%s: wait: runner started [%d]\n", args->name, (int)getpid());
   88 
   89     do {
   90         (void)pause();
   91     } while (keep_stressing());
   92 
   93     (void)kill(getppid(), SIGALRM);
   94     _exit(EXIT_SUCCESS);
   95 }
   96 
   97 /*
   98  *  killer()
   99  *  this continually stops and continues the runner process
  100  */
  101 static void killer(
  102     const args_t *args,
  103     const pid_t pid)
  104 {
  105     double start = time_now();
  106     uint64_t last_counter = get_counter(args);
  107     pid_t ppid = getppid();
  108 
  109     pr_dbg("%s: wait: killer started [%d]\n", args->name, (int)getpid());
  110 
  111     do {
  112         (void)kill(pid, SIGSTOP);
  113         (void)shim_sched_yield();
  114         (void)kill(pid, SIGCONT);
  115 
  116         /*
  117          *  The waits may be blocked and
  118          *  so the counter is not being updated.
  119          *  If it is blocked for too long bail out
  120          *  so we don't get stuck in the parent
  121          *  waiter indefinitely.
  122          */
  123         if (last_counter == get_counter(args)) {
  124             const double now = time_now();
  125             if (now - start > ABORT_TIMEOUT) {
  126                 /* unblock waiting parent */
  127                 (void)kill(ppid, SIGUSR1);
  128                 start = now;
  129             }
  130         } else {
  131             start = time_now();
  132             last_counter = get_counter(args);
  133         }
  134     } while (keep_stressing());
  135 
  136     /* forcefully kill runner, wait is in parent */
  137     (void)kill(pid, SIGKILL);
  138 
  139     /* tell parent to wake up! */
  140     (void)kill(getppid(), SIGALRM);
  141     _exit(EXIT_SUCCESS);
  142 }
  143 
  144 /*
  145  *  stress_wait
  146  *  stress wait*() family of calls
  147  */
  148 static int stress_wait(const args_t *args)
  149 {
  150     int status, ret = EXIT_SUCCESS;
  151     pid_t pid_r, pid_k, wret;
  152     int options = 0;
  153 
  154 #if defined(WUNTRACED)
  155     options |= WUNTRACED;
  156 #endif
  157 #if defined(WCONTINUED)
  158     options |= WCONTINUED;
  159 #endif
  160 
  161     pr_dbg("%s: waiter started [%d]\n",
  162         args->name, (int)args->pid);
  163 
  164     if (stress_sighandler(args->name, SIGUSR1, stress_usr1_handler, NULL) < 0)
  165         return EXIT_FAILURE;
  166 
  167     pid_r = spawn(args, runner, 0);
  168     if (pid_r < 0) {
  169         pr_fail_dbg("fork");
  170         return EXIT_FAILURE;
  171     }
  172 
  173     pid_k = spawn(args, killer, pid_r);
  174     if (pid_k < 0) {
  175         pr_fail_dbg("fork");
  176         ret = EXIT_FAILURE;
  177         goto tidy;
  178     }
  179 
  180     do {
  181         wret = waitpid(pid_r, &status, options);
  182         if ((wret < 0) && (errno != EINTR) && (errno != ECHILD)) {
  183             pr_fail_dbg("waitpid()");
  184             break;
  185         }
  186         if (!g_keep_stressing_flag)
  187             break;
  188 #if defined(WIFCONINUED)
  189         if (WIFCONTINUED(status))
  190             inc_counter(args);
  191 #else
  192         inc_counter(args);
  193 #endif
  194 
  195 #if defined(HAVE_WAITID)
  196         if (options) {
  197             siginfo_t info;
  198 
  199             wret = waitid(P_PID, pid_r, &info, options);
  200             if ((wret < 0) && (errno != EINTR) && (errno != ECHILD)) {
  201                 pr_fail_dbg("waitpid()");
  202                 break;
  203             }
  204             if (!g_keep_stressing_flag)
  205                 break;
  206 #if defined(WIFCONTINUED)
  207             if (WIFCONTINUED(status))
  208                 inc_counter(args);
  209 #else
  210             inc_counter(args);
  211 #endif
  212         }
  213 #endif
  214     } while (g_keep_stressing_flag && (!args->max_ops || get_counter(args) < args->max_ops));
  215 
  216     (void)kill(pid_k, SIGKILL);
  217     (void)shim_waitpid(pid_k, &status, 0);
  218 tidy:
  219     (void)kill(pid_r, SIGKILL);
  220     (void)shim_waitpid(pid_r, &status, 0);
  221 
  222     return ret;
  223 }
  224 
  225 stressor_info_t stress_wait_info = {
  226     .stressor = stress_wait,
  227     .class = CLASS_SCHEDULER | CLASS_OS,
  228     .help = help
  229 };
  230 #else
  231 stressor_info_t stress_wait_info = {
  232     .stressor = stress_not_implemented,
  233     .class = CLASS_SCHEDULER | CLASS_OS,
  234     .help = help
  235 };
  236 #endif