Хорошо, поскольку для запуска тестового кода не требуются внешние библиотеки ruby, я могу скомпилировать 1.9 на своем компьютере без его установки и запустить тестовую программу.
Вот что я вижу:
- Кажется, что Ruby "зависает" (вы не можете его прервать, и он не выходит сам по себе).
top
показывает, что ruby работает на 100% CPU strace
не показывает вывод, когда он переходит в режим 100% CPU.
Из этого очевидно, что Ruby заходит в бесконечный цикл.И, взглянув на each_byte
в io.c
и добавив 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 меньше 137349752.
Во всяком случае ... это все, что я получил на данный момент.До сих пор не знаю, почему это происходит.Но теперь мы, по крайней мере, знаем, ЧТО происходит.Кто-то, кто написал этот код, вероятно, мог бы объяснить, почему это происходит немедленно.
В любом случае ... Я все еще думаю, что вызовы lseek
каким-то образом портят внутренние файловые указатели ruby, и из-за этого вышеприведенный цикл становится бесполезным.*
И вот исправление:
Измените flush_before_seek
в io.c
, чтобы оно выглядело так:
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
без необходимости.Вызов io_unread
в цикле each_byte
- вот что запутывает.Пропуск непрочитанного заставляет все работать, и все тесты для make test
все еще проходят.
Во всяком случае ... это не совсем корректно, так как с f.pos
произошла фундаментальная ошибка.Это просто обходной путь ... но он решает вышеуказанную проблему, тем не менее: - /