非常教程

Ruby 2.4参考手册

过程 | 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_THREAD_CPUTIME_ID CLOCK_UPTIME CLOCK_UPTIME_FAST CLOCK_UPTIME_PRECISE CLOCK_UPTIME_RAW CLOCK_UPTIME_RAW_APPROX CLOCK_VIRTUAL PRIO_PGRP

see ::setpriority

PRIO_PROCESS

see ::setpriority

PRIO_USER

see ::setpriority

RLIMIT_AS

进程的虚拟内存(地址空间)的最大大小(以字节为单位)。

有关详细信息,请参阅系统getrlimit(2)手册。

RLIMIT_CORE

核心文件的最大大小。

有关详细信息,请参阅系统getrlimit(2)手册。

RLIMIT_CPU

以秒为单位的CPU时间限制。

有关详细信息,请参阅系统getrlimit(2)手册。

RLIMIT_DATA

进程数据段的最大大小。

有关详细信息,请参阅系统getrlimit(2)手册。

RLIMIT_FSIZE

该进程可能创建的文件的最大大小。

有关详细信息,请参阅系统getrlimit(2)手册。

RLIMIT_MEMLOCK

可以锁定到RAM的最大内存字节数。

有关详细信息,请参阅系统getrlimit(2)手册。

RLIMIT_MSGQUEUE

指定可为调用进程的实际用户标识分配给POSIX消息队列的字节数限制。

有关详细信息,请参阅系统getrlimit(2)手册。

RLIMIT_NICE

指定可以引发进程的良好值的上限。

有关详细信息,请参阅系统getrlimit(2)手册。

RLIMIT_NOFILE

指定一个大于此进程可以打开的最大文件描述符编号的值。

有关详细信息,请参阅系统getrlimit(2)手册。

RLIMIT_NPROC

可以为调用进程的实际用户标识创建的最大进程数。

有关详细信息,请参阅系统getrlimit(2)手册。

RLIMIT_RSS

指定进程驻留集的限制(以页为单位)。

有关详细信息,请参阅系统getrlimit(2)手册。

RLIMIT_RTPRIO

指定可为此过程设置的实时优先级的上限。

有关详细信息,请参阅系统getrlimit(2)手册。

RLIMIT_RTTIME

指定此进程在实时调度策略下可以使用的CPU时间限制。

有关详细信息,请参阅系统getrlimit(2)手册。

RLIMIT_SBSIZE

套接字缓冲区的最大大小。

RLIMIT_SIGPENDING

指定可能为调用进程的实际用户标识排队的信号数量的限制。

有关详细信息,请参阅系统getrlimit(2)手册。

RLIMIT_STACK

堆栈的最大大小(以字节为单位)。

有关详细信息,请参阅系统getrlimit(2)手册。

RLIM_INFINITY

see ::setrlimit

RLIM_SAVED_CUR

see ::setrlimit

RLIM_SAVED_MAX

see ::setrlimit

WNOHANG

see ::wait

WUNTRACED

see ::wait

公共类方法

abort Show source

Kernel::abort(msg)

abort(msg)

通过调用立即终止执行Kernel.exit(false)。如果给出msg,则在终止之前将其写入STDERR。

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;
}

argv0 → frozen_string Show source

返回正在执行的脚本的名称。将值赋给$ 0不会影响该值。

这个方法首先出现在Ruby 2.1中,作为一个全局变量的免费手段来获取脚本名称。

static VALUE
proc_argv0(VALUE process)
{
    return rb_orig_progname;
}

clock_getres(clock_id , unit) → number Show source

返回由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接受unitProcess.clock_gettime。默认值,:float_second也与Process.clock_gettime。相同。

Process.clock_getres也接受:hertzunit:hertz意味着...的倒数:float_second

:hertz 可用于获取times()函数的每秒时钟滴答的精确值和clock()函数的CLOCKS_PER_SEC的确切值。

+Process.clock_getres(:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz)+ returns the clock ticks per second.

+Process.clock_getres(:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz)+ returns CLOCKS_PER_SEC.

p Process.clock_getres(Process::CLOCK_MONOTONIC)
#=> 1.0e-09
VALUE
rb_clock_getres(int argc, VALUE *argv)
{
    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];

    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. */
    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_gettime(clock_id , unit) → number Show source

返回由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 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 2.1, macOS 10.12

CLOCK_MONOTONIC

SUSv3 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 3.4, macOS 10.12

CLOCK_PROCESS_CPUTIME_ID

SUSv3 to 4, Linux 2.5.63, OpenBSD 5.4, macOS 10.12

CLOCK_THREAD_CPUTIME_ID

SUSv3 to 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

请注意,SUS代表单一Unix规范。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

使用由SUS定义的gettimeofday()。(虽然SUSv4已经过时了。)分辨率为1微秒。

:TIME_BASED_CLOCK_REALTIME

使用ISO C定义的时间()。分辨率为1秒。

适用于CLOCK_MONOTONIC

:MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC

使用mach_absolute_time(),在达尔文上可用。分辨率与CPU相关。

:TIMES_BASED_CLOCK_MONOTONIC

使用POSIX定义的times()的结果值。POSIX将其定义为“times()”应该以时钟滴答的形式返回过去的实时,因为过去的任意点(例如,系统启动时间)“。例如,GNU / Linux返回一个基于jiffies的值,它是单调的。但是,4.4BSD使用gettimeofday()并且它不是单调的。(不过FreeBSD使用:: clock_gettime(CLOCK_MONOTONIC))。分辨率是时钟节拍。“getconf CLK_TCK”命令显示每秒的时钟滴答。(每秒钟的时钟周期由旧系统中的HZ宏定义)。如果它是100,clock_t是32位整数类型,则分辨率为10毫秒,并且不能超过497天。

Emulations for CLOCK_PROCESS_CPUTIME_ID:

:GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID

使用由SUS定义的getrusage()。getrusage()与RUSAGE_SELF一起使用以获取仅用于调用进程的时间(不包括子进程的时间)。结果是添加了用户时间(ru_utime)和系统时间(ru_stime)。分辨率是1微秒。

:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID

使用POSIX定义的times()。结果是添加了用户时间(tms_utime)和系统时间(tms_stime)。tms_cutime和tms_cstime被忽略以排除子进程的时间。分辨率是时钟滴答。“getconf CLK_TCK”命令显示每秒的时钟滴答。(每秒钟的时钟周期由旧系统中的HZ宏定义)。如果是100,则分辨率为10毫秒。

:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID

使用由ISO C定义的clock()。分辨率为1 / CLOCKS_PER_SEC。CLOCKS_PER_SEC是由time.h定义的C级宏。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

返回值的原点(零)不同。例如,系统启动时间,启动时间,Epoch等。

CLOCK_REALTIME中的原点被定义为Epoch(1970-01-01 00:00:00 UTC)。但有些系统会计算闰秒,其他系统则不会。所以结果可以在不同的系统中被解释为不同。推荐使用Time.now,而不是CLOCK_REALTIME。

VALUE
rb_clock_gettime(int argc, VALUE *argv)
{
    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];

    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. */
    rb_syserr_fail(EINVAL, 0);

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

daemon() → 0 Show source

daemon(nochdir=nil,noclose=nil) → 0

从控制终端分离进程并作为系统守护进程在后台运行。除非参数nochdir为真(即非假),否则它将当前工作目录更改为根(“/”)。除非参数noclose为true,否则daemon()会将标准输入,标准输出和标准错误重定向到/ dev / null。成功返回零,或者提高Errno :: *之一。

static VALUE
proc_daemon(int argc, VALUE *argv)
{
    int n, nochdir = FALSE, noclose = FALSE;

    switch (rb_check_arity(argc, 0, 2)) {
      case 2: noclose = RTEST(argv[1]);
      case 1: nochdir = RTEST(argv[0]);
    }

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

detach(pid) → thread Show source

一些操作系统保留终止的子进程的状态,直到父进程收集该状态为止(通常使用某种变体wait())。如果父母从未收集到这种状态,则该孩子会留在僵尸进程中。Process::detach通过设置一个单独的Ruby线程来防止这种情况,该线程的唯一工作是在进程pid终止时收获其状态。detach仅在您不打算明确等待孩子终止时才使用。

等待线程终止时会返回分离进程的退出状态,因此您可以使用它Thread#join来了解结果。如果指定的pid不是有效的子进程ID,则线程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_detach(VALUE obj, VALUE pid)
{
    return rb_detach_process(NUM2PIDT(pid));
}

egid → integer Show source

Process::GID.eid → integer

Process::Sys.geteid → integer

返回此进程的有效组ID。不适用于所有平台。

Process.egid   #=> 500
static VALUE
proc_getegid(VALUE obj)
{
    rb_gid_t egid = getegid();

    return GIDT2NUM(egid);
}

egid = integer → integer Show source

设置此过程的有效组ID。不适用于所有平台。

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 → integer Show source

Process::UID.eid → integer

Process::Sys.geteuid → integer

Returns the effective user ID for this process.

Process.euid   #=> 501
static VALUE
proc_geteuid(VALUE obj)
{
    rb_uid_t euid = geteuid();
    return UIDT2NUM(euid);
}

euid= user Show source

设置此进程的有效用户标识。不适用于所有平台。

static VALUE
proc_seteuid_m(VALUE mod, VALUE euid)
{
    check_uid_switch();
    proc_seteuid(OBJ2UID(euid));
    return euid;
}

exec(env, command... ,options) Show source

通过运行给定的外部命令来替换当前进程,该命令可以采用以下形式之一:

exec(commandline)

传递给标准shell的命令行字符串

exec(cmdname, arg1, ...)

命令名称和一个或多个参数(无shell)

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

命令名,argv和零个或多个参数(无shell)

在第一种形式中,字符串被视为一个命令行,在执行之前需要进行shell扩展。

标准外壳总是意味着"/bin/sh"在类Unix系统上,与Windows NT系列相同,ENV["RUBYSHELL"]ENV["COMSPEC"]类似。

如果来自第一个form(exec("command"))的字符串遵循以下简单规则:

  • 没有元字符
  • 没有外壳保留字,也没有特殊的内置
  • Ruby不使用shell就直接调用该命令

您可以通过向字符串添加“;”来强制执行shell调用(因为“;”是元字符)。

请注意,此行为可通过获取的pid获得(IO.popen的spawn()和IO#pid的返回值)是调用的命令的pid,而不是shell。

在第二个窗体(exec("command1", "arg1", ...))中,第一个被作为命令名,其余的被作为参数传递给没有shell扩展的命令。

在第三种形式(exec(["command", "argv0"], "arg1", ...))中,在命令开始处启动一个双元素数组,第一个元素是要执行的命令,第二个参数用作argv[0]值,可能会在进程列表中显示。

为了执行该命令,使用了一个exec(2)系统调用,所以运行命令可以继承原始程序的某些环境(包括打开的文件描述符)。

此行为是由给定的修改envoptions参数。有关详细信息,请参阅:: spawn。

如果该命令执行失败(通常Errno::ENOENT是未找到该命令),则会引发SystemCallError异常。

此方法根据系统调用options之前的给定值修改进程属性exec(2)。有关给定的更多细节,请参阅:: spawn options

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
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' };
    int err;

    execarg_obj = rb_execarg_new(argc, argv, TRUE);
    eargp = rb_execarg_get(execarg_obj);
    before_exec(); /* stop timer thread before redirects */
    rb_execarg_parent_start(execarg_obj);
    fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;

    rb_exec_async_signal_safe(eargp, errmsg, sizeof(errmsg));

    err = errno;
    after_exec(); /* restart timer thread */

    rb_exec_fail(eargp, err, errmsg);
    RB_GC_GUARD(execarg_obj);
    rb_syserr_fail_str(err, fail_str);
    UNREACHABLE;
}

exit(status=true) Show source

Kernel::exit(status=true)

Process::exit(status=true)

通过引发SystemExit异常来启动Ruby脚本的终止。这个例外可能被捕获。可选参数用于将状态码返回到调用环境。trueFALSE状态分别意味着成功和失败。其他整数值的解释是依赖于系统的。

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
VALUE
rb_f_exit(int argc, const VALUE *argv)
{
    int istatus;

    if (rb_check_arity(argc, 0, 1) == 1) {
        istatus = exit_status_code(argv[0]);
    }
    else {
        istatus = EXIT_SUCCESS;
    }
    rb_exit(istatus);

    UNREACHABLE;
}

exit!(status=false) Show source

立即退出流程。没有退出处理程序运行。状态作为退出状态返回到底层系统。

Process.exit!(true)
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;
}

fork { block } → integer or nil Show source

fork { block } → integer or nil

创建一个子流程。如果指定了一个块,则该块在子进程中运行,并且子进程终止,状态为零。否则,fork调用会返回两次,一次返回父进程,返回该进程的ID,一次进入子进程,返回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
rb_f_fork(VALUE obj)
{
    rb_pid_t pid;

    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);
    }
}

getpgid(pid) → integer Show source

返回给定进程ID的进程组ID。不适用于所有平台。

Process.getpgid(Process.ppid())   #=> 25527
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);
}

getpgrp → integer Show source

返回此进程的进程组标识。不适用于所有平台。

Process.getpgid(0)   #=> 25527
Process.getpgrp      #=> 25527
static VALUE
proc_getpgrp(void)
{
    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
}

getpriority(kind, integer) → integer Show source

获取指定进程,进程组或用户的调度优先级。一种表示一种实体的发现:一Process::PRIO_PGRPProcess::PRIO_USERProcess::PRIO_PROCESS整数是指示特定进程,进程组或用户的ID(0表示当前的ID )。较低的优先级对调度更有利。不适用于所有平台。

Process.getpriority(Process::PRIO_USER, 0)      #=> 19
Process.getpriority(Process::PRIO_PROCESS, 0)   #=> 19
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);
}

getrlimit(resource) → cur_limit, max_limit()

获取进程的资源限制。cur_limit表示当前(软)限制,max_limit表示最大(硬)限制。

资源表示要限制的资源种类。它被指定为一个符号,比如像:CORE一个字符串"CORE"或者一个常数Process::RLIMIT_CORE。有关详细信息,请参阅:setrlimit。

cur_limitmax_limit可能是Process::RLIM_INFINITYProcess::RLIM_SAVED_MAX或者Process::RLIM_SAVED_CUR。有关详细信息,请参阅:setrlimit和系统getrlimit(2)手册。

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));
}

getsid() → integer Show source

getsid(pid) → integer

返回给定进程ID的会话ID。如果没有给出,返回当前进程sid。不适用于所有平台。

Process.getsid()                #=> 27422
Process.getsid(0)               #=> 27422
Process.getsid(Process.pid())   #=> 27422
static VALUE
proc_getsid(int argc, VALUE *argv)
{
    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);
}

gid → integer Show source

Process::GID.rid → integer

Process::Sys.getgid → integer

返回此过程的(实际)组ID。

Process.gid   #=> 500
static VALUE
proc_getgid(VALUE obj)
{
    rb_gid_t gid = getgid();
    return GIDT2NUM(gid);
}

gid= integer → integer Show source

设置此进程的组标识。

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 Show source

找一个Array在这个过程中,补充组访问列表组的的GID。

Process.groups   #=> [27, 6, 10, 11]
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;
}

groups= array → array Show source

将补充组访问列表设置为给定Array组ID。

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_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);
}

initgroups(username, gid) → array Show source

通过读取系统组数据库并使用给定用户所属的所有组来初始化补充组访问列表。具有指定gid的组也被添加到列表中。返回Array补充组访问列表中所有组的gid 的结果。不适用于所有平台。

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_initgroups(VALUE obj, VALUE uname, VALUE base_grp)
{
    if (initgroups(StringValuePtr(uname), OBJ2GID(base_grp)) != 0) {
        rb_sys_fail(0);
    }
    return proc_getgroups(obj);
}

kill(signal, pid, ...) → integer Show source

如果pid为正值,则将给定的信号发送到指定的进程ID 。如果pid为零,则将信号发送到所有进程的组ID等于进程的组ID。信号可以是整数信号编号或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::EINVALRangeError将被提出。否则,除非信号是a String或a Symbol,并且会发出已知的信号名称ArgumentError

另外,Errno::ESRCH或者RangeError对于无效的PIDErrno::EPERM当因没有特权而失败时,会被提出。在这些情况下,信号可能已经发送到前面的过程。

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_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 SIGILL
		  case SIGILL:
#endif
#ifdef SIGFPE
		  case SIGFPE:
#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);
}

maxgroups → integer Show source

返回补充组访问列表中允许的最大gid数。

Process.maxgroups   #=> 32
static VALUE
proc_getmaxgroups(VALUE obj)
{
    return INT2FIX(maxgroups());
}

maxgroups= integer → integer Show source

设置补充组访问列表中允许的最大gid数。

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 → integer Show source

返回此进程的进程标识。不适用于所有平台。

Process.pid   #=> 27415
static VALUE
get_pid(void)
{
    return PIDT2NUM(getpid());
}

ppid → integer Show source

返回此进程的父进程的进程ID。在Win32 / 64上返回不值得信赖的值。不适用于所有平台。

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

产生:

I am 27417
Dad is 27417
static VALUE
get_ppid(void)
{
    return PIDT2NUM(getppid());
}

setpgid(pid, integer) → 0 Show source

pid的进程组标识(0表示此进程)设置为整数。不适用于所有平台。

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);
}

setpgrp → 0 Show source

相当于setpgid(0,0)。不适用于所有平台。

static VALUE
proc_setpgrp(void)
{
  /* 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);
}

setpriority(kind, integer, priority) → 0 Show source

参阅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_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);
}

setproctitle(string) → string Show source

设置ps(1)命令上显示的进程标题。不一定在所有平台上都有效。无论结果如何,都不会引发异常,即使平台不支持该功能也不会引发NotImplementedError。

调用此方法不会影响$ 0的值。

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

这个方法首先出现在Ruby 2.1中,作为一个全局变量的免费方式来改变进程标题。

static VALUE
proc_setproctitle(VALUE process, VALUE title)
{
    StringValue(title);

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

    return title;
}

setrlimit(resource, cur_limit, max_limit) → nil Show source

setrlimit(resource, cur_limit) → nil

设置进程的资源限制。cur_limit表示当前(软)限制,max_limit表示最大(硬)限制。

如果max_limit没有给出,cur_limit使用。

资源表示要限制的资源种类。它应该是一个符号,比如像:CORE一个字符串,"CORE"或者一个常数Process::RLIMIT_CORE。可用资源取决于操作系统。Ruby可能支持以下资源。

总可用内存(字节)(SUSv3,NetBSD,FreeBSD,OpenBSD,但4.4BSD-Lite)

CORE

core size (bytes) (SUSv3)

CPU

CPU time (seconds) (SUSv3)

DATA

data segment (bytes) (SUSv3)

FSIZE

file size (bytes) (SUSv3)

MEMLOCK

total size for mlock(2) (bytes) (4.4BSD, GNU/Linux)

MSGQUEUE

allocation for POSIX message queues (bytes) (GNU/Linux)

NICE

ceiling on process's nice(2) value (number) (GNU/Linux)

NOFILE

文件描述符(编号)(SUSv3)

NPROC

用户进程数(数量)(4.4BSD,GNU / Linux)

RSS

常驻内存大小(字节)(4.2BSD,GNU / Linux)

RTPRIO

进程的实时优先级(数量)上限(GNU / Linux)

RTTIME

实时进程的CPU时间(美国)(GNU / Linux)

SBSIZE

所有套接字缓冲区(字节)(NetBSD,FreeBSD)

SIGPENDING

允许排队的信号数量(信号)(GNU / Linux)

STACK

stack size (bytes) (SUSv3)

cur_limitmax_limit可能是:INFINITY"INFINITY"或者说Process::RLIM_INFINITY,这意味着资源不受限制。它们可能是Process::RLIM_SAVED_MAXProcess::RLIM_SAVED_CUR也是相应的符号和字符串。有关详细信息,请参阅系统setrlimit(2)手册。

以下示例将核心大小的软限制提高到硬核极限,以尝试使核心转储成为可能。

Process.setrlimit(:CORE, Process.getrlimit(:CORE)[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;
}

setsid → integer Show source

建立这个过程作为一个新的会话和过程组领导,没有控制tty。返回会话ID。不适用于所有平台。

Process.setsid   #=> 27422
static VALUE
proc_setsid(void)
{
    rb_pid_t pid;

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

spawn(env, command... ,options) → pid Show source

spawn(env, command... ,options) → pid

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#系统类似,但不等待命令完成。

父程序应该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 => 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的值为零,则该变量将被删除。

# 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使进程保留在同一个进程组中。

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()那就是Windows API的。该选项仅适用于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。相应的值应该是一个整数或一个有一个或两个整数的数组:与:: setrlimit的cur_limit和max_limit参数相同。

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])

该数组指定一个文件名,标志和权限。这些标志可以是一个字符串或一个整数。如果省略标志或零,则假定File :: RDONLY。权限应该是一个整数。如果权限被忽略或零,则假定为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意味着将子stderr重定向到父标准输出。但是: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合并到IO.popen中的stdout中。在这种情况下,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,...

:spawn和IO.popen默认为close_others。

请注意,无论close_others选项如何,已关闭执行close-on-exec标志的fds都会关闭。

所以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被指定为散列值来单独关闭fd。

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标准外壳。

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);
    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
}

times → aProcessTms Show source

返回一个Tms结构(请参阅参考资料Process::Tms),其中包含此进程的用户和系统CPU时间以及子进程。

t = Process.times
[ t.utime, t.stime, t.cutime, t.cstime ]   #=> [0.0, 0.02, 0.00, 0.00]
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;
}

uid → integer Show source

Process::UID.rid → integer

Process::Sys.getuid → integer

返回此进程的(实际)用户标识。

Process.uid   #=> 501
static VALUE
proc_getuid(VALUE obj)
{
    rb_uid_t uid = getuid();
    return UIDT2NUM(uid);
}

uid= user → numeric Show source

设置此进程的(用户)用户标识。不适用于所有平台。

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() → integer Show source

wait(pid=-1, flags=0) → integer

waitpid(pid=-1, flags=0) → integer

等待子进程退出,返回其进程ID,并设置$?Process::Status包含该进程信息的对象。它等待的孩子取决于pid的值:

0

等待进程ID等于pid的子进程。

0

等待进程组ID等于调用进程的任何子进程。

-1

等待任何子进程(默认情况下,如果没有给出PID)。

< -1

等待进程组ID等于pid绝对值的任何子进程。

标志参数可以是逻辑或标志值的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_wait(int argc, VALUE *argv)
{
    rb_pid_t pid;
    int flags, status;

    flags = 0;
    if (rb_check_arity(argc, 0, 2) == 0) {
        pid = -1;
    }
    else {
        VALUE vflags;
        pid = NUM2PIDT(argv[0]);
        if (argc == 2 && !NIL_P(vflags = argv[1])) {
            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);
}

wait2(pid=-1, flags=0) → pid, status()

等待子进程退出(请参阅:: waitpid以了解确切的语义),并返回包含该子进程ID和退出状态(Process::Status对象)的数组。如果没有子进程,则引发SystemCallError。

Process.fork { exit 99 }   #=> 27437
pid, status = Process.wait2
pid                        #=> 27437
status.exitstatus          #=> 99
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());
}

waitall → [pid1,status1], ...()

等待所有的孩子,返回一组pid / 状态对(状态是一个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_waitall(void)
{
    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;
}

waitpid(pid=-1, flags=0) → integer Show source

等待子进程退出,返回其进程ID,并设置$?Process::Status包含该进程信息的对象。它等待的孩子取决于pid的值:

0

等待进程ID等于pid的子进程。

0

等待进程组ID等于调用进程的任何子进程。

-1

等待任何子进程(默认情况下,如果没有给出PID)。

< -1

等待进程组ID等于pid绝对值的任何子进程。

标志参数可以是逻辑或标志值的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_wait(int argc, VALUE *argv)
{
    rb_pid_t pid;
    int flags, status;

    flags = 0;
    if (rb_check_arity(argc, 0, 2) == 0) {
        pid = -1;
    }
    else {
        VALUE vflags;
        pid = NUM2PIDT(argv[0]);
        if (argc == 2 && !NIL_P(vflags = argv[1])) {
            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);
}

waitpid2(pid=-1, flags=0) → pid, status()

等待子进程退出(请参阅:: waitpid以了解确切的语义),并返回包含该子进程ID和退出状态(Process::Status对象)的数组。如果没有子进程,则引发SystemCallError。

Process.fork { exit 99 }   #=> 27437
pid, status = Process.wait2
pid                        #=> 27437
status.exitstatus          #=> 99
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());
}
Ruby 2.4

Ruby 是一种面向对象、命令式、函数式、动态的通用编程语言,是世界上最优美而巧妙的语言。

主页 https://www.ruby-lang.org/
源码 https://github.com/ruby/ruby
版本 2.4
发布版本 2.4.1

Ruby 2.4目录

1.缩略 | Abbrev
2.ARGF
3.数组 | Array
4.Base64
5.基本对象 | BasicObject
6.基准测试 | Benchmark
7.BigDecimal
8.绑定 | Binding
9.CGI
10.类 | Class
11.比较 | Comparable
12.负责 | Complex
13.计算续体 | Continuation
14.覆盖 | Coverage
15.CSV
16.日期 | Date
17.日期时间 | DateTime
18.DBM
19.代理 | Delegator
20.摘要 | Digest
21.Dir
22.DRb
23.编码 | Encoding
24.枚举 | Enumerable
25.枚举 | Enumerator
26.ENV
27.ERB
28.错误 | Errors
29.Etc
30.期望值 | Exception
31.错误类 | FalseClass
32.Fiber
33.Fiddle
34.文件 | File
35.文件实用程序 | FileUtils
36.查找 | Find
37.浮点 | Float
38.Forwardable
39.GC
40.GDBM
41.GetoptLong
42.Hash
43.Integer
44.IO
45.IPAddr
46.JSON
47.Kernel
48.语言 | 3Language
49.记录 | Logger
50.编排 | Marshal
51.MatchData
52.数学 | Math
53.矩阵 | Matrix
54.方法 | Method
55.模型 | Module
56.监控 | Monitor
57. 互斥 | Mutex
58.Net
59.Net::FTP
60.Net::HTTP
61.Net::IMAP
62.Net::SMTP
63.NilClass
64.数字 | Numeric
65.对象 | Object
66.ObjectSpace
67.Observable
68.Open3
69.OpenSSL
70.OpenStruct
71.OpenURI
72.OptionParser
73.路径名 | Pathname
74.完整输出 | PrettyPrint
75.Prime
76.Proc
77.过程 | Process
78.PStore
79.PTY
80.队列 | Queue
81.随机 | Random
82.范围 | Range
83.合理的 | Rational
84.Readline
85.Regexp
86.Resolv
87.Ripper
88.RubyVM
89.Scanf
90.SDBM
91.SecureRandom
92.Set
93.Shell
94.信号 | Signal
95.Singleton
96.套接字 | Socket
97.字符串 | String
98.StringIO
99.StringScanner
100.结构 | Struct