size_t my_fread(FILE *stream, uchar *Buffer, size_t Count, myf MyFlags) { size_t readbytes; DBUG_ENTER("my_fread"); DBUG_PRINT("my",("stream: 0x%lx Buffer: 0x%lx Count: %u MyFlags: %d", (long) stream, (long) Buffer, (uint) Count, MyFlags)); if ((readbytes= fread(Buffer, sizeof(char), Count, stream)) != Count) { DBUG_PRINT("error",("Read only %d bytes", (int) readbytes)); if (MyFlags & (MY_WME | MY_FAE | MY_FNABP)) { if (ferror(stream)) my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG), my_filename(my_fileno(stream)),errno); else if (MyFlags & (MY_NABP | MY_FNABP)) my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG), my_filename(my_fileno(stream)),errno); } my_errno=errno ? errno : -1; if (ferror(stream) || MyFlags & (MY_NABP | MY_FNABP)) DBUG_RETURN((size_t) -1); /* Return with error */ } if (MyFlags & (MY_NABP | MY_FNABP)) DBUG_RETURN(0); /* Read ok */ DBUG_RETURN(readbytes); } /* my_fread */
static VALUE my_accept(struct accept_args *a, int force_nonblock) { int client_fd; VALUE client_io; int retried = 0; retry: client_fd = thread_accept(a, force_nonblock); if (client_fd == -1) { switch (errno) { case EAGAIN: if (force_nonblock) return Qnil; a->fd = my_fileno(a->accept_io); set_blocking_or_block(a->fd); #ifdef ECONNABORTED case ECONNABORTED: #endif /* ECONNABORTED */ #ifdef EPROTO case EPROTO: #endif /* EPROTO */ case EINTR: a->fd = my_fileno(a->accept_io); goto retry; case ENOMEM: case EMFILE: case ENFILE: #ifdef ENOBUFS case ENOBUFS: #endif /* ENOBUFS */ if (!retried) { retried = 1; errno = 0; rb_gc(); goto retry; } default: rb_sys_fail("accept"); } } client_io = sock_for_fd(a->accepted_class, client_fd); post_accept(a->accept_io, client_io); if (a->addr) in_addr_set(client_io, (struct sockaddr_storage *)a->addr, *a->addrlen); else rb_ivar_set(client_io, iv_kgio_addr, localhost); return client_io; }
static int read_check(struct io_args *a, long n, const char *msg, int io_wait) { if (n == -1) { if (errno == EINTR) { a->fd = my_fileno(a->io); return -1; } rb_str_set_len(a->buf, 0); if (errno == EAGAIN) { if (io_wait) { (void)kgio_call_wait_readable(a->io); /* buf may be modified in other thread/fiber */ rb_str_modify(a->buf); rb_str_resize(a->buf, a->len); a->ptr = RSTRING_PTR(a->buf); return -1; } else { a->buf = sym_wait_readable; return 0; } } rd_sys_fail(msg); } rb_str_set_len(a->buf, n); if (n == 0) a->buf = Qnil; return 0; }
FILE *my_fopen(const char *filename, int flags, myf MyFlags) { FILE *fd; char type[5]; char *dup_filename= NULL; DBUG_ENTER("my_fopen"); DBUG_PRINT("my",("Name: '%s' flags: %d MyFlags: %d", filename, flags, MyFlags)); make_ftype(type,flags); #ifdef _WIN32 fd= my_win_fopen(filename, type); #else fd= fopen(filename, type); #endif if (fd != 0) { /* The test works if MY_NFILE < 128. The problem is that fileno() is char on some OS (SUNOS). Actually the filename save isn't that important so we can ignore if this doesn't work. */ int filedesc= my_fileno(fd); if ((uint)filedesc >= my_file_limit) { mysql_mutex_lock(&THR_LOCK_open); my_stream_opened++; mysql_mutex_unlock(&THR_LOCK_open); DBUG_RETURN(fd); /* safeguard */ } dup_filename= my_strdup(key_memory_my_file_info, filename, MyFlags); if (dup_filename != NULL) { mysql_mutex_lock(&THR_LOCK_open); my_file_info[filedesc].name= dup_filename; my_stream_opened++; my_file_total_opened++; my_file_info[filedesc].type= STREAM_BY_FOPEN; mysql_mutex_unlock(&THR_LOCK_open); DBUG_PRINT("exit",("stream: 0x%lx", (long) fd)); DBUG_RETURN(fd); } (void) my_fclose(fd,MyFlags); set_my_errno(ENOMEM); } else set_my_errno(errno); DBUG_PRINT("error",("Got error %d on open",my_errno())); if (MyFlags & (MY_FFNF | MY_FAE | MY_WME)) { char errbuf[MYSYS_STRERROR_SIZE]; my_error((flags & O_RDONLY) || (flags == O_RDONLY ) ? EE_FILENOTFOUND : EE_CANTCREATEFILE, MYF(0), filename, my_errno(), my_strerror(errbuf, sizeof(errbuf), my_errno())); } DBUG_RETURN((FILE*) 0); } /* my_fopen */
/* Close a stream */ int my_fclose(FILE *fd, myf MyFlags) { int err,file; DBUG_ENTER("my_fclose"); DBUG_PRINT("my",("stream: 0x%lx MyFlags: %d", (long) fd, MyFlags)); mysql_mutex_lock(&THR_LOCK_open); file= my_fileno(fd); #ifndef _WIN32 err= fclose(fd); #else err= my_win_fclose(fd); #endif if(err < 0) { set_my_errno(errno); if (MyFlags & (MY_FAE | MY_WME)) { char errbuf[MYSYS_STRERROR_SIZE]; my_error(EE_BADCLOSE, MYF(0), my_filename(file), my_errno(), my_strerror(errbuf, sizeof(errbuf), my_errno())); } } else my_stream_opened--; if ((uint) file < my_file_limit && my_file_info[file].type != UNOPEN) { my_file_info[file].type = UNOPEN; my_free(my_file_info[file].name); } mysql_mutex_unlock(&THR_LOCK_open); DBUG_RETURN(err); } /* my_fclose */
static int kgio_timedwait(VALUE self, VALUE timeout, int write_p) { struct timeval tv = rb_time_interval(timeout); int events = write_p ? RB_WAITFD_OUT : RB_WAITFD_IN; return rb_wait_for_single_fd(my_fileno(self), events, &tv); }
static void prepare_write(struct io_args *a, VALUE io, VALUE str) { a->buf = (TYPE(str) == T_STRING) ? str : rb_obj_as_string(str); a->ptr = RSTRING_PTR(a->buf); a->len = RSTRING_LEN(a->buf); a->io = io; a->fd = my_fileno(io); }
static VALUE FORCE_CLOEXEC(VALUE io) { int fd = my_fileno(io); int flags = fcntl(fd, F_SETFD, FD_CLOEXEC); if (flags == -1) rb_sys_fail("fcntl(F_SETFD, FD_CLOEXEC)"); return io; }
/* * Blocks the running Thread indefinitely until +self+ IO object is writable. * This method is automatically called whenever kgio_write needs to * block on output. * * Users of alternative threading/fiber libraries are * encouraged to override this method in their subclasses or modules to * work with their threading/blocking methods. */ static VALUE kgio_wait_writable(VALUE self) { int fd = my_fileno(self); errno = EAGAIN; if (!rb_io_wait_writable(fd)) rb_sys_fail("kgio_wait_writable"); return self; }
FILE *my_fopen(const char *filename, int flags, myf MyFlags) { FILE *fd; char type[5]; DBUG_ENTER("my_fopen"); DBUG_PRINT("my",("Name: '%s' flags: %d MyFlags: %d", filename, flags, MyFlags)); make_ftype(type,flags); #ifdef _WIN32 fd= my_win_fopen(filename, type); #else fd= fopen(filename, type); #endif if (fd != 0) { /* The test works if MY_NFILE < 128. The problem is that fileno() is char on some OS (SUNOS). Actually the filename save isn't that important so we can ignore if this doesn't work. */ int filedesc= my_fileno(fd); if ((uint)filedesc >= my_file_limit) { thread_safe_increment(my_stream_opened,&THR_LOCK_open); DBUG_RETURN(fd); /* safeguard */ } mysql_mutex_lock(&THR_LOCK_open); if ((my_file_info[filedesc].name= (char*) my_strdup(filename,MyFlags))) { my_stream_opened++; my_file_total_opened++; my_file_info[filedesc].type= STREAM_BY_FOPEN; mysql_mutex_unlock(&THR_LOCK_open); DBUG_PRINT("exit",("stream: 0x%lx", (long) fd)); DBUG_RETURN(fd); } mysql_mutex_unlock(&THR_LOCK_open); (void) my_fclose(fd,MyFlags); my_errno=ENOMEM; } else my_errno=errno; DBUG_PRINT("error",("Got error %d on open",my_errno)); if (MyFlags & (MY_FFNF | MY_FAE | MY_WME)) my_error((flags & O_RDONLY) || (flags == O_RDONLY ) ? EE_FILENOTFOUND : EE_CANTCREATEFILE, MYF(ME_BELL+ME_WAITTANG), filename, my_errno); DBUG_RETURN((FILE*) 0); } /* my_fopen */
/* * call-seq: * * Raindrops::TCP_Info.new(tcp_socket) -> TCP_Info object * * Reads a TCP_Info object from any given +tcp_socket+. See the tcp(7) * manpage and /usr/include/linux/tcp.h for more details. */ static VALUE init(VALUE self, VALUE io) { int fd = my_fileno(io); struct tcp_info *info = DATA_PTR(self); socklen_t len = (socklen_t)sizeof(struct tcp_info); int rc = getsockopt(fd, IPPROTO_TCP, TCP_INFO, info, &len); if (rc != 0) rb_sys_fail("getsockopt"); return self; }
/* * checks to see if we've written anything since the last recv() * If we have, uncork the socket and immediately recork it. */ static void push_pending_data(VALUE io) { int optval = 0; const socklen_t optlen = sizeof(int); const int fd = my_fileno(io); if (setsockopt(fd, IPPROTO_TCP, KGIO_NOPUSH, &optval, optlen) != 0) rb_sys_fail("setsockopt(TCP_CORK/TCP_NOPUSH, 0)"); /* immediately recork */ optval = 1; if (setsockopt(fd, IPPROTO_TCP, KGIO_NOPUSH, &optval, optlen) != 0) rb_sys_fail("setsockopt(TCP_CORK/TCP_NOPUSH, 1)"); }
static int kgio_wait(int argc, VALUE *argv, VALUE self, int write_p) { int fd; VALUE timeout; if (rb_scan_args(argc, argv, "01", &timeout) == 1 && !NIL_P(timeout)) return kgio_timedwait(self, timeout, write_p); fd = my_fileno(self); errno = EAGAIN; write_p ? rb_io_wait_writable(fd) : rb_io_wait_readable(fd); return 1; }
int my_win_fclose(FILE *file) { File fd; DBUG_ENTER("my_win_close"); fd= my_fileno(file); if(fd < 0) DBUG_RETURN(-1); if(fclose(file) < 0) DBUG_RETURN(-1); invalidate_fd(fd); DBUG_RETURN(0); }
/* * call-seq: * * io.kgio_addr! => refreshes the given sock address */ static VALUE addr_bang(VALUE io) { int fd = my_fileno(io); struct sockaddr_storage addr; socklen_t len = sizeof(struct sockaddr_storage); if (getpeername(fd, (struct sockaddr *)&addr, &len) != 0) rb_sys_fail("getpeername"); if (addr.ss_family == AF_UNIX) return rb_ivar_set(io, iv_kgio_addr, localhost); return in_addr_set(io, &addr, len); }
static void prepare_writev(struct wrv_args *a, VALUE io, VALUE ary) { a->io = io; a->fd = my_fileno(io); a->something_written = 0; if (TYPE(ary) == T_ARRAY) /* rb_ary_subseq will not copy array unless it modified */ a->buf = MY_ARY_SUBSEQ(ary, 0, RARRAY_LEN(ary)); else a->buf = rb_Array(ary); a->vec_buf = rb_str_new(0, 0); a->vec = NULL; }
static void prepare_read(struct io_args *a, int argc, VALUE *argv, VALUE io) { VALUE length; a->io = io; a->fd = my_fileno(io); rb_scan_args(argc, argv, "11", &length, &a->buf); a->len = NUM2LONG(length); if (NIL_P(a->buf)) { a->buf = rb_str_new(NULL, a->len); } else { StringValue(a->buf); rb_str_modify(a->buf); rb_str_resize(a->buf, a->len); } a->ptr = RSTRING_PTR(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); }
static enum autopush_state detect_acceptor_state(VALUE io) { int corked = 0; int fd = my_fileno(io); socklen_t optlen = sizeof(int); enum autopush_state state; if (getsockopt(fd, IPPROTO_TCP, KGIO_NOPUSH, &corked, &optlen) != 0) { if (errno != EOPNOTSUPP) rb_sys_fail("getsockopt(TCP_CORK/TCP_NOPUSH)"); errno = 0; state = AUTOPUSH_STATE_ACCEPTOR_IGNORE; } else if (corked) { state = AUTOPUSH_STATE_ACCEPTOR; } else { state = AUTOPUSH_STATE_ACCEPTOR_IGNORE; } state_set(io, state); return state; }
static int write_check(struct io_args *a, long n, const char *msg, int io_wait) { if (a->len == n) { done: a->buf = Qnil; } else if (n == -1) { if (errno == EINTR) { a->fd = my_fileno(a->io); return -1; } if (errno == EAGAIN) { long written = RSTRING_LEN(a->buf) - a->len; if (io_wait) { (void)kgio_call_wait_writable(a->io); /* buf may be modified in other thread/fiber */ a->len = RSTRING_LEN(a->buf) - written; if (a->len <= 0) goto done; a->ptr = RSTRING_PTR(a->buf) + written; return -1; } else if (written > 0) { a->buf = rb_str_new(a->ptr, a->len); } else { a->buf = sym_wait_writable; } return 0; } wr_sys_fail(msg); } else { assert(n >= 0 && n < a->len && "write/send syscall broken?"); a->ptr += n; a->len -= n; return -1; } return 0; }
static void prepare_accept(struct accept_args *a, VALUE self, int argc, const VALUE *argv) { a->fd = my_fileno(self); a->accept_io = self; switch (argc) { case 2: a->flags = NUM2INT(argv[1]); a->accepted_class = NIL_P(argv[0]) ? cClientSocket : argv[0]; return; case 0: /* default, legacy behavior */ a->flags = accept4_flags; a->accepted_class = cClientSocket; return; case 1: a->flags = accept4_flags; a->accepted_class = NIL_P(argv[0]) ? cClientSocket : argv[0]; return; } rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc); }
static long writev_check(struct wrv_args *a, ssize_t n, const char *msg, int io_wait) { if (n >= 0) { if (n > 0) a->something_written = 1; return trim_writev_buffer(a, n); } else if (n < 0) { if (errno == EINTR) { a->fd = my_fileno(a->io); return -1; } if (errno == EAGAIN) { if (io_wait) { (void)kgio_call_wait_writable(a->io); return -1; } else if (!a->something_written) { a->buf = sym_wait_writable; } return 0; } kgio_wr_sys_fail(msg); } return 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; }
size_t my_fwrite(FILE *stream, const uchar *Buffer, size_t Count, myf MyFlags) { size_t writtenbytes =0; my_off_t seekptr; #if !defined(NO_BACKGROUND) && defined(USE_MY_STREAM) uint errors; #endif DBUG_ENTER("my_fwrite"); DBUG_PRINT("my",("stream: 0x%lx Buffer: 0x%lx Count: %u MyFlags: %d", (long) stream, (long) Buffer, (uint) Count, MyFlags)); #if !defined(NO_BACKGROUND) && defined(USE_MY_STREAM) errors=0; #endif seekptr= ftell(stream); for (;;) { size_t written; if ((written = (size_t) fwrite((char*) Buffer,sizeof(char), Count, stream)) != Count) { DBUG_PRINT("error",("Write only %d bytes", (int) writtenbytes)); my_errno=errno; if (written != (size_t) -1) { seekptr+=written; Buffer+=written; writtenbytes+=written; Count-=written; } #ifdef EINTR if (errno == EINTR) { (void) my_fseek(stream,seekptr,MY_SEEK_SET,MYF(0)); continue; } #endif #if !defined(NO_BACKGROUND) && defined(USE_MY_STREAM) if (my_thread_var->abort) MyFlags&= ~ MY_WAIT_IF_FULL; /* End if aborted by user */ if ((errno == ENOSPC || errno == EDQUOT) && (MyFlags & MY_WAIT_IF_FULL)) { wait_for_free_space("[stream]", errors); errors++; (void) my_fseek(stream,seekptr,MY_SEEK_SET,MYF(0)); continue; } #endif if (ferror(stream) || (MyFlags & (MY_NABP | MY_FNABP))) { if (MyFlags & (MY_WME | MY_FAE | MY_FNABP)) { my_error(EE_WRITE, MYF(ME_BELL+ME_WAITTANG), my_filename(my_fileno(stream)),errno); } writtenbytes= (size_t) -1; /* Return that we got error */ break; } } if (MyFlags & (MY_NABP | MY_FNABP)) writtenbytes= 0; /* Everything OK */ else writtenbytes+= written; break; } DBUG_RETURN(writtenbytes); } /* my_fwrite */