"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-shm.c" (15 Mar 2019, 10923 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-shm.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.09.55_vs_0.09.56.

    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 SHM_NAME_LEN    128
   28 
   29 typedef struct {
   30     ssize_t index;
   31     char    shm_name[SHM_NAME_LEN];
   32 } shm_msg_t;
   33 
   34 int stress_set_shm_posix_bytes(const char *opt)
   35 {
   36     size_t shm_posix_bytes;
   37 
   38     shm_posix_bytes = (size_t)get_uint64_byte_memory(opt, 1);
   39     check_range_bytes("shm-bytes", shm_posix_bytes,
   40         MIN_SHM_POSIX_BYTES, MAX_MEM_LIMIT);
   41     return set_setting("shm-bytes", TYPE_ID_SIZE_T, &shm_posix_bytes);
   42 }
   43 
   44 int stress_set_shm_posix_objects(const char *opt)
   45 {
   46     size_t shm_posix_objects;
   47 
   48     shm_posix_objects = (size_t)get_uint64(opt);
   49     check_range("shm-objs", shm_posix_objects,
   50         MIN_SHM_POSIX_OBJECTS, MAX_48);
   51     return set_setting("shm-objs", TYPE_ID_SIZE_T, &shm_posix_objects);
   52 }
   53 
   54 #if defined(HAVE_LIB_RT)
   55 
   56 /*
   57  *  stress_shm_posix_check()
   58  *  simple check if shared memory is sane
   59  */
   60 static int stress_shm_posix_check(
   61     uint8_t *buf,
   62     const size_t sz,
   63     const size_t page_size)
   64 {
   65     uint8_t *ptr, *end = buf + sz;
   66     uint8_t val;
   67 
   68     (void)memset(buf, 0xa5, sz);
   69 
   70     for (val = 0, ptr = buf; ptr < end; ptr += page_size, val++) {
   71         *ptr = val;
   72     }
   73 
   74     for (val = 0, ptr = buf; ptr < end; ptr += page_size, val++) {
   75         if (*ptr != val)
   76             return -1;
   77 
   78     }
   79     return 0;
   80 }
   81 
   82 /*
   83  *  stress_shm_posix_child()
   84  *  stress out the shm allocations. This can be killed by
   85  *  the out of memory killer, so we need to keep the parent
   86  *  informed of the allocated shared memory ids so these can
   87  *  be reaped cleanly if this process gets prematurely killed.
   88  */
   89 static int stress_shm_posix_child(
   90     const args_t *args,
   91     const int fd,
   92     size_t sz,
   93     size_t shm_posix_objects)
   94 {
   95     void **addrs;
   96     char *shm_names;
   97     shm_msg_t msg;
   98     int i;
   99     int rc = EXIT_SUCCESS;
  100     bool ok = true;
  101     pid_t pid = getpid();
  102     uint64_t id = 0;
  103     const size_t page_size = args->page_size;
  104 
  105     addrs = calloc(shm_posix_objects, sizeof(*addrs));
  106     if (!addrs) {
  107         pr_fail_err("calloc on addrs");
  108         return EXIT_NO_RESOURCE;
  109     }
  110     shm_names = calloc(shm_posix_objects, SHM_NAME_LEN);
  111     if (!shm_names) {
  112         free(addrs);
  113         pr_fail_err("calloc on shm_names");
  114         return EXIT_NO_RESOURCE;
  115     }
  116 
  117     /* Make sure this is killable by OOM killer */
  118     set_oom_adjustment(args->name, true);
  119 
  120     do {
  121         for (i = 0; ok && (i < (ssize_t)shm_posix_objects); i++) {
  122             int shm_fd, ret;
  123             void *addr;
  124             char *shm_name = &shm_names[i * SHM_NAME_LEN];
  125             struct stat statbuf;
  126 
  127             shm_name[0] = '\0';
  128 
  129             if (!g_keep_stressing_flag)
  130                 goto reap;
  131 
  132             (void)snprintf(shm_name, SHM_NAME_LEN,
  133                 "/stress-ng-%d-%" PRIx64 "-%" PRIx32,
  134                     (int)pid, id, mwc32());
  135 
  136             shm_fd = shm_open(shm_name, O_CREAT | O_RDWR | O_TRUNC,
  137                 S_IRUSR | S_IWUSR);
  138             if (shm_fd < 0) {
  139                 ok = false;
  140                 pr_fail_err("shm_open");
  141                 rc = EXIT_FAILURE;
  142                 goto reap;
  143             }
  144 
  145             /* Inform parent of the new shm name */
  146             msg.index = i;
  147             shm_name[SHM_NAME_LEN - 1] = '\0';
  148             (void)shim_strlcpy(msg.shm_name, shm_name, SHM_NAME_LEN);
  149             if (write(fd, &msg, sizeof(msg)) < 0) {
  150                 pr_err("%s: write failed: errno=%d: (%s)\n",
  151                     args->name, errno, strerror(errno));
  152                 rc = EXIT_FAILURE;
  153                 (void)close(shm_fd);
  154                 goto reap;
  155             }
  156 
  157             addr = mmap(NULL, sz, PROT_READ | PROT_WRITE,
  158                 MAP_PRIVATE | MAP_ANONYMOUS, shm_fd, 0);
  159             if (addr == MAP_FAILED) {
  160                 ok = false;
  161                 pr_fail_err("mmap");
  162                 rc = EXIT_FAILURE;
  163                 (void)close(shm_fd);
  164                 goto reap;
  165             }
  166             addrs[i] = addr;
  167 
  168             if (!g_keep_stressing_flag) {
  169                 (void)close(shm_fd);
  170                 goto reap;
  171             }
  172             (void)mincore_touch_pages(addr, sz);
  173 
  174             if (!g_keep_stressing_flag) {
  175                 (void)close(shm_fd);
  176                 goto reap;
  177             }
  178             (void)madvise_random(addr, sz);
  179             (void)shim_msync(addr, sz, mwc1() ? MS_ASYNC : MS_SYNC);
  180             (void)shim_fsync(shm_fd);
  181 
  182             /* Expand and shrink the mapping */
  183             (void)shim_fallocate(shm_fd, 0, 0, sz + page_size);
  184             (void)shim_fallocate(shm_fd, 0, 0, sz);
  185 
  186             /* Now truncated it back */
  187             ret = ftruncate(shm_fd, sz);
  188             if (ret < 0)
  189                 pr_fail("%s: ftruncate of shared memory failed\n", args->name);
  190             (void)shim_fsync(shm_fd);
  191 
  192             /* fstat shared memory */
  193             ret = fstat(shm_fd, &statbuf);
  194             if (ret < 0) {
  195                 pr_fail("%s: fstat failed on shared memory\n", args->name);
  196             } else {
  197                 if (statbuf.st_size != (off_t)sz) {
  198                     pr_fail("%s: fstat reports different size of shared memory, "
  199                         "got %jd bytes, expected %zd bytes\n", args->name,
  200                         (intmax_t)statbuf.st_size, sz);
  201                 }
  202             }
  203 
  204             /* Make it read only */
  205             ret = fchmod(shm_fd, S_IRUSR);
  206             if (ret < 0) {
  207                 pr_fail("%s: failed to fchmod to S_IRUSR on shared memory\n", args->name);
  208             }
  209 
  210             (void)close(shm_fd);
  211 
  212             if (!keep_stressing())
  213                 goto reap;
  214             if (stress_shm_posix_check(addr, sz, page_size) < 0) {
  215                 ok = false;
  216                 pr_fail("%s: memory check failed\n", args->name);
  217                 rc = EXIT_FAILURE;
  218                 goto reap;
  219             }
  220             id++;
  221             inc_counter(args);
  222         }
  223 reap:
  224         for (i = 0; ok && (i < (ssize_t)shm_posix_objects); i++) {
  225             char *shm_name = &shm_names[i * SHM_NAME_LEN];
  226 
  227             if (addrs[i])
  228                 (void)munmap(addrs[i], sz);
  229             if (*shm_name) {
  230                 if (shm_unlink(shm_name) < 0) {
  231                     pr_fail_err("shm_unlink");
  232                 }
  233             }
  234 
  235             /* Inform parent shm ID is now free */
  236             msg.index = i;
  237             msg.shm_name[SHM_NAME_LEN - 1] = '\0';
  238             (void)shim_strlcpy(msg.shm_name, shm_name, SHM_NAME_LEN - 1);
  239             if (write(fd, &msg, sizeof(msg)) < 0) {
  240                 pr_dbg("%s: write failed: errno=%d: (%s)\n",
  241                     args->name, errno, strerror(errno));
  242                 ok = false;
  243             }
  244             addrs[i] = NULL;
  245             *shm_name = '\0';
  246         }
  247     } while (ok && keep_stressing());
  248 
  249     /* Inform parent of end of run */
  250     msg.index = -1;
  251     (void)shim_strlcpy(msg.shm_name, "", SHM_NAME_LEN);
  252     if (write(fd, &msg, sizeof(msg)) < 0) {
  253         pr_err("%s: write failed: errno=%d: (%s)\n",
  254             args->name, errno, strerror(errno));
  255         rc = EXIT_FAILURE;
  256     }
  257     free(shm_names);
  258     free(addrs);
  259 
  260     return rc;
  261 }
  262 
  263 /*
  264  *  stress_shm()
  265  *  stress SYSTEM V shared memory
  266  */
  267 static int stress_shm(const args_t *args)
  268 {
  269     const size_t page_size = args->page_size;
  270     size_t orig_sz, sz;
  271     int pipefds[2];
  272     int rc = EXIT_SUCCESS;
  273     ssize_t i;
  274     pid_t pid;
  275     bool retry = true;
  276     uint32_t restarts = 0;
  277     size_t shm_posix_bytes = DEFAULT_SHM_POSIX_BYTES;
  278     size_t shm_posix_objects = DEFAULT_SHM_POSIX_OBJECTS;
  279 
  280     if (!get_setting("shm-bytes", &shm_posix_bytes)) {
  281         if (g_opt_flags & OPT_FLAGS_MAXIMIZE)
  282             shm_posix_bytes = MAX_SHM_POSIX_BYTES;
  283         if (g_opt_flags & OPT_FLAGS_MINIMIZE)
  284             shm_posix_bytes = MIN_SHM_POSIX_BYTES;
  285     }
  286     shm_posix_bytes /= args->num_instances;
  287     if (shm_posix_bytes < MIN_SHM_POSIX_BYTES)
  288         shm_posix_bytes = MIN_SHM_POSIX_BYTES;
  289     if (shm_posix_bytes < page_size)
  290         shm_posix_bytes = page_size;
  291 
  292     if (!get_setting("shm-objs", &shm_posix_objects)) {
  293         if (g_opt_flags & OPT_FLAGS_MAXIMIZE)
  294             shm_posix_objects = MAX_SHM_POSIX_OBJECTS;
  295         if (g_opt_flags & OPT_FLAGS_MINIMIZE)
  296             shm_posix_objects = MIN_SHM_POSIX_OBJECTS;
  297     }
  298     orig_sz = sz = shm_posix_bytes & ~(page_size - 1);
  299 
  300     while (g_keep_stressing_flag && retry) {
  301         if (pipe(pipefds) < 0) {
  302             pr_fail_dbg("pipe");
  303             return EXIT_FAILURE;
  304         }
  305 fork_again:
  306         pid = fork();
  307         if (pid < 0) {
  308             /* Can't fork, retry? */
  309             if (errno == EAGAIN)
  310                 goto fork_again;
  311             pr_err("%s: fork failed: errno=%d: (%s)\n",
  312                 args->name, errno, strerror(errno));
  313             (void)close(pipefds[0]);
  314             (void)close(pipefds[1]);
  315 
  316             /* Nope, give up! */
  317             return EXIT_FAILURE;
  318         } else if (pid > 0) {
  319             /* Parent */
  320             int status;
  321             char *shm_names;
  322 
  323             shm_names = calloc(shm_posix_objects, SHM_NAME_LEN);
  324             if (!shm_names) {
  325                 pr_fail_err("calloc on shm_names");
  326                 rc = EXIT_NO_RESOURCE;
  327                 goto err;
  328             }
  329             (void)setpgid(pid, g_pgrp);
  330             (void)close(pipefds[1]);
  331 
  332             while (g_keep_stressing_flag) {
  333                 ssize_t n;
  334                 shm_msg_t   msg;
  335                 char *shm_name;
  336 
  337                 /*
  338                  *  Blocking read on child shm ID info
  339                  *  pipe.  We break out if pipe breaks
  340                  *  on child death, or child tells us
  341                  *  about its demise.
  342                  */
  343                 memset(&msg, 0, sizeof(msg));
  344                 n = read(pipefds[0], &msg, sizeof(msg));
  345                 if (n <= 0) {
  346                     if ((errno == EAGAIN) || (errno == EINTR))
  347                         continue;
  348                     if (errno) {
  349                         pr_fail_dbg("read");
  350                         break;
  351                     }
  352                     pr_fail_dbg("zero byte read");
  353                     break;
  354                 }
  355                 if ((msg.index < 0) ||
  356                     (msg.index >= (ssize_t)shm_posix_objects)) {
  357                     retry = false;
  358                     break;
  359                 }
  360 
  361                 shm_name = &shm_names[msg.index * SHM_NAME_LEN];
  362                 shm_name[SHM_NAME_LEN - 1] = '\0';
  363                 (void)shim_strlcpy(shm_name, msg.shm_name, SHM_NAME_LEN - 1);
  364             }
  365             (void)kill(pid, SIGKILL);
  366             (void)waitpid(pid, &status, 0);
  367             if (WIFSIGNALED(status)) {
  368                 if ((WTERMSIG(status) == SIGKILL) ||
  369                     (WTERMSIG(status) == SIGKILL)) {
  370                     log_system_mem_info();
  371                     pr_dbg("%s: assuming killed by OOM killer, "
  372                         "restarting again (instance %d)\n",
  373                         args->name, args->instance);
  374                     restarts++;
  375                 }
  376             }
  377             (void)close(pipefds[1]);
  378 
  379             /*
  380              *  The child may have been killed by the OOM killer or
  381              *  some other way, so it may have left the shared
  382              *  memory segment around.  At this point the child
  383              *  has died, so we should be able to remove the
  384              *  shared memory segment.
  385              */
  386             for (i = 0; i < (ssize_t)shm_posix_objects; i++) {
  387                 char *shm_name = &shm_names[i * SHM_NAME_LEN];
  388                 if (*shm_name)
  389                     (void)shm_unlink(shm_name);
  390             }
  391             free(shm_names);
  392         } else if (pid == 0) {
  393             /* Child, stress memory */
  394             (void)setpgid(0, g_pgrp);
  395             stress_parent_died_alarm();
  396 
  397             (void)close(pipefds[0]);
  398             rc = stress_shm_posix_child(args, pipefds[1], sz, shm_posix_objects);
  399             (void)close(pipefds[1]);
  400             _exit(rc);
  401         }
  402     }
  403     if (orig_sz != sz)
  404         pr_dbg("%s: reduced shared memory size from "
  405             "%zu to %zu bytes\n", args->name, orig_sz, sz);
  406     if (restarts) {
  407         pr_dbg("%s: OOM restarts: %" PRIu32 "\n",
  408             args->name, restarts);
  409     }
  410 err:
  411     return rc;
  412 }
  413 
  414 stressor_info_t stress_shm_info = {
  415     .stressor = stress_shm,
  416     .class = CLASS_VM | CLASS_OS
  417 };
  418 #else
  419 stressor_info_t stress_shm_info = {
  420     .stressor = stress_not_implemented,
  421     .class = CLASS_VM | CLASS_OS
  422 };
  423 #endif