1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/ext/-test-/thread/instrumentation/instrumentation.c
2022-07-08 10:55:44 +09:00

141 lines
4.4 KiB
C

#include "ruby/ruby.h"
#include "ruby/atomic.h"
#include "ruby/thread.h"
static rb_atomic_t started_count = 0;
static rb_atomic_t ready_count = 0;
static rb_atomic_t resumed_count = 0;
static rb_atomic_t suspended_count = 0;
static rb_atomic_t exited_count = 0;
#if __STDC_VERSION__ >= 201112
#define RB_THREAD_LOCAL_SPECIFIER _Thread_local
#elif defined(__GNUC__) && !defined(RB_THREAD_LOCAL_SPECIFIER_IS_UNSUPPORTED)
/* note that ICC (linux) and Clang are covered by __GNUC__ */
#define RB_THREAD_LOCAL_SPECIFIER __thread
#else
#define RB_THREAD_LOCAL_SPECIFIER
#endif
static RB_THREAD_LOCAL_SPECIFIER unsigned int local_ready_count = 0;
static RB_THREAD_LOCAL_SPECIFIER unsigned int local_resumed_count = 0;
static RB_THREAD_LOCAL_SPECIFIER unsigned int local_suspended_count = 0;
static void
ex_callback(rb_event_flag_t event, const rb_internal_thread_event_data_t *event_data, void *user_data)
{
switch (event) {
case RUBY_INTERNAL_THREAD_EVENT_STARTED:
RUBY_ATOMIC_INC(started_count);
break;
case RUBY_INTERNAL_THREAD_EVENT_READY:
RUBY_ATOMIC_INC(ready_count);
local_ready_count++;
break;
case RUBY_INTERNAL_THREAD_EVENT_RESUMED:
RUBY_ATOMIC_INC(resumed_count);
local_resumed_count++;
break;
case RUBY_INTERNAL_THREAD_EVENT_SUSPENDED:
RUBY_ATOMIC_INC(suspended_count);
local_suspended_count++;
break;
case RUBY_INTERNAL_THREAD_EVENT_EXITED:
RUBY_ATOMIC_INC(exited_count);
break;
}
}
static rb_internal_thread_event_hook_t * single_hook = NULL;
static VALUE
thread_counters(VALUE thread)
{
VALUE array = rb_ary_new2(5);
rb_ary_push(array, UINT2NUM(started_count));
rb_ary_push(array, UINT2NUM(ready_count));
rb_ary_push(array, UINT2NUM(resumed_count));
rb_ary_push(array, UINT2NUM(suspended_count));
rb_ary_push(array, UINT2NUM(exited_count));
return array;
}
static VALUE
thread_local_counters(VALUE thread)
{
VALUE array = rb_ary_new2(3);
rb_ary_push(array, UINT2NUM(local_ready_count));
rb_ary_push(array, UINT2NUM(local_resumed_count));
rb_ary_push(array, UINT2NUM(local_suspended_count));
return array;
}
static VALUE
thread_reset_counters(VALUE thread)
{
RUBY_ATOMIC_SET(started_count, 0);
RUBY_ATOMIC_SET(ready_count, 0);
RUBY_ATOMIC_SET(resumed_count, 0);
RUBY_ATOMIC_SET(suspended_count, 0);
RUBY_ATOMIC_SET(exited_count, 0);
local_ready_count = 0;
local_resumed_count = 0;
local_suspended_count = 0;
return Qtrue;
}
static VALUE
thread_register_callback(VALUE thread)
{
single_hook = rb_internal_thread_add_event_hook(
ex_callback,
RUBY_INTERNAL_THREAD_EVENT_STARTED |
RUBY_INTERNAL_THREAD_EVENT_READY |
RUBY_INTERNAL_THREAD_EVENT_RESUMED |
RUBY_INTERNAL_THREAD_EVENT_SUSPENDED |
RUBY_INTERNAL_THREAD_EVENT_EXITED,
NULL
);
return Qnil;
}
static VALUE
thread_unregister_callback(VALUE thread)
{
if (single_hook) {
rb_internal_thread_remove_event_hook(single_hook);
single_hook = NULL;
}
return Qnil;
}
static VALUE
thread_register_and_unregister_callback(VALUE thread)
{
rb_internal_thread_event_hook_t * hooks[5];
for (int i = 0; i < 5; i++) {
hooks[i] = rb_internal_thread_add_event_hook(ex_callback, RUBY_INTERNAL_THREAD_EVENT_READY, NULL);
}
if (!rb_internal_thread_remove_event_hook(hooks[4])) return Qfalse;
if (!rb_internal_thread_remove_event_hook(hooks[0])) return Qfalse;
if (!rb_internal_thread_remove_event_hook(hooks[3])) return Qfalse;
if (!rb_internal_thread_remove_event_hook(hooks[2])) return Qfalse;
if (!rb_internal_thread_remove_event_hook(hooks[1])) return Qfalse;
return Qtrue;
}
void
Init_instrumentation(void)
{
VALUE mBug = rb_define_module("Bug");
VALUE klass = rb_define_module_under(mBug, "ThreadInstrumentation");
rb_define_singleton_method(klass, "counters", thread_counters, 0);
rb_define_singleton_method(klass, "local_counters", thread_local_counters, 0);
rb_define_singleton_method(klass, "reset_counters", thread_reset_counters, 0);
rb_define_singleton_method(klass, "register_callback", thread_register_callback, 0);
rb_define_singleton_method(klass, "unregister_callback", thread_unregister_callback, 0);
rb_define_singleton_method(klass, "register_and_unregister_callbacks", thread_register_and_unregister_callback, 0);
}