ひとり勉強会

ひとり楽しく勉強会

ブロッキング

スレッド実行中にI/Oなどシステム関係の操作で処理がブロックするときは、グローバルロックを解除します。YARVのスレッドモデルでは、そうしないと他のスレッドまで一斉に止まってしまうので。これは、ブロックする処理を実装した関数へのポインタを rb_thread_blocking_region @ thread.c 関数に渡すことで実現されるようになっています。

VALUE
rb_thread_blocking_region(
    rb_blocking_function_t *func, void *data,
    rb_unblock_function_t *ubf)
{
  VALUE val;
  rb_thread_t *th = GET_THREAD();

  if (ubf == RB_UBF_DFL) {
    ubf = ubf_select;
  }
  BLOCKING_REGION({
    val = func(th, data);
  }, ubf);

  return val;
}

rb_thread_blocking_region の実体は BLOCKING_REGION マクロで、これの定義は

#define GVL_UNLOCK_BEGIN() do { \
  rb_thread_t *_th_stored = GET_THREAD(); \
  rb_gc_save_machine_context(_th_stored); \
  native_mutex_unlock(&_th_stored->vm->global_interpreter_lock)

#define GVL_UNLOCK_END() \
  native_mutex_lock(&_th_stored->vm->global_interpreter_lock); \
  rb_thread_set_current(_th_stored); \
} while(0)

#define BLOCKING_REGION(exec, ubf) do { \
  rb_thread_t *__th = GET_THREAD(); \
  ...(略)...
  GVL_UNLOCK_BEGIN(); {\
   exec; \
  } \
  GVL_UNLOCK_END(); \
  ...(略)...
} while(0)

rb_thread_scheduleとまったく同じです。
rb_thread_blocking_regionはprocess.cやfile.cなどのライブラリ部分で何カ所か使われているみたいですね。