[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Signaling Ruby from C/C++

Asterix Gallier

7/28/2006 10:00:00 AM

Hello,

I would like to send a signal from c to ruby. So that ruby knows, that
there is some new data in c that can be fetched and extracted.

Currently I'm using ruby 1.8.5 on WindowsXP.

Are there any possibilities like Callbackfunction, Signals,
Interrupthandling ...

I've searched but found nothing for my needs.

Currently I have the following code. the Problem here is, that i have to
wait for the rubyscheduler until the ruby recvThread will be scheduled.
Although it could happen, that data will be lost, when there arrives new
data while ruby is currently "pop"-ing the array.

Have anybody got an idea?

Thanks for any tips.
Asterix

////////////////////////////////////////////////////////
// rubycode

require 'RubyDriver'

recvThread = Thread.new{
loop do
Thread.stop
while ( (msg = recvArray.pop) != nil) do
puts msg
end
end
}

RubyDriver::startReceiver(recvThread, recvArray)

////////////////////////////////////////////////////////
// c code

VALUE receiverThread, receiverArray;

void reciever(void* dummy) {

while(1) {
msg = recieveMessage(); // a C function wich
// returns if there is
// new data arrived
rb_ary_push(receiverArray, msg);
rb_thread_wakeup(receiverThread);

}
}


void startReceiver(VALUE thread, VALUE array) {
receiverThread = thread;
receiverArray = array;

hThread = (HANDLE)_beginthread( reciever, 0, NULL );
}

--
Posted via http://www.ruby-....

20 Answers

Suraj Kurapati

7/29/2006 4:02:00 AM

0

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Asterix Gallier wrote:
> I would like to send a signal from c to ruby. So that ruby knows,
> that there is some new data in c that can be fetched and
> extracted.

How about raising an exception from your C code and catching it in
your Ruby code?
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.2 (GNU/Linux)

iD8DBQFEyt14mV9O7RYnKMcRAhQAAJ4uNmwrApn+JQaXohcp1aHebcRxIwCfW2E0
z2Z+Ev5KbcEjUsrujWod3vI=
=Uore
-----END PGP SIGNATURE-----

Asterix Gallier

7/30/2006 9:11:00 PM

0

> How about raising an exception from your C code and catching it in
> your Ruby code?

Thank you vor this advice. But I didn't find a working solution with
this construct of ruby, so maybe I nee a little bit hand help.

The Code exits with an unknown software exception if rb_raise is called
inside the thread function. Inside the startReceiver function it works.

what is my mistake?

Thanks
Asterix


i extend the c- receiver- function with this line:
////////////////////////////////////////////////////////
// c code
rb_raise(rb_eRuntimeError, "MsgReceived");


////////////////////////////////////////////////////////
// and inside of ruby I call the c- startReceiver- function in a begin
rescue block

started = false
begin
RubyDriver::startReceiver(recvThread, recvArray) if !started
started = true
rescue
puts "Signaled from C"
retry
end

--
Posted via http://www.ruby-....

Francis Cianfrocca

7/30/2006 9:14:00 PM

0

Suraj N. Kurapati wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Asterix Gallier wrote:
>> I would like to send a signal from c to ruby. So that ruby knows,
>> that there is some new data in c that can be fetched and
>> extracted.
>
> How about raising an exception from your C code and catching it in
> your Ruby code?
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.4.2.2 (GNU/Linux)
>
> iD8DBQFEyt14mV9O7RYnKMcRAhQAAJ4uNmwrApn+JQaXohcp1aHebcRxIwCfW2E0
> z2Z+Ev5KbcEjUsrujWod3vI=
> =Uore
> -----END PGP SIGNATURE-----

I haven't tried your solution, but I would be surprised if a Ruby
exception turned out to be thread-safe across a native thread.

--
Posted via http://www.ruby-....

Asterix Gallier

8/1/2006 11:48:00 AM

0

now I've tried another solution. I'm sending a signal to the Rubyprocess
and catch this signal with trap.

- Is this solution threadsafe? I didn't know in which way ruby handles
the signal exactly.
- Could it be, that some Signals are getting lost because of the
Handling Routine is already active?

////////////////////////////////////////////////////////
// rubycode

require 'RubyDriver'

Signal.trap("TERM") do
puts recvArray.pop.to_s
end

RubyDriver::startReceiver(recvThread, recvArray)

////////////////////////////////////////////////////////
// c code

void reciever(void* dummy) {

VALUE msgsignal[2];
msgsignal[0] = rb_str_new2("TERM");
msgsignal[1] = ProcessId;

while(1) {
msg = recieveMessage(); // a C function wich
// returns if there is
// new data arrived
rb_ary_push(receiverArray, msg);
rb_f_kill(2, msgsignal);
}
}


void startReceiver(VALUE pId, VALUE array) {
processId = pId;
receiverArray = array;

hThread = (HANDLE)_beginthread( reciever, 0, NULL );
}


--
Posted via http://www.ruby-....

Francis Cianfrocca

8/1/2006 12:55:00 PM

0

Does this actually work??? Windows doesn't have signals, so maybe
you've gotten lucky with whatever mechanism Ruby uses to simulate
signals on Windows. I would doubt this solution works reliably on Unix
or Linux, because a signal is delivered to the whole process, and in
general you can't predict which thread will handle it. (Unless there's
something magic about rb_f_kill that I don't know about.)

Have you tried sending data to a file descriptor in the native thread,
and selecting the descriptor for readable in the Ruby thread? I know
this works, and there have been several threads about this approach on
this board in the last few months.

On 8/1/06, Asterix Gallier <asterixgallier@freenet.de> wrote:
> now I've tried another solution. I'm sending a signal to the Rubyprocess
> and catch this signal with trap.
>
> - Is this solution threadsafe? I didn't know in which way ruby handles
> the signal exactly.
> - Could it be, that some Signals are getting lost because of the
> Handling Routine is already active?
>
> ////////////////////////////////////////////////////////
> // rubycode
>
> require 'RubyDriver'
>
> Signal.trap("TERM") do
> puts recvArray.pop.to_s
> end
>
> RubyDriver::startReceiver(recvThread, recvArray)
>
> ////////////////////////////////////////////////////////
> // c code
>
> void reciever(void* dummy) {
>
> VALUE msgsignal[2];
> msgsignal[0] = rb_str_new2("TERM");
> msgsignal[1] = ProcessId;
>
> while(1) {
> msg = recieveMessage(); // a C function wich
> // returns if there is
> // new data arrived
> rb_ary_push(receiverArray, msg);
> rb_f_kill(2, msgsignal);
> }
> }
>
>
> void startReceiver(VALUE pId, VALUE array) {
> processId = pId;
> receiverArray = array;
>
> hThread = (HANDLE)_beginthread( reciever, 0, NULL );
> }
>
>
> --
> Posted via http://www.ruby-....
>
>

Asterix Gallier

8/7/2006 8:37:00 AM

0

Francis Cianfrocca wrote:
> Does this actually work??? Windows doesn't have signals, so maybe
> you've gotten lucky with whatever mechanism Ruby uses to simulate
> signals on Windows. I would doubt this solution works reliably on Unix
> or Linux, because a signal is delivered to the whole process, and in
> general you can't predict which thread will handle it. (Unless there's
> something magic about rb_f_kill that I don't know about.)
>
> Have you tried sending data to a file descriptor in the native thread,
> and selecting the descriptor for readable in the Ruby thread? I know
> this works, and there have been several threads about this approach on
> this board in the last few months.

Hello Francis,

the solution above works somehow, but i experienced that this is not
very reliable.

Your solution by using a file descriptor sounds very interesting. I've
searched but didn't find any adequate example or documentation beside
the ruby source itself.

Can you please give me any support for this approach.

As far as i can see, i need to simulate a file filedescriptor to ruby.
Am I right? I've got no idea how to do this. I take a look at the
ruby-serialport source but i think that this is not applicable to my
situation or?

With Regards
Asterix

--
Posted via http://www.ruby-....

Francis Cianfrocca

8/7/2006 10:52:00 AM

0

Asterix Gallier wrote:
>
> Your solution by using a file descriptor sounds very interesting. I've
> searched but didn't find any adequate example or documentation beside
> the ruby source itself.
>
> Can you please give me any support for this approach.
>
> As far as i can see, i need to simulate a file filedescriptor to ruby.
> Am I right? I've got no idea how to do this. I take a look at the
> ruby-serialport source but i think that this is not applicable to my
> situation or?

Asterix, I don't have time right this moment to write and test a working
code sample, but you can try using Ruby's IO.pipe to get a pair of
descriptors connected to each other.

rd,wr = IO.pipe
writeable_descriptor = wr.fileno

Now your Windows thread can write the writeable_descriptor and your Ruby
thread can select([rd]).

Hope that helps. There are probably pitfalls with this approach on
Windows. I know I've done this before or something like it, but will
need a bit of time to find the code.

--
Posted via http://www.ruby-....

Asterix Gallier

8/7/2006 7:23:00 PM

0

Francis Cianfrocca wrote:
> Asterix Gallier wrote:
>>
>> Your solution by using a file descriptor sounds very interesting. I've
>> searched but didn't find any adequate example or documentation beside
>> the ruby source itself.
>>
>> Can you please give me any support for this approach.
>>
>> As far as i can see, i need to simulate a file filedescriptor to ruby.
>> Am I right? I've got no idea how to do this. I take a look at the
>> ruby-serialport source but i think that this is not applicable to my
>> situation or?
>
> Asterix, I don't have time right this moment to write and test a working
> code sample, but you can try using Ruby's IO.pipe to get a pair of
> descriptors connected to each other.
>
> rd,wr = IO.pipe
> writeable_descriptor = wr.fileno
>
> Now your Windows thread can write the writeable_descriptor and your Ruby
> thread can select([rd]).
>
> Hope that helps. There are probably pitfalls with this approach on
> Windows. I know I've done this before or something like it, but will
> need a bit of time to find the code.

Ok I guess I know how it should work, but I'm not able to implement.

For testing I tried the sample code below.

I experienced following problems:
* the select statement returns immediately weather there is data or not
* if count is higher than one, the skript blocks because of the wrong
behavior
of select
* how to write data to the IO Object (wr) with C functions.

Thanks for any help
Asterix

////////////////////////////////////////////////////////
// rubycode

rd, wr = IO.pipe
count = 3

a = Thread.new {
count.times do
puts "#{__LINE__} Waiting for data: ..."
ra, wa, ea = select([rd], nil, nil, nil)
puts __LINE__
p ra[0].read
puts __LINE__
end
rd.close
}

b = Thread.new {
count.times do
puts "#{__LINE__} Sending message..."
wr.write("Hello")
puts __LINE__
end
wr.close
}
puts __LINE__

[a, b].each {|t| t.join if t != nil}

# Output when Count = 1
>ruby test.rb
6 Waiting for data: ...
17 Sending message...
8
23
19
"Hello"
10
>Exit code: 0

# Output when Count = 2 --> blocks
>ruby test.rb
6 Waiting for data: ...
17 Sending message...
8
23
19
17 Sending message...
>Exit code: -1073741510

# Output when Count = 2 and "read" replaced with "inspect"
>ruby test.rb
6 Waiting for data: ...
17 Sending message...
8
"#<IO:0x282385c>"
23
10
6 Waiting for data: ...
19
17 Sending message...
8
"#<IO:0x282385c>"
10
test_2.rb:18:in `write': Invalid argument (Errno::EINVAL)
from test_2.rb:25:in `join'
from test_2.rb:25
from test_2.rb:25
>Exit code: 1

--
Posted via http://www.ruby-....

Francis Cianfrocca

8/7/2006 9:23:00 PM

0

Asterix, try this:

#---------------------------------

rd,wr = IO.pipe

Thread.new {
loop {
puts rd.readpartial(1)
}
}

loop {
sleep 1
wr.write "+"
}

#---------------------------------

This works on Linux but I haven't tested it on Windows. And you're
right, if you try to use Kernel#select in the reader loop, it doesn't
work reliably! (I'm using a Ruby 1.8.4 snapshot from early June, which
has changes in nonblocking I/O.) This may be a Ruby bug.

--
Posted via http://www.ruby-....

Asterix Gallier

8/8/2006 7:55:00 AM

0

Francis Cianfrocca wrote:
> Asterix, try this:
>
> #---------------------------------
>
> rd,wr = IO.pipe
>
> Thread.new {
> loop {
> puts rd.readpartial(1)
> }
> }
>
> loop {
> sleep 1
> wr.write "+"
> }
>
> #---------------------------------
>
> This works on Linux but I haven't tested it on Windows. And you're
> right, if you try to use Kernel#select in the reader loop, it doesn't
> work reliably! (I'm using a Ruby 1.8.4 snapshot from early June, which
> has changes in nonblocking I/O.) This may be a Ruby bug.

What a shame! It doesn't work on Windows. When comming to the
readpartial statement the program blocks.

Thank all very much for the time and effort to help me solving the
problem. Slowly I believe that windows is not able to do blocking
reading =(

Have you got any further ideas?

Greetings
Asterix

--
Posted via http://www.ruby-....