#include #include "ruby.h" #include "ruby/io.h" ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // the following is copied verbatim from the Ruby source code (io.c) struct io_internal_read_struct { int fd; int nonblock; void *buf; size_t capa; }; #define StringValue(v) rb_string_value(&(v)) inline int io_setstrbuf(VALUE *str, long len) { #ifdef _WIN32 len = (len + 1) & ~1L; /* round up for wide char */ #endif if (NIL_P(*str)) { *str = rb_str_new(0, len); return 1; } else { VALUE s = StringValue(*str); long clen = RSTRING_LEN(s); if (clen >= len) { rb_str_modify(s); return 0; } len -= clen; } rb_str_modify_expand(*str, len); return 0; } #define MAX_REALLOC_GAP 4096 inline void io_shrink_read_string(VALUE str, long n) { if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) { rb_str_resize(str, n); } } inline void io_set_read_length(VALUE str, long n, int shrinkable) { if (RSTRING_LEN(str) != n) { rb_str_modify(str); rb_str_set_len(str, n); if (shrinkable) io_shrink_read_string(str, n); } } inline rb_encoding* io_read_encoding(rb_io_t *fptr) { if (fptr->encs.enc) { return fptr->encs.enc; } return rb_default_external_encoding(); } inline VALUE io_enc_str(VALUE str, rb_io_t *fptr) { OBJ_TAINT(str); rb_enc_associate(str, io_read_encoding(fptr)); return str; } ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// inline VALUE backend_await(Backend_t *backend) { VALUE ret; backend->pending_count++; ret = Thread_switch_fiber(rb_thread_current()); backend->pending_count--; RB_GC_GUARD(ret); return ret; } inline VALUE backend_snooze() { Fiber_make_runnable(rb_fiber_current(), Qnil); return Thread_switch_fiber(rb_thread_current()); } // macros for doing read loops #define READ_LOOP_PREPARE_STR() { \ str = Qnil; \ shrinkable = io_setstrbuf(&str, len); \ buf = RSTRING_PTR(str); \ total = 0; \ OBJ_TAINT(str); \ } #define READ_LOOP_YIELD_STR() { \ io_set_read_length(str, total, shrinkable); \ io_enc_str(str, fptr); \ rb_yield(str); \ READ_LOOP_PREPARE_STR(); \ } inline void rectify_io_file_pos(rb_io_t *fptr) { // Apparently after reopening a closed file, the file position is not reset, // which causes the read to fail. Fortunately we can use fptr->rbuf.len to // find out if that's the case. // See: https://github.com/digital-fabric/polyphony/issues/30 if (fptr->rbuf.len > 0) { lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR); fptr->rbuf.len = 0; } } inline double current_time() { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); long long ns = ts.tv_sec; ns = ns * 1e9 + ts.tv_nsec; double t = ns; return t / 1e9; } inline VALUE backend_timeout_exception(VALUE exception) { if (RTEST(rb_obj_is_kind_of(exception, rb_cArray))) return rb_funcall(rb_ary_entry(exception, 0), ID_new, 1, rb_ary_entry(exception, 1)); else if (RTEST(rb_obj_is_kind_of(exception, rb_cClass))) return rb_funcall(exception, ID_new, 0); else return rb_funcall(rb_eRuntimeError, ID_new, 1, exception); }