"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-vforkmany.c" (15 Mar 2019, 5244 Bytes) of package /linux/privat/stress-ng-0.09.56.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-vforkmany.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.09.49_vs_0.09.50.

    1 /*
    2  * Copyright (C) 2017-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 #define STACK_SIZE      (16384)
   28 #define WASTE_SIZE  (64 * MB)
   29 
   30 /*
   31  *  stress_vforkmany()
   32  *  stress by vfork'ing as many processes as possible.
   33  *  vfork has interesting semantics, the parent blocks
   34  *  until the child has exited, plus child processes
   35  *  share the same address space. So we need to be
   36  *  careful not to overrite shared variables across
   37  *  all the processes.
   38  */
   39 static int stress_vforkmany(const args_t *args)
   40 {
   41     static int status;
   42     static pid_t chpid;
   43     static volatile int instance = 0;
   44     static uint8_t stack_sig[SIGSTKSZ + SIGSTKSZ];
   45     static volatile bool *terminate;
   46     static bool *terminate_mmap;
   47 
   48     /* We should use an alterative signal stack */
   49     (void)memset(stack_sig, 0, sizeof(stack_sig));
   50     if (stress_sigaltstack(stack_sig, SIGSTKSZ) < 0)
   51         return EXIT_FAILURE;
   52 
   53     terminate = terminate_mmap =
   54         (bool *)mmap(NULL, args->page_size,
   55                 PROT_READ | PROT_WRITE,
   56                 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
   57     if (terminate_mmap == MAP_FAILED) {
   58         pr_inf("%s: mmap failed: %d (%s)\n",
   59             args->name, errno, strerror(errno));
   60         return EXIT_NO_RESOURCE;
   61     }
   62     *terminate = false;
   63 
   64 fork_again:
   65     if (!g_keep_stressing_flag)
   66         goto tidy;
   67     chpid = fork();
   68     if (chpid < 0) {
   69         if (errno == EAGAIN)
   70             goto fork_again;
   71         pr_err("%s: fork failed: errno=%d: (%s)\n",
   72             args->name, errno, strerror(errno));
   73         munmap((void *)terminate_mmap, args->page_size);
   74         return EXIT_FAILURE;
   75     } else if (chpid == 0) {
   76         static uint8_t *waste;
   77         static size_t waste_size = WASTE_SIZE;
   78 
   79         (void)setpgid(0, g_pgrp);
   80 
   81         /*
   82          *  We want the children to be OOM'd if we
   83          *  eat up too much memory
   84          */
   85         set_oom_adjustment(args->name, true);
   86         stress_parent_died_alarm();
   87 
   88         /*
   89          *  Allocate some wasted space so this child
   90          *  scores more on the OOMable score than the
   91          *  parent waiter so in theory it should be
   92          *  OOM'd before the parent.
   93          */
   94         do {
   95             waste = (uint8_t *)mmap(NULL, waste_size, PROT_READ | PROT_WRITE,
   96                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
   97             if (waste != MAP_FAILED)
   98                 break;
   99 
  100             waste_size >>= 1;
  101         } while (waste_size > 4096);
  102 
  103         if (waste != MAP_FAILED)
  104             (void)memset(waste, 0, WASTE_SIZE);
  105         do {
  106             /*
  107              *  Force pid to be a register, if it's
  108              *  stashed on the stack or as a global
  109              *  then waitpid will pick up the one
  110              *  shared by all the vfork children
  111              *  which is problematic on the wait
  112              */
  113             register pid_t pid;
  114             register bool first = (instance == 0);
  115 
  116 vfork_again:
  117             /*
  118              * SIGALRM is not inherited over vfork so
  119              * instead poll the run time and break out
  120              * of the loop if we've run out of run time
  121              */
  122             if (*terminate) {
  123                 g_keep_stressing_flag = false;
  124                 break;
  125             }
  126             inc_counter(args);
  127             instance++;
  128             if (first) {
  129                 pid = fork();
  130             } else {
  131 PRAGMA_PUSH
  132 PRAGMA_WARN_OFF
  133 #if defined(__NR_vfork)
  134                 pid = (pid_t)syscall(__NR_vfork);
  135 #else
  136                 pid = vfork();
  137 #endif
  138 PRAGMA_POP
  139             }
  140 
  141             if (pid < 0) {
  142                 /* failed, only exit of not the top parent */
  143                 if (!first)
  144                     _exit(0);
  145             } else if (pid == 0) {
  146                 if (waste != MAP_FAILED) {
  147                     register size_t i;
  148 
  149                     for (i = 0; i < WASTE_SIZE; i += 4096)
  150                         waste[i] = 0;
  151                 }
  152 
  153                 /* child, parent is blocked, spawn new child */
  154                 if (!args->max_ops || get_counter(args) < args->max_ops)
  155                     goto vfork_again;
  156                 _exit(0);
  157             }
  158             /* parent, wait for child, and exit if not top parent */
  159             (void)waitpid(pid, &status, 0);
  160             if (!first)
  161                 _exit(0);
  162         } while (keep_stressing());
  163 
  164         if (waste != MAP_FAILED)
  165             munmap((void *)waste, WASTE_SIZE);
  166         _exit(0);
  167     } else {
  168         /*
  169          * Parent sleeps until timeout/SIGALRM and then
  170          * flags terminate state that the vfork children
  171          * see and will then exit.  We wait for the first
  172          * one spawned to unblock and exit
  173          */
  174         int chstatus;
  175 
  176         (void)setpgid(chpid, g_pgrp);
  177         g_opt_flags &= ~OPT_FLAGS_OOMABLE;
  178         set_oom_adjustment(args->name, false);
  179 
  180         (void)sleep(g_opt_timeout);
  181         *terminate = true;
  182         (void)kill(chpid, SIGALRM);
  183 
  184         (void)waitpid(chpid, &chstatus, 0);
  185     }
  186 tidy:
  187     (void)munmap((void *)terminate_mmap, args->page_size);
  188     return EXIT_SUCCESS;
  189 }
  190 
  191 stressor_info_t stress_vforkmany_info = {
  192     .stressor = stress_vforkmany,
  193     .class = CLASS_SCHEDULER | CLASS_OS
  194 };