代码之家  ›  专栏  ›  技术社区  ›  codenamev

Ruby C扩展如何存储proc以供以后执行?

  •  4
  • codenamev  · 技术社区  · 7 年前

    目标:允许c扩展接收延迟执行的block/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
    

    1 回复  |  直到 7 年前
        1
  •  0
  •   codenamev    7 年前

    我在调查的时候找到了答案 a similar issue

    事实证明,我也在尝试使用本机线程信号(使用 pthread_create )MRI不支持的。

    this nice write-up on Ruby Threading 以便更好地全面了解如何在这些范围内工作。

    你可以用鲁比的 native_thread_create(rb_thread_t *th) 哪个会用 pthread\u创建 在幕后。在方法定义上面的文档中可以看到一些缺点。然后可以使用Ruby的 rb_thread_call_with_gvl rb_protect 为了处理异常,回调可能会引发异常(否则它们将被VM吞噬)。

    VALUE execute_callback(VALUE callback)
    {
        return rb_funcall(callback, rb_intern("call"), 0);
    }
    
    // execute the callback when the thread receives signal
    rb_thread_call_with_gvl(execute_callback, data->callback);
    
    推荐文章