Ruby File IO Hang

以下
Ruby代码生成所有预期输出但未正确退出.在完成each_byte循环之前,它会挂起 – 消耗100%的CPU – 直到进程被终止.

f = File.new(ARGV.shift)
i = 0
f.each_byte {printf("%08X\n", f.pos - 1) if (i += 1) % 16 == 1}
f.close

我试过用很多不同的方式设计循环(用i代替f.pos的用法,反之亦然),它们都工作正常!只有这一种方法导致它挂起,我不知道为什么.

有任何想法吗?

最佳答案 好的..因为运行测试代码不需要任何外部ruby库我可以在我的机器上编译1.9而不安装它,并运行测试程序.

这是我看到的:

> Ruby似乎“挂起”(你不能打断它,它本身不会退出).
> top显示ruby以100%CPU运行
> strace进入100%CPU模式后显示无输出.

从这一点来看,很明显Ruby进入了无限循环.在io.c中查看each_byte,并在可疑位置添加printf,可以发现我们陷入困境的地方:

static VALUE
rb_io_each_byte(VALUE io)
{
    rb_io_t *fptr;
    char *p, *e;

    RETURN_ENUMERATOR(io, 0, 0);
    GetOpenFile(io, fptr);

    for (;;) {
        p = fptr->rbuf+fptr->rbuf_off;
        e = p + fptr->rbuf_len;

        printf("UH OH: %d < %d\n", p, e);  /* INFINITE LOOP ALERT */

        while (p < e) {
            fptr->rbuf_off++;
            fptr->rbuf_len--;
            rb_yield(INT2FIX(*p & 0xff));
            p++;
            errno = 0;
        }
        rb_io_check_byte_readable(fptr);
        READ_CHECK(fptr);
        if (io_fillbuf(fptr) < 0) {
            break;
        }
    }
    return io;
}

在我的机器上它打印出来:

UH OH: 0 < 0
UH OH: 137343104 < 137351296
UH OH: 137343119 < 137343104
UH OH: 137343119 < 137343104
UH OH: 137343119 < 137343104
...ad infinitum...

并且137343119不小于137343104,这意味着我们停止进入while循环(这将产生块).

当您运行代码以使其不挂起时,您会得到:

UH OH: 0 < 0
UH OH: 137341560 < 137349752
UH OH: 137341560 < 137349752
UH OH: 137341560 < 137349752
UH OH: 137341560 < 137349752
....

并且137341560 IS小于137349752.

无论如何..这就是我现在所拥有的一切.仍然不知道为什么会发生这种情况.但现在我们至少知道发生了什么.编写该代码的人可能会解释为什么它会立即发生.

无论如何..我仍然认为lseek调用某种方式搞乱了ruby的内部文件指针,上面的循环因此而变得混乱.

编辑

这是一个修复:

在io.c中更改flush_before_seek看起来像这样:

static rb_io_t *
flush_before_seek(rb_io_t *fptr)
{
  int wbuf_len = fptr->wbuf_len;

  if (io_fflush(fptr) < 0)
      rb_sys_fail(0);

    if (wbuf_len != 0)
      io_unread(fptr);

    errno = 0;
    return fptr;
}

我添加的是检查wbuf_len!= 0,这样我们就不会不必要地执行io_unread了.在each_byte循环中调用io_unread是令人烦恼的事情.跳过未读使得工作正常,所有make测试仍然通过.

无论如何..这不是一个正确的解决方案,因为f.pos存在一些基本的思想错误.这只是一个解决方法……但它解决了上述问题: – /

点赞