diff --git a/bindings/ruby/ext/ruby_whisper.c b/bindings/ruby/ext/ruby_whisper.c index 5f1917ee..b1a0d6a4 100644 --- a/bindings/ruby/ext/ruby_whisper.c +++ b/bindings/ruby/ext/ruby_whisper.c @@ -29,6 +29,8 @@ ID id_cache; ID id_n_processors; static bool is_log_callback_finalized = false; +static bool is_ruby_log_callback_present = false; +static bool is_without_gvl = false; // High level API extern VALUE ruby_whisper_segment_allocate(VALUE klass); @@ -106,18 +108,56 @@ static VALUE ruby_whisper_s_finalize_log_callback(VALUE self, VALUE id) { return Qnil; } +void +ruby_whisper_lock_gvl(void) +{ + is_without_gvl = true; +} + +void +ruby_whisper_unlock_gvl(void) +{ + is_without_gvl = false; +} + +typedef struct { + int level; + const char * buffer; + VALUE user_data; +} call_log_callbacks_args; + +static void* +call_log_callbacks(void *v_args) { + VALUE log_callback = rb_iv_get(mWhisper, "log_callback"); + if (NIL_P(log_callback)) { + return NULL; + } + + call_log_callbacks_args *args = (call_log_callbacks_args *)v_args; + rb_funcall(log_callback, id_call, 3, INT2NUM(args->level), rb_str_new2(args->buffer), args->user_data); + + return NULL; +} + static void ruby_whisper_log_callback(enum ggml_log_level level, const char * buffer, void * user_data) { if (is_log_callback_finalized) { return; } - VALUE log_callback = rb_iv_get(mWhisper, "log_callback"); - if (NIL_P(log_callback)) { + if (!is_ruby_log_callback_present) { return; } - VALUE udata = rb_iv_get(mWhisper, "user_data"); - rb_funcall(log_callback, id_call, 3, INT2NUM(level), rb_str_new2(buffer), udata); + call_log_callbacks_args args = { + level, + buffer, + rb_iv_get(mWhisper, "user_data") + }; + if (is_without_gvl) { + rb_thread_call_with_gvl(call_log_callbacks, (void *)&args); + } else { + call_log_callbacks((void *)&args); + } } /* @@ -140,8 +180,10 @@ static VALUE ruby_whisper_s_log_set(VALUE self, VALUE log_callback, VALUE user_d if (NIL_P(log_callback)) { whisper_log_set(NULL, NULL); + is_ruby_log_callback_present = false; } else { whisper_log_set(ruby_whisper_log_callback, NULL); + is_ruby_log_callback_present = true; } return Qnil; diff --git a/bindings/ruby/ext/ruby_whisper_params.c b/bindings/ruby/ext/ruby_whisper_params.c index 17841a53..31e86f67 100644 --- a/bindings/ruby/ext/ruby_whisper_params.c +++ b/bindings/ruby/ext/ruby_whisper_params.c @@ -33,6 +33,8 @@ extern VALUE mWhisper; extern ID id_call; +extern void ruby_whisper_lock_gvl(void); +extern void ruby_whisper_unlock_gvl(void); extern VALUE ruby_whisper_normalize_model_path(VALUE model_path); extern VALUE rb_whisper_segment_s_new(VALUE context, int index); extern const rb_data_type_t ruby_whisper_vad_params_type; @@ -137,6 +139,8 @@ typedef struct { static void* call_new_segment_callbacks(void *v_args) { + ruby_whisper_lock_gvl(); + call_new_segment_callbacks_args *args = (call_new_segment_callbacks_args *)v_args; const ruby_whisper_callback_container *container = args->container; struct whisper_state *state = args->state; @@ -179,6 +183,7 @@ static void new_segment_callback(struct whisper_context *ctx, struct whisper_sta n_new }; rb_thread_call_with_gvl(call_new_segment_callbacks, (void *)&args); + ruby_whisper_unlock_gvl(); } typedef struct { @@ -189,6 +194,8 @@ typedef struct { static void* call_progress_callbacks(void *v_args) { + ruby_whisper_lock_gvl(); + call_progress_callbacks_args *args = (call_progress_callbacks_args *)v_args; const ruby_whisper_callback_container *container = args->container; int progress_cur = args->progress_cur; @@ -225,6 +232,7 @@ static void progress_callback(struct whisper_context *ctx, struct whisper_state progress_cur }; rb_thread_call_with_gvl(call_progress_callbacks, (void *)&args); + ruby_whisper_unlock_gvl(); } typedef struct { @@ -235,6 +243,8 @@ typedef struct { static void* call_encoder_begin_callbacks(void *v_args) { + ruby_whisper_lock_gvl(); + call_encoder_begin_callbacks_args *args = (call_encoder_begin_callbacks_args *)v_args; const ruby_whisper_callback_container *container = args->container; VALUE result = Qnil; @@ -278,6 +288,7 @@ static bool encoder_begin_callback(struct whisper_context *ctx, struct whisper_s true }; rb_thread_call_with_gvl(call_encoder_begin_callbacks, (void *)&args); + ruby_whisper_unlock_gvl(); return args.is_continued; } @@ -290,6 +301,8 @@ typedef struct { static void* call_abort_callbacks(void *v_args) { + ruby_whisper_lock_gvl(); + call_abort_callbacks_args *args = (call_abort_callbacks_args *)v_args; const ruby_whisper_abort_callback_container *container = args->container; @@ -337,6 +350,7 @@ static bool abort_callback(void * user_data) { false }; rb_thread_call_with_gvl(call_abort_callbacks, (void *)&args); + ruby_whisper_unlock_gvl(); return args.is_interrupted; }