"Fossies" - the Fresh Open Source Software Archive

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

    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 RESOURCE_FORKS  (1024)
   28 #define MAX_LOOPS   (1024)
   29 
   30 typedef struct {
   31     void *m_malloc;
   32     void *m_sbrk;
   33     void *m_mmap;
   34     size_t m_mmap_size;
   35     int fd_pipe[2];
   36     int pipe_ret;
   37     int fd_open;
   38     int fd_sock;
   39     int fd_socketpair[2];
   40     pid_t pid;
   41 #if defined(HAVE_EVENTFD)
   42     int fd_ev;
   43 #endif
   44 #if defined(HAVE_MEMFD_CREATE)
   45     int fd_memfd;
   46 #endif
   47 #if defined(HAVE_USERFAULTFD)
   48     int fd_uf;
   49 #endif
   50 #if defined(O_TMPFILE)
   51     int fd_tmp;
   52 #endif
   53 #if defined(HAVE_LIB_PTHREAD)
   54     pthread_t pthread;
   55     int pthread_ret;
   56 #endif
   57 #if defined(HAVE_SYS_INOTIFY_H)
   58     int fd_inotify;
   59     int wd_inotify;
   60 #endif
   61 #if defined(HAVE_PTSNAME)
   62     int pty_master;
   63     int pty_slave;
   64 #endif
   65 #if defined(HAVE_LIB_RT) &&     \
   66     defined(HAVE_TIMER_CREATE) &&   \
   67     defined(HAVE_TIMER_DELETE) &&   \
   68     defined(SIGUNUSED)
   69     bool timerok;
   70     timer_t timerid;
   71 #endif
   72 #if defined(HAVE_LIB_PTHREAD) &&    \
   73     defined(HAVE_SEM_POSIX)
   74     bool semok;
   75     sem_t sem;
   76 #endif
   77 #if defined(HAVE_SEM_SYSV)
   78     int sem_id;
   79 #endif
   80 #if defined(HAVE_MQ_SYSV) &&        \
   81     defined(HAVE_SYS_IPC_H) &&      \
   82     defined(HAVE_SYS_MSG_H)
   83     int msgq_id;
   84 #endif
   85 #if defined(HAVE_LIB_RT) &&     \
   86     defined(HAVE_MQ_POSIX) &&       \
   87     defined(HAVE_MQUEUE_H)
   88     mqd_t mq;
   89     char mq_name[64];
   90 #endif
   91 #if defined(HAVE_PKEY_ALLOC) &&     \
   92     defined(HAVE_PKEY_FREE)
   93     int pkey;
   94 #endif
   95 } info_t;
   96 
   97 static pid_t pids[RESOURCE_FORKS];
   98 
   99 #if defined(HAVE_LIB_PTHREAD)
  100 /*
  101  *  stress_pthread_func()
  102  *  pthread that exits immediately
  103  */
  104 static void *stress_pthread_func(void *ctxt)
  105 {
  106     static void *nowt;
  107 
  108     (void)ctxt;
  109     (void)sleep(1);
  110     return &nowt;
  111 }
  112 #endif
  113 
  114 static void NORETURN waste_resources(
  115     const args_t *args,
  116     const size_t page_size,
  117     const size_t pipe_size,
  118     const size_t mem_slack)
  119 {
  120 #if defined(RLIMIT_MEMLOCK)
  121     struct rlimit rlim;
  122 #endif
  123     size_t mlock_size;
  124     size_t i, n;
  125     size_t shmall, freemem, totalmem, freeswap;
  126 #if defined(HAVE_MEMFD_CREATE) ||   \
  127     defined(O_TMPFILE)
  128     const pid_t pid = getpid();
  129 #endif
  130     static int domains[] = { AF_INET, AF_INET6 };
  131     static int types[] = { SOCK_STREAM, SOCK_DGRAM };
  132     info_t info[MAX_LOOPS];
  133 #if defined(O_NOATIME)
  134     const int flag = O_NOATIME;
  135 #else
  136     const int flag = 0;
  137 #endif
  138 
  139 #if defined(RLIMIT_MEMLOCK)
  140     {
  141         int ret;
  142 
  143         ret = getrlimit(RLIMIT_MEMLOCK, &rlim);
  144         if (ret < 0) {
  145             mlock_size = args->page_size * MAX_LOOPS;
  146         } else {
  147             mlock_size = rlim.rlim_cur;
  148         }
  149     }
  150 #else
  151     mlock_size = args->page_size * MAX_LOOPS;
  152 #endif
  153 
  154 #if !(defined(HAVE_LIB_RT) &&   \
  155       defined(HAVE_MQ_POSIX) && \
  156       defined(HAVE_MQUEUE_H))
  157     (void)args;
  158 #endif
  159     stress_get_memlimits(&shmall, &freemem, &totalmem, &freeswap);
  160 
  161     if ((shmall + freemem + totalmem > 0) &&
  162             (freemem > 0) && (freemem < mem_slack))
  163         _exit(0);
  164 
  165     (void)memset(&info, 0, sizeof(info));
  166 
  167     for (i = 0; g_keep_stressing_flag && (i < MAX_LOOPS); i++) {
  168 #if defined(HAVE_MEMFD_CREATE)
  169         char name[32];
  170 #endif
  171         stress_get_memlimits(&shmall, &freemem, &totalmem, &freeswap);
  172 
  173         if ((shmall + freemem + totalmem > 0) &&
  174                 (freemem > 0) && (freemem < mem_slack))
  175             break;
  176 
  177         if ((mwc8() & 0xf) == 0) {
  178             info[i].m_malloc = calloc(1, page_size);
  179             if (!g_keep_stressing_flag)
  180                 break;
  181         }
  182         if ((mwc8() & 0xf) == 0) {
  183             info[i].m_sbrk = shim_sbrk(page_size);
  184             if (!g_keep_stressing_flag)
  185                 break;
  186         }
  187         if ((mwc8() & 0xf) == 0) {
  188             info[i].m_mmap_size = page_size;
  189             info[i].m_mmap = mmap(NULL, info[i].m_mmap_size,
  190                 PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
  191             if (!g_keep_stressing_flag)
  192                 break;
  193             if (info[i].m_mmap != MAP_FAILED) {
  194                 size_t locked = STRESS_MINIMUM(mlock_size, info[i].m_mmap_size);
  195 
  196                 (void)madvise_random(info[i].m_mmap, info[i].m_mmap_size);
  197                 mincore_touch_pages(info[i].m_mmap, info[i].m_mmap_size);
  198                 if (locked > 0) {
  199                     shim_mlock(info[i].m_mmap, locked);
  200                     mlock_size -= locked;
  201                 }
  202             }
  203         }
  204 
  205         info[i].pipe_ret = pipe(info[i].fd_pipe);
  206 #if defined(F_SETPIPE_SZ)
  207         if (info[i].pipe_ret == 0) {
  208             (void)fcntl(info[i].fd_pipe[0], F_SETPIPE_SZ, pipe_size);
  209             (void)fcntl(info[i].fd_pipe[1], F_SETPIPE_SZ, pipe_size);
  210         }
  211 #else
  212         (void)pipe_size;
  213 #endif
  214         if (!g_keep_stressing_flag)
  215             break;
  216         info[i].fd_open = open("/dev/null", O_RDONLY | flag);
  217         if (!g_keep_stressing_flag)
  218             break;
  219 #if defined(HAVE_EVENTFD)
  220         info[i].fd_ev = eventfd(0, 0);
  221         if (!g_keep_stressing_flag)
  222             break;
  223 #endif
  224 #if defined(HAVE_MEMFD_CREATE)
  225         (void)snprintf(name, sizeof(name), "memfd-%u-%zu", pid, i);
  226         info[i].fd_memfd = shim_memfd_create(name, 0);
  227         if (!g_keep_stressing_flag)
  228             break;
  229 #endif
  230         info[i].fd_sock = socket(
  231             domains[mwc32() % SIZEOF_ARRAY(domains)],
  232             types[mwc32() % SIZEOF_ARRAY(types)], 0);
  233         if (!g_keep_stressing_flag)
  234             break;
  235 
  236         if (socketpair(AF_UNIX, SOCK_STREAM, 0,
  237             info[i].fd_socketpair) < 0) {
  238             info[i].fd_socketpair[0] = -1;
  239             info[i].fd_socketpair[1] = -1;
  240         }
  241 
  242 #if defined(HAVE_USERFAULTFD)
  243         info[i].fd_uf = shim_userfaultfd(0);
  244         if (!g_keep_stressing_flag)
  245             break;
  246 #endif
  247 #if defined(O_TMPFILE)
  248         info[i].fd_tmp = open("/tmp", O_TMPFILE | O_RDWR | flag,
  249                       S_IRUSR | S_IWUSR);
  250         if (!g_keep_stressing_flag)
  251             break;
  252         if (info[i].fd_tmp != -1) {
  253             size_t sz = page_size * mwc32();
  254 
  255             (void)shim_fallocate(info[i].fd_tmp, 0, 0, sz);
  256 #if defined(F_GETLK) &&     \
  257     defined(F_SETLK) &&     \
  258     defined(F_SETLKW) &&    \
  259     defined(F_WRLCK) &&     \
  260     defined(F_UNLCK)
  261             {
  262                 struct flock f;
  263 
  264                 f.l_type = F_WRLCK;
  265                 f.l_whence = SEEK_SET;
  266                 f.l_start = 0;
  267                 f.l_len = sz;
  268                 f.l_pid = pid;
  269 
  270                 (void)fcntl(info[i].fd_tmp, F_SETLK, &f);
  271             }
  272         }
  273 #endif
  274 #endif
  275 #if defined(HAVE_SYS_INOTIFY_H)
  276         info[i].fd_inotify = inotify_init();
  277         if (info[i].fd_inotify > -1) {
  278             info[i].wd_inotify = inotify_add_watch(
  279                 info[i].fd_inotify, ".",
  280                 0
  281 #if defined(IN_ACCESS)
  282                 | IN_ACCESS
  283 #endif
  284 #if defined(IN_MODIFY)
  285                 | IN_MODIFY
  286 #endif
  287 #if defined(IN_ATTRIB)
  288                 | IN_ATTRIB
  289 #endif
  290 #if defined(IN_CLOSE_WRITE)
  291                 | IN_CLOSE_WRITE
  292 #endif
  293 #if defined(IN_OPEN)
  294                 | IN_OPEN
  295 #endif
  296 #if defined(IN_MOVED_FROM)
  297                 | IN_MOVED_FROM
  298 #endif
  299 #if defined(IN_MOVED_TO)
  300                 | IN_MOVED_TO
  301 #endif
  302 #if defined(IN_CREATE)
  303                 | IN_CREATE
  304 #endif
  305 #if defined(IN_DELETE)
  306                 | IN_DELETE
  307 #endif
  308 #if defined(IN_DELETE_SELF)
  309                 | IN_DELETE_SELF
  310 #endif
  311 #if defined(IN_MOVE_SELF)
  312                 | IN_MOVE_SELF
  313 #endif
  314                 );
  315         } else {
  316             info[i].fd_inotify = -1;
  317             info[i].wd_inotify = -1;
  318         }
  319 #endif
  320 #if defined(HAVE_PTSNAME)
  321         {
  322             info[i].pty_master = open("/dev/ptmx", O_RDWR | flag);
  323             info[i].pty_slave = -1;
  324             if (info[i].pty_master >= 0) {
  325                 const char *slavename = ptsname(info[i].pty_master);
  326 
  327                 if (slavename)
  328                     info[i].pty_slave = open(slavename, O_RDWR | flag);
  329             }
  330         }
  331 #endif
  332 
  333 #if defined(HAVE_LIB_PTHREAD)
  334         if (!i)
  335             info[i].pthread_ret =
  336                 pthread_create(&info[i].pthread, NULL,
  337                     stress_pthread_func, NULL);
  338 #endif
  339 
  340 #if defined(HAVE_LIB_RT) &&     \
  341     defined(HAVE_TIMER_CREATE) &&   \
  342     defined(HAVE_TIMER_DELETE) &&   \
  343     defined(SIGUNUSED)
  344         if (!i) {
  345             struct sigevent sevp;
  346 
  347             sevp.sigev_notify = SIGEV_NONE;
  348             sevp.sigev_signo = SIGUNUSED;
  349             sevp.sigev_value.sival_ptr = &info[i].timerid;
  350             info[i].timerok =
  351                 (timer_create(CLOCK_REALTIME, &sevp, &info[i].timerid) == 0);
  352         }
  353 #endif
  354 
  355 #if defined(HAVE_LIB_PTHREAD) &&    \
  356     defined(HAVE_SEM_POSIX)
  357         info[i].semok = (sem_init(&info[i].sem, 1, 1) >= 0);
  358 #endif
  359 
  360 #if defined(HAVE_SEM_SYSV)
  361         key_t sem_key = (key_t)mwc32();
  362         info[i].sem_id = semget(sem_key, 1,
  363             IPC_CREAT | S_IRUSR | S_IWUSR);
  364 #endif
  365 
  366 #if defined(HAVE_MQ_SYSV) &&    \
  367     defined(HAVE_SYS_IPC_H) &&  \
  368     defined(HAVE_SYS_MSG_H)
  369         info[i].msgq_id = msgget(IPC_PRIVATE,
  370                 S_IRUSR | S_IWUSR | IPC_CREAT | IPC_EXCL);
  371 #endif
  372 
  373 #if defined(HAVE_LIB_RT) && \
  374     defined(HAVE_MQ_POSIX) &&   \
  375     defined(HAVE_MQUEUE_H)
  376         struct mq_attr attr;
  377 
  378         (void)snprintf(info[i].mq_name, sizeof(info[i].mq_name),
  379             "/%s-%i-%" PRIu32 "-%zu",
  380             args->name, getpid(), args->instance, i);
  381         attr.mq_flags = 0;
  382         attr.mq_maxmsg = 1;
  383         attr.mq_msgsize = 32;
  384         attr.mq_curmsgs = 0;
  385 
  386         info[i].mq = mq_open(info[i].mq_name,
  387             O_CREAT | O_RDWR | flag, S_IRUSR | S_IWUSR, &attr);
  388 #endif
  389 #if defined(HAVE_PKEY_ALLOC) && \
  390     defined(HAVE_PKEY_FREE)
  391         info[i].pkey = shim_pkey_alloc(0, 0);
  392 #endif
  393 
  394         info[i].pid = fork();
  395         if (info[i].pid == 0) {
  396             sleep(10);
  397             _exit(0);
  398         }
  399     }
  400 
  401     n = i;
  402     for (i = 0; i < n; i++) {
  403         if (info[i].m_malloc)
  404             free(info[i].m_malloc);
  405         if (info[i].m_mmap && (info[i].m_mmap != MAP_FAILED)) {
  406             (void)shim_munlock(info[i].m_mmap, info[i].m_mmap_size);
  407             (void)munmap(info[i].m_mmap, info[i].m_mmap_size);
  408         }
  409         if (info[i].pipe_ret != -1) {
  410             (void)close(info[i].fd_pipe[0]);
  411             (void)close(info[i].fd_pipe[1]);
  412         }
  413         if (info[i].fd_open != -1)
  414             (void)close(info[i].fd_open);
  415 #if defined(HAVE_EVENTFD)
  416         if (info[i].fd_ev != -1)
  417             (void)close(info[i].fd_ev);
  418 #endif
  419 #if defined(HAVE_MEMFD_CREATE)
  420         if (info[i].fd_memfd != -1)
  421             (void)close(info[i].fd_memfd);
  422 #endif
  423         if (info[i].fd_sock != -1)
  424             (void)close(info[i].fd_sock);
  425         if (info[i].fd_socketpair[0] != -1)
  426             (void)close(info[i].fd_socketpair[0]);
  427         if (info[i].fd_socketpair[1] != -1)
  428             (void)close(info[i].fd_socketpair[1]);
  429 
  430 #if defined(HAVE_USERFAULTFD)
  431         if (info[i].fd_uf != -1)
  432             (void)close(info[i].fd_uf);
  433 #endif
  434 
  435 #if defined(O_TMPFILE)
  436         if (info[i].fd_tmp != -1)
  437             (void)close(info[i].fd_tmp);
  438 #endif
  439 
  440 #if defined(HAVE_LIB_PTHREAD)
  441         if ((!i) && (!info[i].pthread_ret))
  442             (void)pthread_join(info[i].pthread, NULL);
  443 #endif
  444 
  445 #if defined(HAVE_LIB_RT) &&     \
  446     defined(HAVE_TIMER_CREATE) &&   \
  447     defined(HAVE_TIMER_DELETE) &&   \
  448     defined(SIGUNUSED)
  449         if ((!i) && (info[i].timerok)) {
  450             (void)timer_delete(info[i].timerid);
  451         }
  452 #endif
  453 
  454 #if defined(HAVE_SYS_INOTIFY)
  455         if (info[i].wd_inotify != -1)
  456             (void)inotify_rm_watch(info[i].fd_inotify, info[i].wd_inotify);
  457         if (info[i].fd_inotify != -1)
  458             (void)close(info[i].fd_inotify);
  459 #endif
  460 
  461 #if defined(HAVE_PTSNAME)
  462         if (info[i].pty_slave != -1)
  463             (void)close(info[i].pty_slave);
  464         if (info[i].pty_master != -1)
  465             (void)close(info[i].pty_master);
  466 #endif
  467 
  468 #if defined(HAVE_LIB_PTHREAD) &&    \
  469     defined(HAVE_SEM_POSIX)
  470         if (info[i].semok)
  471             (void)sem_destroy(&info[i].sem);
  472 #endif
  473 
  474 #if defined(HAVE_SEM_SYSV)
  475         if (info[i].sem_id >= 0)
  476             (void)semctl(info[i].sem_id, 0, IPC_RMID);
  477 #endif
  478 
  479 #if defined(HAVE_MQ_SYSV) && defined(HAVE_SYS_IPC_H) && defined(HAVE_SYS_MSG_H)
  480         if (info[i].msgq_id >= 0)
  481             (void)msgctl(info[i].msgq_id, IPC_RMID, NULL);
  482 #endif
  483 
  484 #if defined(HAVE_LIB_RT) && \
  485     defined(HAVE_MQ_POSIX) &&   \
  486     defined(HAVE_MQUEUE_H)
  487         if (info[i].mq >= 0) {
  488             (void)mq_close(info[i].mq);
  489             (void)mq_unlink(info[i].mq_name);
  490         }
  491 #endif
  492 #if defined(HAVE_PKEY_ALLOC) && \
  493     defined(HAVE_PKEY_FREE)
  494         if (info[i].pkey > -1)
  495              (void)shim_pkey_free(info[i].pkey);
  496 #endif
  497         if (info[i].pid > 0) {
  498             int status;
  499 
  500             (void)kill(info[i].pid, SIGKILL);
  501             (void)waitpid(info[i].pid, &status, 0);
  502         }
  503     }
  504     _exit(0);
  505 }
  506 
  507 static void MLOCKED_TEXT kill_children(const size_t resource_forks)
  508 {
  509     size_t i;
  510 
  511     for (i = 0; i < resource_forks; i++) {
  512         if (pids[i] > 0)
  513             (void)kill(pids[i], SIGALRM);
  514     }
  515 
  516     for (i = 0; i < resource_forks; i++) {
  517         if (pids[i] > 0) {
  518             int status;
  519 
  520             (void)waitpid(pids[i], &status, 0);
  521         }
  522     }
  523 }
  524 
  525 /*
  526  *  stress_resources()
  527  *  stress by forking and exiting
  528  */
  529 static int stress_resources(const args_t *args)
  530 {
  531     const size_t page_size = args->page_size;
  532     const size_t pipe_size = stress_probe_max_pipe_size();
  533     size_t mem_slack;
  534     size_t shmall, freemem, totalmem, freeswap, resource_forks = 0;
  535 
  536     stress_get_memlimits(&shmall, &freemem, &totalmem, &freeswap);
  537     if (totalmem > 0) {
  538         resource_forks = totalmem / (args->num_instances * MAX_LOOPS * 16 * KB);
  539     }
  540     if (resource_forks < 1)
  541         resource_forks = 1;
  542     if (resource_forks > RESOURCE_FORKS)
  543         resource_forks = RESOURCE_FORKS;
  544     mem_slack = (args->num_instances * resource_forks * MB);
  545 
  546     do {
  547         unsigned int i;
  548 
  549         (void)memset(pids, 0, sizeof(pids));
  550         for (i = 0; i < resource_forks; i++) {
  551             pid_t pid;
  552 
  553             stress_get_memlimits(&shmall, &freemem, &totalmem, &freeswap);
  554             if (totalmem > 0 && totalmem < mem_slack)
  555                 break;
  556 
  557             pid = fork();
  558             if (pid == 0) {
  559                 int ret;
  560 
  561                 (void)setpgid(0, g_pgrp);
  562                 set_oom_adjustment(args->name, true);
  563                 ret = stress_drop_capabilities(args->name);
  564                 (void)ret;
  565 
  566                 waste_resources(args, page_size, pipe_size, mem_slack);
  567                 _exit(0); /* should never get here */
  568             }
  569 
  570             if (pid > -1)
  571                 (void)setpgid(pids[i], g_pgrp);
  572             pids[i] = pid;
  573 
  574             if (!keep_stressing()) {
  575                 kill_children(resource_forks);
  576                 return EXIT_SUCCESS;
  577             }
  578             inc_counter(args);
  579         }
  580         kill_children(resource_forks);
  581     } while (keep_stressing());
  582 
  583     return EXIT_SUCCESS;
  584 }
  585 
  586 stressor_info_t stress_resources_info = {
  587     .stressor = stress_resources,
  588     .class = CLASS_MEMORY | CLASS_OS
  589 };