"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-pipe.c" (15 Mar 2019, 5725 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-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 #define PIPE_STOP   "PS!"
   28 
   29 #if defined(F_SETPIPE_SZ)
   30 /*
   31  *  stress_set_pipe_size()
   32  *  set pipe size in bytes
   33  */
   34 int stress_set_pipe_size(const char *opt)
   35 {
   36     size_t pipe_size;
   37 
   38     pipe_size = (size_t)get_uint64_byte(opt);
   39     check_range_bytes("pipe-size", pipe_size, 4, 1024 * 1024);
   40     return set_setting("pipe-size", TYPE_ID_SIZE_T, &pipe_size);
   41 }
   42 #endif
   43 
   44 /*
   45  *  stress_set_pipe_size()
   46  *  set pipe data write size in bytes
   47  */
   48 int stress_set_pipe_data_size(const char *opt)
   49 {
   50     size_t pipe_data_size;
   51 
   52     pipe_data_size = (size_t)get_uint64_byte(opt);
   53     check_range_bytes("pipe-data-size", pipe_data_size,
   54         4, stress_get_pagesize());
   55     return set_setting("pipe-data-size,", TYPE_ID_SIZE_T, &pipe_data_size);
   56 }
   57 
   58 /*
   59  *  pipe_memset()
   60  *  set pipe data to be incrementing chars from val upwards
   61  */
   62 static inline void pipe_memset(char *buf, char val, const size_t sz)
   63 {
   64     size_t i;
   65 
   66     for (i = 0; i < sz; i++)
   67         *buf++ = val++;
   68 }
   69 
   70 /*
   71  *  pipe_memchk()
   72  *  check pipe data contains incrementing chars from val upwards
   73  */
   74 static inline int pipe_memchk(char *buf, char val, const size_t sz)
   75 {
   76     size_t i;
   77 
   78     for (i = 0; i < sz; i++)
   79         if (*buf++ != val++)
   80             return 1;
   81     return 0;
   82 }
   83 
   84 #if defined(F_SETPIPE_SZ)
   85 /*
   86  *  pipe_change_size()
   87  *  see if we can change the pipe size
   88  */
   89 static void pipe_change_size(
   90     const args_t *args,
   91     const int fd,
   92     const size_t pipe_size)
   93 {
   94 #if defined(F_GETPIPE_SZ)
   95     ssize_t sz;
   96 #endif
   97     if (!pipe_size)
   98         return;
   99 
  100 #if !(defined(HAVE_PIPE2) && defined(O_DIRECT))
  101     if (pipe_size < args->page_size)
  102         return;
  103 #endif
  104     if (fcntl(fd, F_SETPIPE_SZ, pipe_size) < 0) {
  105         pr_err("%s: cannot set pipe size, keeping "
  106             "default pipe size, errno=%d (%s)\n",
  107             args->name, errno, strerror(errno));
  108     }
  109 #if defined(F_GETPIPE_SZ)
  110     /* Sanity check size */
  111     if ((sz = fcntl(fd, F_GETPIPE_SZ)) < 0) {
  112         pr_err("%s: cannot get pipe size, errno=%d (%s)\n",
  113             args->name, errno, strerror(errno));
  114     } else {
  115         if ((size_t)sz != pipe_size) {
  116             pr_err("%s: cannot set desired pipe size, "
  117                 "pipe size=%zd, errno=%d (%s)\n",
  118                 args->name, sz, errno, strerror(errno));
  119         }
  120     }
  121 #endif
  122 }
  123 #endif
  124 
  125 
  126 /*
  127  *  stress_pipe
  128  *  stress by heavy pipe I/O
  129  */
  130 static int stress_pipe(const args_t *args)
  131 {
  132     pid_t pid;
  133     int pipefds[2];
  134     size_t pipe_data_size = 512;
  135 
  136     (void)get_setting("pipe-data-size", &pipe_data_size);
  137 
  138 #if defined(HAVE_PIPE2) &&  \
  139     defined(O_DIRECT)
  140     if (pipe2(pipefds, O_DIRECT) < 0) {
  141         /*
  142          *  Failed, fall back to standard pipe
  143          */
  144         if (pipe(pipefds) < 0) {
  145             pr_fail_dbg("pipe");
  146             return EXIT_FAILURE;
  147         }
  148     }
  149 #else
  150     if (pipe(pipefds) < 0) {
  151         pr_fail_dbg("pipe");
  152         return EXIT_FAILURE;
  153     }
  154 #endif
  155 
  156 #if defined(F_SETPIPE_SZ)
  157     {
  158         size_t pipe_size = 0;
  159 
  160         (void)get_setting("pipe-size", &pipe_size);
  161         pipe_change_size(args, pipefds[0], pipe_size);
  162         pipe_change_size(args, pipefds[1], pipe_size);
  163     }
  164 #endif
  165 
  166 again:
  167     pid = fork();
  168     if (pid < 0) {
  169         if (g_keep_stressing_flag && (errno == EAGAIN))
  170             goto again;
  171         (void)close(pipefds[0]);
  172         (void)close(pipefds[1]);
  173         pr_fail_dbg("fork");
  174         return EXIT_FAILURE;
  175     } else if (pid == 0) {
  176         int val = 0;
  177 
  178         (void)setpgid(0, g_pgrp);
  179         stress_parent_died_alarm();
  180 
  181         (void)close(pipefds[1]);
  182         while (g_keep_stressing_flag) {
  183             char buf[pipe_data_size];
  184             ssize_t n;
  185 
  186             n = read(pipefds[0], buf, pipe_data_size);
  187             if (n <= 0) {
  188                 if ((errno == EAGAIN) || (errno == EINTR))
  189                     continue;
  190                 if (errno) {
  191                     pr_fail_dbg("read");
  192                     break;
  193                 }
  194                 pr_fail_dbg("zero byte read");
  195                 break;
  196             }
  197             if (!strcmp(buf, PIPE_STOP))
  198                 break;
  199             if ((g_opt_flags & OPT_FLAGS_VERIFY) &&
  200                 pipe_memchk(buf, val++, (size_t)n)) {
  201                 pr_fail("%s: pipe read error detected, "
  202                     "failed to read expected data\n", args->name);
  203             }
  204         }
  205         (void)close(pipefds[0]);
  206         _exit(EXIT_SUCCESS);
  207     } else {
  208         char buf[pipe_data_size];
  209         int val = 0, status;
  210 
  211         /* Parent */
  212         (void)setpgid(pid, g_pgrp);
  213         (void)close(pipefds[0]);
  214 
  215         do {
  216             ssize_t ret;
  217 
  218             pipe_memset(buf, val++, pipe_data_size);
  219             ret = write(pipefds[1], buf, pipe_data_size);
  220             if (ret <= 0) {
  221                 if ((errno == EAGAIN) || (errno == EINTR))
  222                     continue;
  223                 if (errno) {
  224                     pr_fail_dbg("write");
  225                     break;
  226                 }
  227                 continue;
  228             }
  229             inc_counter(args);
  230         } while (keep_stressing());
  231 
  232         (void)memset(buf, 0, sizeof(buf));
  233         (void)memcpy(buf, PIPE_STOP, sizeof(PIPE_STOP));
  234         if (write(pipefds[1], buf, sizeof(buf)) <= 0) {
  235             if (errno != EPIPE)
  236                 pr_fail_dbg("termination write");
  237         }
  238         (void)kill(pid, SIGKILL);
  239         (void)waitpid(pid, &status, 0);
  240         (void)close(pipefds[1]);
  241     }
  242     return EXIT_SUCCESS;
  243 }
  244 
  245 stressor_info_t stress_pipe_info = {
  246     .stressor = stress_pipe,
  247     .class = CLASS_PIPE_IO | CLASS_MEMORY | CLASS_OS
  248 };