signaling a ruby thread from a win32 native thread

Discussion in 'Ruby' started by Vincenzo Piombo, May 6, 2004.

  1. Hello,
    I am working at a ruby application that needs to be notified of some hw
    event provided by third party driver/DLL. It should run on Win32.
    The hardware events are generated in the context of a native win32 thread,
    and I need to handle them in some ruby code. The main ruby process is
    meanwhile used to handle a TCP/IP dialog with a GUI.

    So basically I need an event queue which a ruby thread can suspend on,
    waiting for events pushed in the queue by a win32 native thread.

    I did some experiment with ruby API in a ruby extension but didn't succeed
    to make it work.
    Can you guys tell me whether I'm trying something plainly impossible (in
    that case are there alternatives ?) or am I just making some implementation
    error ?

    Thanks in advance for your help.

    Here follows some details:
    msgqueue.rb - (a working full ruby test, using SizeQueue to explain what I
    want to achieve)
    msgqueuesignals.c - (C code of the extension)
    msgqueuesignals_test.rb - (ruby code using the msgqueuesignals.so extension)

    The last approach works if I undefine the DOLOOP macro, if it is defined I
    get the error:
    "ERROR #<SystemStackError: c:/ruby/lib/ruby/1.8/thread.rb:259:in `push':
    stack level too deep>"
    after 42 iterations.

    ---------------------------------
    # msgqueue.rb.

    require "thread"

    queue = SizedQueue.new(10)

    pusher_thread = Thread.new {
    100.times {|i|
    queue.push(i)
    }
    queue.push("Quit")
    }

    popper_thread = Thread.new {
    while true
    o = queue.pop()
    puts o
    break if o == "Quit"
    end
    }

    [pusher_thread, popper_thread].each {|t| t.join }
    =================================

    ---------------------------------
    // msgqueuesignals.c
    #include <windows.h>

    #include <stdio.h>
    #include "ruby.h"

    #define DOLOOP 1

    VALUE cMsgqSignals;
    int counter = 0;

    DWORD WINAPI native_thread(
    LPVOID lpParameter // thread data
    )
    {
    int i;
    char command[1000];
    VALUE errinfo;
    int error = 0;


    #ifdef DOLOOP
    for(i=0; i<100; i++)
    {
    counter++;
    sprintf(command, "$queue.push('%d')", i);
    rb_eval_string_protect(command, &error);
    if(error)
    {
    errinfo = rb_inspect(ruby_errinfo);
    rb_backtrace();
    printf("ERROR %s\n", STR2CSTR(errinfo));
    }
    }
    #endif

    rb_eval_string("$queue.push('Quit')");

    return 0;
    }


    static VALUE msgqs_get_count()
    {
    return INT2FIX(counter);
    }

    static VALUE msgqs_initialize(VALUE self)
    {
    HANDLE thread;
    DWORD threadid;


    rb_eval_string("$queue.push('Start')");

    thread = CreateThread(
    NULL, // pointer to security attributes
    0, // initial thread stack size
    native_thread, // pointer to thread function
    (LPVOID)0, // argument for new thread
    0, // creation flags
    &threadid // pointer to receive thread ID
    );
    Sleep(1); // give the thread a chance to execute
    return self;
    }


    __declspec(dllexport) void Init_msgqueuesignals() {
    cMsgqSignals = rb_define_class("MsgQueueSignals", rb_cObject);
    rb_define_method(cMsgqSignals, "initialize", msgqs_initialize, 0);
    rb_define_method(cMsgqSignals, "count", msgqs_get_count, 0);

    }
    =================================

    ---------------------------------
    # msgqueuesignals_test.rb
    require "thread"
    require "msgqueuesignals"

    $stdout.sync = true
    $queue = Queue.new()
    native_pusher = MsgQueueSignals.new

    # I need this idle thread not to get a deadlock error when joining the
    popper thread
    # otherwise ruby thinks no one will ever possibly wake up the popper
    idle_thread = Thread.new {
    while true
    sleep(5000)
    $queue.push("Idle")
    end
    }

    popper_thread = Thread.new {
    while true
    o = $queue.pop()
    puts o
    break if o == "Quit"
    end
    }


    puts "native_pusher event count: #{native_pusher.count}"
    popper_thread.join
    puts "native_pusher event count: #{native_pusher.count}"
    =================================
    Vincenzo Piombo, May 6, 2004
    #1
    1. Advertising

  2. Vincenzo Piombo

    Guest

    Hi,

    At Fri, 7 May 2004 03:55:54 +0900,
    Vincenzo Piombo wrote in [ruby-talk:99416]:
    > I am working at a ruby application that needs to be notified of some hw
    > event provided by third party driver/DLL. It should run on Win32.
    > The hardware events are generated in the context of a native win32 thread,
    > and I need to handle them in some ruby code. The main ruby process is
    > meanwhile used to handle a TCP/IP dialog with a GUI.
    >
    > So basically I need an event queue which a ruby thread can suspend on,
    > waiting for events pushed in the queue by a win32 native thread.
    >
    > I did some experiment with ruby API in a ruby extension but didn't succeed
    > to make it work.
    > Can you guys tell me whether I'm trying something plainly impossible (in
    > that case are there alternatives ?) or am I just making some implementation
    > error ?


    Current ruby interpreter implementation doesn't allow to be
    called from other native threads.

    A) You may be possible to use rb_w32_main_context(), which
    signals the main thread (native thread on which ruby runs),
    handshakes with it and invokes the given function in it.

    B) Once I wrote a patch to improve IO.select issue, which it
    also provides rb_w32_wait_for_handle() function.
    http://nokada.jin.gr.jp/ruby/win32/wait_events.diff
    Note that it absolutely is untested.

    --
    Nobu Nakada
    , May 21, 2004
    #2
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. David Pratt
    Replies:
    1
    Views:
    385
    McBooCzech
    Sep 15, 2005
  2. Replies:
    0
    Views:
    675
  3. Jon Monteleone
    Replies:
    1
    Views:
    835
    Diez B. Roggisch
    Sep 25, 2005
  4. Ara.T.Howard

    signaling another thread

    Ara.T.Howard, May 5, 2004, in forum: Ruby
    Replies:
    9
    Views:
    120
    Robert Klemme
    May 7, 2004
  5. Asterix Gallier

    Signaling Ruby from C/C++

    Asterix Gallier, Jul 28, 2006, in forum: Ruby
    Replies:
    20
    Views:
    300
Loading...

Share This Page