Цель: разрешить расширению c получать блок / proc для отложенного выполнения при сохранении текущего контекста выполнения.
У меня есть метод в c (доступный для ruby), который принимает callback
(через VALUE hash
аргумент) или block
.
// For brevity, lets assume m_CBYO is setup to make a CBYO module available to ruby
extern VALUE m_CBYO;
VALUE CBYO_add_callback(VALUE callback)
{
if (rb_block_given_p()) {
callback = rb_block_proc();
}
if (NIL_P(callback)) {
rb_raise(rb_eArgError, "either a block or callback proc is required");
}
// method is called here to add the callback proc to rb_callbacks
}
rb_define_module_function(m_CBYO, "add_callback", CBYO_add_callback, 1);
У меня есть структура, которую я использую для хранения этих дополнительных данных:
struct rb_callback
{
VALUE rb_cb;
unsigned long long lastcall;
struct rb_callback *next;
};
static struct rb_callback *rb_callbacks = NULL;
Когда придет время (вызваноepoll), я перебираю обратные вызовы и выполняю каждый обратный вызов:
rb_funcall(cb->rb_cb, rb_intern("call"), 0);
Когда это происходит, я вижу, что он успешно выполняет код ruby в обратном вызове, однако он экранирует текущий контекст выполнения.
Пример:
# From ruby including the above extension
CBYO.add_callback do
puts "Hey now."
end
loop do
puts "Waiting for signal..."
sleep 1
end
Когда сигнал получен (через epoll), я увижу следующее:
$> Waiting for signal...
$> Waiting for signal...
$> Hey now.
$> // process hangs
$> // Another signal occurs
$> [BUG] vm_call_cfunc - cfp consistency error
Иногда я могу получить более одного сигнала наобработать до того, как ошибка снова появится.