/* * Holds thread execution while another thread is active. * * Thanks to this, all threads are "frozen" while the user is typing commands. */ void acquire_lock(debug_context_t * dc) { while ((!NIL_P(locker) && locker != rb_thread_current()) || CTX_FL_TEST(dc, CTX_FL_SUSPEND)) { add_to_locked(rb_thread_current()); rb_thread_stop(); if (CTX_FL_TEST(dc, CTX_FL_SUSPEND)) CTX_FL_SET(dc, CTX_FL_WAS_RUNNING); } locker = rb_thread_current(); }
/* * call-seq: * Kernel.each_backtrace_frame( & block ) * * Return array of hashes with object and method frame information for backtrace. * Specifying number_of_frames will cause only the last number_of_frames to be returned. * Kernel.backtrace returns all frames including the current context (__method__/__callee__). */ VALUE rb_RPRuby_Sender_Kernel_each_backtrace_frame( int argc, VALUE* args, VALUE rb_self ) { rb_thread_t* c_thread = (rb_thread_t *)RTYPEDDATA_DATA(rb_thread_current()); // Get the current frame - we're doing a backtrace, so our current working frame to start is the first previous thread rb_control_frame_t* c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( RUBY_VM_PREVIOUS_CONTROL_FRAME( c_thread->cfp ) ); // c_top_of_control_frame describes the top edge of the stack trace // set c_top_of_control_frame to the first frame in <main> rb_control_frame_t* c_top_of_control_frame = RUBY_VM_NEXT_CONTROL_FRAME( RUBY_VM_NEXT_CONTROL_FRAME( (void *)( c_thread->stack + c_thread->stack_size ) ) ); VALUE rb_stored_backtrace_array = Qnil; // if we were passed a stored backtrace array, use it if ( argc == 1 && TYPE( args[ 0 ] ) == T_ARRAY ) { rb_stored_backtrace_array = args[ 0 ]; } // for each control frame: while ( c_current_context_frame < c_top_of_control_frame ) { VALUE rb_frame_hash; // if we are using a stored backtrace we don't need to ask for a new hash if ( rb_stored_backtrace_array == Qnil ) { rb_frame_hash = rb_RPRuby_Sender_Kernel_internal_backtraceHashForControlFrame( & c_current_context_frame ); } else { rb_frame_hash = rb_ary_shift( rb_stored_backtrace_array ); } if ( rb_frame_hash == Qnil ) { break; } // if we try to iterate using an Enumerator we will lose our context if ( ! rb_block_given_p() ) { // we solve this by assuming that the desired context is the moment when each_backtrace_frame is called // this allows us to store the backtrace and iterate it as we want // the only downside is that we have to get the entire backtrace first in order to store it rb_stored_backtrace_array = rb_RPRuby_Sender_Kernel_backtrace( 0, NULL, rb_self ); RETURN_ENUMERATOR( rb_self, 1, & rb_stored_backtrace_array ); } // otherwise, yield the block rb_yield( rb_frame_hash ); // only move the frame if we are not using a stored backtrace if ( rb_stored_backtrace_array == Qnil ) { c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( c_current_context_frame ); } } return Qnil; }
static VALUE queue_do_pop(VALUE self, int should_block) { struct waiting_delete args; args.waiting = GET_QUEUE_WAITERS(self); args.th = rb_thread_current(); while (queue_length(self) == 0) { if (!should_block) { rb_raise(rb_eThreadError, "queue empty"); } else if (queue_closed_p(self)) { return queue_closed_result(self); } else { assert(queue_length(self) == 0); assert(queue_closed_p(self) == 0); rb_ary_push(args.waiting, args.th); rb_ensure(queue_sleep, (VALUE)0, queue_delete_from_waiting, (VALUE)&args); } } return rb_ary_shift(GET_QUEUE_QUE(self)); }
static VALUE rb_czmq_ctx_socket(VALUE obj, VALUE type) { VALUE socket; int socket_type; struct nogvl_socket_args args; zmq_sock_wrapper *sock = NULL; errno = 0; ZmqGetContext(obj); if (TYPE(type) != T_FIXNUM && TYPE(type) != T_SYMBOL) rb_raise(rb_eTypeError, "wrong socket type %s (expected Fixnum or Symbol)", RSTRING_PTR(rb_obj_as_string(type))); socket_type = FIX2INT((SYMBOL_P(type)) ? rb_const_get_at(rb_mZmq, rb_to_id(type)) : type); socket = Data_Make_Struct(rb_czmq_ctx_socket_klass(socket_type), zmq_sock_wrapper, rb_czmq_mark_sock, rb_czmq_free_sock_gc, sock); args.ctx = ctx->ctx; args.type = socket_type; sock->socket = (void*)rb_thread_blocking_region(rb_czmq_nogvl_socket_new, (void *)&args, RUBY_UBF_IO, 0); ZmqAssertObjOnAlloc(sock->socket, sock); #ifndef HAVE_RB_THREAD_BLOCKING_REGION sock->str_buffer = zlist_new(); sock->frame_buffer = zlist_new(); sock->msg_buffer = zlist_new(); #endif sock->handler = Qnil; sock->flags = 0; sock->ctx = ctx->ctx; sock->verbose = FALSE; sock->state = ZMQ_SOCKET_PENDING; sock->endpoint = Qnil; sock->thread = rb_thread_current(); sock->recv_timeout = ZMQ_SOCKET_DEFAULT_TIMEOUT; sock->send_timeout = ZMQ_SOCKET_DEFAULT_TIMEOUT; rb_obj_call_init(socket, 0, NULL); return socket; }
/** * enable_line_trace_for_thread * Turn on line event trace for current thread. Also set a flag * "gcloud_line_trace_set" to Qtrue in current thread's thread variable. */ static VALUE enable_line_trace_for_thread(VALUE self) { VALUE current_thread; VALUE thread_variables_hash; VALUE line_trace_set; ID locals_id; ID line_trace_thread_id; VALUE line_trace_thread_flag; CONST_ID(locals_id, "locals"); CONST_ID(line_trace_thread_id, "gcloud_line_trace_set"); line_trace_thread_flag = ID2SYM(line_trace_thread_id); current_thread = rb_thread_current(); thread_variables_hash = rb_ivar_get(current_thread, locals_id); line_trace_set = rb_hash_aref(thread_variables_hash, line_trace_thread_flag); if (!RTEST(line_trace_set)) { rb_thread_add_event_hook(current_thread, line_trace_callback, RUBY_EVENT_LINE, self); rb_hash_aset(thread_variables_hash, line_trace_thread_flag, Qtrue); } return Qnil; }
/** * disable_return_trace_for_thread * Turn off return events trace hook for a given thread. If no thread is given, it * turns off line event trace hook in current thread. It only takes action if * the thread has a thread variable "gcloud_return_trace_set" that's true. */ static VALUE disable_return_trace_for_thread(VALUE thread) { VALUE thread_variables_hash; VALUE return_trace_set; ID locals_id; ID return_trace_thread_id; VALUE return_trace_thread_flag; CONST_ID(locals_id, "locals"); CONST_ID(return_trace_thread_id, "gcloud_return_trace_set"); return_trace_thread_flag = ID2SYM(return_trace_thread_id); if (!RTEST(thread)) { thread = rb_thread_current(); } thread_variables_hash = rb_ivar_get(thread, locals_id); return_trace_set = rb_hash_aref(thread_variables_hash, return_trace_thread_flag); if (RTEST(return_trace_set)) { rb_thread_remove_event_hook(thread, (rb_event_hook_func_t)return_trace_callback); rb_hash_aset(thread_variables_hash, return_trace_thread_flag, Qfalse); } return Qnil; }
static VALUE blocking_function_execute(blocking_region_arg_t *arg) { oci8_svcctx_t *svcctx = arg->svcctx; void *(*func)(void *) = arg->func; void *data = arg->data; struct timeval tv; sword rv; tv.tv_sec = 0; tv.tv_usec = 10000; svcctx->executing_thread = rb_thread_current(); while ((rv = (sword)(VALUE)func(data)) == OCI_STILL_EXECUTING) { rb_thread_wait_for(tv); if (tv.tv_usec < 500000) tv.tv_usec <<= 1; } if (rv == OCI_ERROR) { if (oci8_get_error_code(oci8_errhp) == 1013) { OCIReset(svcctx->base.hp.ptr, oci8_errhp); svcctx->executing_thread = Qnil; rb_raise(eOCIBreak, "Canceled by user request."); } } svcctx->executing_thread = Qnil; return rv; }
static VALUE frame_count(VALUE self) { rb_thread_t *th; GetThreadPtr(rb_thread_current(), th); rb_control_frame_t *cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp); rb_control_frame_t *limit_cfp = (void *)(th->stack + th->stack_size); int i = 1; while (cfp < limit_cfp) { cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); if (cfp >= limit_cfp) return INT2FIX(i); // skip invalid frames if (!valid_frame_p(cfp, limit_cfp)) cfp = find_valid_frame(cfp, limit_cfp); if (!cfp) break; i++; } return INT2FIX(i); }
static VALUE lock_mutex(Mutex *mutex) { VALUE current; current = rb_thread_current(); rb_thread_critical = 1; if (!MUTEX_LOCKED_P(mutex)) { mutex->owner = current; } else { do { wait_list(&mutex->waiting); rb_thread_critical = 1; if (!MUTEX_LOCKED_P(mutex)) { mutex->owner = current; break; } } while (mutex->owner != current); } rb_thread_critical = 0; return Qnil; }
/** * enable_return_trace_for_thread * Turn on return events trace for current thread. Also set a flag * "gcloud_return_trace_set" to Qtrue in current thread's thread variable. */ static VALUE enable_return_trace_for_thread(VALUE self) { VALUE current_thread; VALUE thread_variables_hash; VALUE return_trace_set; ID locals_id; ID return_trace_thread_id; VALUE return_trace_thread_flag; CONST_ID(locals_id, "locals"); CONST_ID(return_trace_thread_id, "gcloud_return_trace_set"); return_trace_thread_flag = ID2SYM(return_trace_thread_id); current_thread = rb_thread_current(); thread_variables_hash = rb_ivar_get(current_thread, locals_id); return_trace_set = rb_hash_aref(thread_variables_hash, return_trace_thread_flag); if (!RTEST(return_trace_set)) { rb_thread_add_event_hook2(current_thread, (rb_event_hook_func_t)return_trace_callback, RETURN_TRACEPOINT_EVENTS, self, RUBY_EVENT_HOOK_FLAG_RAW_ARG | RUBY_EVENT_HOOK_FLAG_SAFE); rb_hash_aset(thread_variables_hash, return_trace_thread_flag, Qtrue); } return Qnil; }
static VALUE rb_enable_method_trace_for_thread(VALUE self) { VALUE current_thread; VALUE thread_variables_hash; VALUE trace_set; VALUE evaluator; ID current_evaluator_id; ID locals_id; ID eval_trace_thread_id; VALUE eval_trace_thread_flag; CONST_ID(current_evaluator_id, "current"); CONST_ID(locals_id, "locals"); CONST_ID(eval_trace_thread_id, "gcloud_eval_trace_set"); eval_trace_thread_flag = ID2SYM(eval_trace_thread_id); current_thread = rb_thread_current(); thread_variables_hash = rb_ivar_get(current_thread, locals_id); trace_set = rb_hash_aref(thread_variables_hash, eval_trace_thread_flag); evaluator = rb_funcall(self, current_evaluator_id, 0); if (!RTEST(trace_set)) { rb_thread_add_event_hook2(current_thread, (rb_event_hook_func_t)eval_trace_callback, RUBY_EVENT_CALL | RUBY_EVENT_C_CALL, evaluator, RUBY_EVENT_HOOK_FLAG_RAW_ARG | RUBY_EVENT_HOOK_FLAG_SAFE); rb_hash_aset(thread_variables_hash, eval_trace_thread_flag, Qtrue); } return Qnil; }
// default behavior of async (doesn't accept Symbol) // call-seq: // async { } // async Proc.new static VALUE kern_async(int argc, VALUE *argv, VALUE self) { VALUE obj; rb_proc_t *proc; rb_iseq_t *niseq; rb_scan_args(argc, argv, "01", &obj); if (!NIL_P(obj)) { if (!rb_obj_is_proc(obj)) { VALUE thread = rb_thread_current(); rb_thread_t * th; TypedData_Get_Struct(thread, rb_thread_t, RTYPEDDATA_TYPE(thread), th); if (self == th->vm->top_self) { return mod_async(CLASS_OF(self), obj); } else { rb_raise(rb_eTypeError, "wrong argument type (expected Proc)"); } } } else if (rb_block_given_p()) { obj = rb_block_proc(); } else { rb_raise(rb_eArgError, "Proc or block is required"); } proc = (rb_proc_t *)DATA_PTR(obj); // うーーー niseq = transform(obj); proc->block.iseq = niseq; return obj; }
static VALUE wait_list_inner(List *list) { push_list(list, rb_thread_current()); rb_thread_stop(); return Qnil; }
static VALUE wait_list_cleanup(List *list) { /* cleanup in case of spurious wakeups */ remove_one(list, rb_thread_current()); return Qnil; }
static VALUE dnssd_service_stop(VALUE self) { VALUE thread; DNSServiceRef *client; get(cDNSSDService, self, DNSServiceRef, client); RDATA(self)->data = NULL; if (client == NULL) rb_raise(eDNSSDError, "service is already stopped"); thread = rb_ivar_get(self, dnssd_iv_thread); rb_ivar_set(self, dnssd_iv_continue, Qfalse); if (!NIL_P(thread) && thread != rb_thread_current()) { rb_thread_run(thread); rb_funcall(thread, dnssd_id_join, 0); } dnssd_service_free_client(client); rb_ivar_set(self, dnssd_iv_type, Qnil); return self; }
VALUE rho_ruby_current_thread() { if ( ruby_native_thread_p() != 1 ) return 0; return rb_thread_current(); }
static VALUE rb_szqueue_push(int argc, VALUE *argv, VALUE self) { struct waiting_delete args; int should_block = szqueue_push_should_block(argc, argv); args.waiting = GET_SZQUEUE_WAITERS(self); args.th = rb_thread_current(); while (queue_length(self) >= GET_SZQUEUE_ULONGMAX(self)) { if (!should_block) { rb_raise(rb_eThreadError, "queue full"); } else if (queue_closed_p(self)) { goto closed; } else { rb_ary_push(args.waiting, args.th); rb_ensure((VALUE (*)())rb_thread_sleep_deadly, (VALUE)0, queue_delete_from_waiting, (VALUE)&args); } } if (queue_closed_p(self)) { closed: raise_closed_queue_error(self); } return queue_do_push(self, argv[0]); }
static VALUE application_initialize(VALUE self, VALUE args) { if (rb_thread_main() != rb_thread_current()) { rb_raise(rb_eThreadError, "Initializing QML::Application outside the main thread"); } application_t *data; TypedData_Get_Struct(self, application_t, &data_type, data); if (rb_type(args) != T_ARRAY) { rb_raise(rb_eTypeError, "Expected Array"); } args = rb_ary_concat(rb_ary_new_from_args(1, rb_argv0), args); int argc = RARRAY_LEN(args); char **argv = malloc(argc * sizeof(char *)); for (int i = 0; i < argc; ++i) { VALUE arg = RARRAY_AREF(args, i); argv[i] = rb_string_value_cstr(&arg); } data->application = qmlbind_application_new(argc, argv); return self; }
rb_control_frame_t* RPRuby_internal_framePriorTo( rb_control_frame_t* c_control_frame ) { rb_thread_t* c_thread = (rb_thread_t *)RTYPEDDATA_DATA(rb_thread_current()); rb_control_frame_t* c_prior_control_frame = NULL; // get the current frame pointer if ( c_control_frame == NULL ) { c_control_frame = c_thread->cfp; } if ( ( c_prior_control_frame = rb_vm_get_ruby_level_next_cfp( c_thread, c_control_frame ) ) != 0) { // not sure why we have to call this a second time after it was called at the end of rb_vm_get_ruby_level_next_cfp, // but for some reason it seems to be necessary c_prior_control_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( c_prior_control_frame ); } else { c_prior_control_frame = NULL; } // if we have a nil object we've passed main, we're done if ( c_prior_control_frame->self == Qnil ) { return NULL; } return c_prior_control_frame; }
static VALUE rb_disable_method_trace_for_thread(VALUE self) { VALUE current_thread; VALUE thread_variables_hash; VALUE trace_set; ID locals_id; ID eval_trace_thread_id; VALUE eval_trace_thread_flag; CONST_ID(locals_id, "locals"); CONST_ID(eval_trace_thread_id, "gcloud_eval_trace_set"); eval_trace_thread_flag = ID2SYM(eval_trace_thread_id); current_thread = rb_thread_current(); thread_variables_hash = rb_ivar_get(current_thread, locals_id); trace_set = rb_hash_aref(thread_variables_hash, eval_trace_thread_flag); if (RTEST(trace_set)) { rb_thread_remove_event_hook(current_thread, (rb_event_hook_func_t)eval_trace_callback); rb_hash_aset(thread_variables_hash, eval_trace_thread_flag, Qfalse); } return Qnil; }
static VALUE cb_unset_tracer(VALUE self) { if(rb_iv_get(self, "@tracer_set")) { rb_thread_remove_event_hook(rb_thread_current(), trace_line_handler_ext); rb_iv_set(self, "@tracer_set", Qfalse); } return Qnil; }
/** * rb_disable_traces_for_thread * It disables line tracing and return event tracing for current thread. */ static VALUE rb_disable_traces_for_thread(VALUE self) { VALUE thread = rb_thread_current(); disable_line_trace_for_thread(thread); disable_return_trace_for_thread(thread); return Qnil; }
/* * call-seq: * Byebug.lock -> Thread.current * * Locks global switch to reserve execution to current thread exclusively. */ static VALUE Lock(VALUE self) { debug_context_t *dc; VALUE context; UNUSED(self); if (!is_living_thread(rb_thread_current())) rb_raise(rb_eRuntimeError, "Current thread is dead!"); thread_context_lookup(rb_thread_current(), &context); Data_Get_Struct(context, debug_context_t, dc); acquire_lock(dc); return locker; }
static VALUE chdir_yield(struct chdir_data *args) { dir_chdir(args->new_path); args->done = Qtrue; chdir_blocking++; if (chdir_thread == Qnil) chdir_thread = rb_thread_current(); return rb_yield(args->new_path); }
VALUE rho_ruby_current_thread() { if (!rho_ruby_is_started()) return 0; if ( ruby_native_thread_p() != 1 ) return 0; return rb_thread_current(); }
static inline const rb_data_type_t * threadptr_data_type(void) { static const rb_data_type_t *thread_data_type; if (!thread_data_type) { VALUE current_thread = rb_thread_current(); thread_data_type = RTYPEDDATA_TYPE(current_thread); } return thread_data_type; }
static VALUE cb_set_tracer(VALUE self) { if(!rb_iv_get(self, "@tracer_set")) { // NOTE: We are using rb_add_event_hook opposed to rb_tracepoint_new for 1.9.X compat // not using higher level C functions of set_trace_func to avoid extra overhead we don't need since we only need the RUBY_EVENT_LINE hook as well as only needing file / line number opposed to everything else. rb_thread_add_event_hook(rb_thread_current(), trace_line_handler_ext, RUBY_EVENT_LINE, 0); rb_iv_set(self, "@tracer_set", Qtrue); } return Qnil; }
VALUE rb_xthread_monitor_enter_for_cond(VALUE self, long count) { xthread_monitor_t *mon; VALUE th = rb_thread_current(); GetXThreadMonitorPtr(self, mon); mon->owner = th; mon->count = count; }
static void wait_condvar(ConditionVariable *condvar, Mutex *mutex) { //rb_thread_critical = 1; if (rb_thread_current() != mutex->owner) { //rb_thread_critical = 0; rb_raise(private_eThreadError, "not owner of the synchronization mutex"); } unlock_mutex_inner(mutex); rb_ensure(wait_list, (VALUE)&condvar->waiting, lock_mutex, (VALUE)mutex); }
/* * call-seq: * Byebug.current_context -> context * * Returns the current context. * <i>Note:</i> Byebug.current_context.thread == Thread.current */ static VALUE Current_context(VALUE self) { VALUE context; UNUSED(self); thread_context_lookup(rb_thread_current(), &context); return context; }