diff --git a/.travis.yml b/.travis.yml index 3847529..2b8848f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,9 @@ env: - MRUBY_VERSION=1.2.0 - MRUBY_VERSION=1.3.0 - MRUBY_VERSION=1.4.0 + - MRUBY_VERSION=1.4.1 + - MRUBY_VERSION=2.0.0 + - MRUBY_VERSION=2.1.0 before_script: # Add an IPv6 config - see the corresponding Travis issue # https://github.com/travis-ci/travis-ci/issues/8361 diff --git a/.travis_config.rb b/.travis_config.rb index 236ef40..81f57e8 100644 --- a/.travis_config.rb +++ b/.travis_config.rb @@ -6,5 +6,21 @@ gem :core => 'mruby-print' gem :core => 'mruby-sprintf' gem :core => 'mruby-time' - gem "#{MRUBY_ROOT}/.." + gem "#{MRUBY_ROOT}/.." do |c| + c.bundle_uv + end +end + +MRuby::Build.new('libuv-v1.0.0') do |conf| + toolchain :gcc + enable_debug + enable_test + + gem :core => 'mruby-print' + gem :core => 'mruby-sprintf' + gem :core => 'mruby-time' + ENV['SKIP_UV_BUNDLE'] = '1' + gem "#{MRUBY_ROOT}/.." do |c| + c.bundle_uv '1.0.0' + end end diff --git a/mrbgem.rake b/mrbgem.rake index c89d0f0..c06873c 100644 --- a/mrbgem.rake +++ b/mrbgem.rake @@ -13,11 +13,11 @@ MRuby::Gem::Specification.new('mruby-uv') do |spec| def cross?; build.kind_of? MRuby::CrossBuild end - def self.bundle_uv + DEFAULT_UV_VERSION = '1.34.0' + + def self.bundle_uv(version = DEFAULT_UV_VERSION) visualcpp = ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR'] - # version = '1.0.0' - version = '1.19.1' libuv_dir = "#{build_dir}/libuv-#{version}" libuv_lib = libfile "#{libuv_dir}/.libs/libuv" header = "#{libuv_dir}/include/uv.h" @@ -99,7 +99,7 @@ MRuby::Gem::Specification.new('mruby-uv') do |spec| if build.cc.respond_to? :search_header_path next if build.cc.search_header_path 'uv.h' end - if ENV['OS'] == 'Windows_NT' + if ENV['OS'] == 'Windows_NT' || ENV['SKIP_UV_BUNDLE'] next end diff --git a/mrblib/yarn.rb b/mrblib/yarn.rb index 729322c..419cd04 100644 --- a/mrblib/yarn.rb +++ b/mrblib/yarn.rb @@ -1,6 +1,10 @@ module UV def self.sleep sec - current_yarn.sleep sec + if UV.current_loop.current_yarn + current_yarn.sleep sec + else + UV.sleep_milli sec * 1000 + end end def self.quote cmd diff --git a/src/fs.c b/src/fs.c index 70f6865..c4537d9 100644 --- a/src/fs.c +++ b/src/fs.c @@ -102,6 +102,53 @@ mrb_uv_to_fd(mrb_state *mrb, mrb_value v) return ((mrb_uv_file*)mrb_uv_get_ptr(mrb, v, &mrb_uv_file_type))->fd; } +#if MRB_UV_CHECK_VERSION(1, 28, 0) + +static void +mrb_uv_dir_free(mrb_state *mrb, void *p) +{ + uv_fs_t req; + uv_dir_t *dir = (uv_dir_t*)p; + if (!dir) { + return; + } + mrb_uv_check_error(mrb, uv_fs_closedir(uv_default_loop(), &req, dir, NULL)); +} + +static mrb_data_type const mrb_uv_dir_type = { + "UV::Dir", mrb_uv_dir_free, +}; + +static mrb_value +dir_to_mrb(mrb_state *mrb, uv_dir_t *dir) +{ + struct RClass *dir_cls = mrb_class_get_under(mrb, mrb_module_get(mrb, "UV"), "Dir"); + mrb_value ret = mrb_obj_value(mrb_obj_alloc(mrb, MRB_TT_DATA, dir_cls)); + DATA_PTR(ret) = dir; + DATA_TYPE(ret) = &mrb_uv_dir_type; + return ret; +} + +#endif + +#if MRB_UV_CHECK_VERSION(1, 31, 0) + +static mrb_value +statfs_to_mrb(mrb_state *mrb, const uv_statfs_t *stat) +{ + mrb_value ret = mrb_hash_new(mrb); + mrb_hash_set(mrb, ret, mrb_symbol_value(mrb_intern_lit(mrb, "type")), mrb_uv_from_uint64(mrb, stat->f_type)); + mrb_hash_set(mrb, ret, mrb_symbol_value(mrb_intern_lit(mrb, "bsize")), mrb_uv_from_uint64(mrb, stat->f_bsize)); + mrb_hash_set(mrb, ret, mrb_symbol_value(mrb_intern_lit(mrb, "blocks")), mrb_uv_from_uint64(mrb, stat->f_blocks)); + mrb_hash_set(mrb, ret, mrb_symbol_value(mrb_intern_lit(mrb, "bfree")), mrb_uv_from_uint64(mrb, stat->f_bfree)); + mrb_hash_set(mrb, ret, mrb_symbol_value(mrb_intern_lit(mrb, "bavail")), mrb_uv_from_uint64(mrb, stat->f_bavail)); + mrb_hash_set(mrb, ret, mrb_symbol_value(mrb_intern_lit(mrb, "files")), mrb_uv_from_uint64(mrb, stat->f_files)); + mrb_hash_set(mrb, ret, mrb_symbol_value(mrb_intern_lit(mrb, "ffree")), mrb_uv_from_uint64(mrb, stat->f_ffree)); + return ret; +} + +#endif + static mrb_value dirtype_to_sym(mrb_state *mrb, uv_dirent_type_t t) { @@ -187,6 +234,20 @@ _uv_fs_cb(uv_fs_t* uv_req) mrb_uv_req_yield(req, 1, &res); } break; +#if MRB_UV_CHECK_VERSION(1, 28, 0) + case UV_FS_OPENDIR: { + mrb_value const dir = dir_to_mrb(mrb, (uv_dir_t*)uv_req->ptr); + mrb_uv_req_yield(req, 1, &dir); + } break; +#endif + +#if MRB_UV_CHECK_VERSION(1, 31, 0) + case UV_FS_STATFS: { + mrb_value const stat = statfs_to_mrb(mrb, (uv_statfs_t*)uv_req->ptr); + mrb_uv_req_yield(req, 1, &stat); + } break; +#endif + default: { mrb_value const res = mrb_fixnum_value(uv_req->result); mrb_uv_req_yield(req, 1, &res); @@ -201,6 +262,12 @@ mrb_uv_fs_fd(mrb_state *mrb, mrb_value self) return mrb_fixnum_value(ctx->fd); } +static mrb_value +mrb_uv_fs_path(mrb_state *mrb, mrb_value self) +{ + return mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "path")); +} + static void _uv_fs_open_cb(uv_fs_t* uv_req) { @@ -214,6 +281,7 @@ _uv_fs_open_cb(uv_fs_t* uv_req) mrb_iv_set(mrb, req->instance, mrb_intern_lit(mrb, "fs_open"), mrb_nil_value()); file = (mrb_uv_file*)DATA_PTR(args[0]); file->fd = uv_req->result; + mrb_iv_set(mrb, args[0], mrb_intern_lit(mrb, "path"), mrb_str_new_cstr(mrb, uv_req->path)); mrb_uv_req_yield(req, 2, args); } @@ -245,12 +313,51 @@ mrb_uv_fs_open(mrb_state *mrb, mrb_value self) mrb_uv_req_check_error(mrb, req, res); if (mrb_nil_p(req->block)) { context->fd = res; + mrb_iv_set(mrb, c, mrb_intern_lit(mrb, "path"), mrb_str_new_cstr(mrb, arg_filename)); return c; } mrb_iv_set(mrb, req->instance, mrb_intern_lit(mrb, "fs_open"), c); return ret; } +#if MRB_UV_CHECK_VERSION(1, 34, 0) + +static mrb_value +mrb_uv_fs_mkstemp(mrb_state *mrb, mrb_value self) +{ + char const *arg_filename; + mrb_value c, b, ret; + struct RClass* _class_uv_fs; + mrb_uv_file* context; + mrb_uv_req_t* req; + int res; + + mrb_get_args(mrb, "&z", &b, &arg_filename); + + _class_uv_fs = mrb_class_get_under(mrb, mrb_module_get(mrb, "UV"), "FS"); + c = mrb_obj_value(mrb_obj_alloc(mrb, MRB_TT_DATA, _class_uv_fs)); + context = (mrb_uv_file*)mrb_malloc(mrb, sizeof(mrb_uv_file)); + context->mrb = mrb; + context->instance = c; + context->fd = -1; + DATA_PTR(c) = context; + DATA_TYPE(c) = &mrb_uv_file_type; + + req = mrb_uv_req_current(mrb, b, &ret); + res = uv_fs_mkdtemp(mrb_uv_current_loop(mrb), &req->req.fs, + arg_filename, mrb_nil_p(req->block)? NULL : _uv_fs_open_cb); + mrb_uv_req_check_error(mrb, req, res); + if (mrb_nil_p(req->block)) { + context->fd = res; + mrb_iv_set(mrb, c, mrb_intern_lit(mrb, "path"), mrb_str_new_cstr(mrb, req->req.fs.path)); + return c; + } + mrb_iv_set(mrb, req->instance, mrb_intern_lit(mrb, "fs_open"), c); + return ret; +} + +#endif + static mrb_value mrb_uv_fs_close(mrb_state *mrb, mrb_value self) { @@ -793,10 +900,129 @@ mrb_uv_fs_copyfile(mrb_state *mrb, mrb_value self) #endif +#if MRB_UV_CHECK_VERSION(1, 21, 0) + +static mrb_value +mrb_uv_fs_lchown(mrb_state *mrb, mrb_value self) +{ + char const *path; + mrb_value b, ret; + mrb_uv_req_t *req; + int res, uid, gid; + + mrb_get_args(mrb, "&zii", &b, &path, &uid, &gid); + + req = mrb_uv_req_current(mrb, b, &ret); + res = uv_fs_lchown(mrb_uv_current_loop(mrb), &req->req.fs, path, uid, gid, + mrb_nil_p(req->block)? NULL : _uv_fs_cb); + + if (mrb_nil_p(req->block)) { + mrb_value const ret = mrb_str_new_cstr(mrb, req->req.fs.ptr); + mrb_uv_req_clear(req); + return ret; + } + mrb_uv_req_check_error(mrb, req, res); + return ret; +} + +#endif + +#if MRB_UV_CHECK_VERSION(1, 28, 0) + +static mrb_value +mrb_uv_fs_opendir(mrb_state* mrb, mrb_value self) { + const char *path; + mrb_value proc, ret; + mrb_uv_req_t *req; + int res; + + mrb_get_args(mrb, "&z", &proc, &path); + req = mrb_uv_req_current(mrb, proc, &ret); + res = uv_fs_opendir( + mrb_uv_current_loop(mrb), &req->req.fs, path, + mrb_nil_p(req->block)? NULL : _uv_fs_cb); + if (mrb_nil_p(req->block)) { + mrb_uv_req_clear(req); + return mrb_uv_create_status(mrb, res); + } + mrb_uv_req_check_error(mrb, req, res); + return ret; +} + +static mrb_value +mrb_uv_dir_read(mrb_state* mrb, mrb_value self) { + mrb_value proc, ret; + mrb_uv_req_t *req; + int res; + uv_dir_t *dir = (uv_dir_t*)mrb_data_get_ptr(mrb, self, &mrb_uv_dir_type); + + mrb_get_args(mrb, "&", &proc); + req = mrb_uv_req_current(mrb, proc, &ret); + res = uv_fs_readdir( + mrb_uv_current_loop(mrb), &req->req.fs, dir, + mrb_nil_p(req->block)? NULL : _uv_fs_cb); + if (mrb_nil_p(req->block)) { + mrb_uv_req_clear(req); + return mrb_uv_create_status(mrb, res); + } + mrb_uv_req_check_error(mrb, req, res); + return ret; +} + +static mrb_value +mrb_uv_dir_close(mrb_state* mrb, mrb_value self) { + mrb_value proc, ret; + mrb_uv_req_t *req; + int res; + uv_dir_t *dir = (uv_dir_t*)mrb_data_get_ptr(mrb, self, &mrb_uv_dir_type); + + mrb_get_args(mrb, "&", &proc); + req = mrb_uv_req_current(mrb, proc, &ret); + res = uv_fs_closedir( + mrb_uv_current_loop(mrb), &req->req.fs, dir, + mrb_nil_p(req->block)? NULL : _uv_fs_cb); + if (mrb_nil_p(req->block)) { + mrb_uv_req_clear(req); + return mrb_uv_create_status(mrb, res); + } + mrb_uv_req_check_error(mrb, req, res); + return ret; +} + +#endif + +#if MRB_UV_CHECK_VERSION(1, 31, 0) + +static mrb_value +mrb_uv_fs_statfs(mrb_state *mrb, mrb_value self) +{ + char const *path; + mrb_value b, ret; + mrb_uv_req_t *req; + int res; + + mrb_get_args(mrb, "&z", &b, &path); + + req = mrb_uv_req_current(mrb, b, &ret); + res = uv_fs_statfs(mrb_uv_current_loop(mrb), &req->req.fs, path, + mrb_nil_p(req->block)? NULL : _uv_fs_cb); + + if (mrb_nil_p(req->block)) { + mrb_value const ret = statfs_to_mrb(mrb, (uv_statfs_t*)req->req.fs.ptr); + mrb_uv_req_clear(req); + return ret; + } + mrb_uv_req_check_error(mrb, req, res); + return ret; +} + +#endif + void mrb_mruby_uv_gem_init_fs(mrb_state *mrb, struct RClass *UV) { struct RClass *_class_uv_fs; struct RClass *_class_uv_stat; + struct RClass *_class_uv_dir; _class_uv_fs = mrb_define_class_under(mrb, UV, "FS", mrb->object_class); MRB_SET_INSTANCE_TT(_class_uv_fs, MRB_TT_DATA); @@ -823,6 +1049,10 @@ void mrb_mruby_uv_gem_init_fs(mrb_state *mrb, struct RClass *UV) mrb_define_const(mrb, _class_uv_fs, "X_OK", mrb_fixnum_value(X_OK)); #if MRB_UV_CHECK_VERSION(1, 14, 0) mrb_define_const(mrb, _class_uv_fs, "COPYFILE_EXCL", mrb_fixnum_value(UV_FS_COPYFILE_EXCL)); +#endif +#if MRB_UV_CHECK_VERSION(1, 20, 0) + mrb_define_const(mrb, _class_uv_fs, "COPYFILE_FICLONE", mrb_fixnum_value(UV_FS_COPYFILE_FICLONE)); + mrb_define_const(mrb, _class_uv_fs, "COPYFILE_FICLONE_FORCE", mrb_fixnum_value(UV_FS_COPYFILE_FICLONE_FORCE)); #endif mrb_define_method(mrb, _class_uv_fs, "write", mrb_uv_fs_write, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(2)); mrb_define_method(mrb, _class_uv_fs, "read", mrb_uv_fs_read, MRB_ARGS_REQ(0) | MRB_ARGS_OPT(2)); @@ -835,6 +1065,7 @@ void mrb_mruby_uv_gem_init_fs(mrb_state *mrb, struct RClass *UV) mrb_define_method(mrb, _class_uv_fs, "chown", mrb_uv_fs_fchown, MRB_ARGS_REQ(2)); mrb_define_method(mrb, _class_uv_fs, "close", mrb_uv_fs_close, MRB_ARGS_NONE()); mrb_define_method(mrb, _class_uv_fs, "fd", mrb_uv_fs_fd, MRB_ARGS_NONE()); + mrb_define_method(mrb, _class_uv_fs, "path", mrb_uv_fs_path, MRB_ARGS_NONE()); mrb_define_class_method(mrb, _class_uv_fs, "open", mrb_uv_fs_open, MRB_ARGS_REQ(2)); mrb_define_class_method(mrb, _class_uv_fs, "unlink", mrb_uv_fs_unlink, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, _class_uv_fs, "mkdir", mrb_uv_fs_mkdir, MRB_ARGS_REQ(1)); @@ -859,6 +1090,21 @@ void mrb_mruby_uv_gem_init_fs(mrb_state *mrb, struct RClass *UV) #if MRB_UV_CHECK_VERSION(1, 8, 0) mrb_define_class_method(mrb, _class_uv_fs, "realpath", mrb_uv_fs_realpath, MRB_ARGS_REQ(1)); #endif +#if MRB_UV_CHECK_VERSION(1, 21, 0) + mrb_define_class_method(mrb, _class_uv_fs, "lchown", mrb_uv_fs_lchown, MRB_ARGS_REQ(3)); +#endif +#if MRB_UV_CHECK_VERSION(1, 28, 0) + _class_uv_dir = mrb_define_class_under(mrb, UV, "Dir", mrb->object_class); + mrb_define_class_method(mrb, _class_uv_fs, "opendir", mrb_uv_fs_opendir, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, _class_uv_dir, "read", mrb_uv_dir_read, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, _class_uv_dir, "close", mrb_uv_dir_close, MRB_ARGS_BLOCK()); +#endif +#if MRB_UV_CHECK_VERSION(1, 31, 0) + mrb_define_class_method(mrb, _class_uv_fs, "statfs", mrb_uv_fs_statfs, MRB_ARGS_REQ(1)); +#endif +#if MRB_UV_CHECK_VERSION(1, 34, 0) + mrb_define_class_method(mrb, _class_uv_fs, "mkstemp", mrb_uv_fs_mkstemp, MRB_ARGS_REQ(1)); +#endif /* for compatibility */ mrb_define_class_method(mrb, _class_uv_fs, "readdir", mrb_uv_fs_scandir, MRB_ARGS_REQ(2)); @@ -883,4 +1129,12 @@ void mrb_mruby_uv_gem_init_fs(mrb_state *mrb, struct RClass *UV) mrb_define_method(mrb, _class_uv_stat, "birthtim", mrb_uv_stat_birthtim, MRB_ARGS_NONE()); /* cannot create from mruby side */ mrb_undef_class_method(mrb, _class_uv_stat, "new"); + +#if MRB_UV_CHECK_VERSION(1, 28, 0) + _class_uv_dir = mrb_define_class_under(mrb, UV, "Dir", mrb->object_class); + MRB_SET_INSTANCE_TT(_class_uv_dir, MRB_TT_DATA); + mrb_undef_class_method(mrb, _class_uv_dir, "new"); + mrb_define_method(mrb, _class_uv_dir, "close", mrb_uv_dir_close, MRB_ARGS_OPT(1)); + mrb_define_method(mrb, _class_uv_dir, "readdir", mrb_uv_dir_read, MRB_ARGS_OPT(1)); +#endif } diff --git a/src/handle.c b/src/handle.c index bf0af6f..28b7c9e 100644 --- a/src/handle.c +++ b/src/handle.c @@ -605,38 +605,45 @@ mrb_uv_tcp_nodelay_set(mrb_state *mrb, mrb_value self) } static mrb_value -mrb_uv_tcp_getpeername(mrb_state *mrb, mrb_value self) +sockaddr_to_mrb(mrb_state *mrb, struct sockaddr *addr) { - int len; - struct sockaddr_storage addr; - struct RClass* _class_uv; - struct RClass* _class_uv_ipaddr; + struct RClass *class_uv, *class_uv_ipaddr; struct RData *data; - mrb_value value_data, value_result = mrb_nil_value(); - mrb_uv_handle* context = (mrb_uv_handle*)mrb_uv_get_ptr(mrb, self, &mrb_uv_handle_type); - - len = sizeof(addr); - mrb_uv_check_error(mrb, uv_tcp_getpeername((uv_tcp_t*)&context->handle, (struct sockaddr *)&addr, &len)); - switch (addr.ss_family) { + switch (addr->sa_family) { case AF_INET: case AF_INET6: - _class_uv = mrb_module_get(mrb, "UV"); - if (addr.ss_family == AF_INET) { - _class_uv_ipaddr = mrb_class_get_under(mrb, _class_uv, "Ip4Addr"); - data = Data_Wrap_Struct(mrb, mrb->object_class, - &mrb_uv_ip4addr_nofree_type, (void *) &addr); + class_uv = mrb_module_get(mrb, "UV"); + if (addr->sa_family == AF_INET) { + struct sockaddr_in* ptr; + class_uv_ipaddr = mrb_class_get_under(mrb, class_uv, "Ip4Addr"); + ptr = mrb_malloc(mrb, sizeof(struct sockaddr_in)); + memcpy(ptr, addr, sizeof(struct sockaddr_in)); + data = Data_Wrap_Struct(mrb, class_uv_ipaddr, &mrb_uv_ip4addr_type, (void *)ptr); } else { - _class_uv_ipaddr = mrb_class_get_under(mrb, _class_uv, "Ip6Addr"); - data = Data_Wrap_Struct(mrb, mrb->object_class, - &mrb_uv_ip6addr_nofree_type, (void *) &addr); + struct sockaddr_in6* ptr; + class_uv_ipaddr = mrb_class_get_under(mrb, class_uv, "Ip6Addr"); + ptr = mrb_malloc(mrb, sizeof(struct sockaddr_in6)); + memcpy(ptr, addr, sizeof(struct sockaddr_in6)); + data = Data_Wrap_Struct(mrb, class_uv_ipaddr, &mrb_uv_ip6addr_type, (void *)ptr); } - value_data = mrb_obj_value((void *) data); - value_result = mrb_class_new_instance(mrb, 1, &value_data, - _class_uv_ipaddr); break; + default: + mrb_assert(FALSE); } - return value_result; + return mrb_obj_value(data); +} + +static mrb_value +mrb_uv_tcp_getpeername(mrb_state *mrb, mrb_value self) +{ + int len; + struct sockaddr_storage addr; + mrb_uv_handle* context = (mrb_uv_handle*)mrb_uv_get_ptr(mrb, self, &mrb_uv_handle_type); + + len = sizeof(addr); + mrb_uv_check_error(mrb, uv_tcp_getpeername((uv_tcp_t*)&context->handle, (struct sockaddr *)&addr, &len)); + return sockaddr_to_mrb(mrb, (struct sockaddr *)&addr); } static mrb_value @@ -644,10 +651,6 @@ mrb_uv_getsockname(mrb_state *mrb, mrb_value self, int tcp) { int len; struct sockaddr_storage addr; - struct RClass* _class_uv; - struct RClass* _class_uv_ipaddr; - struct RData *data; - mrb_value value_data, value_result = mrb_nil_value(); mrb_uv_handle* context = (mrb_uv_handle*)mrb_uv_get_ptr(mrb, self, &mrb_uv_handle_type); len = sizeof(addr); @@ -657,26 +660,7 @@ mrb_uv_getsockname(mrb_state *mrb, mrb_value self, int tcp) else { mrb_uv_check_error(mrb, uv_udp_getsockname((uv_udp_t*)&context->handle, (struct sockaddr *)&addr, &len)); } - switch (addr.ss_family) { - case AF_INET: - case AF_INET6: - _class_uv = mrb_module_get(mrb, "UV"); - if (addr.ss_family == AF_INET) { - _class_uv_ipaddr = mrb_class_get_under(mrb, _class_uv, "Ip4Addr"); - data = Data_Wrap_Struct(mrb, mrb->object_class, - &mrb_uv_ip4addr_nofree_type, (void *) &addr); - } - else { - _class_uv_ipaddr = mrb_class_get_under(mrb, _class_uv, "Ip6Addr"); - data = Data_Wrap_Struct(mrb, mrb->object_class, - &mrb_uv_ip6addr_nofree_type, (void *) &addr); - } - value_data = mrb_obj_value((void *) data); - value_result = mrb_class_new_instance(mrb, 1, &value_data, - _class_uv_ipaddr); - break; - } - return value_result; + return sockaddr_to_mrb(mrb, (struct sockaddr*)&addr); } static mrb_value @@ -685,6 +669,24 @@ mrb_uv_tcp_getsockname(mrb_state *mrb, mrb_value self) return mrb_uv_getsockname(mrb, self, 1); } +#if MRB_UV_CHECK_VERSION(1, 32, 0) + +static mrb_value +mrb_uv_tcp_close_reset(mrb_state *mrb, mrb_value self) +{ + mrb_uv_handle* context = (mrb_uv_handle*)mrb_uv_get_ptr(mrb, self, &mrb_uv_handle_type); + mrb_value b = mrb_nil_value(); + + mrb_get_args(mrb, "&", &b); + + mrb_iv_set(mrb, context->instance, mrb_intern_lit(mrb, "close_cb"), b); + mrb_uv_check_error(mrb, uv_tcp_close_reset( + (uv_tcp_t*)&context->handle, (uv_close_cb)_uv_close_cb)); + return mrb_nil_value(); +} + +#endif + /********************************************************* * UV::UDP *********************************************************/ @@ -1000,6 +1002,64 @@ mrb_uv_udp_send_queue_size(mrb_state *mrb, mrb_value self) return mrb_fixnum_value(uv_udp_get_send_queue_size((uv_udp_t*)&ctx->handle)); } +#if MRB_UV_CHECK_VERSION(1, 27, 0) + +static mrb_value +mrb_uv_udp_get_peername(mrb_state *mrb, mrb_value self) +{ + int len; + struct sockaddr_storage addr; + mrb_uv_handle* context = (mrb_uv_handle*)mrb_uv_get_ptr(mrb, self, &mrb_uv_handle_type); + + len = sizeof(addr); + mrb_uv_check_error(mrb, uv_udp_getpeername((uv_udp_t*)&context->handle, (struct sockaddr *)&addr, &len)); + return sockaddr_to_mrb(mrb, (struct sockaddr *)&addr); +} + +static mrb_value +mrb_uv_udp_connect(mrb_state *mrb, mrb_value self) +{ + struct sockaddr* addr; + mrb_value addr_obj; + mrb_uv_handle* context = (mrb_uv_handle*)mrb_uv_get_ptr(mrb, self, &mrb_uv_handle_type); + + mrb_get_args(mrb, "o", &addr_obj); + if (mrb_type(addr_obj) != MRB_TT_DATA) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "Invalid sockaddr: %S", addr_obj); + } + addr = + DATA_PTR(addr_obj) == &mrb_uv_ip4addr_type? (struct sockaddr*)DATA_PTR(addr_obj): + DATA_PTR(addr_obj) == &mrb_uv_ip4addr_nofree_type? (struct sockaddr*)DATA_PTR(addr_obj): + DATA_PTR(addr_obj) == &mrb_uv_ip6addr_type? (struct sockaddr*)DATA_PTR(addr_obj): + DATA_PTR(addr_obj) == &mrb_uv_ip6addr_nofree_type? (struct sockaddr*)DATA_PTR(addr_obj): + NULL; + if (!addr) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "Invalid sockaddr: %S", addr_obj); + } + + mrb_uv_check_error(mrb, uv_udp_connect((uv_udp_t*)&context->handle, addr)); + return self; +} + +#endif + +#if MRB_UV_CHECK_VERSION(1, 32, 0) + +static mrb_value +mrb_uv_udp_set_source_membership(mrb_state *mrb, mrb_value self) +{ + mrb_uv_handle* context = (mrb_uv_handle*)mrb_uv_get_ptr(mrb, self, &mrb_uv_handle_type); + const char *mc, *inf, *src; + mrb_int mem; + + mrb_get_args(mrb, "zzzi", &mc, &inf, &src, &mem); + + mrb_uv_check_error(mrb, uv_udp_set_source_membership((uv_udp_t*)&context->handle, mc, inf, src, mem)); + return self; +} + +#endif + /********************************************************* * UV::Prepare *********************************************************/ @@ -1208,8 +1268,8 @@ _uv_exit_cb(uv_process_t* process, int64_t exit_status, int term_signal) yield_handle_cb((mrb_uv_handle*)process->data, 2, args); } -static mrb_value -get_hash_opt(mrb_state *mrb, mrb_value h, const char *str) +mrb_value +mrb_uv_get_hash_opt(mrb_state *mrb, mrb_value h, const char *str) { mrb_value ret = mrb_hash_get(mrb, h, mrb_symbol_value(mrb_intern_cstr(mrb, str))); if (mrb_nil_p(ret)) { @@ -1242,6 +1302,9 @@ mrb_uv_process_spawn(mrb_state *mrb, mrb_value self) mrb_value arg_file, arg_args, arg_env, arg_cwd, arg_uid, arg_gid, arg_detached, arg_windows_hide, arg_windows_verbatim_arguments, arg_stdio; +#if MRB_UV_CHECK_VERSION(1, 24, 0) + mrb_value arg_windows_hide_console, arg_windows_hide_gui; +#endif mrb_value stdio_pipe[3]; char cwd[PATH_MAX]; size_t cwd_size = sizeof(cwd); @@ -1253,16 +1316,20 @@ mrb_uv_process_spawn(mrb_state *mrb, mrb_value self) uv_loop_t *loop; options = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "options")); - arg_file = get_hash_opt(mrb, options, "file"); - arg_args = get_hash_opt(mrb, options, "args"); - arg_env = get_hash_opt(mrb, options, "env"); - arg_cwd = get_hash_opt(mrb, options, "cwd"); - arg_uid = get_hash_opt(mrb, options, "uid"); - arg_gid = get_hash_opt(mrb, options, "gid"); - arg_detached = get_hash_opt(mrb, options, "detached"); - arg_windows_verbatim_arguments = get_hash_opt(mrb, options, "windows_verbatim_arguments"); - arg_windows_hide = get_hash_opt(mrb, options, "windows_hide"); - arg_stdio = get_hash_opt(mrb, options, "stdio"); + arg_file = mrb_uv_get_hash_opt(mrb, options, "file"); + arg_args = mrb_uv_get_hash_opt(mrb, options, "args"); + arg_env = mrb_uv_get_hash_opt(mrb, options, "env"); + arg_cwd = mrb_uv_get_hash_opt(mrb, options, "cwd"); + arg_uid = mrb_uv_get_hash_opt(mrb, options, "uid"); + arg_gid = mrb_uv_get_hash_opt(mrb, options, "gid"); + arg_detached = mrb_uv_get_hash_opt(mrb, options, "detached"); + arg_windows_verbatim_arguments = mrb_uv_get_hash_opt(mrb, options, "windows_verbatim_arguments"); + arg_windows_hide = mrb_uv_get_hash_opt(mrb, options, "windows_hide"); +#if MRB_UV_CHECK_VERSION(1, 24, 0) + arg_windows_hide_console = mrb_uv_get_hash_opt(mrb, options, "windows_hide_console"); + arg_windows_hide_gui = mrb_uv_get_hash_opt(mrb, options, "windows_hide_gui"); +#endif + arg_stdio = mrb_uv_get_hash_opt(mrb, options, "stdio"); stdio_pipe[0] = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "stdin_pipe")); stdio_pipe[1] = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "stdout_pipe")); stdio_pipe[2] = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "stderr_pipe")); @@ -1363,6 +1430,10 @@ mrb_uv_process_spawn(mrb_state *mrb, mrb_value self) } if (mrb_bool(arg_detached)) { opt.flags |= UV_PROCESS_DETACHED; } if (mrb_bool(arg_windows_hide)) { opt.flags |= UV_PROCESS_WINDOWS_HIDE; } +#if MRB_UV_CHECK_VERSION(1, 24, 0) + if (mrb_bool(arg_windows_hide_console)) { opt.flags |= UV_PROCESS_WINDOWS_HIDE_CONSOLE; } + if (mrb_bool(arg_windows_hide_gui)) { opt.flags |= UV_PROCESS_WINDOWS_HIDE_GUI; } +#endif if (mrb_bool(arg_windows_verbatim_arguments)) { opt.flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS; } opt.exit_cb = _uv_exit_cb; @@ -1444,6 +1515,33 @@ mrb_uv_process_stderr_pipe_set(mrb_state *mrb, mrb_value self) return self; } +#if MRB_UV_CHECK_VERSION(1, 23, 0) + +static mrb_value +mrb_uv_process_get_priority(mrb_state *mrb, mrb_value self) +{ + mrb_uv_handle* context = (mrb_uv_handle*)mrb_uv_get_ptr(mrb, self, &mrb_uv_handle_type); + uv_pid_t pid = uv_process_get_pid((uv_process_t*)&context->handle); + int priority; + mrb_uv_check_error(mrb, uv_os_getpriority(pid, &priority)); + return mrb_fixnum_value(priority); +} + +static mrb_value +mrb_uv_process_set_priority(mrb_state *mrb, mrb_value self) +{ + mrb_uv_handle* context = (mrb_uv_handle*)mrb_uv_get_ptr(mrb, self, &mrb_uv_handle_type); + uv_pid_t pid = uv_process_get_pid((uv_process_t*)&context->handle); + int priority; + + mrb_get_args(mrb, "i", &priority); + + mrb_uv_check_error(mrb, uv_os_setpriority(pid, priority)); + return mrb_fixnum_value(priority); +} + +#endif + /********************************************************* * UV::Timer *********************************************************/ @@ -2092,6 +2190,13 @@ mrb_mruby_uv_gem_init_handle(mrb_state *mrb, struct RClass *UV) mrb_define_method(mrb, _class_uv_udp, "send_queue_size", mrb_uv_udp_send_queue_size, MRB_ARGS_NONE()); mrb_define_const(mrb, _class_uv_udp, "LEAVE_GROUP", mrb_fixnum_value(UV_LEAVE_GROUP)); mrb_define_const(mrb, _class_uv_udp, "JOIN_GROUP", mrb_fixnum_value(UV_JOIN_GROUP)); +#if MRB_UV_CHECK_VERSION(1, 27, 0) + mrb_define_method(mrb, _class_uv_udp, "peername", mrb_uv_udp_get_peername, MRB_ARGS_NONE()); + mrb_define_method(mrb, _class_uv_udp, "connect", mrb_uv_udp_connect, MRB_ARGS_REQ(1)); +#endif +#if MRB_UV_CHECK_VERSION(1, 32, 0) + mrb_define_method(mrb, _class_uv_udp, "set_source_membership", mrb_uv_udp_set_source_membership, MRB_ARGS_REQ(3)); +#endif mrb_gc_arena_restore(mrb, ai); _class_uv_process = mrb_define_class_under(mrb, UV, "Process", mrb->object_class); @@ -2107,6 +2212,10 @@ mrb_mruby_uv_gem_init_handle(mrb_state *mrb, struct RClass *UV) mrb_define_method(mrb, _class_uv_process, "stderr_pipe", mrb_uv_process_stderr_pipe_get, MRB_ARGS_NONE()); mrb_define_method(mrb, _class_uv_process, "kill", mrb_uv_process_kill, MRB_ARGS_NONE()); mrb_define_method(mrb, _class_uv_process, "pid", mrb_uv_process_pid, MRB_ARGS_NONE()); +#if MRB_UV_CHECK_VERSION(1, 23, 0) + mrb_define_method(mrb, _class_uv_process, "priority", mrb_uv_process_get_priority, MRB_ARGS_NONE()); + mrb_define_method(mrb, _class_uv_process, "priority=", mrb_uv_process_set_priority, MRB_ARGS_REQ(1)); +#endif mrb_gc_arena_restore(mrb, ai); _class_uv_signal = mrb_define_class_under(mrb, UV, "Signal", mrb->object_class); @@ -2207,6 +2316,9 @@ mrb_mruby_uv_gem_init_handle(mrb_state *mrb, struct RClass *UV) mrb_define_method(mrb, _class_uv_tcp, "getsockname", mrb_uv_tcp_getsockname, MRB_ARGS_NONE()); mrb_define_method(mrb, _class_uv_tcp, "peername", mrb_uv_tcp_getpeername, MRB_ARGS_NONE()); mrb_define_method(mrb, _class_uv_tcp, "sockname", mrb_uv_tcp_getsockname, MRB_ARGS_NONE()); +#if MRB_UV_CHECK_VERSION(1, 32, 0) + mrb_define_method(mrb, _class_uv_tcp, "close_reset", mrb_uv_tcp_close_reset, MRB_ARGS_BLOCK()); +#endif mrb_gc_arena_restore(mrb, ai); _class_uv_pipe = mrb_define_class_under(mrb, UV, "Pipe", mrb->object_class); @@ -2264,4 +2376,7 @@ mrb_mruby_uv_gem_init_handle(mrb_state *mrb, struct RClass *UV) mrb_define_const(mrb, UV, "READABLE", mrb_fixnum_value(UV_READABLE)); mrb_define_const(mrb, UV, "WRITABLE", mrb_fixnum_value(UV_WRITABLE)); +#if MRB_UV_CHECK_VERSION(1, 21, 0) + mrb_define_const(mrb, UV, "OVERLAPPED_PIPE", mrb_fixnum_value(UV_OVERLAPPED_PIPE)); +#endif } diff --git a/src/mrb_uv.c b/src/mrb_uv.c index ef140d2..3821ee4 100644 --- a/src/mrb_uv.c +++ b/src/mrb_uv.c @@ -835,6 +835,48 @@ mrb_uv_getnameinfo(mrb_state *mrb, mrb_value self) return ret; } +#if MRB_UV_CHECK_VERSION(1, 33, 0) + +static void +mrb_uv_random_cb(uv_random_t *uv_req, int status, void *buf, size_t len) +{ + mrb_uv_req_t *req = (mrb_uv_req_t*)uv_req->data; + mrb_state *mrb = req->mrb; + mrb_value str = mrb_str_new(mrb, buf, len); + mrb_free(mrb, buf); + mrb_uv_req_yield(req, 1, &str); +} + +static mrb_value +mrb_uv_random(mrb_state *mrb, mrb_value self) +{ + mrb_int len; + mrb_value b = mrb_nil_value(), opts = mrb_nil_value(), ret; + const unsigned flags = 0; + char *buf; + uv_random_cb cb = NULL; + mrb_uv_req_t *req = NULL; + + // TODO(take-cheeze): opts to flags conversion + mrb_get_args(mrb, "&i|H", &b, &len, &opts); + + buf = mrb_malloc(mrb, len); + if (!mrb_nil_p(b)) { + cb = mrb_uv_random_cb; + } + req = mrb_uv_req_current(mrb, b, &ret); + mrb_uv_req_check_error(mrb, req, uv_random( + mrb_uv_current_loop(mrb), &req->req.random, buf, len, flags, cb)); + if (mrb_nil_p(b)) { + ret = mrb_str_new(mrb, buf, len); + mrb_free(mrb, buf); + mrb_uv_req_clear(req); + } + return ret; +} + +#endif + /********************************************************* * UV::Addrinfo *********************************************************/ @@ -1117,7 +1159,6 @@ mrb_uv_create_status(mrb_state *mrb, int st) { if (st < 0) { return mrb_uv_create_error(mrb, st); } - mrb_assert(st == 0); return mrb_nil_value(); } @@ -1170,6 +1211,16 @@ mrb_uv_total_memory(mrb_state *mrb, mrb_value self) return mrb_uv_from_uint64(mrb, uv_get_total_memory()); } +#if MRB_UV_CHECK_VERSION(1, 29, 0) + +static mrb_value +mrb_uv_get_constrained_memory(mrb_state* mrb, mrb_value self) +{ + return mrb_uv_from_uint64(mrb, uv_get_constrained_memory()); +} + +#endif + static mrb_value mrb_uv_hrtime(mrb_state *mrb, mrb_value self) { @@ -1480,6 +1531,23 @@ mrb_uv_get_osfhandle(mrb_state *mrb, mrb_value self) #endif +#if MRB_UV_CHECK_VERSION(1, 23, 0) + +static mrb_value +mrb_uv_fs_open_osfandle(mrb_state *mrb, mrb_value self) +{ + mrb_value o; + mrb_get_args(mrb, "o", &o); + + if (!mrb_cptr_p(o)) { + mrb_raisef(mrb, E_RUNTIME_ERROR, "Invalid object: %S", o); + } + + return mrb_fixnum_value(uv_open_osfhandle((uintptr_t)mrb_cptr(o))); +} + +#endif + #if MRB_UV_CHECK_VERSION(1, 6, 0) static mrb_value @@ -1616,6 +1684,116 @@ mrb_uv_os_getppid(mrb_state *mrb, mrb_value self) #endif +#if MRB_UV_CHECK_VERSION(1, 23, 0) + +static mrb_value +mrb_uv_get_priority(mrb_state *mrb, mrb_value self) +{ + int priority; + mrb_int pid; + mrb_get_args(mrb, "i", &pid); + mrb_uv_check_error(mrb, uv_os_getpriority(pid, &priority)); + return mrb_fixnum_value(priority); +} + +static mrb_value +mrb_uv_set_priority(mrb_state *mrb, mrb_value self) +{ + mrb_int priority; + mrb_int pid; + mrb_get_args(mrb, "ii", &pid, &priority); + + mrb_uv_check_error(mrb, uv_os_setpriority(pid, priority)); + return mrb_fixnum_value(priority); +} + +#endif + +#if MRB_UV_CHECK_VERSION(1, 25, 0) + +static mrb_value +mrb_uv_os_uname(mrb_state *mrb, mrb_value self) +{ + mrb_value ret = mrb_hash_new_capa(mrb, 4); + uv_utsname_t uts; + mrb_uv_check_error(mrb, uv_os_uname(&uts)); + mrb_hash_set(mrb, ret, mrb_symbol_value(mrb_intern_lit(mrb, "sysname")), mrb_str_new_cstr(mrb, uts.sysname)); + mrb_hash_set(mrb, ret, mrb_symbol_value(mrb_intern_lit(mrb, "release")), mrb_str_new_cstr(mrb, uts.release)); + mrb_hash_set(mrb, ret, mrb_symbol_value(mrb_intern_lit(mrb, "version")), mrb_str_new_cstr(mrb, uts.version)); + mrb_hash_set(mrb, ret, mrb_symbol_value(mrb_intern_lit(mrb, "machine")), mrb_str_new_cstr(mrb, uts.machine)); + return ret; +} + +#endif + +#if MRB_UV_CHECK_VERSION(1, 31, 0) + +static mrb_value +mrb_uv_os_environ(mrb_state *mrb, mrb_value self) +{ + mrb_value ret; + uv_env_item_t *items; + int i, count; + + mrb_uv_check_error(mrb, uv_os_environ(&items, &count)); + ret = mrb_hash_new_capa(mrb, count); + + for (i = 0; i < count; ++i) { + mrb_hash_set(mrb, ret, mrb_str_new_cstr(mrb, items[i].name), mrb_str_new_cstr(mrb, items[i].value)); + } + uv_os_free_environ(items, count); + return ret; +} + +#endif + +#if MRB_UV_CHECK_VERSION(1, 28, 0) + +static mrb_value +mrb_uv_gettimeofday(mrb_state *mrb, mrb_value self) +{ + uv_timeval64_t tv; + mrb_uv_check_error(mrb, uv_gettimeofday(&tv)); + return mrb_funcall(mrb, mrb_obj_value(mrb_class_get(mrb, "Time")), "at", 2, \ + mrb_uv_from_uint64(mrb, tv.tv_sec), \ + mrb_uv_from_uint64(mrb, tv.tv_usec)); \ +} + +#endif + +#if MRB_UV_CHECK_VERSION(1, 33, 0) + +static mrb_value +mrb_uv_get_vterm_state(mrb_state *mrb, mrb_value self) +{ + uv_tty_vtermstate_t state; + mrb_uv_check_error(mrb, uv_tty_get_vterm_state(&state)); + return mrb_fixnum_value(state); +} + +static mrb_value +mrb_uv_set_vterm_state(mrb_state *mrb, mrb_value self) +{ + mrb_int state; + mrb_get_args(mrb, "i", &state); + uv_tty_set_vterm_state((uv_tty_vtermstate_t)state); + return self; +} + +#endif + +#if MRB_UV_CHECK_VERSION(1, 34, 0) + +static mrb_value +mrb_uv_sleep(mrb_state *mrb, mrb_value self) { + mrb_int ms; + mrb_get_args(mrb, "i", &ms); + uv_sleep(ms); + return self; +} + +#endif + /********************************************************* * register *********************************************************/ @@ -1674,6 +1852,25 @@ mrb_mruby_uv_gem_init(mrb_state* mrb) { #if MRB_UV_CHECK_VERSION(1, 12, 0) mrb_define_module_function(mrb, _class_uv, "osfhandle", mrb_uv_get_osfhandle, MRB_ARGS_REQ(1)); #endif +#if MRB_UV_CHECK_VERSION(1, 23, 0) + mrb_define_class_method(mrb, _class_uv, "open_osfhandle", mrb_uv_fs_open_osfandle, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, _class_uv, "get_priority", mrb_uv_get_priority, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, _class_uv, "set_priority", mrb_uv_set_priority, MRB_ARGS_REQ(2)); +#define add_priority(name) mrb_define_const(mrb, _class_uv, "PRIORITY_" #name, mrb_fixnum_value(UV_PRIORITY_ ## name)) + add_priority(LOW); + add_priority(BELOW_NORMAL); + add_priority(NORMAL); + add_priority(ABOVE_NORMAL); + add_priority(HIGH); + add_priority(HIGHEST); +#undef add_priority +#endif +#if MRB_UV_CHECK_VERSION(1, 33, 0) + mrb_define_module_function(mrb, _class_uv, "random", mrb_uv_random, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(1)); +#endif +#if MRB_UV_CHECK_VERSION(1, 34, 0) + mrb_define_module_function(mrb, _class_uv, "sleep_milli", mrb_uv_sleep, MRB_ARGS_REQ(1)); +#endif mrb_define_const(mrb, _class_uv, "UV_RUN_DEFAULT", mrb_fixnum_value(UV_RUN_DEFAULT)); mrb_define_const(mrb, _class_uv, "UV_RUN_ONCE", mrb_fixnum_value(UV_RUN_ONCE)); @@ -1817,6 +2014,12 @@ mrb_mruby_uv_gem_init(mrb_state* mrb) { #if MRB_UV_CHECK_VERSION(1, 18, 0) mrb_define_module_function(mrb, _class_uv_os, "getpid", mrb_uv_os_getpid, MRB_ARGS_NONE()); #endif +#if MRB_UV_CHECK_VERSION(1, 25, 0) + mrb_define_module_function(mrb, _class_uv_os, "uname", mrb_uv_os_uname, MRB_ARGS_NONE()); +#endif +#if MRB_UV_CHECK_VERSION(1, 31, 0) + mrb_define_module_function(mrb, _class_uv_os, "environ", mrb_uv_os_environ, MRB_ARGS_NONE()); +#endif #if MRB_UV_CHECK_VERSION(1, 9, 0) _class_uv_passwd = mrb_define_class_under(mrb, _class_uv_os, "Passwd", mrb->object_class); @@ -1829,6 +2032,21 @@ mrb_mruby_uv_gem_init(mrb_state* mrb) { mrb_define_method(mrb, _class_uv_passwd, "gid", mrb_uv_passwd_gid, MRB_ARGS_NONE()); #endif +#if MRB_UV_CHECK_VERSION(1, 28, 0) + mrb_define_module_function(mrb, _class_uv, "timeofday", mrb_uv_gettimeofday, MRB_ARGS_NONE()); +#endif + +#if MRB_UV_CHECK_VERSION(1, 29, 0) + mrb_define_module_function(mrb, _class_uv, "constrained_memory", mrb_uv_get_constrained_memory, MRB_ARGS_NONE()); +#endif + +#if MRB_UV_CHECK_VERSION(1, 33, 0) + mrb_define_module_function(mrb, _class_uv, "vterm_state", mrb_uv_get_vterm_state, MRB_ARGS_NONE()); + mrb_define_module_function(mrb, _class_uv, "vterm_state=", mrb_uv_set_vterm_state, MRB_ARGS_REQ(1)); + mrb_define_const(mrb, _class_uv, "TTY_SUPPORTED", mrb_fixnum_value(UV_TTY_SUPPORTED)); + mrb_define_const(mrb, _class_uv, "TTY_UNSUPPORTED", mrb_fixnum_value(UV_TTY_UNSUPPORTED)); +#endif + mrb_mruby_uv_gem_init_fs(mrb, _class_uv); mrb_mruby_uv_gem_init_handle(mrb, _class_uv); mrb_mruby_uv_gem_init_thread(mrb, _class_uv); diff --git a/src/mrb_uv.h b/src/mrb_uv.h index fe1025b..f0c3029 100644 --- a/src/mrb_uv.h +++ b/src/mrb_uv.h @@ -118,4 +118,6 @@ void mrb_uv_close_handle_belongs_to_vm(uv_handle_t * h, void *arg); mrb_value mrb_uv_create_error(mrb_state *mrb, int err); mrb_value mrb_uv_create_status(mrb_state *mrb, int status); +mrb_value mrb_uv_get_hash_opt(mrb_state *mrb, mrb_value h, const char *str); + #endif diff --git a/src/thread.c b/src/thread.c index 99441f0..8d1552f 100644 --- a/src/thread.c +++ b/src/thread.c @@ -100,10 +100,10 @@ static mrb_value mrb_uv_thread_init(mrb_state *mrb, mrb_value self) { mrb_value thread_arg = mrb_nil_value(); - mrb_value b = mrb_nil_value(); + mrb_value b = mrb_nil_value(), opts; mrb_uv_thread* context = NULL; - mrb_get_args(mrb, "&|o", &b, &thread_arg); + mrb_get_args(mrb, "&|oH", &b, &thread_arg, &opts); context = (mrb_uv_thread*)mrb_malloc(mrb, sizeof(mrb_uv_thread)); context->mrb = mrb; @@ -114,7 +114,21 @@ mrb_uv_thread_init(mrb_state *mrb, mrb_value self) DATA_PTR(self) = context; DATA_TYPE(self) = &mrb_uv_thread_type; - mrb_uv_check_error(mrb, uv_thread_create(&context->thread, _uv_thread_proc, context)); + if (mrb_nil_p(opts)) { + mrb_uv_check_error(mrb, uv_thread_create(&context->thread, _uv_thread_proc, context)); + } else { +#if MRB_UV_CHECK_VERSION(1, 26, 0) + uv_thread_options_t o = { UV_THREAD_NO_FLAGS }; + mrb_value stack_size = mrb_uv_get_hash_opt(mrb, opts, "stack_size"); + if (!mrb_nil_p(stack_size)) { + o.flags |= UV_THREAD_HAS_STACK_SIZE; + o.stack_size = mrb_int(mrb, stack_size); + } + mrb_uv_check_error(mrb, uv_thread_create_ex(&context->thread, &o, _uv_thread_proc, context)); +#else + mrb_raisef(mrb, E_ARGUMENT_ERROR, "Invalid option: %S", opts); +#endif + } return self; } @@ -596,7 +610,7 @@ void mrb_mruby_uv_gem_init_thread(mrb_state *mrb, struct RClass *UV) _class_uv_thread = mrb_define_class_under(mrb, UV, "Thread", mrb->object_class); MRB_SET_INSTANCE_TT(_class_uv_thread, MRB_TT_DATA); - mrb_define_method(mrb, _class_uv_thread, "initialize", mrb_uv_thread_init, MRB_ARGS_NONE()); + mrb_define_method(mrb, _class_uv_thread, "initialize", mrb_uv_thread_init, MRB_ARGS_OPT(1)); mrb_define_method(mrb, _class_uv_thread, "join", mrb_uv_thread_join, MRB_ARGS_NONE()); mrb_define_method(mrb, UV, "==", mrb_uv_thread_eq, MRB_ARGS_REQ(1)); mrb_gc_arena_restore(mrb, ai); diff --git a/test/callback.rb b/test/callback.rb index e5d2612..4436666 100644 --- a/test/callback.rb +++ b/test/callback.rb @@ -45,13 +45,16 @@ def assert_uv(name, &block) test_str = 'helloworld' UV::FS.mkdir 'foo-bar' f = UV::FS.open 'foo-bar/foo.txt', UV::FS::O_CREAT|UV::FS::O_WRONLY, UV::FS::S_IWRITE | UV::FS::S_IREAD + assert_equal 'foo-bar/foo.txt', f.path f.write test_str f.close - f = UV::FS.open 'foo-bar/foo.txt', UV::FS::O_RDONLY, UV::FS::S_IREAD - assert_equal 'hello', f.read(5) - assert_equal test_str, f.read - f.close + UV::FS.open 'foo-bar/foo.txt', UV::FS::O_RDONLY, UV::FS::S_IREAD do |r| + assert_equal 'foo-bar/foo.txt', r.path + assert_equal 'hello', r.read(5) + assert_equal test_str, r.read + r.close + end remove_uv_test_tmpfile end diff --git a/test/uv.rb b/test/uv.rb index 22e17b0..46f9d38 100644 --- a/test/uv.rb +++ b/test/uv.rb @@ -206,3 +206,36 @@ assert_kind_of Fixnum, p.uid assert_kind_of Fixnum, p.gid end + +assert 'UV.constrained_memory' do + skip unless UV.respond_to? :constrained_memory + assert_kind_of Fixnum, UV.constrained_memory +end + +assert 'UV.timeofday' do + skip unless UV.respond_to? :timeofday + assert_kind_of Time, UV.timeofday +end + +assert 'UV.sleep_milli' do + skip unless UV.respond_to? :sleep_milli + skip unless UV.respond_to? :timeofday + t = UV.timeofday + UV.sleep_milli 1 + assert_true (UV.timeofday - t) >= 0.001 +end + +assert 'UV::OS.environ' do + skip unless UV::OS.respond_to? :environ + assert_kind_of Hash, UV::OS.environ +end + +assert 'UV::OS.uname' do + skip unless UV::OS.respond_to? :uname + u = UV::OS.uname + assert_kind_of Hash, u + assert_kind_of String, u[:sysname] + assert_kind_of String, u[:release] + assert_kind_of String, u[:version] + assert_kind_of String, u[:machine] +end