static VALUE thread_spec_rb_thread_select(VALUE self, VALUE msec) { struct timeval tv; tv.tv_sec = 0; tv.tv_usec = NUM2INT(msec); rb_thread_select(0, NULL, NULL, NULL, &tv); return Qnil; }
PGresult * do_postgres_cCommand_execute_async(VALUE self, VALUE connection, PGconn *db, VALUE query) { PGresult *response; char* str = StringValuePtr(query); while ((response = PQgetResult(db))) { PQclear(response); } struct timeval start; int retval; gettimeofday(&start, NULL); retval = PQsendQuery(db, str); if (!retval) { if (PQstatus(db) != CONNECTION_OK) { PQreset(db); if (PQstatus(db) == CONNECTION_OK) { retval = PQsendQuery(db, str); } else { do_postgres_full_connect(connection, db); retval = PQsendQuery(db, str); } } if (!retval) { rb_raise(eDO_ConnectionError, "%s", PQerrorMessage(db)); } } int socket_fd = PQsocket(db); fd_set rset; while (1) { FD_ZERO(&rset); FD_SET(socket_fd, &rset); retval = rb_thread_select(socket_fd + 1, &rset, NULL, NULL, NULL); if (retval < 0) { rb_sys_fail(0); } if (retval == 0) { continue; } if (PQconsumeInput(db) == 0) { rb_raise(eDO_ConnectionError, "%s", PQerrorMessage(db)); } if (PQisBusy(db) == 0) { break; } } data_objects_debug(connection, query, &start); return PQgetResult(db); }
static VALUE fcgi_s_accept(VALUE self) { int status; FCGX_Request *req; fd_set readfds; req = ALLOC(FCGX_Request); status = FCGX_InitRequest(req,0,0); if (status != 0) { rb_raise(eFCGIError, "FCGX_Init() failed"); return Qnil; } FD_ZERO(&readfds); FD_SET(req->listen_sock, &readfds); if (rb_thread_select(req->listen_sock+1, &readfds, NULL, NULL, NULL) < 1) { return Qnil; } status = FCGX_Accept_r(req); if (status >= 0) { fcgi_data *data; char **env; VALUE obj,key, value; char *pkey,*pvalue; int flags, fd; /* Unset NONBLOCKING */ fd = ((FCGX_Request*) req)->ipcFd; flags = fcntl(fd, F_GETFL); if (flags & O_NONBLOCK) { fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); } obj = Data_Make_Struct(self, fcgi_data, fcgi_mark, fcgi_free_req, data); data->req = req; data->in = Data_Wrap_Struct(cFCGIStream, 0, 0, req->in); data->out = Data_Wrap_Struct(cFCGIStream, 0, 0, req->out); data->err = Data_Wrap_Struct(cFCGIStream, 0, 0, req->err); data->env = rb_hash_new(); env = req->envp; for (; *env; env++) { int size = 0; pkey = *env; pvalue = pkey; while( *(pvalue++) != '=') size++; key = rb_str_new(pkey, size); value = rb_str_new2(pvalue); OBJ_TAINT(key); OBJ_TAINT(value); rb_hash_aset(data->env, key, value); } return obj; } else { return Qnil; } }
/* * call-seq: * multi = Curl::Multi.new * easy1 = Curl::Easy.new('url') * easy2 = Curl::Easy.new('url') * * multi.add(easy1) * multi.add(easy2) * * multi.perform do * # while idle other code my execute here * end * * Run multi handles, looping selecting when data can be transfered */ static VALUE ruby_curl_multi_perform(VALUE self) { CURLMcode mcode; ruby_curl_multi *rbcm; int maxfd, rc; fd_set fdread, fdwrite, fdexcep; long timeout; struct timeval tv = {0, 0}; Data_Get_Struct(self, ruby_curl_multi, rbcm); //rb_gc_mark(self); rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) ); while(rbcm->running) { FD_ZERO(&fdread); FD_ZERO(&fdwrite); FD_ZERO(&fdexcep); /* load the fd sets from the multi handle */ mcode = curl_multi_fdset(rbcm->handle, &fdread, &fdwrite, &fdexcep, &maxfd); if (mcode != CURLM_OK) { raise_curl_multi_error_exception(mcode); } /* get the curl suggested time out */ mcode = curl_multi_timeout(rbcm->handle, &timeout); if (mcode != CURLM_OK) { raise_curl_multi_error_exception(mcode); } if (timeout == 0) { /* no delay */ rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) ); continue; } else if (timeout == -1) { timeout = 1; /* You must not wait too long (more than a few seconds perhaps) before you call curl_multi_perform() again */ } if (rb_block_given_p()) { rb_yield(self); } tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout * 1000) % 1000000; rc = rb_thread_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &tv); if (rc < 0) { rb_raise(rb_eRuntimeError, "select(): %s", strerror(errno)); } rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) ); } return Qnil; }
static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) { struct nogvl_send_query_args args; fd_set fdset; int fd, retval; int async = 0; VALUE opts; VALUE rb_async; MYSQL * client; if (rb_scan_args(argc, argv, "11", &args.sql, &opts) == 2) { if ((rb_async = rb_hash_aref(opts, sym_async)) != Qnil) { async = rb_async == Qtrue ? 1 : 0; } } Check_Type(args.sql, T_STRING); #ifdef HAVE_RUBY_ENCODING_H rb_encoding *conn_enc = rb_to_encoding(rb_iv_get(self, "@encoding")); // ensure the string is in the encoding the connection is expecting args.sql = rb_str_export_to_enc(args.sql, conn_enc); #endif Data_Get_Struct(self, MYSQL, client); REQUIRE_OPEN_DB(client); args.mysql = client; if (rb_thread_blocking_region(nogvl_send_query, &args, RUBY_UBF_IO, 0) == Qfalse) { return rb_raise_mysql2_error(client); } if (!async) { // the below code is largely from do_mysql // http://github.com/datamapper/do fd = client->net.fd; for(;;) { FD_ZERO(&fdset); FD_SET(fd, &fdset); retval = rb_thread_select(fd + 1, &fdset, NULL, NULL, NULL); if (retval < 0) { rb_sys_fail(0); } if (retval > 0) { break; } } return rb_mysql_client_async_result(self); } else { return Qnil; } }
int SelectData_t::_Select() { #ifdef HAVE_TBR rb_thread_blocking_region (_SelectDataSelect, (void*)this, RB_UBF_DFL, 0); return nSockets; #endif #ifndef HAVE_TBR return rb_thread_select (maxsocket+1, &fdreads, &fdwrites, NULL, &tv); #endif }
static VALUE thread_spec_rb_thread_select_fd(VALUE self, VALUE fd_num, VALUE msec) { int fd = NUM2INT(fd_num); fd_set read; FD_ZERO(&read); FD_SET(fd, &read); struct timeval tv = {0, NUM2INT(msec)}; int n = rb_thread_select(fd + 1, &read, NULL, NULL, &tv); if(n == 1 && FD_ISSET(fd, &read)) return Qtrue; return Qfalse; }
static VALUE do_query(void *args) { struct async_query_args *async_args; struct timeval tv; struct timeval* tvp; long int sec; fd_set fdset; int retval; int fd_set_fd; VALUE read_timeout; async_args = (struct async_query_args *)args; read_timeout = rb_iv_get(async_args->self, "@read_timeout"); tvp = NULL; if (!NIL_P(read_timeout)) { Check_Type(read_timeout, T_FIXNUM); tvp = &tv; sec = FIX2INT(read_timeout); // TODO: support partial seconds? // also, this check is here for sanity, we also check up in Ruby if (sec >= 0) { tvp->tv_sec = sec; } else { rb_raise(cMysql2Error, "read_timeout must be a positive integer, you passed %ld", sec); } tvp->tv_usec = 0; } fd_set_fd = async_args->fd; for(;;) { // the below code is largely from do_mysql // http://github.com/datamapper/do FD_ZERO(&fdset); FD_SET(fd_set_fd, &fdset); retval = rb_thread_select(fd_set_fd + 1, &fdset, NULL, NULL, tvp); if (retval == 0) { rb_raise(cMysql2Error, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout)); } if (retval < 0) { rb_sys_fail(0); } if (retval > 0) { break; } } return Qnil; }
static VALUE wait_for_thread(void *data) { struct BlockingThread* thr = (struct BlockingThread *) data; char c, res; fd_set rfds; FD_ZERO(&rfds); FD_SET(thr->rdfd, &rfds); rb_thread_select(thr->rdfd + 1, &rfds, NULL, NULL, NULL); read(thr->rdfd, &c, 1); return Qnil; }
static int readline_event() { #if BUSY_WAIT rb_thread_schedule(); #else fd_set rset; FD_ZERO(&rset); FD_SET(fileno(rl_instream), &rset); rb_thread_select(fileno(rl_instream) + 1, &rset, NULL, NULL, NULL); return 0; #endif }
MYSQL_RES *do_mysql_cCommand_execute_async(VALUE self, VALUE connection, MYSQL *db, VALUE query) { int retval; if ((retval = mysql_ping(db)) && mysql_errno(db) == CR_SERVER_GONE_ERROR) { do_mysql_full_connect(connection, db); } struct timeval start; const char *str = rb_str_ptr_readonly(query); long len = rb_str_len(query); gettimeofday(&start, NULL); retval = mysql_send_query(db, str, len); CHECK_AND_RAISE(retval, query); int socket_fd = db->net.fd; fd_set rset; while (1) { FD_ZERO(&rset); FD_SET(socket_fd, &rset); retval = rb_thread_select(socket_fd + 1, &rset, NULL, NULL, NULL); if (retval < 0) { rb_sys_fail(0); } if (retval == 0) { continue; } if (db->status == MYSQL_STATUS_READY) { break; } } retval = mysql_read_query_result(db); CHECK_AND_RAISE(retval, query); data_objects_debug(connection, query, &start); MYSQL_RES *result = mysql_store_result(db); if (!result) { CHECK_AND_RAISE(mysql_errno(db), query); } return result; }
static gint rbglib_poll (GPollFD *fds, guint nfds, gint timeout) { struct timeval tv; fd_set rset, wset, xset; GPollFD *f; int ready; int maxfd = 0; FD_ZERO (&rset); FD_ZERO (&wset); FD_ZERO (&xset); for (f = fds; f < &fds[nfds]; ++f) { if (f->fd >= 0) { if (f->events & G_IO_IN) FD_SET (f->fd, &rset); if (f->events & G_IO_OUT) FD_SET (f->fd, &wset); if (f->events & G_IO_PRI) FD_SET (f->fd, &xset); if (f->fd > maxfd && (f->events & (G_IO_IN|G_IO_OUT|G_IO_PRI))) maxfd = f->fd; } } tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; ready = rb_thread_select (maxfd + 1, &rset, &wset, &xset, timeout == -1 ? NULL : &tv); if (ready > 0) { for (f = fds; f < &fds[nfds]; ++f) { f->revents = 0; if (f->fd >= 0) { if (FD_ISSET (f->fd, &rset)) f->revents |= G_IO_IN; if (FD_ISSET (f->fd, &wset)) f->revents |= G_IO_OUT; if (FD_ISSET (f->fd, &xset)) f->revents |= G_IO_PRI; } } } return ready; }
static VALUE method_get_next_event(VALUE self) { char buf[64]; zkrb_event_t *event ; int fd; fd_set rset; VALUE hash ; FETCH_DATA_PTR(self, zk); for (;;) { // we use the is_running(self) method here because it allows us to have a // ruby-land semaphore that we can also use in the java extension // if (!is_running(self)) { /* fprintf(stderr, "method_get_next_event: running is false, returning nil\n");*/ return Qnil; // this case for shutdown } event = zkrb_dequeue(zk->queue, 1); /* Wait for an event using rb_thread_select() on the queue's pipe */ if (event == NULL) { fd = zk->queue->pipe_read; FD_ZERO(&rset); FD_SET(fd, &rset); if (rb_thread_select(fd + 1, &rset, NULL, NULL, NULL) == -1) rb_raise(rb_eRuntimeError, "select failed: %d", errno); if (read(fd, buf, sizeof(buf)) == -1) rb_raise(rb_eRuntimeError, "read failed: %d", errno); continue; } hash = zkrb_event_to_ruby(event); zkrb_event_free(event); return hash; } }
static VALUE method_zkrb_iterate_event_loop(VALUE self) { FETCH_DATA_PTR(self, zk); fd_set rfds, wfds, efds; FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); int fd=0, interest=0, events=0, rc=0, maxfd=0; struct timeval tv; zookeeper_interest(zk->zh, &fd, &interest, &tv); if (fd != -1) { if (interest & ZOOKEEPER_READ) { FD_SET(fd, &rfds); } else { FD_CLR(fd, &rfds); } if (interest & ZOOKEEPER_WRITE) { FD_SET(fd, &wfds); } else { FD_CLR(fd, &wfds); } } else { fd = 0; } // add our self-pipe to the read set, allow us to wake up in case our attention is needed int pipe_r_fd = get_self_pipe_read_fd(self); FD_SET(pipe_r_fd, &rfds); maxfd = (pipe_r_fd > fd) ? pipe_r_fd : fd; rc = rb_thread_select(maxfd+1, &rfds, &wfds, &efds, &tv); if (rc > 0) { if (FD_ISSET(fd, &rfds)) { events |= ZOOKEEPER_READ; } if (FD_ISSET(fd, &wfds)) { events |= ZOOKEEPER_WRITE; } // we got woken up by the self-pipe if (FD_ISSET(pipe_r_fd, &rfds)) { // one event has awoken us, so we clear one event from the pipe char b[1]; if (read(pipe_r_fd, b, 1) < 0) { rb_raise(rb_eRuntimeError, "read from pipe failed: %s", clean_errno()); } } rc = zookeeper_process(zk->zh, events); } else if (rc == 0) { zkrb_debug("timed out waiting for descriptor to be ready"); } else { log_err("select returned: %d", rc); } return INT2FIX(rc); }
VALUE nlh_handle_events() { char buff[CONNECTOR_MAX_MSG_SIZE]; struct nlmsghdr *hdr; struct proc_event *event; VALUE extra_data; fd_set fds; FD_ZERO(&fds); FD_SET(nl_sock, &fds); if (0 > rb_thread_select(nl_sock + 1, &fds, NULL, NULL, NULL)) { rb_raise(rb_eStandardError, strerror(errno)); } /* If there were no events detected, return */ if (! FD_ISSET(nl_sock, &fds)) { return INT2FIX(0); } /* if there are events, make calls */ if (-1 == recv(nl_sock, buff, sizeof(buff), 0)) { rb_raise(rb_eStandardError, strerror(errno)); } hdr = (struct nlmsghdr *)buff; if (NLMSG_ERROR == hdr->nlmsg_type) { rb_raise(rb_eStandardError, strerror(errno)); } else if (NLMSG_DONE == hdr->nlmsg_type) { event = (struct proc_event *)((struct cn_msg *)NLMSG_DATA(hdr))->data; switch(event->what) { case PROC_EVENT_EXIT: if (Qnil == rb_funcall(cEventHandler, m_watching_pid, 1, INT2FIX(event->event_data.exit.process_pid))) { return INT2FIX(0); } extra_data = rb_hash_new(); rb_hash_aset(extra_data, ID2SYM(rb_intern("pid")), INT2FIX(event->event_data.exit.process_pid)); rb_hash_aset(extra_data, ID2SYM(rb_intern("exit_code")), INT2FIX(event->event_data.exit.exit_code)); rb_hash_aset(extra_data, ID2SYM(rb_intern("exit_signal")), INT2FIX(event->event_data.exit.exit_signal)); rb_hash_aset(extra_data, ID2SYM(rb_intern("thread_group_id")), INT2FIX(event->event_data.exit.process_tgid)); rb_funcall(cEventHandler, m_call, 3, INT2FIX(event->event_data.exit.process_pid), ID2SYM(proc_exit), extra_data); return INT2FIX(1); case PROC_EVENT_FORK: if (Qnil == rb_funcall(cEventHandler, m_watching_pid, 1, INT2FIX(event->event_data.fork.parent_pid))) { return INT2FIX(0); } extra_data = rb_hash_new(); rb_hash_aset(extra_data, rb_intern("parent_pid"), INT2FIX(event->event_data.fork.parent_pid)); rb_hash_aset(extra_data, rb_intern("parent_thread_group_id"), INT2FIX(event->event_data.fork.parent_tgid)); rb_hash_aset(extra_data, rb_intern("child_pid"), INT2FIX(event->event_data.fork.child_pid)); rb_hash_aset(extra_data, rb_intern("child_thread_group_id"), INT2FIX(event->event_data.fork.child_tgid)); rb_funcall(cEventHandler, m_call, 3, INT2FIX(event->event_data.fork.parent_pid), ID2SYM(proc_fork), extra_data); return INT2FIX(1); case PROC_EVENT_NONE: case PROC_EVENT_EXEC: case PROC_EVENT_UID: case PROC_EVENT_GID: break; } } return Qnil; }
static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) { struct nogvl_send_query_args args; fd_set fdset; int fd, retval; int async = 0; VALUE opts, defaults, read_timeout; GET_CLIENT(self); REQUIRE_OPEN_DB(wrapper); args.mysql = wrapper->client; // see if this connection is still waiting on a result from a previous query if (wrapper->active == 0) { // mark this connection active wrapper->active = 1; } else { rb_raise(cMysql2Error, "This connection is still waiting for a result, try again once you have the result"); } defaults = rb_iv_get(self, "@query_options"); if (rb_scan_args(argc, argv, "11", &args.sql, &opts) == 2) { opts = rb_funcall(defaults, intern_merge, 1, opts); rb_iv_set(self, "@query_options", opts); if (rb_hash_aref(opts, sym_async) == Qtrue) { async = 1; } } else { opts = defaults; } Check_Type(args.sql, T_STRING); #ifdef HAVE_RUBY_ENCODING_H rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding); // ensure the string is in the encoding the connection is expecting args.sql = rb_str_export_to_enc(args.sql, conn_enc); #endif if (rb_thread_blocking_region(nogvl_send_query, &args, RUBY_UBF_IO, 0) == Qfalse) { // an error occurred, we're not active anymore MARK_CONN_INACTIVE(self); return rb_raise_mysql2_error(wrapper->client); } read_timeout = rb_iv_get(self, "@read_timeout"); struct timeval tv; struct timeval* tvp = NULL; if (!NIL_P(read_timeout)) { Check_Type(read_timeout, T_FIXNUM); tvp = &tv; long int sec = FIX2INT(read_timeout); // TODO: support partial seconds? // also, this check is here for sanity, we also check up in Ruby if (sec >= 0) { tvp->tv_sec = sec; } else { rb_raise(cMysql2Error, "read_timeout must be a positive integer, you passed %d", sec); } tvp->tv_usec = 0; } if (!async) { // the below code is largely from do_mysql // http://github.com/datamapper/do fd = wrapper->client->net.fd; for(;;) { FD_ZERO(&fdset); FD_SET(fd, &fdset); retval = rb_thread_select(fd + 1, &fdset, NULL, NULL, tvp); if (retval == 0) { rb_raise(cMysql2Error, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout)); } if (retval < 0) { rb_sys_fail(0); } if (retval > 0) { break; } } VALUE result = rb_mysql_client_async_result(self); return result; } else { return Qnil; } }
/* * call-seq: * multi = Curl::Multi.new * easy1 = Curl::Easy.new('url') * easy2 = Curl::Easy.new('url') * * multi.add(easy1) * multi.add(easy2) * * multi.perform do * # while idle other code my execute here * end * * Run multi handles, looping selecting when data can be transfered */ VALUE ruby_curl_multi_perform(int argc, VALUE *argv, VALUE self) { CURLMcode mcode; ruby_curl_multi *rbcm; int maxfd, rc; fd_set fdread, fdwrite, fdexcep; #ifdef _WIN32 fd_set crt_fdread, crt_fdwrite, crt_fdexcep; #endif long timeout_milliseconds; struct timeval tv = {0, 0}; VALUE block = Qnil; rb_scan_args(argc, argv, "0&", &block); Data_Get_Struct(self, ruby_curl_multi, rbcm); timeout_milliseconds = cCurlMutiDefaulttimeout; rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) ); do { while (rbcm->running) { #ifdef HAVE_CURL_MULTI_TIMEOUT /* get the curl suggested time out */ mcode = curl_multi_timeout(rbcm->handle, &timeout_milliseconds); if (mcode != CURLM_OK) { raise_curl_multi_error_exception(mcode); } #else /* libcurl doesn't have a timeout method defined, initialize to -1 we'll pick up the default later */ timeout_milliseconds = -1; #endif if (timeout_milliseconds == 0) { /* no delay */ rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) ); continue; } else if (timeout_milliseconds < 0) { timeout_milliseconds = cCurlMutiDefaulttimeout; /* libcurl doesn't know how long to wait, use a default timeout */ } if (timeout_milliseconds > cCurlMutiDefaulttimeout) { timeout_milliseconds = cCurlMutiDefaulttimeout; /* buggy versions libcurl sometimes reports huge timeouts... let's cap it */ } tv.tv_sec = 0; /* never wait longer than 1 second */ tv.tv_usec = (int)(timeout_milliseconds * 1000); /* XXX: int is the right type for OSX, what about linux? */ if (timeout_milliseconds == 0) { /* no delay */ rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) ); continue; } if (block != Qnil) { rb_funcall(block, rb_intern("call"), 1, self); } FD_ZERO(&fdread); FD_ZERO(&fdwrite); FD_ZERO(&fdexcep); /* load the fd sets from the multi handle */ mcode = curl_multi_fdset(rbcm->handle, &fdread, &fdwrite, &fdexcep, &maxfd); if (mcode != CURLM_OK) { raise_curl_multi_error_exception(mcode); } #ifdef _WIN32 create_crt_fd(&fdread, &crt_fdread); create_crt_fd(&fdwrite, &crt_fdwrite); create_crt_fd(&fdexcep, &crt_fdexcep); #endif rc = rb_thread_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &tv); #ifdef _WIN32 cleanup_crt_fd(&fdread, &crt_fdread); cleanup_crt_fd(&fdwrite, &crt_fdwrite); cleanup_crt_fd(&fdexcep, &crt_fdexcep); #endif switch(rc) { case -1: rb_raise(rb_eRuntimeError, "select(): %s", strerror(errno)); break; case 0: rb_curl_multi_read_info( self, rbcm->handle ); if (block != Qnil) { rb_funcall(block, rb_intern("call"), 1, self); } default: rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) ); break; } } rb_curl_multi_read_info( self, rbcm->handle ); if (block != Qnil) { rb_funcall(block, rb_intern("call"), 1, self); } } while( rbcm->running ); return Qtrue; }
static VALUE thread_spec_rb_thread_select(VALUE self, VALUE msec) { struct timeval tv = {0, NUM2INT(msec)}; rb_thread_select(0, NULL, NULL, NULL, &tv); return Qnil; }
static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) { struct nogvl_send_query_args args; fd_set fdset; int fd, retval; int async = 0; VALUE opts, defaults, read_timeout; #ifdef HAVE_RUBY_ENCODING_H rb_encoding *conn_enc; #endif struct timeval tv; struct timeval* tvp; long int sec; VALUE result; GET_CLIENT(self); REQUIRE_OPEN_DB(wrapper); args.mysql = wrapper->client; // see if this connection is still waiting on a result from a previous query if (wrapper->active == 0) { // mark this connection active wrapper->active = 1; } else { rb_raise(cMysql2Error, "This connection is still waiting for a result, try again once you have the result"); } defaults = rb_iv_get(self, "@query_options"); if (rb_scan_args(argc, argv, "11", &args.sql, &opts) == 2) { opts = rb_funcall(defaults, intern_merge, 1, opts); rb_iv_set(self, "@query_options", opts); if (rb_hash_aref(opts, sym_async) == Qtrue) { async = 1; } } else { opts = defaults; } Check_Type(args.sql, T_STRING); #ifdef HAVE_RUBY_ENCODING_H conn_enc = rb_to_encoding(wrapper->encoding); // ensure the string is in the encoding the connection is expecting args.sql = rb_str_export_to_enc(args.sql, conn_enc); #endif if (rb_thread_blocking_region(nogvl_send_query, &args, RUBY_UBF_IO, 0) == Qfalse) { // an error occurred, we're not active anymore MARK_CONN_INACTIVE(self); return rb_raise_mysql2_error(wrapper); } read_timeout = rb_iv_get(self, "@read_timeout"); tvp = NULL; if (!NIL_P(read_timeout)) { Check_Type(read_timeout, T_FIXNUM); tvp = &tv; sec = FIX2INT(read_timeout); // TODO: support partial seconds? // also, this check is here for sanity, we also check up in Ruby if (sec >= 0) { tvp->tv_sec = sec; } else { rb_raise(cMysql2Error, "read_timeout must be a positive integer, you passed %ld", sec); } tvp->tv_usec = 0; } if (!async) { // the below code is largely from do_mysql // http://github.com/datamapper/do fd = wrapper->client->net.fd; for(;;) { int fd_set_fd = fd; #if defined(_WIN32) && !defined(HAVE_RB_THREAD_BLOCKING_REGION) WSAPROTOCOL_INFO wsa_pi; // dupicate the SOCKET from libmysql int r = WSADuplicateSocket(fd, GetCurrentProcessId(), &wsa_pi); SOCKET s = WSASocket(wsa_pi.iAddressFamily, wsa_pi.iSocketType, wsa_pi.iProtocol, &wsa_pi, 0, 0); // create the CRT fd so ruby can get back to the SOCKET fd_set_fd = _open_osfhandle(s, O_RDWR|O_BINARY); #endif FD_ZERO(&fdset); FD_SET(fd_set_fd, &fdset); retval = rb_thread_select(fd_set_fd + 1, &fdset, NULL, NULL, tvp); #if defined(_WIN32) && !defined(HAVE_RB_THREAD_BLOCKING_REGION) // cleanup the CRT fd _close(fd_set_fd); // cleanup the duplicated SOCKET closesocket(s); #endif if (retval == 0) { rb_raise(cMysql2Error, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout)); } if (retval < 0) { rb_sys_fail(0); } if (retval > 0) { break; } } result = rb_mysql_client_async_result(self); return result; } else { return Qnil; } }
/* * call-seq: * multi = Curl::Multi.new * easy1 = Curl::Easy.new('url') * easy2 = Curl::Easy.new('url') * * multi.add(easy1) * multi.add(easy2) * * multi.perform do * # while idle other code my execute here * end * * Run multi handles, looping selecting when data can be transfered */ VALUE ruby_curl_multi_perform(int argc, VALUE *argv, VALUE self) { CURLMcode mcode; ruby_curl_multi *rbcm; int maxfd, rc; fd_set fdread, fdwrite, fdexcep; long timeout_milliseconds; struct timeval tv = {0, 0}; VALUE block = Qnil; rb_scan_args(argc, argv, "0&", &block); Data_Get_Struct(self, ruby_curl_multi, rbcm); rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) ); while(rbcm->running) { FD_ZERO(&fdread); FD_ZERO(&fdwrite); FD_ZERO(&fdexcep); /* load the fd sets from the multi handle */ mcode = curl_multi_fdset(rbcm->handle, &fdread, &fdwrite, &fdexcep, &maxfd); if (mcode != CURLM_OK) { raise_curl_multi_error_exception(mcode); } #ifdef HAVE_CURL_MULTI_TIMEOUT /* get the curl suggested time out */ mcode = curl_multi_timeout(rbcm->handle, &timeout_milliseconds); if (mcode != CURLM_OK) { raise_curl_multi_error_exception(mcode); } #else /* libcurl doesn't have a timeout method defined... make a wild guess */ timeout_milliseconds = -1; #endif //printf("libcurl says wait: %ld ms or %ld s\n", timeout_milliseconds, timeout_milliseconds/1000); if (timeout_milliseconds == 0) { /* no delay */ rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) ); continue; } else if(timeout_milliseconds < 0) { timeout_milliseconds = 500; /* wait half a second, libcurl doesn't know how long to wait */ } #ifdef __APPLE_CC__ if(timeout_milliseconds > 1000) { timeout_milliseconds = 1000; /* apple libcurl sometimes reports huge timeouts... let's cap it */ } #endif tv.tv_sec = timeout_milliseconds / 1000; // convert milliseconds to seconds tv.tv_usec = (timeout_milliseconds % 1000) * 1000; // get the remainder of milliseconds and convert to micro seconds rc = rb_thread_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &tv); switch(rc) { case -1: rb_raise(rb_eRuntimeError, "select(): %s", strerror(errno)); break; case 0: if (block != Qnil) { rb_funcall(block, rb_intern("call"), 1, self); } // if (rb_block_given_p()) { // rb_yield(self); // } default: rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) ); break; } } return Qtrue; }