"Fossies" - the Fresh Open Source Software Archive

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

    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(HAVE_SWAPCONTEXT) &&    \
   28     defined(HAVE_UCONTEXT_H)
   29 
   30 #define MMAPSTACK_SIZE      (256 * KB)
   31 
   32 static ucontext_t c_main, c_test;
   33 static void *stack_mmap;            /* mmap'd stack */
   34 static uintptr_t page_mask;
   35 static size_t page_size;
   36 
   37 /*
   38  *  Just terminate the child when SEGV occurs on the
   39  *  mmap'd stack.
   40  */
   41 static void MLOCKED_TEXT stress_segvhandler(int signum)
   42 {
   43     (void)signum;
   44 
   45     _exit(0);
   46 }
   47 
   48 /*
   49  *  push values onto file backed mmap'd stack and
   50  *  force msync on the map'd region if page boundary
   51  *  has changed
   52  */
   53 static void stress_stackmmap_push_msync(void)
   54 {
   55     void *addr = (void *)(((uintptr_t)&addr) & page_mask);
   56     static void *laddr;
   57     char waste[64];
   58 
   59     waste[0] = 0;
   60     waste[sizeof(waste) - 1] = 0;
   61 
   62     if (addr != laddr) {
   63         (void)shim_msync(addr, page_size,
   64             (mwc8() & 1) ? MS_ASYNC : MS_SYNC);
   65         laddr = addr;
   66     }
   67     if (g_keep_stressing_flag)
   68         stress_stackmmap_push_msync();
   69 }
   70 
   71 /*
   72  *  start the push here
   73  */
   74 static void stress_stackmmap_push_start(void)
   75 {
   76     /* stack for SEGV handler must not be on the stack */
   77     static uint8_t stack_sig[SIGSTKSZ + STACK_ALIGNMENT];
   78     struct sigaction new_action;
   79 
   80     /*
   81      *  We need to handle SEGV signals when we
   82      *  hit the end of the mmap'd stack; however
   83      *  an alternative signal handling stack
   84      *  is required because we ran out of stack
   85      */
   86     (void)memset(&new_action, 0, sizeof new_action);
   87     new_action.sa_handler = stress_segvhandler;
   88     (void)sigemptyset(&new_action.sa_mask);
   89     new_action.sa_flags = SA_ONSTACK;
   90     if (sigaction(SIGSEGV, &new_action, NULL) < 0)
   91         return;
   92 
   93     /*
   94      *  We need an alternative signal stack
   95      *  to handle segfaults on an overrun
   96      *  mmap'd stack
   97      */
   98     (void)memset(stack_sig, 0, sizeof(stack_sig));
   99     if (stress_sigaltstack(stack_sig, SIGSTKSZ) < 0)
  100         return;
  101 
  102     stress_stackmmap_push_msync();
  103 }
  104 
  105 /*
  106  *  stress_stackmmap
  107  *  stress a file memory map'd stack
  108  */
  109 static int stress_stackmmap(const args_t *args)
  110 {
  111     int fd;
  112     volatile int rc = EXIT_FAILURE;     /* could be clobbered */
  113     char filename[PATH_MAX];
  114 
  115     page_size = args->page_size;
  116     page_mask = ~(page_size - 1);
  117 
  118     /* Create file back'd mmaping for the stack */
  119     if (stress_temp_dir_mk_args(args) < 0)
  120         return EXIT_FAILURE;
  121     (void)stress_temp_filename_args(args,
  122         filename, sizeof(filename), mwc32());
  123 
  124     fd = open(filename, O_SYNC | O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
  125     if (fd < 0) {
  126         pr_fail_err("mmap'd stack file open");
  127         goto tidy_dir;
  128     }
  129     (void)unlink(filename);
  130     if (ftruncate(fd, MMAPSTACK_SIZE) < 0) {
  131         pr_fail_err("ftruncate");
  132         (void)close(fd);
  133         goto tidy_dir;
  134     }
  135     stack_mmap = mmap(NULL, MMAPSTACK_SIZE, PROT_READ | PROT_WRITE,
  136         MAP_SHARED, fd, 0);
  137     if (stack_mmap == MAP_FAILED) {
  138         if (errno == ENXIO) {
  139             pr_inf("%s: skipping stressor, mmap not possible on file %s\n",
  140                 args->name, filename);
  141             rc = EXIT_NO_RESOURCE;
  142             (void)close(fd);
  143             goto tidy_dir;
  144         }
  145         pr_fail_err("mmap");
  146         (void)close(fd);
  147         goto tidy_dir;
  148     }
  149     (void)close(fd);
  150 
  151     if (shim_madvise(stack_mmap, MMAPSTACK_SIZE, MADV_RANDOM) < 0) {
  152         pr_dbg("%s: madvise failed: errno=%d (%s)\n",
  153             args->name, errno, strerror(errno));
  154     }
  155     (void)memset(stack_mmap, 0, MMAPSTACK_SIZE);
  156     (void)memset(&c_test, 0, sizeof(c_test));
  157     if (getcontext(&c_test) < 0) {
  158         pr_fail_err("getcontext");
  159         goto tidy_mmap;
  160     }
  161     c_test.uc_stack.ss_sp = stack_mmap;
  162     c_test.uc_stack.ss_size = MMAPSTACK_SIZE;
  163     c_test.uc_link = &c_main;
  164 
  165     /*
  166      *  set jmp handler to jmp back into the loop on a full
  167      *  stack segfault.  Use swapcontext to jump into a
  168      *  new context using the new mmap'd stack
  169      */
  170     do {
  171         pid_t pid;
  172 again:
  173         if (!g_keep_stressing_flag)
  174             break;
  175         pid = fork();
  176         if (pid < 0) {
  177             if ((errno == EAGAIN) || (errno == ENOMEM))
  178                 goto again;
  179             pr_err("%s: fork failed: errno=%d (%s)\n",
  180                 args->name, errno, strerror(errno));
  181         } else if (pid > 0) {
  182             int status, waitret;
  183 
  184             /* Parent, wait for child */
  185             (void)setpgid(pid, g_pgrp);
  186             waitret = waitpid(pid, &status, 0);
  187             if (waitret < 0) {
  188                 if (errno != EINTR)
  189                     pr_dbg("%s: waitpid(): errno=%d (%s)\n",
  190                         args->name, errno, strerror(errno));
  191                 (void)kill(pid, SIGTERM);
  192                 (void)kill(pid, SIGKILL);
  193                 (void)waitpid(pid, &status, 0);
  194             }
  195         } else if (pid == 0) {
  196             /* Child */
  197 
  198             (void)setpgid(0, g_pgrp);
  199             stress_parent_died_alarm();
  200 
  201             /* Make sure this is killable by OOM killer */
  202             set_oom_adjustment(args->name, true);
  203 
  204             (void)makecontext(&c_test, stress_stackmmap_push_start, 0);
  205             (void)swapcontext(&c_main, &c_test);
  206 
  207             _exit(0);
  208         }
  209         inc_counter(args);
  210     } while (keep_stressing());
  211 
  212     rc = EXIT_SUCCESS;
  213 
  214 tidy_mmap:
  215     (void)munmap(stack_mmap, MMAPSTACK_SIZE);
  216 tidy_dir:
  217     (void)stress_temp_dir_rm_args(args);
  218     return rc;
  219 }
  220 
  221 stressor_info_t stress_stackmmap_info = {
  222     .stressor = stress_stackmmap,
  223     .class = CLASS_VM | CLASS_MEMORY
  224 };
  225 #else
  226 stressor_info_t stress_stackmmap_info = {
  227     .stressor = stress_not_implemented,
  228     .class = CLASS_VM | CLASS_MEMORY
  229 };
  230 #endif