1

Тема: [C, UNIX, Сигналы] Sloth - утилита для замедления выполнения процесса

Sloth приостанавливает выполненеие заданного процесса каждые N миллисекунд с помощью SIGSTOP, и через 10*N миллисекунд возобновляет его работу с помощью SIGCONT. Может пригодится, например, если у вас на сервере по расписанию распаковываются большие архивы и tar при этом создает слишком большую нагрузку. В этом случае renice скорее всего окажется бесполезным, а вот sloth - то, что надо. Утилита может как самостоятельно запускать процесс, так и контролировать уже запущенный процесс по его ID.

/*
 *  sloth v1.1.0
 *  Copyright (C) 2002  Nick Jennings nick___at____namodn.com
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; version 2 of the License. 
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 *  This program is developed and maintained by Nick Jennings.
 * Contact Information:
 *
 * $Id: sloth.c,v 1.9 2002/02/10 08:58:20 nick Exp $
 *
 */

#include <stdio.h>
#include <wait.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/time.h>

// Constants
#define VERSION "1.1.0"
#define DEFAULT_SPEED 0
#define POS_SPEED 1
#define POS_PROG 2
#define TOTAL_ARGS 3

// Prototypes
void usage();

/*****************************************************************************
 * int main(int argc, char *argv[]);
 *
 * sloth <0-99999> <progname>
 *
 */
int main(int argc, char *argv[]) {
    pid_t pid;
    int exit_code = 0;
    int i = 0;
    int spawn = 0;
    int status = 0;
    long dspeed = DEFAULT_SPEED;  // delay speed
    long wspeed = DEFAULT_SPEED; // wait speed
    struct timeval timeout;

    if (argc < TOTAL_ARGS) {
        usage();
        exit_code = 1;
    } else if ((long)atoi(argv[POS_SPEED]) < 0) {
        usage();
        exit_code = 1;
    } else {
        // get wait between delays
        wspeed = (long)atoi(argv[POS_SPEED]); 
    }

    // calc delay
    dspeed = wspeed * 10;

    // determin process management behavior
    while (*(argv[POS_PROG]+i) != '\0' && (!spawn)) {
        if ( *(argv[POS_PROG]+i) >= 48 &&
             *(argv[POS_PROG]+i) <= 57 ) {
            // character is a number
            spawn = 0;
        } else {
            spawn = 1;
        }
        i++;
    }
    
    if (!exit_code) {
        if (spawn) {
            // control spawned process
            pid = fork();
            if (pid != 0) {
                while(!waitpid(pid, &status, WNOHANG)) {
                    // wait
                    timeout.tv_sec = 0;
                    timeout.tv_usec = wspeed;
                    select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &timeout);
                    // stop
                    kill(pid, SIGSTOP);
                    // delay
                    timeout.tv_sec = 0;
                    timeout.tv_usec = dspeed;
                    select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &timeout);
                    // continue
                    kill(pid, SIGCONT);
                }
            }
            else {
                // child execution begins 
                execvp(argv[POS_PROG], &argv[POS_PROG]);
                return(0);
            }
        } else {
            // control existing process
            pid = (pid_t)atoi(argv[POS_PROG]);
            while(!exit_code) {
                // wait
                timeout.tv_sec = 0;
                timeout.tv_usec = wspeed;
                select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &timeout);
                // stop
                if (0 > kill(pid, SIGSTOP)) {
                    printf("sloth: failed sending signal to PID '%d'. No permission or PID does not exist.\n", pid);
                    exit_code = 2;
                } else {
                    // delay
                    timeout.tv_sec = 0;
                    timeout.tv_usec = dspeed;
                    select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &timeout);
                    // continue
                    if (0 > kill(pid, SIGCONT)) {
                        printf("sloth: failed sending signal to PID '%d'. No permission or PID does not exist.\n", pid);
                        exit_code = 2;
                    }
                }
            }
        }
    }
    exit(exit_code);
}


/*****************************************************************************
 * void usage();
 *
 * displays usage text
 *
 */
void usage() {
    printf("sloth version %s\n", VERSION);
    printf("usage: sloth <0-99999> <progname>\n");
}

Архив можно скачать отсюда: http://www.sourcefiles.org/Utilities/Mi … 1.0.tar.gz

2

Re: [C, UNIX, Сигналы] Sloth - утилита для замедления выполнения процесса

Имхо логичней выглядит работа сpulimit - те же сигналы, но отправляются не по таймеру, а по превышению заданного лимита использования приложением CPU. Если он в допустимых пределах скушал - зачем его дергать постоянно? Есть и под линуху, и под фряху, аналогично обрабатывает как вновь запускаемые, так и уже работающие приложения (по PID). Ну а вообще под линуху cgroups самое то для умных ограничений.