Beispiel #1
0
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);
}
Beispiel #2
0
/*
 * 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;
}
Beispiel #3
0
/*
 * 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);
}
Beispiel #4
0
/*
 * 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;
}
Beispiel #5
0
/*
 * 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);
}