Spec-Zone.ru › Ruby 2.2

модуль Process

Константы

CLOCK_BOOTTIME
CLOCK_BOOTTIME_ALARM
CLOCK_MONOTONIC
CLOCK_MONOTONIC_COARSE
CLOCK_MONOTONIC_FAST
CLOCK_MONOTONIC_PRECISE
CLOCK_MONOTONIC_RAW
CLOCK_PROCESS_CPUTIME_ID
CLOCK_PROF
CLOCK_REALTIME
CLOCK_REALTIME_ALARM
CLOCK_REALTIME_COARSE
CLOCK_REALTIME_FAST
CLOCK_REALTIME_PRECISE
CLOCK_SECOND
CLOCK_THREAD_CPUTIME_ID
CLOCK_UPTIME
CLOCK_UPTIME_FAST
CLOCK_UPTIME_PRECISE
CLOCK_VIRTUAL
PRIO_PGRP

см. ::setpriority

PRIO_PROCESS

см. ::setpriority

PRIO_USER

см. ::setpriority

RLIMIT_AS

Максимальный размер виртуальной памяти (адресного пространства) процесса в байтах.

см. системную справку getrlimit(2) для подробностей.

RLIMIT_CORE

Максимальный размер файла ядра.

см. системную справку getrlimit(2) для подробностей.

RLIMIT_CPU

Предел времени процессора в секундах.

см. системную справку getrlimit(2) для подробностей.

RLIMIT_DATA

Максимальный размер сегмента данных процесса.

см. системную справку getrlimit(2) для подробностей.

RLIMIT_FSIZE

Максимальный размер файлов, которые может создать процесс.

см. системную справку getrlimit(2) для подробностей.

RLIMIT_MEMLOCK

Максимальное количество байтов памяти, которые могут быть заблокированы в оперативной памяти.

см. системную справку getrlimit(2) для подробностей.

RLIMIT_MSGQUEUE

Определяет ограничение на количество байтов, которые могут быть выделены для очередей сообщений POSIX для реального идентификатора пользователя вызывающего процесса.

см. системную справку getrlimit(2) для подробностей.

RLIMIT_NICE

Устанавливает потолок, до которого можно повысить значение nice процесса.

см. системную справку getrlimit(2) для подробностей.

RLIMIT_NOFILE

Указывает значение, на единицу большее, чем максимальное число дескрипторов файлов, которое может открыть этот процесс.

см. системную справку getrlimit(2) для подробностей.

RLIMIT_NPROC

Максимальное количество процессов, которые могут быть созданы для реального идентификатора пользователя вызывающего процесса.

см. системную справку getrlimit(2) для подробностей.

RLIMIT_RSS

Устанавливает ограничение (в страницах) резидентного набора процесса.

см. системную справку getrlimit(2) для подробностей.

RLIMIT_RTPRIO

Указывает потолок для реального приоритета, который может быть установлен для данного процесса.

см. системную справку getrlimit(2) для подробностей.

RLIMIT_RTTIME

Устанавливает ограничение на время процессора, которое может потреблять этот процесс, запланированный под политикой планирования в реальном времени.

см. системную справку getrlimit(2) для подробностей.

RLIMIT_SBSIZE

Максимальный размер буфера сокета.

RLIMIT_SIGPENDING

Устанавливает ограничение на количество сигналов, которые могут быть помещены в очередь для реального идентификатора пользователя вызывающего процесса.

см. системную справку getrlimit(2) для подробностей.

RLIMIT_STACK

Максимальный размер стека в байтах.

см. системную справку getrlimit(2) для подробностей.

RLIM_INFINITY

см. ::setrlimit

RLIM_SAVED_CUR

см. ::setrlimit

RLIM_SAVED_MAX

см. ::setrlimit

WNOHANG

см. ::wait

WUNTRACED

см. ::wait

Методы публичного класса

abort Показать исходный код
Kernel::abort([msg])
Process::abort([msg])
VALUE
rb_f_abort(int argc, const VALUE *argv)
{
    rb_check_arity(argc, 0, 1);
    if (argc == 0) {
        if (!NIL_P(GET_THREAD()->errinfo)) {
            ruby_error_print();
        }
        rb_exit(EXIT_FAILURE);
    }
    else {
        VALUE args[2];

        args[1] = args[0] = argv[0];
        StringValue(args[0]);
        rb_io_puts(1, args, rb_stderr);
        args[0] = INT2NUM(EXIT_FAILURE);
        rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemExit));
    }

    UNREACHABLE;
}

Немедленно завершить выполнение, фактически вызвав Kernel.exit(false). Если msg задан, он выводится в STDERR перед завершением.

argv0 → frozen_string Показать исходный код
static VALUE
proc_argv0(VALUE process)
{
    return rb_orig_progname;
}

Возвращает имя выполняемого скрипта. Значение не изменяется при присваивании нового значения переменной $0.

Этот метод впервые появился в Ruby 2.1, чтобы предоставить глобально доступный способ получения имени скрипта.

clock_getres(clock_id [, unit]) → number Показать исходный код
VALUE
rb_clock_getres(int argc, VALUE *argv)
{
    VALUE clk_id, unit;

    struct timetick tt;
    timetick_int_t numerators[2];
    timetick_int_t denominators[2];
    int num_numerators = 0;
    int num_denominators = 0;

    rb_scan_args(argc, argv, "11", &clk_id, &unit);

    if (SYMBOL_P(clk_id)) {
#ifdef RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
        if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
            tt.giga_count = 0;
            tt.count = 1000;
            denominators[num_denominators++] = 1000000000;
            goto success;
        }
#endif

#ifdef RUBY_TIME_BASED_CLOCK_REALTIME
        if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
            tt.giga_count = 1;
            tt.count = 0;
            denominators[num_denominators++] = 1000000000;
            goto success;
        }
#endif

#ifdef RUBY_TIMES_BASED_CLOCK_MONOTONIC
        if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
            tt.count = 1;
            tt.giga_count = 0;
            denominators[num_denominators++] = get_clk_tck();
            goto success;
        }
#endif

#ifdef RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
        if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
            tt.giga_count = 0;
            tt.count = 1000;
            denominators[num_denominators++] = 1000000000;
            goto success;
        }
#endif

#ifdef RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
        if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
            tt.count = 1;
            tt.giga_count = 0;
            denominators[num_denominators++] = get_clk_tck();
            goto success;
        }
#endif

#ifdef RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
        if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) {
            tt.count = 1;
            tt.giga_count = 0;
            denominators[num_denominators++] = CLOCKS_PER_SEC;
            goto success;
        }
#endif

#ifdef RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
        if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
            mach_timebase_info_data_t *info = get_mach_timebase_info();
            tt.count = 1;
            tt.giga_count = 0;
            numerators[num_numerators++] = info->numer;
            denominators[num_denominators++] = info->denom;
            denominators[num_denominators++] = 1000000000;
            goto success;
        }
#endif
    }
    else {
#if defined(HAVE_CLOCK_GETRES)
        struct timespec ts;
        clockid_t c = NUM2CLOCKID(clk_id);
        int ret = clock_getres(c, &ts);
        if (ret == -1)
            rb_sys_fail("clock_getres");
        tt.count = (int32_t)ts.tv_nsec;
        tt.giga_count = ts.tv_sec;
        denominators[num_denominators++] = 1000000000;
        goto success;
#endif
    }
    /* EINVAL emulates clock_getres behavior when clock_id is invalid. */
    errno = EINVAL;
    rb_sys_fail(0);

  success:
    if (unit == ID2SYM(id_hertz)) {
        return timetick2dblnum_reciprocal(&tt, numerators, num_numerators, denominators, num_denominators);
    }
    else {
        return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
    }
}

Возвращает разрешение времени, возвращаемое функцией POSIX ::clock_getres().

clock_id указывает вид таймера. Подробности см. в документации Process.clock_gettime.

clock_id может быть символом, как Process.clock_gettime. Однако результат может быть неточным. Например, +Process.clock_getres(:GETTIMEOFDAY_BASED_CLOCK_REALTIME)+ возвращает 1.0e-06, что означает 1 микросекунду, но фактическое разрешение может быть грубее.

Если указанный clock_id не поддерживается, генерируется исключение Errno::EINVAL.

unit указывает тип возвращаемого значения.

Process.clock_getres принимает unit в качестве Process.clock_gettime. Значение по умолчанию, :float_second, также совпадает с Process.clock_gettime.

Process.clock_getres также принимает :hertz в качестве unit. :hertz означает обратную величину :float_second.

:hertz можно использовать для получения точного значения тиков таймера в секунду для функции times() и CLOCKS_PER_SEC для функции clock().

+Process.clock_getres(:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz)+ возвращает тики таймера в секунду.

+Process.clock_getres(:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz)+ возвращает CLOCKS_PER_SEC.

p Process.clock_getres(Process::CLOCK_MONOTONIC)
#=> 1.0e-09
clock_gettime(clock_id [, unit]) → number Показать исходный код
VALUE
rb_clock_gettime(int argc, VALUE *argv)
{
    VALUE clk_id, unit;
    int ret;

    struct timetick tt;
    timetick_int_t numerators[2];
    timetick_int_t denominators[2];
    int num_numerators = 0;
    int num_denominators = 0;

    rb_scan_args(argc, argv, "11", &clk_id, &unit);

    if (SYMBOL_P(clk_id)) {
        /*
         * Non-clock_gettime clocks are provided by symbol clk_id.
         *
         * gettimeofday is always available on platforms supported by Ruby.
         * GETTIMEOFDAY_BASED_CLOCK_REALTIME is used for
         * CLOCK_REALTIME if clock_gettime is not available.
         */
#define RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME ID2SYM(id_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
        if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
            struct timeval tv;
            ret = gettimeofday(&tv, 0);
            if (ret != 0)
                rb_sys_fail("gettimeofday");
            tt.giga_count = tv.tv_sec;
            tt.count = (int32_t)tv.tv_usec * 1000;
            denominators[num_denominators++] = 1000000000;
            goto success;
        }

#define RUBY_TIME_BASED_CLOCK_REALTIME ID2SYM(id_TIME_BASED_CLOCK_REALTIME)
        if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
            time_t t;
            t = time(NULL);
            if (t == (time_t)-1)
                rb_sys_fail("time");
            tt.giga_count = t;
            tt.count = 0;
            denominators[num_denominators++] = 1000000000;
            goto success;
        }

#ifdef HAVE_TIMES
#define RUBY_TIMES_BASED_CLOCK_MONOTONIC \
        ID2SYM(id_TIMES_BASED_CLOCK_MONOTONIC)
        if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
            struct tms buf;
            clock_t c;
            unsigned_clock_t uc;
            c = times(&buf);
            if (c ==  (clock_t)-1)
                rb_sys_fail("times");
            uc = (unsigned_clock_t)c;
            tt.count = (int32_t)(uc % 1000000000);
            tt.giga_count = (uc / 1000000000);
            denominators[num_denominators++] = get_clk_tck();
            goto success;
        }
#endif

#ifdef RUSAGE_SELF
#define RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID \
        ID2SYM(id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
        if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
            struct rusage usage;
            int32_t usec;
            ret = getrusage(RUSAGE_SELF, &usage);
            if (ret != 0)
                rb_sys_fail("getrusage");
            tt.giga_count = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec;
            usec = (int32_t)(usage.ru_utime.tv_usec + usage.ru_stime.tv_usec);
            if (1000000 <= usec) {
                tt.giga_count++;
                usec -= 1000000;
            }
            tt.count = usec * 1000;
            denominators[num_denominators++] = 1000000000;
            goto success;
        }
#endif

#ifdef HAVE_TIMES
#define RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID \
        ID2SYM(id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID)
        if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
            struct tms buf;
            unsigned_clock_t utime, stime;
            if (times(&buf) ==  (clock_t)-1)
                rb_sys_fail("times");
            utime = (unsigned_clock_t)buf.tms_utime;
            stime = (unsigned_clock_t)buf.tms_stime;
            tt.count = (int32_t)((utime % 1000000000) + (stime % 1000000000));
            tt.giga_count = (utime / 1000000000) + (stime / 1000000000);
            if (1000000000 <= tt.count) {
                tt.count -= 1000000000;
                tt.giga_count++;
            }
            denominators[num_denominators++] = get_clk_tck();
            goto success;
        }
#endif

#define RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID \
        ID2SYM(id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID)
        if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) {
            clock_t c;
            unsigned_clock_t uc;
            errno = 0;
            c = clock();
            if (c == (clock_t)-1)
                rb_sys_fail("clock");
            uc = (unsigned_clock_t)c;
            tt.count = (int32_t)(uc % 1000000000);
            tt.giga_count = uc / 1000000000;
            denominators[num_denominators++] = CLOCKS_PER_SEC;
            goto success;
        }

#ifdef __APPLE__
#define RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC ID2SYM(id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
        if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
            mach_timebase_info_data_t *info = get_mach_timebase_info();
            uint64_t t = mach_absolute_time();
            tt.count = (int32_t)(t % 1000000000);
            tt.giga_count = t / 1000000000;
            numerators[num_numerators++] = info->numer;
            denominators[num_denominators++] = info->denom;
            denominators[num_denominators++] = 1000000000;
            goto success;
        }
#endif
    }
    else {
#if defined(HAVE_CLOCK_GETTIME)
        struct timespec ts;
        clockid_t c;
        c = NUM2CLOCKID(clk_id);
        ret = clock_gettime(c, &ts);
        if (ret == -1)
            rb_sys_fail("clock_gettime");
        tt.count = (int32_t)ts.tv_nsec;
        tt.giga_count = ts.tv_sec;
        denominators[num_denominators++] = 1000000000;
        goto success;
#endif
    }
    /* EINVAL emulates clock_gettime behavior when clock_id is invalid. */
    errno = EINVAL;
    rb_sys_fail(0);

  success:
    return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
}

Возвращает время, возвращаемое функцией POSIX ::clock_gettime().

p Process.clock_gettime(Process::CLOCK_MONOTONIC)
#=> 896053.968060096

clock_id указывает вид таймера. Он задаётся как константа, начинающаяся с Process::CLOCK_, например, Process::CLOCK_REALTIME и Process::CLOCK_MONOTONIC.

Поддерживаемые константы зависят от ОС и версии. Ruby предоставляет следующие типы clock_id, если они доступны.

CLOCK_REALTIME

SUSv2 до 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 2.1

CLOCK_MONOTONIC

SUSv3 до 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 3.4

CLOCK_PROCESS_CPUTIME_ID

SUSv3 до 4, Linux 2.5.63, OpenBSD 5.4

CLOCK_THREAD_CPUTIME_ID

SUSv3 до 4, Linux 2.5.63, FreeBSD 7.1, OpenBSD 5.4

CLOCK_VIRTUAL

FreeBSD 3.0, OpenBSD 2.1

CLOCK_PROF

FreeBSD 3.0, OpenBSD 2.1

CLOCK_REALTIME_FAST

FreeBSD 8.1

CLOCK_REALTIME_PRECISE

FreeBSD 8.1

CLOCK_REALTIME_COARSE

Linux 2.6.32

CLOCK_REALTIME_ALARM

Linux 3.0

CLOCK_MONOTONIC_FAST

FreeBSD 8.1

CLOCK_MONOTONIC_PRECISE

FreeBSD 8.1

CLOCK_MONOTONIC_COARSE

Linux 2.6.32

CLOCK_MONOTONIC_RAW

Linux 2.6.28

CLOCK_BOOTTIME

Linux 2.6.39

CLOCK_BOOTTIME_ALARM

Linux 3.0

CLOCK_UPTIME

FreeBSD 7.0, OpenBSD 5.5

CLOCK_UPTIME_FAST

FreeBSD 8.1

CLOCK_UPTIME_PRECISE

FreeBSD 8.1

CLOCK_SECOND

FreeBSD 8.1

Обратите внимание, что SUS означает Single Unix Specification. SUS содержит POSIX, и ::clock_gettime определен в части POSIX. SUS определяет CLOCK_REALTIME как обязательный, но CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID и CLOCK_THREAD_CPUTIME_ID являются необязательными.

Также несколько символов принимаются как clock_id. Существуют эмуляции для ::clock_gettime().

Например, Process::CLOCK_REALTIME определен как :GETTIMEOFDAY_BASED_CLOCK_REALTIME, когда ::clock_gettime() недоступен.

Эмуляции для CLOCK_REALTIME.

:GETTIMEOFDAY_BASED_CLOCK_REALTIME

Используйте gettimeofday(), определенный в SUS. (SUSv4 устарело, хотя.) Разрешение составляет 1 микросекунда.

:TIME_BASED_CLOCK_REALTIME

Используйте time(), определенный в ISO C. Разрешение составляет 1 секунду.

Эмуляции для CLOCK_MONOTONIC.

:MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC

Используйте mach_absolute_time(), доступный в Darwin. Разрешение зависит от процессора.

:TIMES_BASED_CLOCK_MONOTONIC

Используйте результат функции times(), определенной в POSIX. POSIX определяет, что “times() должен вернуть затраченное реальное время в тактах таймера с произвольной точки прошлого (например, время запуска системы)”. Например, GNU/Linux возвращает значение, основанное на jiffies, и оно монотонно. Однако 4.4BSD использует gettimeofday(), и оно не монотонно. (FreeBSD использует ::clock_gettime(CLOCK_MONOTONIC) вместо этого.) Разрешение — такт таймера. Команда “getconf CLK_TCK” показывает тики таймера в секунду. (Тики таймера в секунду определяются макросом HZ в старых системах.) Если это 100, разрешение составляет 10 миллисекунд, и оно не может представить более 497 дней.

Эмуляции для CLOCK_PROCESS_CPUTIME_ID.

:GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID

Используйте getrusage(), определенный в SUS. getrusage() используется с RUSAGE_SELF для получения времени только для вызывающего процесса (исключая время для дочерних процессов). Результат — сумма пользовательского времени (ru_utime) и системного времени (ru_stime). Разрешение составляет 1 микросекунда.

:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID

Используйте times(), определенный в POSIX. Результат — сумма пользовательского времени (tms_utime) и системного времени (tms_stime). tms_cutime и tms_cstime игнорируются для исключения времени для дочерних процессов. Разрешение — такт таймера. Команда “getconf CLK_TCK” показывает тики таймера в секунду. (Тики таймера в секунду определяются макросом HZ в старых системах.) Если это 100, разрешение составляет 10 миллисекунд.

:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID

Используйте clock(), определенный в ISO C. Разрешение составляет 1/CLOCKS_PER_SEC. CLOCKS_PER_SEC — C-уровневое макро, определенное в time.h. SUS определяет, что CLOCKS_PER_SEC составляет 1000000. Системы, не являющиеся Unix, могут определить его по-другому. Если CLOCKS_PER_SEC составляет 1000000 как в SUS, разрешение составляет 1 микросекунда. Если CLOCKS_PER_SEC составляет 1000000, а clock_t — 32-битный целочисленный тип, он не может представить более 72 минут.

Если указанный clock_id не поддерживается, генерируется исключение Errno::EINVAL.

unit указывает тип возвращаемого значения.

:float_second

количество секунд как число с плавающей точкой (по умолчанию)

:float_millisecond

количество миллисекунд как число с плавающей точкой

:float_microsecond

количество микросекунд как число с плавающей точкой

:second

количество секунд как целое число

:millisecond

количество миллисекунд как целое число

:microsecond

количество микросекунд как целое число

:nanosecond

количество наносекунд как целое число

Базовая функция ::clock_gettime() возвращает количество наносекунд. Объект Float (IEEE 754 double) недостаточно для представления возвращаемого значения для CLOCK_REALTIME. Если требуется точное значение наносекунд, используйте :nanoseconds в качестве unit.

Начальное значение (ноль) возвращаемого значения варьируется. Например, время запуска системы, время запуска процесса, Эпоха и т. д.

Начальное значение в CLOCK_REALTIME определяется как Эпоха (01.01.1970 00:00:00 UTC). Однако некоторые системы учитывают високосные секунды, а другие нет. Поэтому результат может интерпретироваться по-разному на разных системах. Рекомендуется использовать Time.now вместо CLOCK_REALTIME.

daemon() → 0 Показать исходный код
daemon(nochdir=nil,noclose=nil) → 0
static VALUE
proc_daemon(int argc, VALUE *argv)
{
    VALUE nochdir, noclose;
    int n;

    rb_secure(2);
    rb_scan_args(argc, argv, "02", &nochdir, &noclose);

    prefork();
    n = rb_daemon(RTEST(nochdir), RTEST(noclose));
    if (n < 0) rb_sys_fail("daemon");
    return INT2FIX(n);
}

Отсоединяет процесс от управляющего терминала и запускает его в фоновом режиме в качестве системного демона. Если аргумент nochdir имеет значение true (т.е. не false), он изменяет текущий рабочий каталог на корневой (“/”). Если аргумент noclose имеет значение true, daemon() перенаправит стандартный ввод, стандартный вывод и стандартную ошибку в /dev/null. Возвращает ноль при успехе или вызывает одно из исключений Errno::*.

detach(pid) → thread Показать исходный код
static VALUE
proc_detach(VALUE obj, VALUE pid)
{
    rb_secure(2);
    return rb_detach_process(NUM2PIDT(pid));
}

Некоторые операционные системы сохраняют статус завершенных дочерних процессов до тех пор, пока родительский процесс не соберет этот статус (обычно с помощью некоторой разновидности wait(). Если родительский процесс никогда не собирает этот статус, дочерний процесс остаётся как зомби-процесс. Process::detach предотвращает это, создавая отдельный поток Ruby, чья единственная задача — собрать статус процесса pid при его завершении. Используйте detach только в том случае, если вы не планируете явно ждать завершения дочернего процесса.

Ожидающий поток возвращает код завершения отсоединённого процесса при его завершении, так что вы можете использовать Thread#join для получения результата. Если указанный pid не является допустимым идентификатором дочернего процесса, поток возвращает nil немедленно.

Ожидающий поток имеет метод pid , который возвращает значение pid.

В этом первом примере мы не собираем первый дочерний процесс, поэтому он отображается как зомби в представлении статуса процесса.

p1 = fork { sleep 0.1 }
p2 = fork { sleep 0.2 }
Process.waitpid(p2)
sleep 2
system("ps -ho pid,state -p #{p1}")

выводит:

27389 Z

В следующем примере используется Process::detach для автоматического сбора дочернего процесса.

p1 = fork { sleep 0.1 }
p2 = fork { sleep 0.2 }
Process.detach(p1)
Process.waitpid(p2)
sleep 2
system("ps -ho pid,state -p #{p1}")

(не выводит ничего)

egid → fixnum Показать исходный код
Process::GID.eid → fixnum
Process::Sys.geteid → fixnum
static VALUE
proc_getegid(VALUE obj)
{
    rb_gid_t egid = getegid();

    return GIDT2NUM(egid);
}

Возвращает эффективный идентификатор группы для данного процесса. Не доступно на всех платформах.

Process.egid   #=> 500
egid = fixnum → fixnum Показать исходный код
static VALUE
proc_setegid(VALUE obj, VALUE egid)
{
#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
    rb_gid_t gid;
#endif

    check_gid_switch();

#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
    gid = OBJ2GID(egid);
#endif

#if defined(HAVE_SETRESGID)
    if (setresgid(-1, gid, -1) < 0) rb_sys_fail(0);
#elif defined HAVE_SETREGID
    if (setregid(-1, gid) < 0) rb_sys_fail(0);
#elif defined HAVE_SETEGID
    if (setegid(gid) < 0) rb_sys_fail(0);
#elif defined HAVE_SETGID
    if (gid == getgid()) {
        if (setgid(gid) < 0) rb_sys_fail(0);
    }
    else {
        rb_notimplement();
    }
#else
    rb_notimplement();
#endif
    return egid;
}

Устанавливает эффективный идентификатор группы для данного процесса. Не доступно на всех платформах.

euid → fixnum Показать исходный код
Process::UID.eid → fixnum
Process::Sys.geteuid → fixnum
static VALUE
proc_geteuid(VALUE obj)
{
    rb_uid_t euid = geteuid();
    return UIDT2NUM(euid);
}

Возвращает эффективный идентификатор пользователя для данного процесса.

Process.euid   #=> 501
euid= user Показать исходный код
static VALUE
proc_seteuid_m(VALUE mod, VALUE euid)
{
    check_uid_switch();
    proc_seteuid(OBJ2UID(euid));
    return euid;
}

Устанавливает эффективный идентификатор пользователя для данного процесса. Не доступно на всех платформах.

exec([env,] command... [,options]) Показать исходный код
VALUE
rb_f_exec(int argc, const VALUE *argv)
{
    VALUE execarg_obj, fail_str;
    struct rb_execarg *eargp;
#define CHILD_ERRMSG_BUFLEN 80
    char errmsg[CHILD_ERRMSG_BUFLEN] = { '\0' };

    execarg_obj = rb_execarg_new(argc, argv, TRUE);
    eargp = rb_execarg_get(execarg_obj);
    rb_execarg_fixup(execarg_obj);
    fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;

#if defined(__APPLE__) || defined(__HAIKU__)
    rb_exec_without_timer_thread(eargp, errmsg, sizeof(errmsg));
#else
    before_exec_async_signal_safe(); /* async-signal-safe */
    rb_exec_async_signal_safe(eargp, errmsg, sizeof(errmsg));
    preserving_errno(after_exec_async_signal_safe()); /* async-signal-safe */
#endif
    RB_GC_GUARD(execarg_obj);
    if (errmsg[0])
        rb_sys_fail(errmsg);
    rb_sys_fail_str(fail_str);
    return Qnil;                /* dummy */
}

Заменяет текущий процесс, выполняя указанную внешнюю команду, которая может иметь один из следующих форматов:

exec(commandline)

строка командной строки, которая передаётся стандартной оболочке

exec(cmdname, arg1, ...)

имя команды и один или несколько аргументов (без оболочки)

exec([cmdname, argv0], arg1, ...)

имя команды, argv и ноль или более аргументов (без оболочки)

В первом формате строка рассматривается как командная строка, которая подвергается расширению оболочки перед выполнением.

Стандартная оболочка всегда означает "/bin/sh" на системах Unix-подобных, то же, что и ENV["RUBYSHELL"] (или ENV["COMSPEC"] в системах Windows NT), и подобные.

Если строка из первого формата (exec("command")) следует этим простым правилам:

  • нет метасимволов

  • нет зарезервированных слов оболочки и нет специальных встроенных команд

  • Ruby вызывает команду напрямую без оболочки

Вы можете принудительно вызвать оболочку, добавив «;» в строку (потому что «;» является метасимволом).

Обратите внимание, что это поведение наблюдаемо по pid, полученному (возвращаемое значение spawn() и IO#pid для IO.popen) — это pid вызванной команды, а не оболочки.

Во втором формате (exec("command1", "arg1", ...)) первое значение принимается как имя команды, а остальные передаются как параметры команды без расширения оболочки.

В третьем формате (exec(["command", "argv0"], "arg1", ...)) начиная с двухелементного массива в начале команды, первый элемент — это команда для выполнения, а второй аргумент используется как значение argv[0], которое может появиться в списках процессов.

Для выполнения команды используются системные вызовы exec(2), поэтому выполняемая команда может унаследовать часть окружения исходной программы (включая открытые дескрипторы файлов).

Это поведение изменяется параметрами env и options. Подробнее см. ::spawn.

Если команда не выполняется (обычно Errno::ENOENT при её отсутствии), возникает исключение SystemCallError.

Этот метод изменяет атрибуты процесса в соответствии с заданными options перед вызовом exec(2) системного вызова. Дополнительные сведения об указанных options см. в ::spawn.

Изменённые атрибуты могут сохраняться, когда вызов exec(2) системного вызова завершается ошибкой.

Например, жёсткие лимиты ресурсов не восстанавливаются.

Рассмотрите создание дочернего процесса с помощью ::spawn или Kernel#system, если это неприемлемо.

exec "echo *"       # echoes list of files in current directory
# never get here

exec "echo", "*"    # echoes an asterisk
# never get here
exit(status=true) Показать исходный код
Kernel::exit(status=true)
Process::exit(status=true)
VALUE
rb_f_exit(int argc, const VALUE *argv)
{
    VALUE status;
    int istatus;

    if (argc > 0 && rb_scan_args(argc, argv, "01", &status) == 1) {
        istatus = exit_status_code(status);
    }
    else {
        istatus = EXIT_SUCCESS;
    }
    rb_exit(istatus);

    UNREACHABLE;
}

Инициирует завершение скрипта Ruby, вызвав исключение SystemExit. Это исключение может быть перехвачено. Необязательный параметр используется для возвращения кода состояния в вызывающую среду. true и FALSE значения status обозначают успех и неудачу соответственно. Интерпретация других целочисленных значений зависит от системы.

begin
  exit
  puts "never get here"
rescue SystemExit
  puts "rescued a SystemExit exception"
end
puts "after begin block"

выводит:

rescued a SystemExit exception
after begin block

Непосредственно перед завершением Ruby выполняет все at_exit функции (см. Kernel::at_exit) и выполняет все финализаторы объектов (см. ObjectSpace.define_finalizer).

at_exit { puts "at_exit function" }
ObjectSpace.define_finalizer("string",  proc { puts "in finalizer" })
exit

выводит:

at_exit function
in finalizer
exit!(status=false) Показать исходный код
static VALUE
rb_f_exit_bang(int argc, VALUE *argv, VALUE obj)
{
    VALUE status;
    int istatus;

    if (argc > 0 && rb_scan_args(argc, argv, "01", &status) == 1) {
        istatus = exit_status_code(status);
    }
    else {
        istatus = EXIT_FAILURE;
    }
    _exit(istatus);

    UNREACHABLE;
}

Немедленно завершает процесс. Обработчики выхода не выполняются. status возвращается в базовую систему в качестве кода выхода.

Process.exit!(true)
fork [{ block }] → fixnum or nil Показать исходный код
fork [{ block }] → fixnum or nil
static VALUE
rb_f_fork(VALUE obj)
{
    rb_pid_t pid;

    rb_secure(2);

    switch (pid = rb_fork_ruby(NULL)) {
      case 0:
        rb_thread_atfork();
        if (rb_block_given_p()) {
            int status;

            rb_protect(rb_yield, Qundef, &status);
            ruby_stop(status);
        }
        return Qnil;

      case -1:
        rb_sys_fail("fork(2)");
        return Qnil;

      default:
        return PIDT2NUM(pid);
    }
}

Создаёт дочерний процесс. Если блок указан, этот блок выполняется в дочернем процессе, и дочерний процесс завершается со статусом ноль. В противном случае системный вызов fork возвращает дважды: один раз в родительском процессе, возвращая идентификатор процесса дочернего процесса, и один раз в дочернем процессе, возвращая nil. Дочерний процесс может завершиться, используя Kernel.exit! , чтобы избежать выполнения любых at_exit функций. Родительский процесс должен использовать Process.wait , чтобы собрать коды завершения своих дочерних процессов, или использовать Process.detach , чтобы указать, что он не заинтересован в их статусе; в противном случае операционная система может накапливать зомби-процессы.

Поток, вызывающий fork, является единственным потоком в созданном дочернем процессе. fork не копирует другие потоки.

Если fork недоступен, Process.respond_to?(:fork) возвращает false.

Обратите внимание, что fork(2) недоступен на некоторых платформах, таких как Windows и NetBSD 4. Поэтому следует использовать spawn() вместо fork().

getpgid(pid) → integer Показать исходный код
static VALUE
proc_getpgid(VALUE obj, VALUE pid)
{
    rb_pid_t i;

    rb_secure(2);
    i = getpgid(NUM2PIDT(pid));
    if (i < 0) rb_sys_fail(0);
    return PIDT2NUM(i);
}

Возвращает идентификатор группы процессов для данного идентификатора процесса. Не доступно на всех платформах.

Process.getpgid(Process.ppid())   #=> 25527
END_OF_DOCUMENT_MARKER
getpgrp → integer Показать исходный код
static VALUE
proc_getpgrp(void)
{
    rb_pid_t pgrp;

    rb_secure(2);
#if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)
    pgrp = getpgrp();
    if (pgrp < 0) rb_sys_fail(0);
    return PIDT2NUM(pgrp);
#else /* defined(HAVE_GETPGID) */
    pgrp = getpgid(0);
    if (pgrp < 0) rb_sys_fail(0);
    return PIDT2NUM(pgrp);
#endif
}

Возвращает идентификатор группы процессов для данного процесса. Не доступно на всех платформах.

Process.getpgid(0)   #=> 25527
Process.getpgrp      #=> 25527
getpriority(kind, integer) → fixnum Показать исходный код
static VALUE
proc_getpriority(VALUE obj, VALUE which, VALUE who)
{
    int prio, iwhich, iwho;

    rb_secure(2);
    iwhich = NUM2INT(which);
    iwho   = NUM2INT(who);

    errno = 0;
    prio = getpriority(iwhich, iwho);
    if (errno) rb_sys_fail(0);
    return INT2FIX(prio);
}

Получает приоритет планирования для указанного процесса, группы процессов или пользователя. kind указывает тип сущности для поиска: один из Process::PRIO_PGRP, Process::PRIO_USER, или Process::PRIO_PROCESS. integer — идентификатор, указывающий конкретный процесс, группу процессов или пользователя (идентификатор 0 означает текущий). Более низкие приоритеты предпочтительнее для планирования. Не доступно на всех платформах.

Process.getpriority(Process::PRIO_USER, 0)      #=> 19
Process.getpriority(Process::PRIO_PROCESS, 0)   #=> 19
getrlimit(resource) → [cur_limit, max_limit] Показать исходный код
static VALUE
proc_getrlimit(VALUE obj, VALUE resource)
{
    struct rlimit rlim;

    rb_secure(2);

    if (getrlimit(rlimit_resource_type(resource), &rlim) < 0) {
        rb_sys_fail("getrlimit");
    }
    return rb_assoc_new(RLIM2NUM(rlim.rlim_cur), RLIM2NUM(rlim.rlim_max));
}

Получает ограничение ресурсов процесса. cur_limit означает текущее (мягкое) ограничение, а max_limit — максимальное (жёсткое) ограничение.

resource указывает тип ресурса для ограничения. Он задаётся как символ, например :CORE, строка, например "CORE", или константа, например Process::RLIMIT_CORE. Подробнее см. ::setrlimit.

cur_limit и max_limit могут быть Process::RLIM_INFINITY, Process::RLIM_SAVED_MAX или Process::RLIM_SAVED_CUR. Подробнее см. ::setrlimit и руководство по системе getrlimit(2).

getsid() → integer Показать исходный код
getsid(pid) → integer
static VALUE
proc_getsid(int argc, VALUE *argv)
{
    rb_pid_t sid;
    VALUE pid;

    rb_secure(2);
    rb_scan_args(argc, argv, "01", &pid);

    if (NIL_P(pid))
        pid = INT2FIX(0);

    sid = getsid(NUM2PIDT(pid));
    if (sid < 0) rb_sys_fail(0);
    return PIDT2NUM(sid);
}

Возвращает идентификатор сеанса для указанного идентификатора процесса. Если не указан, возвращает идентификатор сеанса текущего процесса. Не доступно на всех платформах.

Process.getsid()                #=> 27422
Process.getsid(0)               #=> 27422
Process.getsid(Process.pid())   #=> 27422
gid → fixnum Показать исходный код
Process::GID.rid → fixnum
Process::Sys.getgid → fixnum
static VALUE
proc_getgid(VALUE obj)
{
    rb_gid_t gid = getgid();
    return GIDT2NUM(gid);
}

Возвращает (действительный) идентификатор группы для данного процесса.

Process.gid   #=> 500
gid= fixnum → fixnum Показать исходный код
static VALUE
proc_setgid(VALUE obj, VALUE id)
{
    rb_gid_t gid;

    check_gid_switch();

    gid = OBJ2GID(id);
#if defined(HAVE_SETRESGID)
    if (setresgid(gid, -1, -1) < 0) rb_sys_fail(0);
#elif defined HAVE_SETREGID
    if (setregid(gid, -1) < 0) rb_sys_fail(0);
#elif defined HAVE_SETRGID
    if (setrgid(gid) < 0) rb_sys_fail(0);
#elif defined HAVE_SETGID
    {
        if (getegid() == gid) {
            if (setgid(gid) < 0) rb_sys_fail(0);
        }
        else {
            rb_notimplement();
        }
    }
#endif
    return GIDT2NUM(gid);
}

Устанавливает идентификатор группы для данного процесса.

groups → array Показать исходный код
static VALUE
proc_getgroups(VALUE obj)
{
    VALUE ary, tmp;
    int i, ngroups;
    rb_gid_t *groups;

    ngroups = getgroups(0, NULL);
    if (ngroups == -1)
        rb_sys_fail(0);

    groups = ALLOCV_N(rb_gid_t, tmp, ngroups);

    ngroups = getgroups(ngroups, groups);
    if (ngroups == -1)
        rb_sys_fail(0);

    ary = rb_ary_new();
    for (i = 0; i < ngroups; i++)
        rb_ary_push(ary, GIDT2NUM(groups[i]));

    ALLOCV_END(tmp);

    return ary;
}

Получает Array идентификаторов групп в списке дополнительных групп доступа для данного процесса.

Process.groups   #=> [27, 6, 10, 11]
groups= array → array Показать исходный код
static VALUE
proc_setgroups(VALUE obj, VALUE ary)
{
    int ngroups, i;
    rb_gid_t *groups;
    VALUE tmp;
    PREPARE_GETGRNAM;

    Check_Type(ary, T_ARRAY);

    ngroups = RARRAY_LENINT(ary);
    if (ngroups > maxgroups())
        rb_raise(rb_eArgError, "too many groups, %d max", maxgroups());

    groups = ALLOCV_N(rb_gid_t, tmp, ngroups);

    for (i = 0; i < ngroups; i++) {
        VALUE g = RARRAY_AREF(ary, i);

        groups[i] = OBJ2GID1(g);
    }
    FINISH_GETGRNAM;

    if (setgroups(ngroups, groups) == -1) /* ngroups <= maxgroups */
        rb_sys_fail(0);

    ALLOCV_END(tmp);

    return proc_getgroups(obj);
}

Устанавливает список дополнительных групп доступа к заданному Array идентификаторов групп.

Process.groups   #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
Process.groups = [27, 6, 10, 11]   #=> [27, 6, 10, 11]
Process.groups   #=> [27, 6, 10, 11]
initgroups(username, gid) → array Показать исходный код
static VALUE
proc_initgroups(VALUE obj, VALUE uname, VALUE base_grp)
{
    if (initgroups(StringValuePtr(uname), OBJ2GID(base_grp)) != 0) {
        rb_sys_fail(0);
    }
    return proc_getgroups(obj);
}

Инициализирует список дополнительных групп доступа, считывая базу данных системных групп и используя все группы, членами которых является данный пользователь. Группа со значением gid также добавляется в список. Возвращает результирующий Array идентификаторов всех групп в списке дополнительных групп доступа. Не доступно на всех платформах.

Process.groups   #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
Process.initgroups( "mgranger", 30 )   #=> [30, 6, 10, 11]
Process.groups   #=> [30, 6, 10, 11]
kill(signal, pid, ...) → fixnum Показать исходный код
VALUE
rb_f_kill(int argc, const VALUE *argv)
{
#ifndef HAVE_KILLPG
#define killpg(pg, sig) kill(-(pg), (sig))
#endif
    int negative = 0;
    int sig;
    int i;
    VALUE str;
    const char *s;

    rb_secure(2);
    rb_check_arity(argc, 2, UNLIMITED_ARGUMENTS);

    switch (TYPE(argv[0])) {
      case T_FIXNUM:
	sig = FIX2INT(argv[0]);
	break;

      case T_SYMBOL:
	str = rb_sym2str(argv[0]);
	goto str_signal;

      case T_STRING:
	str = argv[0];
      str_signal:
	s = RSTRING_PTR(str);
	if (s[0] == '-') {
	    negative++;
	    s++;
	}
	if (strncmp(signame_prefix, s, sizeof(signame_prefix)) == 0)
	    s += 3;
	if ((sig = signm2signo(s)) == 0) {
	    long ofs = s - RSTRING_PTR(str);
	    if (ofs) str = rb_str_subseq(str, ofs, RSTRING_LEN(str)-ofs);
	    rb_raise(rb_eArgError, "unsupported name `SIG%"PRIsVALUE"'", str);
	}

	if (negative)
	    sig = -sig;
	break;

      default:
	str = rb_check_string_type(argv[0]);
	if (!NIL_P(str)) {
	    goto str_signal;
	}
	rb_raise(rb_eArgError, "bad signal type %s",
		 rb_obj_classname(argv[0]));
	break;
    }

    if (argc <= 1) return INT2FIX(0);

    if (sig < 0) {
	sig = -sig;
	for (i=1; i<argc; i++) {
	    if (killpg(NUM2PIDT(argv[i]), sig) < 0)
		rb_sys_fail(0);
	}
    }
    else {
	const rb_pid_t self = (GET_THREAD() == GET_VM()->main_thread) ? getpid() : -1;
	int wakeup = 0;

	for (i=1; i<argc; i++) {
	    rb_pid_t pid = NUM2PIDT(argv[i]);

	    if ((sig != 0) && (self != -1) && (pid == self)) {
		int t;
		/*
		 * When target pid is self, many caller assume signal will be
		 * delivered immediately and synchronously.
		 */
		switch (sig) {
		  case SIGSEGV:
#ifdef SIGBUS
		  case SIGBUS:
#endif
#ifdef SIGKILL
		  case SIGKILL:
#endif
#ifdef SIGSTOP
		  case SIGSTOP:
#endif
		    ruby_kill(pid, sig);
		    break;
		  default:
		    t = signal_ignored(sig);
		    if (t) {
			if (t < 0 && kill(pid, sig))
			    rb_sys_fail(0);
			break;
		    }
		    signal_enque(sig);
		    wakeup = 1;
		}
	    }
	    else if (kill(pid, sig) < 0) {
		rb_sys_fail(0);
	    }
	}
	if (wakeup) {
	    rb_threadptr_check_signal(GET_VM()->main_thread);
	}
    }
    rb_thread_execute_interrupts(rb_thread_current());

    return INT2FIX(i-1);
}

Отправляет заданный сигнал указанному(ым) идентификатору(ам) процесса(ов), если pid положительный. Если pid равен нулю, signal отправляется всем процессам, у которых идентификатор группы равен идентификатору группы процесса. signal может быть целым номером сигнала или именем сигнала POSIX (с или без префикса SIG). Если signal отрицательный (или начинается с минуса), уничтожаются группы процессов вместо процессов. Не все сигналы доступны на всех платформах. Ключи и значения Signal.list известные имена и номера сигналов соответственно.

pid = fork do
   Signal.trap("HUP") { puts "Ouch!"; exit }
   # ... do some work ...
end
# ...
Process.kill("HUP", pid)
Process.wait

возвращает:

Ouch!

Если signal — целое число, но неверное для сигнала, Errno::EINVAL или RangeError будут подняты. В противном случае, если signal не является String или Symbol, и известным именем сигнала, ArgumentError будет поднята.

Также Errno::ESRCH или RangeError для неверного pid, Errno::EPERM при неудаче из-за отсутствия привилегий, будут подняты. В этих случаях сигналы могут быть отправлены предшествующим процессам.

maxgroups → fixnum Показать исходный код
static VALUE
proc_getmaxgroups(VALUE obj)
{
    return INT2FIX(maxgroups());
}

Возвращает максимальное количество идентификаторов групп, разрешенных в списке дополнительных групп доступа.

Process.maxgroups   #=> 32
maxgroups= fixnum → fixnum Показать исходный код
static VALUE
proc_setmaxgroups(VALUE obj, VALUE val)
{
    int ngroups = FIX2INT(val);
    int ngroups_max = get_sc_ngroups_max();

    if (ngroups <= 0)
        rb_raise(rb_eArgError, "maxgroups %d shold be positive", ngroups);

    if (ngroups > RB_MAX_GROUPS)
        ngroups = RB_MAX_GROUPS;

    if (ngroups_max > 0 && ngroups > ngroups_max)
        ngroups = ngroups_max;

    _maxgroups = ngroups;

    return INT2FIX(_maxgroups);
}

Устанавливает максимальное количество идентификаторов групп, разрешенных в списке дополнительных групп доступа.

pid → fixnum Показать исходный код
static VALUE
get_pid(void)
{
    rb_secure(2);
    return PIDT2NUM(getpid());
}

Возвращает идентификатор процесса данного процесса. Не доступно на всех платформах.

Process.pid   #=> 27415
ppid → fixnum Показать исходный код
static VALUE
get_ppid(void)
{
    rb_secure(2);
    return PIDT2NUM(getppid());
}

Возвращает идентификатор процесса родительского процесса. Возвращает недостоверные значения в Win32/64. Не доступно на всех платформах.

puts "I am #{Process.pid}"
Process.fork { puts "Dad is #{Process.ppid}" }

возвращает:

I am 27417
Dad is 27417
setpgid(pid, integer) → 0 Показать исходный код
static VALUE
proc_setpgid(VALUE obj, VALUE pid, VALUE pgrp)
{
    rb_pid_t ipid, ipgrp;

    rb_secure(2);
    ipid = NUM2PIDT(pid);
    ipgrp = NUM2PIDT(pgrp);

    if (setpgid(ipid, ipgrp) < 0) rb_sys_fail(0);
    return INT2FIX(0);
}

Устанавливает идентификатор группы процессов для pid (0 означает этот процесс) на integer. Не доступно на всех платформах.

setpgrp → 0 Показать исходный код
static VALUE
proc_setpgrp(void)
{
    rb_secure(2);
  /* check for posix setpgid() first; this matches the posix */
  /* getpgrp() above.  It appears that configure will set SETPGRP_VOID */
  /* even though setpgrp(0,0) would be preferred. The posix call avoids */
  /* this confusion. */
#ifdef HAVE_SETPGID
    if (setpgid(0,0) < 0) rb_sys_fail(0);
#elif defined(HAVE_SETPGRP) && defined(SETPGRP_VOID)
    if (setpgrp() < 0) rb_sys_fail(0);
#endif
    return INT2FIX(0);
}

Эквивалентно setpgid(0,0). Не доступно на всех платформах.

setpriority(kind, integer, priority) → 0 Показать исходный код
static VALUE
proc_setpriority(VALUE obj, VALUE which, VALUE who, VALUE prio)
{
    int iwhich, iwho, iprio;

    rb_secure(2);
    iwhich = NUM2INT(which);
    iwho   = NUM2INT(who);
    iprio  = NUM2INT(prio);

    if (setpriority(iwhich, iwho, iprio) < 0)
        rb_sys_fail(0);
    return INT2FIX(0);
}

См. Process#getpriority.

Process.setpriority(Process::PRIO_USER, 0, 19)      #=> 0
Process.setpriority(Process::PRIO_PROCESS, 0, 19)   #=> 0
Process.getpriority(Process::PRIO_USER, 0)          #=> 19
Process.getpriority(Process::PRIO_PROCESS, 0)       #=> 19
setproctitle(string) → string Показать исходный код
static VALUE
proc_setproctitle(VALUE process, VALUE title)
{
    StringValue(title);

    setproctitle("%.*s", RSTRING_LENINT(title), RSTRING_PTR(title));

    return title;
}

Устанавливает заголовок процесса, отображаемый в команде ps(1). Не обязательно эффективно на всех платформах. Исключение не будет поднято независимо от результата, также NotImplementedError не будет поднят, даже если платформа не поддерживает функцию.

Вызов этого метода не влияет на значение $0.

Process.setproctitle('myapp: worker #%d' % worker_id)

Этот метод впервые появился в Ruby 2.1, чтобы обеспечить глобальную переменную как способ изменения заголовка процесса.

setrlimit(resource, cur_limit, max_limit) → nil Показать исходный код
setrlimit(resource, cur_limit) → nil
static VALUE
proc_setrlimit(int argc, VALUE *argv, VALUE obj)
{
    VALUE resource, rlim_cur, rlim_max;
    struct rlimit rlim;

    rb_secure(2);

    rb_scan_args(argc, argv, "21", &resource, &rlim_cur, &rlim_max);
    if (rlim_max == Qnil)
        rlim_max = rlim_cur;

    rlim.rlim_cur = rlimit_resource_value(rlim_cur);
    rlim.rlim_max = rlimit_resource_value(rlim_max);

    if (setrlimit(rlimit_resource_type(resource), &rlim) < 0) {
        rb_sys_fail("setrlimit");
    }
    return Qnil;
}

Устанавливает ограничение на ресурсы процесса. cur_limit означает текущее (мягкое) ограничение, а max_limit означает максимальное (жёсткое) ограничение.

Если max_limit не задан, используется cur_limit.

resource указывает тип ресурса, который нужно ограничить. Он должен быть символом, например, :CORE, строкой, например, "CORE", или константой, например, Process::RLIMIT_CORE. Доступные ресурсы зависят от операционной системы. Ruby может поддерживать следующие ресурсы.

AS

общий доступный объём памяти (байты) (SUSv3, NetBSD, FreeBSD, OpenBSD, но не 4.4BSD-Lite)

CORE

размер файла ядра (байты) (SUSv3)

CPU

время работы процессора (секунды) (SUSv3)

DATA

размер сегмента данных (байты) (SUSv3)

FSIZE

размер файла (байты) (SUSv3)

MEMLOCK

общий размер для mlock(2) (байты) (4.4BSD, GNU/Linux)

MSGQUEUE

распределение для очередей сообщений POSIX (байты) (GNU/Linux)

NICE

потолок значения nice(2) процесса (число) (GNU/Linux)

NOFILE

дескрипторы файлов (число) (SUSv3)

NPROC

количество процессов для пользователя (число) (4.4BSD, GNU/Linux)

RSS

размер резидентной памяти (байты) (4.2BSD, GNU/Linux)

RTPRIO

потолок реального времени приоритета процесса (число) (GNU/Linux)

RTTIME

время работы процессора для процесса реального времени (мкс) (GNU/Linux)

SBSIZE

все буферы сокетов (байты) (NetBSD, FreeBSD)

SIGPENDING

разрешённое количество очередей сигналов (сигналы) (GNU/Linux)

STACK

размер стека (байты) (SUSv3)

cur_limit и max_limit могут быть :INFINITY, "INFINITY" или Process::RLIM_INFINITY, что означает, что ресурс не ограничен. Они могут быть Process::RLIM_SAVED_MAX, Process::RLIM_SAVED_CUR и соответствующими символами и строками тоже. Для получения подробной информации см. руководство по системе setrlimit(2).

Следующий пример повышает мягкое ограничение на размер файла ядра до жёсткого ограничения, чтобы сделать возможным создание дампов ядра.

Process.setrlimit(:CORE, Process.getrlimit(:CORE)[1])
setsid → fixnum Показать исходный код
static VALUE
proc_setsid(void)
{
    rb_pid_t pid;

    rb_secure(2);
    pid = setsid();
    if (pid < 0) rb_sys_fail(0);
    return PIDT2NUM(pid);
}

Делает этот процесс лидером новой сессии и группы процессов без управляющего терминала. Возвращает идентификатор сессии. Не доступно на всех платформах.

Process.setsid   #=> 27422
spawn([env,] command... [,options]) → pid Показать исходный код
spawn([env,] command... [,options]) → pid
static VALUE
rb_f_spawn(int argc, VALUE *argv)
{
    rb_pid_t pid;
    char errmsg[CHILD_ERRMSG_BUFLEN] = { '\0' };
    VALUE execarg_obj, fail_str;
    struct rb_execarg *eargp;

    execarg_obj = rb_execarg_new(argc, argv, TRUE);
    eargp = rb_execarg_get(execarg_obj);
    rb_execarg_fixup(execarg_obj);
    fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;

    pid = rb_spawn_process(eargp, errmsg, sizeof(errmsg));
    RB_GC_GUARD(execarg_obj);

    if (pid == -1) {
        const char *prog = errmsg;
        if (!prog[0]) {
            rb_sys_fail_str(fail_str);
        }
        rb_sys_fail(prog);
    }
#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
    return PIDT2NUM(pid);
#else
    return Qnil;
#endif
}

spawn выполняет указанную команду и возвращает её идентификатор процесса.

pid = spawn("tar xf ruby-2.0.0-p195.tar.bz2")
Process.wait pid

pid = spawn(RbConfig.ruby, "-eputs'Hello, world!'")
Process.wait pid

Этот метод похож на Kernel#system, но он не ожидает завершения команды.

Родительский процесс должен использовать Process.wait для получения статуса завершения своего дочернего процесса или использовать Process.detach для регистрации отсутствия интереса к их статусу; в противном случае операционная система может накапливать процессы-зомби.

spawn имеет множество опций для указания атрибутов процесса:

env: hash
  name => val : set the environment variable
  name => nil : unset the environment variable
command...:
  commandline                 : command line string which is passed to the standard shell
  cmdname, arg1, ...          : command name and one or more arguments (This form does not use the shell. See below for caveats.)
  [cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)
options: hash
  clearing environment variables:
    :unsetenv_others => true   : clear environment variables except specified by env
    :unsetenv_others => false  : don't clear (default)
  process group:
    :pgroup => true or 0 : make a new process group
    :pgroup => pgid      : join to specified process group
    :pgroup => nil       : don't change the process group (default)
  create new process group: Windows only
    :new_pgroup => true  : the new process is the root process of a new process group
    :new_pgroup => false : don't create a new process group (default)
  resource limit: resourcename is core, cpu, data, etc.  See Process.setrlimit.
    :rlimit_resourcename => limit
    :rlimit_resourcename => [cur_limit, max_limit]
  umask:
    :umask => int
  redirection:
    key:
      FD              : single file descriptor in child process
      [FD, FD, ...]   : multiple file descriptor in child process
    value:
      FD                        : redirect to the file descriptor in parent process
      string                    : redirect to file with open(string, "r" or "w")
      [string]                  : redirect to file with open(string, File::RDONLY)
      [string, open_mode]       : redirect to file with open(string, open_mode, 0644)
      [string, open_mode, perm] : redirect to file with open(string, open_mode, perm)
      [:child, FD]              : redirect to the redirected file descriptor
      :close                    : close the file descriptor in child process
    FD is one of follows
      :in     : the file descriptor 0 which is the standard input
      :out    : the file descriptor 1 which is the standard output
      :err    : the file descriptor 2 which is the standard error
      integer : the file descriptor of specified the integer
      io      : the file descriptor specified as io.fileno
  file descriptor inheritance: close non-redirected non-standard fds (3, 4, 5, ...) or not
    :close_others => true  : don't inherit
  current directory:
    :chdir => str

  The 'cmdname, arg1, ...' form does not use the shell. However,
  on different OSes, different things are provided as built-in
  commands. An example of this is 'echo', which is a built-in
  on Windows, but is a normal program on Linux and Mac OS X.
  This means that `Process.spawn 'echo', '%Path%'` will display
  the contents of the `%Path%` environment variable on Windows,
  but `Process.spawn 'echo', '$PATH'` prints the literal '$PATH'.

Если в качестве env передаётся хэш, среда обновляется с помощью env перед exec(2) в дочернем процессе. Если пара в env имеет значение nil, переменная удаляется.

# set FOO as BAR and unset BAZ.
pid = spawn({"FOO"=>"BAR", "BAZ"=>nil}, command)

Если в качестве options передаётся хэш, он указывает на группу процессов, создание новой группы процессов, ограничения на ресурсы, текущий каталог, umask и перенаправления для дочернего процесса. Также можно указать на очистку переменных среды.

Ключ :unsetenv_others в options указывает на очистку переменных среды, кроме тех, что указаны env.

pid = spawn(command, :unsetenv_others=>true) # no environment variable
pid = spawn({"FOO"=>"BAR"}, command, :unsetenv_others=>true) # FOO only

Ключ :pgroup в options указывает на группу процессов. Соответствующее значение должно быть true, нулём или положительным целым числом. true и ноль означают, что процесс должен быть лидером новой группы процессов. Другие значения указывают на группу процессов, к которой должен принадлежать процесс.

pid = spawn(command, :pgroup=>true) # process leader
pid = spawn(command, :pgroup=>10) # belongs to the process group 10

Ключ :new_pgroup в options указывает на передачу флага CREATE_NEW_PROCESS_GROUP в CreateProcessW(), который является функцией API Windows. Этот параметр предназначен только для Windows. true означает, что новый процесс является корневым процессом новой группы процессов. Новый процесс имеет отключенный CTRL+C. Этот флаг необходим для Process.kill(:SIGINT, pid) в подпроцессе. :new_pgroup по умолчанию равен false.

pid = spawn(command, :new_pgroup=>true)  # new process group
pid = spawn(command, :new_pgroup=>false) # same process group

Ключ :rlimit_foo указывает на ограничения ресурса. foo должен быть одним из типов ресурсов, например, core. Соответствующее значение должно быть целым числом или массивом, содержащим одно или два целых числа: аналогично аргументам cur_limit и max_limit для ::setrlimit.

cur, max = Process.getrlimit(:CORE)
pid = spawn(command, :rlimit_core=>[0,max]) # disable core temporary.
pid = spawn(command, :rlimit_core=>max) # enable core dump
pid = spawn(command, :rlimit_core=>0) # never dump core.

Ключ :umask в options указывает на umask.

pid = spawn(command, :umask=>077)

Ключи :in, :out, :err, целое число, объект IO и массив задают перенаправление. Перенаправление отображает дескриптор файла в дочернем процессе.

Например, stderr можно объединить со stdout следующим образом:

pid = spawn(command, :err=>:out)
pid = spawn(command, 2=>1)
pid = spawn(command, STDERR=>:out)
pid = spawn(command, STDERR=>STDOUT)

Ключи хэша задают дескриптор файла в дочернем процессе, запущенном с помощью spawn. :err, 2 и STDERR указывают на стандартный поток ошибок (stderr).

Значения хэша задают дескриптор файла в родительском процессе, вызывающем spawn. :out, 1 и STDOUT указывают на стандартный поток вывода (stdout).

В приведенном примере стандартный вывод в дочернем процессе не указан. Поэтому он наследуется от родительского процесса.

Стандартный входной поток (stdin) можно указать с помощью :in, 0 и STDIN.

Имя файла можно указать в качестве значения хэша.

pid = spawn(command, :in=>"/dev/null") # read mode
pid = spawn(command, :out=>"/dev/null") # write mode
pid = spawn(command, :err=>"log") # write mode
pid = spawn(command, [:out, :err]=>"/dev/null") # write mode
pid = spawn(command, 3=>"/dev/null") # read mode

Для stdout и stderr (и их комбинации) он открывается в режиме записи. В противном случае используется режим чтения.

Для явного указания флагов и разрешений при создании файла используется массив.

pid = spawn(command, :in=>["file"]) # read mode is assumed
pid = spawn(command, :in=>["file", "r"])
pid = spawn(command, :out=>["log", "w"]) # 0644 assumed
pid = spawn(command, :out=>["log", "w", 0600])
pid = spawn(command, :out=>["log", File::WRONLY|File::EXCL|File::CREAT, 0600])

Массив задаёт имя файла, флаги и разрешения. Флаги могут быть строкой или целым числом. Если флаги опущены или равны nil, предполагается File::RDONLY. Разрешения должны быть целым числом. Если разрешения опущены или равны nil, предполагается 0644.

Если в качестве ключа хэша указан массив объектов IO и целых чисел, все элементы перенаправляются.

# stdout and stderr is redirected to log file.
# The file "log" is opened just once.
pid = spawn(command, [:out, :err]=>["log", "w"])

Другой способ объединения нескольких дескрипторов файлов — [:child, fd]. [:child, fd] означает дескриптор файла в дочернем процессе. Это отличается от fd. Например, :err=>:out означает перенаправление child stderr в родительский stdout. Но :err=>[:child, :out] означает перенаправление child stderr в child stdout. Разница заключается в том, если stdout перенаправлен в дочернем процессе следующим образом.

# stdout and stderr is redirected to log file.
# The file "log" is opened just once.
pid = spawn(command, :out=>["log", "w"], :err=>[:child, :out])

[:child, :out] может использоваться для объединения stderr и stdout в IO.popen. В этом случае IO.popen перенаправляет stdout в канал в дочернем процессе, и [:child, :out] ссылается на перенаправленный stdout.

io = IO.popen(["sh", "-c", "echo out; echo err >&2", :err=>[:child, :out]])
p io.read #=> "out\nerr\n"

Ключ :chdir в options указывает на текущий каталог.

pid = spawn(command, :chdir=>"/var/tmp")

spawn по умолчанию закрывает все нестандартные, не указанные дескрипторы. «Стандартные» дескрипторы — 0, 1 и 2. Это поведение задаётся опцией :close_others. :close_others не влияет на стандартные дескрипторы, которые закрываются только при явном указании :close.

pid = spawn(command, :close_others=>true)  # close 3,4,5,... (default)
pid = spawn(command, :close_others=>false) # don't close 3,4,5,...

:close_others по умолчанию true для spawn и IO.popen.

Обратите внимание, что дескрипторы файлов, для которых установлен флаг close-on-exec, закрываются независимо от опции :close_others.

Таким образом, IO.pipe и spawn могут использоваться как IO.popen.

# similar to r = IO.popen(command)
r, w = IO.pipe
pid = spawn(command, :out=>w)   # r, w is closed in the child process.
w.close

:close указывается как значение хэша для закрытия дескриптора файла индивидуально.

f = open(foo)
system(command, f=>:close)        # don't inherit f.

Если требуется наследование дескриптора файла, можно использовать io=>io.

# valgrind has --log-fd option for log destination.
# log_w=>log_w indicates log_w.fileno inherits to child process.
log_r, log_w = IO.pipe
pid = spawn("valgrind", "--log-fd=#{log_w.fileno}", "echo", "a", log_w=>log_w)
log_w.close
p log_r.read

Также возможно обмен дескрипторами файлов.

pid = spawn(command, :out=>:err, :err=>:out)

Ключи хэша указывают дескрипторы файлов в дочернем процессе. Значения хэша указывают дескрипторы файлов в родительском процессе. Таким образом, вышеприведенное указывает обмен stdout и stderr. Внутренне, spawn использует дополнительный дескриптор файла для разрешения такой циклической сопоставления дескрипторов файлов.

См. Kernel.exec для стандартной оболочки.

times → aProcessTms Показать исходный код
VALUE
rb_proc_times(VALUE obj)
{
    const double hertz = get_clk_tck();
    struct tms buf;
    VALUE utime, stime, cutime, cstime, ret;

    times(&buf);
    utime = DBL2NUM(buf.tms_utime / hertz);
    stime = DBL2NUM(buf.tms_stime / hertz);
    cutime = DBL2NUM(buf.tms_cutime / hertz);
    cstime = DBL2NUM(buf.tms_cstime / hertz);
    ret = rb_struct_new(rb_cProcessTms, utime, stime, cutime, cstime);
    RB_GC_GUARD(utime);
    RB_GC_GUARD(stime);
    RB_GC_GUARD(cutime);
    RB_GC_GUARD(cstime);
    return ret;
}

Возвращает структуру Tms (см. Process::Tms), содержащую время работы процессора в пользовательском режиме и в режиме ядра для данного процесса, а также для дочерних процессов.

t = Process.times
[ t.utime, t.stime, t.cutime, t.cstime ]   #=> [0.0, 0.02, 0.00, 0.00]
uid → fixnum Показать исходный код
Process::UID.rid → fixnum
Process::Sys.getuid → fixnum
static VALUE
proc_getuid(VALUE obj)
{
    rb_uid_t uid = getuid();
    return UIDT2NUM(uid);
}

Возвращает (действительный) идентификатор пользователя этого процесса.

Process.uid   #=> 501
uid= user → numeric Показать исходный код
static VALUE
proc_setuid(VALUE obj, VALUE id)
{
    rb_uid_t uid;

    check_uid_switch();

    uid = OBJ2UID(id);
#if defined(HAVE_SETRESUID)
    if (setresuid(uid, -1, -1) < 0) rb_sys_fail(0);
#elif defined HAVE_SETREUID
    if (setreuid(uid, -1) < 0) rb_sys_fail(0);
#elif defined HAVE_SETRUID
    if (setruid(uid) < 0) rb_sys_fail(0);
#elif defined HAVE_SETUID
    {
        if (geteuid() == uid) {
            if (setuid(uid) < 0) rb_sys_fail(0);
        }
        else {
            rb_notimplement();
        }
    }
#endif
    return id;
}

Устанавливает (пользовательский) идентификатор пользователя для этого процесса. Не доступно на всех платформах.

wait() → fixnum Показать исходный код
wait(pid=-1, flags=0) → fixnum
waitpid(pid=-1, flags=0) → fixnum
static VALUE
proc_wait(int argc, VALUE *argv)
{
    VALUE vpid, vflags;
    rb_pid_t pid;
    int flags, status;

    rb_secure(2);
    flags = 0;
    if (argc == 0) {
        pid = -1;
    }
    else {
        rb_scan_args(argc, argv, "02", &vpid, &vflags);
        pid = NUM2PIDT(vpid);
        if (argc == 2 && !NIL_P(vflags)) {
            flags = NUM2UINT(vflags);
        }
    }
    if ((pid = rb_waitpid(pid, &status, flags)) < 0)
        rb_sys_fail(0);
    if (pid == 0) {
        rb_last_status_clear();
        return Qnil;
    }
    return PIDT2NUM(pid);
}

Ожидает завершения дочернего процесса, возвращает его идентификатор процесса и устанавливает $? в объект Process::Status, содержащий информацию об этом процессе. Какой дочерний процесс ожидать, зависит от значения pid:

> 0

Ожидает дочернего процесса с идентификатором процесса, равным pid.

0

Ожидает любой дочерний процесс, группа процессов которого совпадает с группой процессов вызывающего процесса.

-1

Ожидает любой дочерний процесс (значение по умолчанию, если pid не указан).

< -1

Ожидает любой дочерний процесс, группа процессов которого совпадает с абсолютным значением pid.

Аргумент flags может быть логическим ИЛИ значений флагов Process::WNOHANG (не блокировать, если нет доступных дочерних процессов) или Process::WUNTRACED (возвращать приостановленные дочерние процессы, которые ещё не были сообщены). Не все флаги доступны на всех платформах, но значение нуля будет работать на всех платформах.

Вызов этого метода вызывает SystemCallError, если нет дочерних процессов. Не доступно на всех платформах.

include Process
fork { exit 99 }                 #=> 27429
wait                             #=> 27429
$?.exitstatus                    #=> 99

pid = fork { sleep 3 }           #=> 27440
Time.now                         #=> 2008-03-08 19:56:16 +0900
waitpid(pid, Process::WNOHANG)   #=> nil
Time.now                         #=> 2008-03-08 19:56:16 +0900
waitpid(pid, 0)                  #=> 27440
Time.now                         #=> 2008-03-08 19:56:19 +0900
wait2(pid=-1, flags=0) → [pid, status] Показать исходный код
static VALUE
proc_wait2(int argc, VALUE *argv)
{
    VALUE pid = proc_wait(argc, argv);
    if (NIL_P(pid)) return Qnil;
    return rb_assoc_new(pid, rb_last_status_get());
}

Ожидает завершения дочернего процесса (см. ::waitpid для точного смысла) и возвращает массив, содержащий идентификатор процесса и код завершения (объект Process::Status) этого дочернего процесса. Вызывает SystemCallError, если нет дочерних процессов.

Process.fork { exit 99 }   #=> 27437
pid, status = Process.wait2
pid                        #=> 27437
status.exitstatus          #=> 99
waitall → [ [pid1,status1], ...] Показать исходный код
static VALUE
proc_waitall(void)
{
    VALUE result;
    rb_pid_t pid;
    int status;

    rb_secure(2);
    result = rb_ary_new();
#ifdef NO_WAITPID
    if (pid_tbl) {
        st_foreach(pid_tbl, waitall_each, result);
    }
#else
    rb_last_status_clear();
#endif

    for (pid = -1;;) {
#ifdef NO_WAITPID
        pid = wait(&status);
#else
        pid = rb_waitpid(-1, &status, 0);
#endif
        if (pid == -1) {
            if (errno == ECHILD)
                break;
#ifdef NO_WAITPID
            if (errno == EINTR) {
                rb_thread_schedule();
                continue;
            }
#endif
            rb_sys_fail(0);
        }
#ifdef NO_WAITPID
        rb_last_status_set(status, pid);
#endif
        rb_ary_push(result, rb_assoc_new(PIDT2NUM(pid), rb_last_status_get()));
    }
    return result;
}

Ожидает всех дочерних процессов, возвращая массив пар pid/status (где status — объект Process::Status).

fork { sleep 0.2; exit 2 }   #=> 27432
fork { sleep 0.1; exit 1 }   #=> 27433
fork {            exit 0 }   #=> 27434
p Process.waitall

производит:

[[30982, #<Process::Status: pid 30982 exit 0>],
 [30979, #<Process::Status: pid 30979 exit 1>],
 [30976, #<Process::Status: pid 30976 exit 2>]]
waitpid(pid=-1, flags=0) → fixnum Показать исходный код
static VALUE
proc_wait(int argc, VALUE *argv)
{
    VALUE vpid, vflags;
    rb_pid_t pid;
    int flags, status;

    rb_secure(2);
    flags = 0;
    if (argc == 0) {
        pid = -1;
    }
    else {
        rb_scan_args(argc, argv, "02", &vpid, &vflags);
        pid = NUM2PIDT(vpid);
        if (argc == 2 && !NIL_P(vflags)) {
            flags = NUM2UINT(vflags);
        }
    }
    if ((pid = rb_waitpid(pid, &status, flags)) < 0)
        rb_sys_fail(0);
    if (pid == 0) {
        rb_last_status_clear();
        return Qnil;
    }
    return PIDT2NUM(pid);
}

Ожидает завершения дочернего процесса, возвращает его идентификатор процесса и устанавливает $? в объект Process::Status, содержащий информацию об этом процессе. Какой дочерний процесс ожидать, зависит от значения pid:

> 0

Ожидает дочерний процесс с идентификатором процесса, равным pid.

0

Ожидает любой дочерний процесс, группа процессов которого совпадает с группой процессов вызывающего процесса.

-1

Ожидает любой дочерний процесс (значение по умолчанию, если pid не указан).

< -1

Ожидает любой дочерний процесс, группа процессов которого совпадает с абсолютным значением pid.

Аргумент flags может быть логическим ИЛИ значений флагов Process::WNOHANG (не блокировать, если нет доступных дочерних процессов) или Process::WUNTRACED (возвращать приостановленные дочерние процессы, которые ещё не были сообщены). Не все флаги доступны на всех платформах, но значение нуля будет работать на всех платформах.

Вызов этого метода вызывает SystemCallError, если нет дочерних процессов. Не доступно на всех платформах.

include Process
fork { exit 99 }                 #=> 27429
wait                             #=> 27429
$?.exitstatus                    #=> 99

pid = fork { sleep 3 }           #=> 27440
Time.now                         #=> 2008-03-08 19:56:16 +0900
waitpid(pid, Process::WNOHANG)   #=> nil
Time.now                         #=> 2008-03-08 19:56:16 +0900
waitpid(pid, 0)                  #=> 27440
Time.now                         #=> 2008-03-08 19:56:19 +0900
waitpid2(pid=-1, flags=0) → [pid, status] Показать исходный код
static VALUE
proc_wait2(int argc, VALUE *argv)
{
    VALUE pid = proc_wait(argc, argv);
    if (NIL_P(pid)) return Qnil;
    return rb_assoc_new(pid, rb_last_status_get());
}

Ожидает завершения дочернего процесса (см. ::waitpid для точного смысла) и возвращает массив, содержащий идентификатор процесса и код завершения (объект Process::Status ) этого дочернего процесса. Вызывает SystemCallError, если нет дочерних процессов.

Process.fork { exit 99 }   #=> 27437
pid, status = Process.wait2
pid                        #=> 27437
status.exitstatus          #=> 99

Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API