static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE port, VALUE database, VALUE socket, VALUE flags) { struct nogvl_connect_args args; VALUE rv; GET_CLIENT(self); args.host = NIL_P(host) ? NULL : StringValuePtr(host); args.unix_socket = NIL_P(socket) ? NULL : StringValuePtr(socket); args.port = NIL_P(port) ? 0 : NUM2INT(port); args.user = NIL_P(user) ? NULL : StringValuePtr(user); args.passwd = NIL_P(pass) ? NULL : StringValuePtr(pass); args.db = NIL_P(database) ? NULL : StringValuePtr(database); args.mysql = wrapper->client; args.client_flag = NUM2ULONG(flags); rv = (VALUE) rb_thread_call_without_gvl(nogvl_connect, &args, RUBY_UBF_IO, 0); if (rv == Qfalse) { while (rv == Qfalse && errno == EINTR && !mysql_errno(wrapper->client)) { errno = 0; rv = (VALUE) rb_thread_call_without_gvl(nogvl_connect, &args, RUBY_UBF_IO, 0); } if (rv == Qfalse) return rb_raise_mysql2_error(wrapper); } wrapper->server_version = mysql_get_server_version(wrapper->client); wrapper->connected = 1; return self; }
/* call-seq: insecure_channel = Channel:new("myhost:8080", {'arg1': 'value1'}, :this_channel_is_insecure) creds = ... secure_channel = Channel:new("myhost:443", {'arg1': 'value1'}, creds) Creates channel instances. */ static VALUE grpc_rb_channel_init(int argc, VALUE* argv, VALUE self) { VALUE channel_args = Qnil; VALUE credentials = Qnil; VALUE target = Qnil; grpc_rb_channel* wrapper = NULL; grpc_channel* ch = NULL; grpc_channel_credentials* creds = NULL; char* target_chars = NULL; grpc_channel_args args; channel_init_try_register_stack stack; int stop_waiting_for_thread_start = 0; MEMZERO(&args, grpc_channel_args, 1); grpc_ruby_once_init(); rb_thread_call_without_gvl( wait_until_channel_polling_thread_started_no_gil, &stop_waiting_for_thread_start, wait_until_channel_polling_thread_started_unblocking_func, &stop_waiting_for_thread_start); /* "3" == 3 mandatory args */ rb_scan_args(argc, argv, "3", &target, &channel_args, &credentials); TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); target_chars = StringValueCStr(target); grpc_rb_hash_convert_to_channel_args(channel_args, &args); if (TYPE(credentials) == T_SYMBOL) { if (id_insecure_channel != SYM2ID(credentials)) { rb_raise(rb_eTypeError, "bad creds symbol, want :this_channel_is_insecure"); return Qnil; } ch = grpc_insecure_channel_create(target_chars, &args, NULL); } else { wrapper->credentials = credentials; creds = grpc_rb_get_wrapped_channel_credentials(credentials); ch = grpc_secure_channel_create(creds, target_chars, &args, NULL); } GPR_ASSERT(ch); stack.channel = ch; stack.wrapper = wrapper; rb_thread_call_without_gvl( channel_init_try_register_connection_polling_without_gil, &stack, NULL, NULL); if (args.args != NULL) { xfree(args.args); /* Allocated by grpc_rb_hash_convert_to_channel_args */ } if (ch == NULL) { rb_raise(rb_eRuntimeError, "could not create an rpc channel to target:%s", target_chars); return Qnil; } rb_ivar_set(self, id_target, target); return self; }
static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE port, VALUE database, VALUE socket, VALUE flags) { struct nogvl_connect_args args; time_t start_time, end_time; unsigned int elapsed_time, connect_timeout; VALUE rv; GET_CLIENT(self); args.host = NIL_P(host) ? NULL : StringValueCStr(host); args.unix_socket = NIL_P(socket) ? NULL : StringValueCStr(socket); args.port = NIL_P(port) ? 0 : NUM2INT(port); args.user = NIL_P(user) ? NULL : StringValueCStr(user); args.passwd = NIL_P(pass) ? NULL : StringValueCStr(pass); args.db = NIL_P(database) ? NULL : StringValueCStr(database); args.mysql = wrapper->client; args.client_flag = NUM2ULONG(flags); if (wrapper->connect_timeout) time(&start_time); rv = (VALUE) rb_thread_call_without_gvl(nogvl_connect, &args, RUBY_UBF_IO, 0); if (rv == Qfalse) { while (rv == Qfalse && errno == EINTR) { if (wrapper->connect_timeout) { time(&end_time); /* avoid long connect timeout from system time changes */ if (end_time < start_time) start_time = end_time; elapsed_time = end_time - start_time; /* avoid an early timeout due to time truncating milliseconds off the start time */ if (elapsed_time > 0) elapsed_time--; if (elapsed_time >= wrapper->connect_timeout) break; connect_timeout = wrapper->connect_timeout - elapsed_time; mysql_options(wrapper->client, MYSQL_OPT_CONNECT_TIMEOUT, &connect_timeout); } errno = 0; rv = (VALUE) rb_thread_call_without_gvl(nogvl_connect, &args, RUBY_UBF_IO, 0); } /* restore the connect timeout for reconnecting */ if (wrapper->connect_timeout) mysql_options(wrapper->client, MYSQL_OPT_CONNECT_TIMEOUT, &wrapper->connect_timeout); if (rv == Qfalse) return rb_raise_mysql2_error(wrapper); } wrapper->server_version = mysql_get_server_version(wrapper->client); wrapper->connected = 1; return self; }
/* Wait until the channel's connectivity state becomes different from * "last_state", or "deadline" expires. * Returns true if the channel's connectivity state becomes different * from "last_state" within "deadline". * Returns false if "deadline" expires before the channel's connectivity * state changes from "last_state". * */ static VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, VALUE last_state, VALUE deadline) { grpc_rb_channel* wrapper = NULL; watch_state_stack stack; void* op_success = 0; TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); if (wrapper->bg_wrapped == NULL) { rb_raise(rb_eRuntimeError, "closed!"); return Qnil; } if (!FIXNUM_P(last_state)) { rb_raise( rb_eTypeError, "bad type for last_state. want a GRPC::Core::ChannelState constant"); return Qnil; } stack.bg_wrapped = wrapper->bg_wrapped; stack.deadline = grpc_rb_time_timeval(deadline, 0), stack.last_state = NUM2LONG(last_state); op_success = rb_thread_call_without_gvl( wait_for_watch_state_op_complete_without_gvl, &stack, wait_for_watch_state_op_complete_unblocking_func, wrapper->bg_wrapped); return op_success ? Qtrue : Qfalse; }
/* * @overload poll(is_stderr: false, timeout: -1) * Poll a channel for data to read. * @since 0.1.0 * @param [Boolean] is_stderr A boolean to select the stderr stream. * @param [Fixnum] timeout A timeout in milliseconds. A negative value means an * infinite timeout. * @return [Fixnum, nil] The number of bytes available for reading. +nil+ if * timed out. * @see http://api.libssh.org/stable/group__libssh__channel.html * ssh_channel_poll_timeout */ static VALUE m_poll(int argc, VALUE *argv, VALUE self) { ChannelHolder *holder; VALUE opts; const ID table[] = {id_stderr, id_timeout}; VALUE kwvals[sizeof(table) / sizeof(*table)]; struct nogvl_poll_args args; TypedData_Get_Struct(self, ChannelHolder, &channel_type, holder); rb_scan_args(argc, argv, "00:", &opts); rb_get_kwargs(opts, table, 0, 2, kwvals); if (kwvals[0] == Qundef) { args.is_stderr = 0; } else { args.is_stderr = RTEST(kwvals[0]) ? 1 : 0; } if (kwvals[1] == Qundef) { args.timeout = -1; } else { Check_Type(kwvals[1], T_FIXNUM); args.timeout = FIX2INT(kwvals[1]); } args.channel = holder->channel; rb_thread_call_without_gvl(nogvl_poll, &args, RUBY_UBF_IO, NULL); RAISE_IF_ERROR(args.rc); if (args.rc == SSH_EOF) { return Qnil; } else { return INT2FIX(args.rc); } }
/* * @overload read(count, is_stderr: false, timeout: -1) * Read data from a channel. * @since 0.1.0 * @param [Fixnum] count The count of bytes to be read. * @param [Boolean] is_stderr Read from the stderr flow or not. * @param [Fixnum] timeout A timeout in seconds. +-1+ means infinite timeout. * @return [String] Data read from the channel. * @see http://api.libssh.org/stable/group__libssh__channel.html * ssh_channel_read_timeout */ static VALUE m_read(int argc, VALUE *argv, VALUE self) { ChannelHolder *holder; VALUE count, opts; const ID table[] = {id_stderr, id_timeout}; VALUE kwvals[sizeof(table) / sizeof(*table)]; struct nogvl_read_args args; VALUE ret; TypedData_Get_Struct(self, ChannelHolder, &channel_type, holder); rb_scan_args(argc, argv, "10:", &count, &opts); Check_Type(count, T_FIXNUM); rb_get_kwargs(opts, table, 0, 2, kwvals); if (kwvals[0] == Qundef) { args.is_stderr = 0; } else { args.is_stderr = RTEST(kwvals[0]) ? 1 : 0; } if (kwvals[1] == Qundef) { args.timeout = -1; } else { Check_Type(kwvals[1], T_FIXNUM); args.timeout = FIX2INT(kwvals[1]); } args.channel = holder->channel; args.count = FIX2UINT(count); args.buf = ALLOC_N(char, args.count); rb_thread_call_without_gvl(nogvl_read, &args, RUBY_UBF_IO, NULL); ret = rb_utf8_str_new(args.buf, args.rc); ruby_xfree(args.buf); return ret; }
static VALUE na_add(VALUE self, VALUE other, VALUE repeat, void*(*func)(void *)) { volatile VALUE result; struct narray3 a; int i; Data_Get_Struct(self,narray_t,a.x); Data_Get_Struct(other,narray_t,a.y); if (a.x->size != a.y->size) { rb_raise(rb_eArgError,"size mismatch"); } result = na_s_allocate(cNArray); Data_Get_Struct(result,narray_t,a.z); a.z->size = a.x->size; a.z->ptr = ALLOC_N(char,a.z->size*sizeof(double)); a.stop = Qfalse; a.repeat = NUM2INT(repeat); for (i=0; i<a.repeat; i++) { #ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL rb_thread_call_without_gvl(func, &a, na_para_stop, &a); #else func(&a); #endif } return result; }
int rb_file_load_ok(const char *path) { DWORD attr; int ret = 1; long len; wchar_t* wpath; wpath = mbstr_to_wstr(CP_UTF8, path, -1, &len); if (!wpath) return 0; attr = GetFileAttributesW(wpath); if (attr == INVALID_FILE_ATTRIBUTES || (attr & FILE_ATTRIBUTE_DIRECTORY)) { ret = 0; } else { HANDLE h = (HANDLE)rb_thread_call_without_gvl(loadopen_func, (void *)wpath, RUBY_UBF_IO, 0); if (h != INVALID_HANDLE_VALUE) { CloseHandle(h); } else { ret = 0; } } free(wpath); return ret; }
static int rbthreads_wait_fd_read(int fd, int timeout) { struct uwsgi_rbthread urbt; urbt.fd = fd; urbt.timeout = timeout; rb_thread_call_without_gvl(rbthreads_wait_fd_read_do, &urbt, NULL, NULL); return urbt.ret; }
static VALUE helium_event_thread(void *unused) { struct helium_waiter_t waiter = { .callback = NULL, .abort = 0 }; while (waiter.abort == 0) { rb_thread_call_without_gvl(wait_for_callback, &waiter, &stop_waiting, &waiter); if (waiter.callback != NULL) { rb_thread_create(helium_callback_handler_thread, (void *)waiter.callback); } } return Qnil; } void Init_rbhelium() { mHelium = rb_define_module("Helium"); cConnection = rb_define_class_under(mHelium, "Connection", rb_cObject); rb_define_alloc_func(cConnection, helium_rb_allocate); rb_define_method(cConnection, "initialize", helium_rb_initialize, -1); rb_define_method(cConnection, "write", helium_rb_send, 3); rb_define_method(cConnection, "subscribe", helium_rb_subscribe, 2); rb_define_method(cConnection, "unsubscribe", helium_rb_unsubscribe, 1); rb_define_method(cConnection, "close", helium_rb_close, 0); rb_thread_create(helium_event_thread, NULL); }
/* Shuts down and drains the completion queue if necessary. * * This is done when the ruby completion queue object is about to be GCed. */ static void grpc_rb_completion_queue_shutdown_drain(grpc_completion_queue *cq) { next_call_stack next_call; grpc_completion_type type; int drained = 0; MEMZERO(&next_call, next_call_stack, 1); grpc_completion_queue_shutdown(cq); next_call.cq = cq; next_call.event.type = GRPC_QUEUE_TIMEOUT; /* TODO: the timeout should be a module level constant that defaults * to gpr_inf_future(GPR_CLOCK_REALTIME). * * - at the moment this does not work, it stalls. Using a small timeout like * this one works, and leads to fast test run times; a longer timeout was * causing unnecessary delays in the test runs. * * - investigate further, this is probably another example of C-level cleanup * not working consistently in all cases. */ next_call.timeout = gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_micros(5e3, GPR_TIMESPAN)); do { rb_thread_call_without_gvl(grpc_rb_completion_queue_next_no_gil, (void *)&next_call, NULL, NULL); type = next_call.event.type; if (type == GRPC_QUEUE_TIMEOUT) break; if (type != GRPC_QUEUE_SHUTDOWN) { ++drained; rb_warning("completion queue shutdown: %d undrained events", drained); } } while (type != GRPC_QUEUE_SHUTDOWN); }
static void consumer_consume_loop(HermannInstanceConfig* consumerConfig) { rd_kafka_message_t *msg; TRACER("\n"); while (consumerConfig->run) { #ifdef HAVE_RB_THREAD_BLOCKING_REGION msg = (rd_kafka_message_t *) rb_thread_blocking_region((rb_blocking_function_t *) consumer_recv_msg, consumerConfig, consumer_consume_stop_callback, consumerConfig); #elif HAVE_RB_THREAD_CALL_WITHOUT_GVL msg = rb_thread_call_without_gvl(consumer_recv_msg, consumerConfig, consumer_consume_stop_callback, consumerConfig); #else msg = consumer_recv_msg(consumerConfig); #endif if ( msg ) { msg_consume(msg, consumerConfig); rd_kafka_message_destroy(msg); } } }
// Poll channel connectivity states in background thread without the GIL. static VALUE run_poll_channels_loop(VALUE arg) { (void)arg; gpr_log(GPR_DEBUG, "GRPC_RUBY: run_poll_channels_loop - create connection polling thread"); rb_thread_call_without_gvl(run_poll_channels_loop_no_gil, NULL, grpc_rb_event_unblocking_func, NULL); return Qnil; }
static VALUE consumer_consume_loop(VALUE self) { HermannInstanceConfig* consumerConfig; rd_kafka_message_t *msg; Data_Get_Struct(self, HermannInstanceConfig, consumerConfig); TRACER("\n"); while (consumerConfig->run) { #if HAVE_RB_THREAD_BLOCKING_REGION && RUBY_API_VERSION_MAJOR < 2 msg = (rd_kafka_message_t *) rb_thread_blocking_region((rb_blocking_function_t *) consumer_recv_msg, consumerConfig, consumer_consume_stop_callback, consumerConfig); #elif HAVE_RB_THREAD_CALL_WITHOUT_GVL msg = rb_thread_call_without_gvl(consumer_recv_msg, consumerConfig, consumer_consume_stop_callback, consumerConfig); #else msg = consumer_recv_msg(consumerConfig); #endif if ( msg ) { msg_consume(msg, consumerConfig); } } return Qnil; }
/* * Immediately disconnect from the server; normally the garbage collector * will disconnect automatically when a connection is no longer needed. * Explicitly closing this will free up server resources sooner than waiting * for the garbage collector. * * @return [nil] */ static VALUE rb_mysql_client_close(VALUE self) { GET_CLIENT(self); if (wrapper->connected) { rb_thread_call_without_gvl(nogvl_close, wrapper, RUBY_UBF_IO, 0); } return Qnil; }
/* call-seq: * client.ping * * Checks whether the connection to the server is working. If the connection * has gone down and auto-reconnect is enabled an attempt to reconnect is made. * If the connection is down and auto-reconnect is disabled, ping returns an * error. */ static VALUE rb_mysql_client_ping(VALUE self) { GET_CLIENT(self); if (!wrapper->connected) { return Qfalse; } else { return (VALUE)rb_thread_call_without_gvl(nogvl_ping, wrapper->client, RUBY_UBF_IO, 0); } }
VALUE rb_mysql_stmt_new(VALUE rb_client, VALUE sql) { mysql_stmt_wrapper *stmt_wrapper; VALUE rb_stmt; #ifdef HAVE_RUBY_ENCODING_H rb_encoding *conn_enc; #endif Check_Type(sql, T_STRING); rb_stmt = Data_Make_Struct(cMysql2Statement, mysql_stmt_wrapper, rb_mysql_stmt_mark, rb_mysql_stmt_free, stmt_wrapper); { stmt_wrapper->client = rb_client; stmt_wrapper->refcount = 1; stmt_wrapper->closed = 0; stmt_wrapper->stmt = NULL; } // instantiate stmt { GET_CLIENT(rb_client); stmt_wrapper->stmt = mysql_stmt_init(wrapper->client); #ifdef HAVE_RUBY_ENCODING_H conn_enc = rb_to_encoding(wrapper->encoding); #endif } if (stmt_wrapper->stmt == NULL) { rb_raise(cMysql2Error, "Unable to initialize prepared statement: out of memory"); } // set STMT_ATTR_UPDATE_MAX_LENGTH attr { my_bool truth = 1; if (mysql_stmt_attr_set(stmt_wrapper->stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &truth)) { rb_raise(cMysql2Error, "Unable to initialize prepared statement: set STMT_ATTR_UPDATE_MAX_LENGTH"); } } // call mysql_stmt_prepare w/o gvl { struct nogvl_prepare_statement_args args; args.stmt = stmt_wrapper->stmt; args.sql = sql; #ifdef HAVE_RUBY_ENCODING_H // ensure the string is in the encoding the connection is expecting args.sql = rb_str_export_to_enc(args.sql, conn_enc); #endif args.sql_ptr = RSTRING_PTR(sql); args.sql_len = RSTRING_LEN(sql); if ((VALUE)rb_thread_call_without_gvl(nogvl_prepare_statement, &args, RUBY_UBF_IO, 0) == Qfalse) { rb_raise_mysql2_stmt_error(stmt_wrapper); } } return rb_stmt; }
static VALUE do_send_query(void *args) { struct nogvl_send_query_args *query_args = args; mysql_client_wrapper *wrapper = query_args->wrapper; if ((VALUE)rb_thread_call_without_gvl(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); } return Qnil; }
/* * @overload send_eof * Send EOF on the channel. * @since 0.1.0 * @return [nil] * @see http://api.libssh.org/stable/group__libssh__channel.html * ssh_channel_send_eof */ static VALUE m_send_eof(VALUE self) { ChannelHolder *holder; struct nogvl_channel_args args; TypedData_Get_Struct(self, ChannelHolder, &channel_type, holder); args.channel = holder->channel; rb_thread_call_without_gvl(nogvl_send_eof, &args, RUBY_UBF_IO, NULL); RAISE_IF_ERROR(args.rc); return Qnil; }
static VALUE component_create(VALUE self) { component_t *data; TypedData_Get_Struct(self, component_t, &data_type, data); qmlbind_value obj = rb_thread_call_without_gvl((void *(*)(void *))&qmlbind_component_create, data->component, RUBY_UBF_IO, NULL); VALUE result = rbqml_to_ruby(obj); qmlbind_value_release(obj); return result; }
static int service(VALUE self, Connection* connection, enet_uint32 timeout) { CallbackData data = {connection, timeout, -1}; if (timeout > 0) { rb_thread_call_without_gvl(do_service, &data, RUBY_UBF_IO, NULL); } else { do_service(&data); } return data.result; }
static VALUE initialize_ext(VALUE self) { GET_CLIENT(self); if ((VALUE)rb_thread_call_without_gvl(nogvl_init, wrapper, RUBY_UBF_IO, 0) == Qfalse) { /* TODO: warning - not enough memory? */ return rb_raise_mysql2_error(wrapper); } wrapper->initialized = 1; return self; }
/* * @overload request_exec(cmd) * Run a shell command without an interactive shell. * @since 0.1.0 * @param [String] cmd The command to execute * @return [nil] * @see http://api.libssh.org/stable/group__libssh__channel.html * ssh_channel_request_exec */ static VALUE m_request_exec(VALUE self, VALUE cmd) { ChannelHolder *holder; struct nogvl_request_exec_args args; TypedData_Get_Struct(self, ChannelHolder, &channel_type, holder); args.channel = holder->channel; args.cmd = StringValueCStr(cmd); rb_thread_call_without_gvl(nogvl_request_exec, &args, RUBY_UBF_IO, NULL); RAISE_IF_ERROR(args.rc); return Qnil; }
/* Perform the actual HTTP request by calling libcurl. */ static VALUE perform_request(VALUE self) { struct curl_state *state = get_curl_state(self); CURL* curl = state->handle; membuffer* header_buffer = NULL; membuffer* body_buffer = NULL; CURLcode ret = 0; state->interrupt = 0; /* clear any interrupt flags */ header_buffer = &state->header_buffer; body_buffer = &state->body_buffer; membuffer_clear(header_buffer); membuffer_clear(body_buffer); /* headers */ curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, &session_write_handler); curl_easy_setopt(curl, CURLOPT_HEADERDATA, header_buffer); /* body */ if (!state->download_file) { curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &session_write_handler); curl_easy_setopt(curl, CURLOPT_WRITEDATA, body_buffer); } #if (defined(HAVE_TBR) || defined(HAVE_TCWOGVL)) && defined(USE_TBR) #if defined(HAVE_TCWOGVL) ret = (CURLcode) rb_thread_call_without_gvl( (void *(*)(void *)) curl_easy_perform, curl, RUBY_UBF_IO, 0 ); #else ret = (CURLcode) rb_thread_blocking_region( (rb_blocking_function_t*) curl_easy_perform, curl, RUBY_UBF_IO, 0 ); #endif #else ret = curl_easy_perform(curl); #endif if (CURLE_OK == ret) { VALUE header_str = membuffer_to_rb_str(header_buffer); VALUE body_str = Qnil; if (!state->download_file) { body_str = membuffer_to_rb_str(body_buffer); } curl_easy_setopt(curl, CURLOPT_COOKIELIST, "FLUSH"); // Flush cookies to the cookie jar return create_response(self, curl, header_str, body_str); } else { rb_raise(select_error(ret), "%s", state->error_buf); } }
/* Note this is an API-level call; a wrapped channel's finalizer doesn't call * this */ static VALUE grpc_rb_channel_destroy(VALUE self) { grpc_rb_channel* wrapper = NULL; TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); if (wrapper->bg_wrapped != NULL) { rb_thread_call_without_gvl(channel_safe_destroy_without_gil, wrapper->bg_wrapped, NULL, NULL); wrapper->bg_wrapped = NULL; } return Qnil; }
/* call-seq: * client.async_result * * Returns the result for the last async issued query. */ static VALUE rb_mysql_client_async_result(VALUE self) { MYSQL_RES * result; VALUE resultObj; VALUE current, is_streaming; GET_CLIENT(self); /* if we're not waiting on a result, do nothing */ if (NIL_P(wrapper->active_thread)) return Qnil; REQUIRE_CONNECTED(wrapper); if ((VALUE)rb_thread_call_without_gvl(nogvl_read_query_result, wrapper->client, RUBY_UBF_IO, 0) == Qfalse) { /* an error occurred, mark this connection inactive */ MARK_CONN_INACTIVE(self); return rb_raise_mysql2_error(wrapper); } is_streaming = rb_hash_aref(rb_iv_get(self, "@current_query_options"), sym_stream); if (is_streaming == Qtrue) { result = (MYSQL_RES *)rb_thread_call_without_gvl(nogvl_use_result, wrapper, RUBY_UBF_IO, 0); } else { result = (MYSQL_RES *)rb_thread_call_without_gvl(nogvl_store_result, wrapper, RUBY_UBF_IO, 0); } if (result == NULL) { if (mysql_errno(wrapper->client) != 0) { MARK_CONN_INACTIVE(self); rb_raise_mysql2_error(wrapper); } /* no data and no error, so query was not a SELECT */ return Qnil; } current = rb_hash_dup(rb_iv_get(self, "@current_query_options")); (void)RB_GC_GUARD(current); Check_Type(current, T_HASH); resultObj = rb_mysql_result_to_obj(self, wrapper->encoding, current, result, Qnil); return resultObj; }
/* Returns true if the thread is interrupted. */ static VALUE thread_spec_rb_thread_call_without_gvl(VALUE self) { int fds[2]; void* ret; if (pipe(fds) == -1) { return Qfalse; } ret = rb_thread_call_without_gvl(blocking_gvl_func, (void*)(size_t)fds[0], unblock_gvl_func, (void*)(size_t)fds[1]); close(fds[0]); close(fds[1]); return (VALUE)ret; }
/* * @overload get_exit_status * Get the exit status of the channel. * @since 0.1.0 * @return [Fixnum, nil] The exit status. +nil+ if no exit status has been * returned. * @see http://api.libssh.org/stable/group__libssh__channel.html * ssh_channel_get_exit_status */ static VALUE m_get_exit_status(VALUE self) { ChannelHolder *holder; struct nogvl_channel_args args; TypedData_Get_Struct(self, ChannelHolder, &channel_type, holder); args.channel = holder->channel; rb_thread_call_without_gvl(nogvl_get_exit_status, &args, RUBY_UBF_IO, NULL); if (args.rc == -1) { return Qnil; } else { return INT2FIX(args.rc); } }
/* * @overload write(data) * Write data on the channel. * @since 0.1.0 * @param [String] data Data to write. * @return [Fixnum] The number of bytes written. * @see http://api.libssh.org/stable/group__libssh__channel.html * ssh_channel_write */ static VALUE m_write(VALUE self, VALUE data) { ChannelHolder *holder; struct nogvl_write_args args; Check_Type(data, T_STRING); TypedData_Get_Struct(self, ChannelHolder, &channel_type, holder); args.channel = holder->channel; args.data = RSTRING_PTR(data); args.len = RSTRING_LEN(data); rb_thread_call_without_gvl(nogvl_write, &args, RUBY_UBF_IO, NULL); RAISE_IF_ERROR(args.rc); return INT2FIX(args.rc); }
/* Blocks until the next event is available, and returns the event. */ static VALUE grpc_rb_completion_queue_next(VALUE self, VALUE timeout) { next_call_stack next_call; MEMZERO(&next_call, next_call_stack, 1); Data_Get_Struct(self, grpc_completion_queue, next_call.cq); next_call.timeout = grpc_rb_time_timeval(timeout, /* absolute time*/ 0); next_call.event = NULL; rb_thread_call_without_gvl(grpc_rb_completion_queue_next_no_gil, (void *)&next_call, NULL, NULL); if (next_call.event == NULL) { return Qnil; } return grpc_rb_new_event(next_call.event); }