static VALUE tcp_stats(struct nogvl_args *args, VALUE addr) { union any_addr query_addr; parse_addr(&query_addr, addr); gen_bytecode(&args->iov[2], &query_addr); memset(&args->stats, 0, sizeof(struct listen_stats)); nl_errcheck(rb_thread_io_blocking_region(diag, args, args->fd)); return rb_listen_stats(&args->stats); }
/* * call-seq: * * io.kgio_syssend(str, flags) -> nil, String or :wait_writable * * Returns nil if the write was completed in full. * * Returns a String containing the unwritten portion if EAGAIN * was encountered, but some portion was successfully written. * * Returns :wait_writable if EAGAIN is encountered and nothing * was written. * * This method is only available on Ruby 1.9.3 or later. */ static VALUE kgio_syssend(VALUE io, VALUE str, VALUE flags) { struct wr_args a; long n; a.flags = NUM2INT(flags); prepare_write(&a, io, str); if (a.flags & MY_MSG_DONTWAIT) { do { n = (long)send(a.fd, a.ptr, a.len, a.flags); } while (write_check(&a, n, "send", 0) != 0); } else { do { n = (long)rb_thread_io_blocking_region( nogvl_send, &a, a.fd); } while (write_check(&a, n, "send", 0) != 0); } return a.buf; }
/* * call-seq: * * s = Kgio::Socket.new(:INET, :STREAM) * addr = Socket.pack_sockaddr_in(80, "example.com") * s.kgio_fastopen("hello world", addr) -> nil * * Starts a TCP connection using TCP Fast Open. This uses a blocking * sendto() syscall and is only available on Ruby 1.9 or later. * This raises exceptions (including Errno::EINPROGRESS/Errno::EAGAIN) * on errors. Using this is only recommended for blocking sockets. * * Timeouts may be set with setsockopt: * * s.setsockopt(:SOCKET, :SNDTIMEO, [1,0].pack("l_l_")) */ static VALUE fastopen(VALUE sock, VALUE buf, VALUE addr) { struct tfo_args a; VALUE str = (TYPE(buf) == T_STRING) ? buf : rb_obj_as_string(buf); ssize_t w; a.fd = my_fileno(sock); a.buf = RSTRING_PTR(str); a.buflen = (size_t)RSTRING_LEN(str); a.addr = sockaddr_from(&a.addrlen, addr); /* n.b. rb_thread_blocking_region preserves errno */ w = (ssize_t)rb_thread_io_blocking_region(tfo_sendto, &a, a.fd); if (w < 0) rb_sys_fail("sendto"); if ((size_t)w == a.buflen) return Qnil; return rb_str_subseq(str, w, a.buflen - w); }
/* * call-seq: * Raindrops::Linux.tcp_listener_stats([addrs[, sock]]) => hash * * If specified, +addr+ may be a string or array of strings representing * listen addresses to filter for. Returns a hash with given addresses as * keys and ListenStats objects as the values or a hash of all addresses. * * addrs = %w(0.0.0.0:80 127.0.0.1:8080) * * If +addr+ is nil or not specified, all (IPv4) addresses are returned. * If +sock+ is specified, it should be a Raindrops::InetDiagSock object. */ static VALUE tcp_listener_stats(int argc, VALUE *argv, VALUE self) { VALUE rv = rb_hash_new(); struct nogvl_args args; VALUE addrs, sock; rb_scan_args(argc, argv, "02", &addrs, &sock); /* * allocating page_size instead of OP_LEN since we'll reuse the * buffer for recvmsg() later, we already checked for * OPLEN <= page_size at initialization */ args.iov[2].iov_len = OPLEN; args.iov[2].iov_base = alloca(page_size); args.table = NULL; if (NIL_P(sock)) sock = rb_funcall(cIDSock, id_new, 0); args.fd = my_fileno(sock); switch (TYPE(addrs)) { case T_STRING: rb_hash_aset(rv, addrs, tcp_stats(&args, addrs)); return rv; case T_ARRAY: { long i; long len = RARRAY_LEN(addrs); VALUE cur; if (len == 1) { cur = rb_ary_entry(addrs, 0); rb_hash_aset(rv, cur, tcp_stats(&args, cur)); return rv; } for (i = 0; i < len; i++) { union any_addr check; VALUE cur = rb_ary_entry(addrs, i); parse_addr(&check, cur); rb_hash_aset(rv, cur, Qtrue); } /* fall through */ } case T_NIL: args.table = st_init_strtable(); gen_bytecode_all(&args.iov[2]); break; default: rb_raise(rb_eArgError, "addr must be an array of strings, a string, or nil"); } nl_errcheck(rb_thread_io_blocking_region(diag, &args, args.fd)); st_foreach(args.table, NIL_P(addrs) ? st_to_hash : st_AND_hash, rv); st_free_table(args.table); /* let GC deal with corner cases */ if (argc < 2) rb_io_close(sock); return rv; }
/* * Try to use a (real) blocking accept() since that can prevent * thundering herds under Linux: * http://www.citi.umich.edu/projects/linux-scalability/reports/accept.html * * So we periodically disable non-blocking, but not too frequently * because other processes may set non-blocking (especially during * a process upgrade) with Rainbows! concurrency model changes. */ static int thread_accept(struct accept_args *a, int force_nonblock) { if (force_nonblock) set_nonblocking(a->fd); return (int)rb_thread_io_blocking_region(xaccept, a, a->fd); }