"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-oom-pipe.c" (15 Mar 2019, 5732 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-oom-pipe.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.09.50_vs_0.09.51.

    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 #if defined(F_SETPIPE_SZ) &&    \
   28     defined(O_NONBLOCK) &&  \
   29     defined(F_SETFL)
   30 
   31 /*
   32  *  pipe_empty()
   33  *  read data from read end of pipe
   34  */
   35 static void pipe_empty(const int fd, const int max, const size_t page_size)
   36 {
   37     int i;
   38 
   39     for (i = 0; i < max; i += page_size) {
   40         ssize_t ret;
   41         char buffer[page_size];
   42 
   43         ret = read(fd, buffer, sizeof(buffer));
   44         if (ret < 0)
   45             return;
   46     }
   47 }
   48 
   49 /*
   50  *  pipe_fill()
   51  *  write data to fill write end of pipe
   52  */
   53 static void pipe_fill(const int fd, const size_t max, const size_t page_size)
   54 {
   55     size_t i;
   56     char buffer[page_size];
   57 
   58     (void)memset(buffer, 'X', sizeof(buffer));
   59 
   60     for (i = 0; i < max; i += page_size) {
   61         ssize_t ret;
   62 
   63         ret = write(fd, buffer, sizeof(buffer));
   64         if (ret < (ssize_t)sizeof(buffer))
   65             return;
   66     }
   67 }
   68 
   69 /*
   70  *  stress_oom_pipe_expander
   71  *
   72  */
   73 static int stress_oom_pipe_expander(
   74     const args_t *args,
   75     const size_t max_pipe_size,
   76     const int max_pipes,
   77     const size_t page_size)
   78 {
   79     pid_t pid;
   80 
   81 again:
   82     pid = fork();
   83     if (pid < 0) {
   84         if (g_keep_stressing_flag && (errno == EAGAIN))
   85             goto again;
   86         pr_err("%s: fork failed: errno=%d (%s)\n",
   87             args->name, errno, strerror(errno));
   88         return -1;
   89     } else if (pid > 0) {
   90         int status, ret;
   91 
   92         (void)setpgid(pid, g_pgrp);
   93         stress_parent_died_alarm();
   94 
   95         /* Patent, wait for child */
   96         ret = waitpid(pid, &status, 0);
   97         if (ret < 0) {
   98             if (errno != EINTR)
   99                 pr_dbg("%s: waitpid() errno=%d (%s)\n",
  100                     args->name, errno, strerror(errno));
  101             (void)kill(pid, SIGTERM);
  102             (void)kill(pid, SIGKILL);
  103             (void)waitpid(pid, &status, 0);
  104         } else if (WIFSIGNALED(status)) {
  105             pr_dbg( "%s: child died: %s (instance %d)\n",
  106                 args->name, stress_strsignal(WTERMSIG(status)),
  107                 args->instance);
  108             /* If we got kill by OOM killer, re-start */
  109             if (WTERMSIG(status) == SIGKILL) {
  110                 log_system_mem_info();
  111                 pr_dbg("%s: assuming killed by OOM "
  112                     "killer, restarting again "
  113                     "(instance %d)\n",
  114                     args->name, args->instance);
  115                 goto again;
  116             }
  117         }
  118     } else if (pid == 0) {
  119         /* Child */
  120         int fds[max_pipes * 2], *fd, i, pipes_open = 0, ret;
  121         const bool aggressive = (g_opt_flags & OPT_FLAGS_AGGRESSIVE);
  122 
  123         (void)setpgid(0, g_pgrp);
  124         set_oom_adjustment(args->name, true);
  125 
  126         /* Explicitly drop capabilites, makes it more OOM-able */
  127         ret = stress_drop_capabilities(args->name);
  128         (void)ret;
  129 
  130         for (i = 0; i < max_pipes * 2; i++)
  131             fds[i] = -1;
  132 
  133         for (i = 0; i < max_pipes; i++) {
  134             int *pfd = fds + (2 * i);
  135             if (pipe(pfd) < 0) {
  136                 pfd[0] = -1;
  137                 pfd[1] = -1;
  138             } else {
  139                 if (fcntl(pfd[0], F_SETFL, O_NONBLOCK) < 0) {
  140                     pr_fail_err("fcntl O_NONBLOCK");
  141                     goto clean;
  142                 }
  143                 if (fcntl(pfd[1], F_SETFL, O_NONBLOCK) < 0) {
  144                     pr_fail_err("fcntl O_NONBLOCK");
  145                     goto clean;
  146                 }
  147                 pipes_open++;
  148             }
  149         }
  150 
  151         if (!pipes_open) {
  152             pr_dbg("%s: failed to open any pipes, aborted\n",
  153                 args->name);
  154             _exit(EXIT_NO_RESOURCE);
  155         }
  156 
  157         do {
  158             /* Set to maximum size */
  159             for (i = 0, fd = fds; i < max_pipes; i++, fd += 2) {
  160                 size_t max_size = max_pipe_size;
  161 
  162                 if ((fd[0] < 0) || (fd[1] < 0))
  163                     continue;
  164                 if (fcntl(fd[0], F_SETPIPE_SZ, max_size) < 0)
  165                     max_size = page_size;
  166                 if (fcntl(fd[1], F_SETPIPE_SZ, max_size) < 0)
  167                     max_size = page_size;
  168                 pipe_fill(fd[1], max_size, page_size);
  169                 if (!aggressive)
  170                     pipe_empty(fd[0], max_size, page_size);
  171             }
  172             /* Set to minimum size */
  173             for (i = 0, fd = fds; i < max_pipes; i++, fd += 2) {
  174                 if ((fd[0] < 0) || (fd[1] < 0))
  175                     continue;
  176                 (void)fcntl(fd[0], F_SETPIPE_SZ, page_size);
  177                 (void)fcntl(fd[1], F_SETPIPE_SZ, page_size);
  178                 pipe_fill(fd[1], max_pipe_size, page_size);
  179                 if (!aggressive)
  180                     pipe_empty(fd[0], page_size, page_size);
  181             }
  182             inc_counter(args);
  183         } while (keep_stressing());
  184 
  185         /* And close the pipes */
  186 clean:
  187         for (i = 0, fd = fds; i < max_pipes * 2; i++, fd++) {
  188             if (*fd >= 0)
  189                 (void)close(*fd);
  190         }
  191         _exit(EXIT_SUCCESS);
  192     }
  193     return 0;
  194 }
  195 
  196 
  197 /*
  198  *  stress_oom_pipe
  199  *  stress pipe memory allocation
  200  */
  201 static int stress_oom_pipe(const args_t *args)
  202 {
  203     const size_t max_fd = stress_get_file_limit();
  204     const size_t max_pipes = max_fd / 2;
  205     const size_t page_size = args->page_size;
  206     size_t max_pipe_size = stress_probe_max_pipe_size();
  207 
  208     if (max_pipe_size < page_size)
  209         max_pipe_size = page_size;
  210     max_pipe_size &= ~(page_size - 1);
  211 
  212     return stress_oom_pipe_expander(args, max_pipe_size, max_pipes, page_size);
  213 }
  214 
  215 stressor_info_t stress_oom_pipe_info = {
  216     .stressor = stress_oom_pipe,
  217     .class = CLASS_MEMORY | CLASS_OS | CLASS_PATHOLOGICAL
  218 };
  219 #else
  220 stressor_info_t stress_oom_pipe_info = {
  221     .stressor = stress_not_implemented,
  222     .class = CLASS_MEMORY | CLASS_OS | CLASS_PATHOLOGICAL
  223 };
  224 #endif