модуль Process
Модуль Process представляет собой набор методов для управления процессами.
Константы
- CLOCK_BOOTTIME
- CLOCK_BOOTTIME_ALARM
- CLOCK_MONOTONIC
- CLOCK_MONOTONIC_COARSE
- CLOCK_MONOTONIC_FAST
- CLOCK_MONOTONIC_PRECISE
- CLOCK_MONOTONIC_RAW
- CLOCK_MONOTONIC_RAW_APPROX
- CLOCK_PROCESS_CPUTIME_ID
- CLOCK_PROF
- CLOCK_REALTIME
- CLOCK_REALTIME_ALARM
- CLOCK_REALTIME_COARSE
- CLOCK_REALTIME_FAST
- CLOCK_REALTIME_PRECISE
- CLOCK_SECOND
- CLOCK_TAI
- CLOCK_THREAD_CPUTIME_ID
- CLOCK_UPTIME
- CLOCK_UPTIME_FAST
- CLOCK_UPTIME_PRECISE
- CLOCK_UPTIME_RAW
- CLOCK_UPTIME_RAW_APPROX
- CLOCK_VIRTUAL
- PRIO_PGRP
- PRIO_PROCESS
- PRIO_USER
- 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_NPTS
-
Максимальное количество псевдотерминалов, которые могут быть созданы для реального идентификатора пользователя вызывающего процесса.
Подробности см. в руководстве системы 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
- RLIM_SAVED_CUR
- RLIM_SAVED_MAX
- WNOHANG
-
см.
Process.wait - WUNTRACED
-
см.
Process.wait
Методы публичного класса
VALUE
rb_proc__fork(VALUE _obj)
{
rb_pid_t pid = proc_fork_pid();
return PIDT2NUM(pid);
} Внутренний API для fork. Не вызывайте этот метод напрямую. В настоящее время он вызывается через Kernel#fork, Process.fork и IO.popen со значением "-".
Этот метод предназначен не для обычного кода, а для библиотек мониторинга приложений. Вы можете добавить пользовательский код до и после событий fork, переопределяя этот метод.
Примечание: Process.daemon может быть реализован с помощью fork(2), НО не проходит через этот метод. Таким образом, в зависимости от вашей цели подключения к этому методу, вы также можете подключиться к этому методу. Более подробное обсуждение этого вопроса см. в этой проблеме.
static VALUE
f_abort(int c, const VALUE *a, VALUE _)
{
rb_f_abort(c, a);
UNREACHABLE_RETURN(Qnil);
} Немедленно завершить выполнение, фактически вызвав Kernel.exit(false). Если msg задан, он выводится в STDERR перед завершением.
static VALUE
proc_argv0(VALUE process)
{
return rb_orig_progname;
} Возвращает имя выполняемого скрипта. Значение не изменяется при присвоении нового значения переменной $0.
Этот метод впервые появился в Ruby 2.1, чтобы служить средством получения имени скрипта, не зависящим от глобальных переменных.
static VALUE
rb_clock_getres(int argc, VALUE *argv, VALUE _)
{
int ret;
struct timetick tt;
timetick_int_t numerators[2];
timetick_int_t denominators[2];
int num_numerators = 0;
int num_denominators = 0;
clockid_t c;
VALUE unit = (rb_check_arity(argc, 1, 2) == 2) ? argv[1] : Qnil;
VALUE clk_id = argv[0];
if (SYMBOL_P(clk_id)) {
#ifdef CLOCK_REALTIME
if (clk_id == RUBY_CLOCK_REALTIME) {
c = CLOCK_REALTIME;
goto getres;
}
#endif
#ifdef CLOCK_MONOTONIC
if (clk_id == RUBY_CLOCK_MONOTONIC) {
c = CLOCK_MONOTONIC;
goto getres;
}
#endif
#ifdef CLOCK_PROCESS_CPUTIME_ID
if (clk_id == RUBY_CLOCK_PROCESS_CPUTIME_ID) {
c = CLOCK_PROCESS_CPUTIME_ID;
goto getres;
}
#endif
#ifdef CLOCK_THREAD_CPUTIME_ID
if (clk_id == RUBY_CLOCK_THREAD_CPUTIME_ID) {
c = CLOCK_THREAD_CPUTIME_ID;
goto getres;
}
#endif
#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) {
const 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 (NUMERIC_CLOCKID) {
#if defined(HAVE_CLOCK_GETRES)
struct timespec ts;
c = NUM2CLOCKID(clk_id);
getres:
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. */
rb_syserr_fail(EINVAL, 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);
}
} Возвращает оценку разрешения clock_id с использованием функции POSIX clock_getres().
Обратите внимание, что указанное разрешение часто неточно на большинстве платформ из-за ошибок в этой функции, и поэтому указанное разрешение часто отличается от фактического разрешения часов на практике. Неточное указанное разрешение было замечено для различных часов, включая CLOCK_MONOTONIC и CLOCK_MONOTONIC_RAW при использовании платформ Linux, macOS, BSD или AIX, при использовании процессоров ARM или при использовании виртуализации.
clock_id задает тип часов. Подробности см. в документации Process.clock_gettime. clock_id может быть символом, как в Process.clock_gettime.
Если заданный 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
static VALUE
rb_clock_gettime(int argc, VALUE *argv, VALUE _)
{
int ret;
struct timetick tt;
timetick_int_t numerators[2];
timetick_int_t denominators[2];
int num_numerators = 0;
int num_denominators = 0;
VALUE unit = (rb_check_arity(argc, 1, 2) == 2) ? argv[1] : Qnil;
VALUE clk_id = argv[0];
clockid_t c;
if (SYMBOL_P(clk_id)) {
#ifdef CLOCK_REALTIME
if (clk_id == RUBY_CLOCK_REALTIME) {
c = CLOCK_REALTIME;
goto gettime;
}
#endif
#ifdef CLOCK_MONOTONIC
if (clk_id == RUBY_CLOCK_MONOTONIC) {
c = CLOCK_MONOTONIC;
goto gettime;
}
#endif
#ifdef CLOCK_PROCESS_CPUTIME_ID
if (clk_id == RUBY_CLOCK_PROCESS_CPUTIME_ID) {
c = CLOCK_PROCESS_CPUTIME_ID;
goto gettime;
}
#endif
#ifdef CLOCK_THREAD_CPUTIME_ID
if (clk_id == RUBY_CLOCK_THREAD_CPUTIME_ID) {
c = CLOCK_THREAD_CPUTIME_ID;
goto gettime;
}
#endif
/*
* Non-clock_gettime clocks are provided by symbol clk_id.
*/
#ifdef HAVE_GETTIMEOFDAY
/*
* 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;
}
#endif
#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__
if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
const 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 (NUMERIC_CLOCKID) {
#if defined(HAVE_CLOCK_GETTIME)
struct timespec ts;
c = NUM2CLOCKID(clk_id);
gettime:
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. */
rb_syserr_fail(EINVAL, 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, macOS 10.12, Windows-8/Server-2012
-
CLOCK_MONOTONIC -
SUSv3–4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 3.4, macOS 10.12, Windows-2000
-
CLOCK_PROCESS_CPUTIME_ID -
SUSv3–4, Linux 2.5.63, FreeBSD 9.3, OpenBSD 5.4, macOS 10.12
-
CLOCK_THREAD_CPUTIME_ID -
SUSv3–4, Linux 2.5.63, FreeBSD 7.1, OpenBSD 5.4, macOS 10.12
-
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, macOS 10.12
-
CLOCK_MONOTONIC_RAW_APPROX -
macOS 10.12
-
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_RAW -
macOS 10.12
-
CLOCK_UPTIME_RAW_APPROX -
macOS 10.12
-
CLOCK_UPTIME_PRECISE -
FreeBSD 8.1
-
CLOCK_SECOND -
FreeBSD 8.1
-
CLOCK_TAI -
Linux 3.10
Обратите внимание, что 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, и clock_t — 32-битовое целое, разрешение составляет 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. Если требуется точное значение наносекунд, используйте :nanosecond в качестве unit.
Начало отсчёта (ноль) возвращаемого значения варьируется. Например, время запуска системы, время запуска процесса, эпоха и т. д.
Начало отсчёта в CLOCK_REALTIME определяется как эпоха (01.01.1970 00:00:00 UTC). Однако некоторые системы учитывают високосные секунды, а другие — нет. Поэтому результат может интерпретироваться по-разному на разных системах. Рекомендуется использовать Time.now вместо CLOCK_REALTIME.
static VALUE
proc_daemon(int argc, VALUE *argv, VALUE _)
{
int n, nochdir = FALSE, noclose = FALSE;
switch (rb_check_arity(argc, 0, 2)) {
case 2: noclose = TO_BOOL(argv[1], "noclose");
case 1: nochdir = TO_BOOL(argv[0], "nochdir");
}
prefork();
n = rb_daemon(nochdir, noclose);
if (n < 0) rb_sys_fail("daemon");
return INT2FIX(n);
} Отсоединить процесс от управляющего терминала и запустить в фоновом режиме в качестве системного демона. Если аргумент nochdir имеет значение true (т. е. не false), он меняет текущий рабочий каталог на корневой каталог («/»). Если аргумент noclose имеет значение true, daemon() перенаправит стандартный ввод, стандартный вывод и стандартную ошибку в /dev/null. Возвращает ноль при успехе или возбуждает одну из исключений Errno::*.
static VALUE
proc_detach(VALUE obj, VALUE pid)
{
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}")
(не выводит ничего)
static VALUE
proc_getegid(VALUE obj)
{
rb_gid_t egid = getegid();
return GIDT2NUM(egid);
} Возвращает эффективную группу ID для данного процесса. Не доступно на всех платформах.
Process.egid #=> 500
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;
} Устанавливает эффективную группу ID для данного процесса. Не доступно на всех платформах.
static VALUE
proc_geteuid(VALUE obj)
{
rb_uid_t euid = geteuid();
return UIDT2NUM(euid);
} Возвращает эффективный идентификатор пользователя для данного процесса.
Process.euid #=> 501
static VALUE
proc_seteuid_m(VALUE mod, VALUE euid)
{
check_uid_switch();
proc_seteuid(OBJ2UID(euid));
return euid;
} Устанавливает эффективный идентификатор пользователя для данного процесса. Не доступно на всех платформах.
static VALUE
f_exec(int c, const VALUE *a, VALUE _)
{
rb_f_exec(c, a);
UNREACHABLE_RETURN(Qnil);
} Заменяет текущий процесс запуском указанной внешней команды, которая может иметь один из следующих форматов:
-
exec(commandline) -
строка командной строки, которая передаётся стандартной оболочке
-
exec(cmdname, arg1, ...) -
имя команды и один или несколько аргументов (без оболочки)
-
exec([cmdname, argv0], arg1, ...) -
имя команды,
argv[0]и ноль или более аргументов (без оболочки)
В первом формате строка воспринимается как командная строка, которая подвергается расширению оболочки перед выполнением.
Стандартная оболочка всегда означает "/bin/sh" в Unix-подобных системах, в противном случае ENV["RUBYSHELL"] или ENV["COMSPEC"] в Windows и подобных системах. Команда передаётся в качестве аргумента ключу "-c" оболочки, за исключением случаев COMSPEC.
Если строка из первого формата (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
static VALUE
f_exit(int c, const VALUE *a, VALUE _)
{
rb_f_exit(c, a);
UNREACHABLE_RETURN(Qnil);
} Инициирует завершение скрипта 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
static VALUE
rb_f_exit_bang(int argc, VALUE *argv, VALUE obj)
{
int istatus;
if (rb_check_arity(argc, 0, 1) == 1) {
istatus = exit_status_code(argv[0]);
}
else {
istatus = EXIT_FAILURE;
}
_exit(istatus);
UNREACHABLE_RETURN(Qnil);
} Немедленно завершает процесс. Обработчики завершения не выполняются. status возвращается в базовую систему как код завершения.
Process.exit!(true)
static VALUE
rb_f_fork(VALUE obj)
{
rb_pid_t pid;
pid = rb_call_proc__fork();
if (pid == 0) {
if (rb_block_given_p()) {
int status;
rb_protect(rb_yield, Qundef, &status);
ruby_stop(status);
}
return Qnil;
}
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().
static VALUE
proc_getpgid(VALUE obj, VALUE pid)
{
rb_pid_t i;
i = getpgid(NUM2PIDT(pid));
if (i < 0) rb_sys_fail(0);
return PIDT2NUM(i);
} Возвращает идентификатор группы процессов для данного идентификатора процесса. Не доступно на всех платформах.
Process.getpgid(Process.ppid()) #=> 25527
static VALUE
proc_getpgrp(VALUE _)
{
rb_pid_t pgrp;
#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
static VALUE
proc_getpriority(VALUE obj, VALUE which, VALUE who)
{
int prio, iwhich, iwho;
iwhich = NUM2INT(which);
iwho = NUM2INT(who);
errno = 0;
prio = getpriority(iwhich, iwho);
if (errno) rb_sys_fail(0);
return INT2FIX(prio);
} Получает приоритет планирования для указанного процесса, группы процессов или пользователя. вид указывает тип сущности для поиска: один из Process::PRIO_PGRP, Process::PRIO_USER или Process::PRIO_PROCESS. целое число — идентификатор, указывающий конкретный процесс, группу процессов или пользователя (идентификатор 0 означает текущий). Более низкие приоритеты предпочтительнее для планирования. Не доступно на всех платформах.
Process.getpriority(Process::PRIO_USER, 0) #=> 19 Process.getpriority(Process::PRIO_PROCESS, 0) #=> 19
static VALUE
proc_getrlimit(VALUE obj, VALUE resource)
{
struct rlimit rlim;
if (getrlimit(rlimit_resource_type(resource), &rlim) < 0) {
rb_sys_fail("getrlimit");
}
return rb_assoc_new(RLIM2NUM(rlim.rlim_cur), RLIM2NUM(rlim.rlim_max));
} Получает ограничение ресурса процесса. текущее_ограничение означает текущее (мягкое) ограничение, а максимальное_ограничение — максимальное (жёсткое) ограничение.
ресурс указывает тип ресурса, подлежащего ограничению. Он задаётся как символ, например :CORE, строка, например "CORE", или константа, например Process::RLIMIT_CORE. Подробнее см. Process.setrlimit.
текущее_ограничение и максимальное_ограничение могут быть Process::RLIM_INFINITY, Process::RLIM_SAVED_MAX или Process::RLIM_SAVED_CUR. Подробнее см. Process.setrlimit и системную справку getrlimit(2).
static VALUE
proc_getsid(int argc, VALUE *argv, VALUE _)
{
rb_pid_t sid;
rb_pid_t pid = 0;
if (rb_check_arity(argc, 0, 1) == 1 && !NIL_P(argv[0]))
pid = NUM2PIDT(argv[0]);
sid = getsid(pid);
if (sid < 0) rb_sys_fail(0);
return PIDT2NUM(sid);
} Возвращает идентификатор сессии для данного идентификатора процесса. Если не задан, возвращает идентификатор сессии текущего процесса. Не доступно на всех платформах.
Process.getsid() #=> 27422 Process.getsid(0) #=> 27422 Process.getsid(Process.pid()) #=> 27422
static VALUE
proc_getgid(VALUE obj)
{
rb_gid_t gid = getgid();
return GIDT2NUM(gid);
} Возвращает (действительный) идентификатор группы для данного процесса.
Process.gid #=> 500
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);
} Устанавливает идентификатор группы для данного процесса.
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]
Обратите внимание, что этот метод является просто обёрткой над getgroups(2). Это означает, что следующие характеристики результата полностью зависят от вашей системы:
-
результат отсортирован
-
результат включает эффективные идентификаторы групп
-
результат не содержит дублированных идентификаторов групп
-
размер результата не превышает значение
Process.maxgroups
Вы можете получить отсортированный уникальный GID список текущего процесса следующим выражением:
Process.groups.uniq.sort
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);
} Set список дополнительных групп доступа на заданный 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]
static VALUE
proc_initgroups(VALUE obj, VALUE uname, VALUE base_grp)
{
if (initgroups(StringValueCStr(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]
static VALUE
proc_rb_f_kill(int c, const VALUE *v, VALUE _)
{
return rb_f_kill(c, v);
} Отправляет заданный сигнал указанному(ым) идентификатору(ам) процесса, если pid положительно. Если pid равно нулю, сигнал отправляется всем процессам, идентификатор группы которых равен идентификатору группы процесса. Если pid отрицательно, результаты зависят от операционной системы. сигнал может быть целым номером сигнала или именем POSIX-сигнала (с префиксом SIG или без него). Если сигнал отрицательный (или начинается с минуса), отправляет сигнал группам процессов вместо процессов. Не все сигналы доступны на всех платформах. Ключи и значения Signal.list — известные имена и номера сигналов соответственно.
pid = fork do
Signal.trap("HUP") { puts "Ouch!"; exit }
# ... do some work ...
end
# ...
Process.kill("HUP", pid)
Process.wait
результат:
Ouch!
Если сигнал — целое число, но неверный для сигнала, будет поднято Errno::EINVAL или RangeError. Иначе, если сигнал — не String или Symbol и известное имя сигнала, будет поднято ArgumentError.
Также, Errno::ESRCH или RangeError для неверного pid, Errno::EPERM при неудачной отправке из-за отсутствия привилегий, будут подняты. В этих случаях сигналы могут быть отправлены предшествующим процессам.
static VALUE
proc_s_last_status(VALUE mod)
{
return rb_last_status_get();
} Возвращает статус последнего выполненного дочернего процесса в текущей потоке.
Process.wait Process.spawn("ruby", "-e", "exit 13")
Process.last_status #=> #<Process::Status: pid 4825 exit 13>
Если в текущей потоке дочерние процессы никогда не выполнялись, возвращается nil.
Process.last_status #=> nil
static VALUE
proc_getmaxgroups(VALUE obj)
{
return INT2FIX(maxgroups());
} Возвращает максимальное количество идентификаторов групп, разрешённых в списке дополнительных групп доступа.
Process.maxgroups #=> 32
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 should 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);
} Устанавливает максимальное количество идентификаторов групп, разрешённых в списке дополнительных групп доступа.
static VALUE
proc_get_pid(VALUE _)
{
return get_pid();
} Возвращает идентификатор процесса для данного процесса. Не доступно на всех платформах.
Process.pid #=> 27415
static VALUE
proc_get_ppid(VALUE _)
{
return get_ppid();
} Возвращает идентификатор процесса родительского процесса. Возвращает ненадежное значение на Win32/64. Не доступно на всех платформах.
puts "I am #{Process.pid}"
Process.fork { puts "Dad is #{Process.ppid}" }
результат:
I am 27417 Dad is 27417
static VALUE
proc_setpgid(VALUE obj, VALUE pid, VALUE pgrp)
{
rb_pid_t ipid, ipgrp;
ipid = NUM2PIDT(pid);
ipgrp = NUM2PIDT(pgrp);
if (setpgid(ipid, ipgrp) < 0) rb_sys_fail(0);
return INT2FIX(0);
} Устанавливает идентификатор группы процессов для pid (0 — для текущего процесса) на целое число. Не доступно на всех платформах.
static VALUE
proc_setpgrp(VALUE _)
{
/* 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). Не доступно на всех платформах.
static VALUE
proc_setpriority(VALUE obj, VALUE which, VALUE who, VALUE prio)
{
int iwhich, iwho, iprio;
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
static VALUE
proc_setproctitle(VALUE process, VALUE title)
{
return ruby_setproctitle(title);
} Устанавливает заголовок процесса, отображаемый в команде ps(1). Возможно неэффективно на всех платформах. Не будет генерировать исключений независимо от результата, а также NotImplementedError не будет генерироваться, даже если платформа не поддерживает эту функцию.
Вызов этого метода не влияет на значение $0.
Process.setproctitle('myapp: worker #%d' % worker_id)
Этот метод появился в Ruby 2.1 как способ изменения заголовка процесса без использования глобальных переменных.
static VALUE
proc_setrlimit(int argc, VALUE *argv, VALUE obj)
{
VALUE resource, rlim_cur, rlim_max;
struct rlimit rlim;
rb_check_arity(argc, 2, 3);
resource = argv[0];
rlim_cur = argv[1];
if (argc < 3 || NIL_P(rlim_max = argv[2]))
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)
- NPTS
-
количество псевдотерминалов (число) (FreeBSD)
- 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])
static VALUE
proc_setsid(VALUE _)
{
rb_pid_t pid;
pid = setsid();
if (pid < 0) rb_sys_fail(0);
return PIDT2NUM(pid);
} Устанавливает этот процесс как лидера новой сессии и группы процессов без контролируемого tty. Возвращает идентификатор сессии. Не доступно на всех платформах.
Process.setsid #=> 27422
static VALUE
rb_f_spawn(int argc, VALUE *argv, VALUE _)
{
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, FALSE);
eargp = rb_execarg_get(execarg_obj);
fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
pid = rb_execarg_spawn(execarg_obj, errmsg, sizeof(errmsg));
if (pid == -1) {
int err = errno;
rb_exec_fail(eargp, err, errmsg);
RB_GC_GUARD(execarg_obj);
rb_syserr_fail_str(err, fail_str);
}
#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
return PIDT2NUM(pid);
#else
return Qnil;
#endif
} spawn выполняет указанную команду и возвращает её pid.
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
the keys and the values except for +nil+ must be strings.
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 the 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 => false : inherit
current directory:
:chdir => str Форма cmdname, arg1, ... не использует оболочку. Однако на разных ОС разные вещи предоставляются в качестве встроенных команд. Примером является `echo`, который является встроенной командой в Windows, но обычной программой в Linux и Mac OS X. Это означает, что Process.spawn 'echo', '%Path%' отобразит содержимое переменной среды %Path% в Windows, но Process.spawn 'echo', '$PATH' выведет строку $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, ноль, положительным целым числом или nil. true и ноль заставляют процесс стать лидером процесса новой группы. Положительное целое число, отличное от нуля, заставляет процесс присоединиться к указанной группе процессов. Значение по умолчанию, nil, заставляет процесс остаться в той же группе процессов.
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 для Process.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.
Если в качестве ключа хэша указан массив IOs и целых чисел, все элементы перенаправляются.
# 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 означает перенаправление stderr дочернего процесса на stdout родительского процесса. А :err=>[:child, :out] означает перенаправление stderr дочернего процесса на 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 по умолчанию равен false для 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 для стандартной оболочки.
VALUE
rb_proc_times(VALUE obj)
{
VALUE utime, stime, cutime, cstime, ret;
#if defined(RUSAGE_SELF) && defined(RUSAGE_CHILDREN)
struct rusage usage_s, usage_c;
if (getrusage(RUSAGE_SELF, &usage_s) != 0 || getrusage(RUSAGE_CHILDREN, &usage_c) != 0)
rb_sys_fail("getrusage");
utime = DBL2NUM((double)usage_s.ru_utime.tv_sec + (double)usage_s.ru_utime.tv_usec/1e6);
stime = DBL2NUM((double)usage_s.ru_stime.tv_sec + (double)usage_s.ru_stime.tv_usec/1e6);
cutime = DBL2NUM((double)usage_c.ru_utime.tv_sec + (double)usage_c.ru_utime.tv_usec/1e6);
cstime = DBL2NUM((double)usage_c.ru_stime.tv_sec + (double)usage_c.ru_stime.tv_usec/1e6);
#else
const double hertz = (double)get_clk_tck();
struct tms buf;
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);
#endif
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]
static VALUE
proc_getuid(VALUE obj)
{
rb_uid_t uid = getuid();
return UIDT2NUM(uid);
} Возвращает (действительный) идентификатор пользователя этого процесса.
Process.uid #=> 501
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;
} Устанавливает (пользовательский) идентификатор пользователя для данного процесса. Не доступен на всех платформах.
static VALUE
proc_m_wait(int c, VALUE *v, VALUE _)
{
return proc_wait(c, v);
} Ожидает завершения дочернего процесса, возвращает его идентификатор и устанавливает $? в объект Process::Status, содержащий информацию об этом процессе. Какой дочерний процесс ожидать, зависит от значения pid:
- > 0
-
Ожидает дочерний процесс с идентификатором, равным pid.
- 0
-
Ожидает любой дочерний процесс, группа которого совпадает с группой вызывающего процесса.
- -1
-
Ожидает любой дочерний процесс (по умолчанию, если pid не указан).
- < -1
-
Ожидает любой дочерний процесс, группа которого совпадает с абсолютным значением pid.
Аргумент flags может быть логическим ИЛИ значений флагов Process::WNOHANG (не блокировать, если нет доступных дочерних процессов) или Process::WUNTRACED (возвращать приостановленные дочерние процессы, которые не были сообщены). Не все флаги доступны на всех платформах, но значение флага 0 будет работать на всех платформах.
Вызов этого метода вызывает 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
static VALUE
proc_wait2(int argc, VALUE *argv, VALUE _)
{
VALUE pid = proc_wait(argc, argv);
if (NIL_P(pid)) return Qnil;
return rb_assoc_new(pid, rb_last_status_get());
} Ожидает завершения дочернего процесса (см. Process::waitpid для точных семантик) и возвращает массив, содержащий идентификатор процесса и код завершения (объект Process::Status) этого дочернего процесса. Вызывает исключение SystemCallError, если нет дочерних процессов.
Process.fork { exit 99 } #=> 27437
pid, status = Process.wait2
pid #=> 27437
status.exitstatus #=> 99
static VALUE
proc_waitall(VALUE _)
{
VALUE result;
rb_pid_t pid;
int status;
result = rb_ary_new();
rb_last_status_clear();
for (pid = -1;;) {
pid = rb_waitpid(-1, &status, 0);
if (pid == -1) {
int e = errno;
if (e == ECHILD)
break;
rb_syserr_fail(e, 0);
}
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>]]
static VALUE
proc_m_wait(int c, VALUE *v, VALUE _)
{
return proc_wait(c, v);
} Ожидает завершения дочернего процесса, возвращает его идентификатор процесса и устанавливает $? в объект 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
static VALUE
proc_wait2(int argc, VALUE *argv, VALUE _)
{
VALUE pid = proc_wait(argc, argv);
if (NIL_P(pid)) return Qnil;
return rb_assoc_new(pid, rb_last_status_get());
} Ожидает завершения дочернего процесса (см. Process::waitpid для точных семантик) и возвращает массив, содержащий идентификатор процесса и код завершения (объект Process::Status) этого дочернего процесса. Вызывает исключение SystemCallError, если нет дочерних процессов.
Process.fork { exit 99 } #=> 27437
pid, status = Process.wait2
pid #=> 27437
status.exitstatus #=> 99
Ruby Core © 1993–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.