Re: multiple interpreters x multiple threads x multiple environments

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Re: multiple interpreters x multiple threads x multiple environments

Mark Ian Barlow
In message <199709091844.PAA08845@server02> [hidden email] writes:
 > About the on-going discussion on multiple threads:

Well, it *was* ongoing; sorry, I had to do a bit of paying work.

 > Like Roberto said, multiple threads of execution in Lua would require
 > support on the C part, something that neither ANSI C nor POSIX can give.

Am I right or wrong in thinking that the ANSI C definition of setjmp() and
longjmp() permits home-cooked co-routines? I can certainly do it in Turbo C,
which I have always found to be pretty strict in adhering to the standard.

Basically, I chop up the available stack by recursing down it, planting
a setjmp() at my chosen intervals and filling in an array of jmp_bufs as I
go. I can then longjmp() to any one I choose from my scheduling kernel, but
of course there's no protection to prevent me exceeding my self-imposed
stack size in each co-routine, so recursion within individual co-routines
whould require some caution. Am I exploiting a feature that pure ANSI C does
not necessarily support? Here's a simple function that chops the stack
into equal chunks...

#include <setjmp.h>

extern void reschedule(const int thread_tag);


void prepare_stacks( const int n_stacks,
                     const int stack_depth,
                     const int depth_count,
                     jmp_buf   *jbuf_array  )

/* N.B:  Units of 'stack_depth' are sizeof(this function's stack frame) */

{
    if (depth_count)
    {
        prepare_stacks( n_stacks,
                        stack_depth,          /* continue recursing and */
                        depth_count - 1,       /* decrement frame count */
                        jbuf_array       );
    }
    else
    {
        const int stacks_remaining = n_stacks - 1;

        int thread_tag = setjmp(jbuf_array[stacks_remaining]);

        if (thread_tag)
        {
            reschedule(thread_tag);   /* scheduler called our longjmp() */
        }
        else if (stacks_remaining)
        {
            prepare_stacks( stacks_remaining,
                            stack_depth,         /* head down again but */
                            stack_depth,           /* reset frame count */
                            jbuf_array    );
        }
    }
}


 <snip stuff about multiple interpreters>
 > 
 > Multiple environments are easy to implement in Lua.
 > One way is as Roberto mentioned: use tables to save and restore the global
 > environment.
 > Another way is to use the setglobal/getglobal tag methods.
 > In this solution, these tag methods are used to filter and redirect requests
 > to read and write the global environment, say to tables.
 > To switch environments, simply change the handlers for setglobal/getglobal.

This (latter) method takes care of a fast environment switch; If I
restricted myself to, say, switching context only at specific time-
slice de-scheduling points, maybe even only at function entry/exit
(via the debugger interface) how much else would I need to save?

--  Mark Ian Barlow                Non-Linear Control Consultants Ltd.
    -----------------------------------------------------------------
    [hidden email]            Voice / Fax: +44 (0)1207 562 154

Reply | Threaded
Open this post in threaded view
|

Re: multiple interpreters x multiple threads x multiple environments

Alan Watson-2
> Basically, I chop up the available stack by recursing down it, planting
> a setjmp() at my chosen intervals and filling in an array of jmp_bufs as I
> go. I can then longjmp() to any one I choose from my scheduling kernel, but
> of course there's no protection to prevent me exceeding my self-imposed
> stack size in each co-routine, so recursion within individual co-routines
> whould require some caution. 

Neat, but nasty.

> Am I exploiting a feature that pure ANSI C does
> not necessarily support? 

Yes. The description of longjmp in ISO 7.6.2 reads in part: "if the
function containing the invocation of the setjmp macro has terminated
execution in the interim, the behaviour is undefined". A footnote to
"terminated execution" reads "For example, by executing a return
statement or because another longjmp call has caused a transfer to a
setjmp invocation in a function earlier in the set of nested calls".
Now, footnotes aren't part of the standard, but you aren't going to
win that one.

In summary, you can use longjmp to jump to an earlier function, but
not a later one.

>         int thread_tag = setjmp(jbuf_array[stacks_remaining]);

Also, this use of setjmp is not allowed by the environmental
constraint in 7.6.1. It must appear as an expression
statements in one of the following forms:

	setjmp(...);
	(void) setjmp(...);
	
and as an expression controlling a selection or iteration
statement in tne of the following forms
	
	setjmp(...)
	integral-constant-expression rel-op setjmp(...)
	setjmp(...) rel-op integral-constant-expression 
	! setjmp(...)

Notice in particular that there is no way to determine in general the
value returned by a setjmp function. (Although if you know it must be
one of a limited number of values, you can determine the value using a
suitable selection statement.)

Strictly conformant ISO C is very limiting.

Alan Watson

Reply | Threaded
Open this post in threaded view
|

Re: multiple interpreters x multiple threads x multiple environments

Norman Ramsey-3
In reply to this post by Mark Ian Barlow
Those interested in simulating multiple threads on a uniprocessor might
want to check out the Threads chapter in Dave Hanson's book entitled
`C Interfaces and Implementations'.  A Lua binding for Hanson's thread
primitives might be interesting...

Norman