Ruby thread problems

B

Brad

All:

Ruby threading problems
Using ruby 1.8.0 Preview 5 (Porting ruby to OpenVMS Alpha)
============================================================================
==
I Realize that OpenVMS is not an officially supported OS for ruby but I'm
hoping that someone will see something that I'm missing or have encountered
the problems described.
Using a simple ruby script that makes use of threads causes ruby interpreter
to stack dump on OpenVMS.
The following is the ruby threading script that is used:
puts "main"
thread1=Thread.new do
puts "thread"
end
I've narrowed the problem down to what I think is a setjmp/longjmp problem.
But the problem is not solely a
setjmp/longjmp problem as the following example proves that setjmp/longjmp
on OpenVMS works just fine.

#include <stdio.h>
#include <stdlib.h>
#include<setjmp.h>
void main()
{
jmp_buf env;
int i;
i=setjmp(env);
printf("i= %d\n",i);
if(i==0)
printf("I am in if ..\n");
else{
printf("I am in else too...\n");
exit(0);
}
longjmp(env,2);
}

I first thought that the context (contained in rb_thread_t structure) was
being corrupted. However, when run through the debugger the context is not
changed. The next idea
was to edit eval.c to generate a "no-op" by using the following code:

(* This is located in rb_thread_start_0 *)
(* restThr is a global integer value that is initialized to 0. This is
a safeguard so ruby doesn't try to restore a non-existent context *)
....
THREAD_SAVE_CONTEXT(curr_thread);
if(restThr == 0) {
rb_thread_restore_context(curr_thread,RESTORE_NORMAL);
}
....
There appear to be no defines in config.h or defines.h related to threads.

Running ruby through the debugger with the "no-op" shows ruby dying in
stack_extend. A few questions about stack_extend:
Q: (a) What is the intent of this routine?
(b) Why does this routine call rb_thread_restore_context?
Q: Are there any known thread implementation issues for alternate platforms.

Any help would be appreciated.


============================================================================
=
 
T

ts

B> Using ruby 1.8.0 Preview 5 (Porting ruby to OpenVMS Alpha)

perhaps best if you use 1.8.1 (if you can)

B> Q: (a) What is the intent of this routine?
B> (b) Why does this routine call rb_thread_restore_context?

Like the name say it : to extend the stack :)

Imagine that a thread was stopped with 0xe000000 for the stack pointer
(th->stk_pos)

When ruby restore the context of this thread, the thread must be restarted
with a valid stack pointer. To do this it compare the actual stack value (&v)
with the saved value (th->stk_pos).

For example, if I'm on a system where the stack grow downward, and ruby find

&v == 0xf0000000
th->stk_pos = 0xe0000000

ruby must put elements on the stack until it have (&v <= th->stk_pos). At
this step it can restore the thread.

To do this rb_thread_restore_context() call stack_extend(). stack_extend()
store 1024 VALUE on the stack (this is the declaration VALUE space[1024];)
to decrease the stack pointer, and it call recursively
rb_thread_restore_context() until it find (&v <= th->stk_pos)
 
B

Brad

ts said:
B> Using ruby 1.8.0 Preview 5 (Porting ruby to OpenVMS Alpha)

perhaps best if you use 1.8.1 (if you can)

B> Q: (a) What is the intent of this routine?
B> (b) Why does this routine call rb_thread_restore_context?

Like the name say it : to extend the stack :)

Imagine that a thread was stopped with 0xe000000 for the stack pointer
(th->stk_pos)

When ruby restore the context of this thread, the thread must be restarted
with a valid stack pointer. To do this it compare the actual stack value (&v)
with the saved value (th->stk_pos).

For example, if I'm on a system where the stack grow downward, and ruby find

&v == 0xf0000000
th->stk_pos = 0xe0000000

ruby must put elements on the stack until it have (&v <= th->stk_pos). At
this step it can restore the thread.

To do this rb_thread_restore_context() call stack_extend(). stack_extend()
store 1024 VALUE on the stack (this is the declaration VALUE space[1024];)
to decrease the stack pointer, and it call recursively
rb_thread_restore_context() until it find (&v <= th->stk_pos)

Thanks for the speedy reply, sorry took so long to get back to you. I've
updated to using ruby 1.8.1 preview 2; However, the problem continues to
persist.

Q: Doesn't the setjmp/longjmp maintain the stack information? Seems to me that
setjmp/longjmp would be quite unusable if it didn't maintain stack
information.

Perhaps this is a naive assumption on my part as I have not had opportunity to
use setjmp/longjmp before now.
 
T

ts

B> Q: Doesn't the setjmp/longjmp maintain the stack information? Seems to me that
B> setjmp/longjmp would be quite unusable if it didn't maintain stack
B> information.

longjmp restore the stack registers (%esp on 80x86), not the stack content.
Say another way, this is valid in C

int g()
{
longjmp(jmp, val);
}

int f()
{
setjmp(jmp);
g();
}

but this don't work

int g()
{
setjmp(jmp);
}

int f()
{
g();
longjmp(jmp, val);
}



B> Perhaps this is a naive assumption on my part as I have not had opportunity to
B> use setjmp/longjmp before now.

When a thread is stopped, ruby store the content of the stack in stk_ptr,
when it want to resume a thread it must restore the stack pointers before
calling longjmp()


Guy Decoux
 
B

Brad

ts said:
B> Q: Doesn't the setjmp/longjmp maintain the stack information? Seems to me that
B> setjmp/longjmp would be quite unusable if it didn't maintain stack
B> information.

longjmp restore the stack registers (%esp on 80x86), not the stack content.
Say another way, this is valid in C

int g()
{
longjmp(jmp, val);
}

int f()
{
setjmp(jmp);
g();
}

but this don't work

int g()
{
setjmp(jmp);
}

int f()
{
g();
longjmp(jmp, val);
}



B> Perhaps this is a naive assumption on my part as I have not had opportunity to
B> use setjmp/longjmp before now.

When a thread is stopped, ruby store the content of the stack in stk_ptr,
when it want to resume a thread it must restore the stack pointers before
calling longjmp()


Guy Decoux


Mr. Decoux,

Thank you again for your speedy response. I now feel I have a better
understanding of what's going on during the thread context switch/restore.
My problem was, I didn't get that setjmp/longjmp only maintained stack
addresses and not content. And that the content had to be manually restored.

The problem, as it turns out, can be easily fixed by adding the following
define to the build procedure:

__FAST_SETJMP

This tells the compiler to use the Alpha OpenVMS system specific version of
setjmp/longjmp rather than the CRTL version.

Regards,
Brad
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,079
Latest member
ElidaWarin

Latest Threads

Top