Skip to content

Commit

Permalink
Call the gvl hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
byroot committed Jan 25, 2022
1 parent 4d48cfe commit 1d72486
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 38 deletions.
4 changes: 2 additions & 2 deletions ext/-test-/gvl/call_without_gvl/call_without_gvl.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ static gvl_hook_t * single_hook = NULL;

static VALUE
thread_register_gvl_callback(VALUE thread) {
single_hook = rb_gvl_event_new(*ex_callback, 0x12);
single_hook = rb_gvl_event_new(*ex_callback, RUBY_INTERNAL_EVENT_GVL_ACQUIRE_ENTER, 1);

return Qnil;
}
Expand All @@ -103,7 +103,7 @@ static VALUE
thread_register_and_unregister_gvl_callback(VALUE thread) {
gvl_hook_t * hooks[5];
for (int i = 0; i < 5; i++) {
hooks[i] = rb_gvl_event_new(*ex_callback, 0x12);
hooks[i] = rb_gvl_event_new(*ex_callback, RUBY_INTERNAL_EVENT_GVL_ACQUIRE_ENTER);
}

if (!rb_gvl_event_delete(hooks[4])) return Qfalse;
Expand Down
28 changes: 16 additions & 12 deletions include/ruby/internal/event.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,18 +82,22 @@
*
* @{
*/
#define RUBY_INTERNAL_EVENT_SWITCH 0x040000 /**< Thread switched. */
#define RUBY_EVENT_SWITCH 0x040000 /**< @old{RUBY_INTERNAL_EVENT_SWITCH} */
/* 0x080000 */
#define RUBY_INTERNAL_EVENT_NEWOBJ 0x100000 /**< Object allocated. */
#define RUBY_INTERNAL_EVENT_FREEOBJ 0x200000 /**< Object swept. */
#define RUBY_INTERNAL_EVENT_GC_START 0x400000 /**< GC started. */
#define RUBY_INTERNAL_EVENT_GC_END_MARK 0x800000 /**< GC ended mark phase. */
#define RUBY_INTERNAL_EVENT_GC_END_SWEEP 0x1000000 /**< GC ended sweep phase. */
#define RUBY_INTERNAL_EVENT_GC_ENTER 0x2000000 /**< `gc_enter()` is called. */
#define RUBY_INTERNAL_EVENT_GC_EXIT 0x4000000 /**< `gc_exit()` is called. */
#define RUBY_INTERNAL_EVENT_OBJSPACE_MASK 0x7f00000 /**< Bitmask of GC events. */
#define RUBY_INTERNAL_EVENT_MASK 0xffff0000 /**< Bitmask of internal events. */
#define RUBY_INTERNAL_EVENT_SWITCH 0x00040000 /**< Thread switched. */
#define RUBY_EVENT_SWITCH 0x00040000 /**< @old{RUBY_INTERNAL_EVENT_SWITCH} */
/*0x00080000 */
#define RUBY_INTERNAL_EVENT_NEWOBJ 0x00100000 /**< Object allocated. */
#define RUBY_INTERNAL_EVENT_FREEOBJ 0x00200000 /**< Object swept. */
#define RUBY_INTERNAL_EVENT_GC_START 0x00400000 /**< GC started. */
#define RUBY_INTERNAL_EVENT_GC_END_MARK 0x00800000 /**< GC ended mark phase. */
#define RUBY_INTERNAL_EVENT_GC_END_SWEEP 0x01000000 /**< GC ended sweep phase. */
#define RUBY_INTERNAL_EVENT_GC_ENTER 0x02000000 /**< `gc_enter()` is called. */
#define RUBY_INTERNAL_EVENT_GC_EXIT 0x04000000 /**< `gc_exit()` is called. */
#define RUBY_INTERNAL_EVENT_OBJSPACE_MASK 0x07f00000 /**< Bitmask of GC events. */
#define RUBY_INTERNAL_EVENT_GVL_ACQUIRE_ENTER 0x10000000 /** `gvl_acquire() is called */
#define RUBY_INTERNAL_EVENT_GVL_ACQUIRE_EXIT 0x20000000 /** `gvl_acquire() is exiting successfully */
#define RUBY_INTERNAL_EVENT_GVL_RELEASE 0x40000000 /** `gvl_release() is called */
#define RUBY_INTERNAL_EVENT_GVL_MASK 0x70000000 /**< Bitmask of GVL events. */
#define RUBY_INTERNAL_EVENT_MASK 0xffff0000 /**< Bitmask of internal events. */

/** @} */

Expand Down
16 changes: 7 additions & 9 deletions include/ruby/thread_native.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,26 +201,24 @@ void rb_native_cond_initialize(rb_nativethread_cond_t *cond);
*/
void rb_native_cond_destroy(rb_nativethread_cond_t *cond);

#include <stdint.h>
struct gvl_hook_event_args {
//
};
#include <stdint.h>
typedef struct gvl_hook_event_args {
unsigned long waiting;
} gvl_hook_event_args_t;

typedef void (*rb_gvl_callback)(uint32_t event, struct gvl_hook_event_args args);
typedef void (*rb_gvl_callback)(uint32_t event, gvl_hook_event_args_t args);

// TODO: this is going to be the same on Windows so move it somewhere sensible
typedef struct gvl_hook {
rb_gvl_callback callback;
uint32_t event;
rb_event_flag_t event;

struct gvl_hook *next;
} gvl_hook_t;

#include "ruby/internal/memory.h"

gvl_hook_t * rb_gvl_event_new(void *callback, uint32_t event);
gvl_hook_t * rb_gvl_event_new(void *callback, rb_event_flag_t event);
bool rb_gvl_event_delete(gvl_hook_t * hook);
void rb_gvl_execute_hooks(uint32_t event);
void rb_gvl_execute_hooks(rb_event_flag_t event, unsigned long waiting);
RBIMPL_SYMBOL_EXPORT_END()
#endif
41 changes: 26 additions & 15 deletions thread_pthread.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ static gvl_hook_t * rb_gvl_hooks = NULL;
static pthread_rwlock_t rb_gvl_hooks_rw_lock = PTHREAD_RWLOCK_INITIALIZER;

gvl_hook_t *
rb_gvl_event_new(void *callback, uint32_t event) {
rb_gvl_event_new(void *callback, rb_event_flag_t event) {
gvl_hook_t *hook = ALLOC_N(gvl_hook_t, 1);
hook->callback = callback;
hook->event = event;
Expand Down Expand Up @@ -155,25 +155,21 @@ rb_gvl_event_delete(gvl_hook_t * hook) {
}

void
rb_gvl_execute_hooks(uint32_t event) {
if (!rb_gvl_hooks) {
return;
}

rb_gvl_execute_hooks(rb_event_flag_t event, unsigned long waiting) {
if (pthread_rwlock_rdlock(&rb_gvl_hooks_rw_lock)) {
// TODO: better way to deal with error?
return;
}

gvl_hook_t *h = rb_gvl_hooks;
struct gvl_hook_event_args args = {};

do {
if (h->event & event) {
(*h->callback)(event, args);
}
} while((h = h->next));

if (rb_gvl_hooks) {
gvl_hook_t *h = rb_gvl_hooks;
gvl_hook_event_args_t args = { .waiting = waiting };
do {
if (h->event & event) {
(*h->callback)(event, args);
}
} while((h = h->next));
}
pthread_rwlock_unlock(&rb_gvl_hooks_rw_lock);
}

Expand Down Expand Up @@ -366,6 +362,10 @@ gvl_acquire_common(rb_global_vm_lock_t *gvl, rb_thread_t *th)
"we must not be in ubf_list and GVL waitq at the same time");

list_add_tail(&gvl->waitq, &nd->node.gvl);
gvl->waiting++;
if (rb_gvl_hooks) {
rb_gvl_execute_hooks(RUBY_INTERNAL_EVENT_GVL_ACQUIRE_ENTER, gvl->waiting);
}

do {
if (!gvl->timer) {
Expand All @@ -377,6 +377,7 @@ gvl_acquire_common(rb_global_vm_lock_t *gvl, rb_thread_t *th)
} while (gvl->owner);

list_del_init(&nd->node.gvl);
gvl->waiting--;

if (gvl->need_yield) {
gvl->need_yield = 0;
Expand All @@ -387,6 +388,11 @@ gvl_acquire_common(rb_global_vm_lock_t *gvl, rb_thread_t *th)
gvl->timer_err = ETIMEDOUT;
}
gvl->owner = th;

if (rb_gvl_hooks) {
rb_gvl_execute_hooks(RUBY_INTERNAL_EVENT_GVL_ACQUIRE_EXIT, gvl->waiting);
}

if (!gvl->timer) {
if (!designate_timer_thread(gvl) && !ubf_threads_empty()) {
rb_thread_wakeup_timer_thread(-1);
Expand All @@ -405,6 +411,10 @@ gvl_acquire(rb_global_vm_lock_t *gvl, rb_thread_t *th)
static const native_thread_data_t *
gvl_release_common(rb_global_vm_lock_t *gvl)
{
if (rb_gvl_hooks) {
rb_gvl_execute_hooks(RUBY_INTERNAL_EVENT_GVL_RELEASE, gvl->waiting);
}

native_thread_data_t *next;
gvl->owner = 0;
next = list_top(&gvl->waitq, native_thread_data_t, node.ubf);
Expand Down Expand Up @@ -466,6 +476,7 @@ rb_gvl_init(rb_global_vm_lock_t *gvl)
rb_native_cond_initialize(&gvl->switch_wait_cond);
list_head_init(&gvl->waitq);
gvl->owner = 0;
gvl->waiting = 0;
gvl->timer = 0;
gvl->timer_err = ETIMEDOUT;
gvl->need_yield = 0;
Expand Down
1 change: 1 addition & 0 deletions thread_pthread.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ typedef struct rb_global_vm_lock_struct {
* timer.
*/
struct list_head waitq; /* <=> native_thread_data_t.node.ubf */
volatile unsigned long waiting;
const struct rb_thread_struct *timer;
int timer_err;

Expand Down

0 comments on commit 1d72486

Please sign in to comment.