violating procedure calling convention

K

KIRAN

hi,

the grammer for any programming language says that when a function is
called by another function,the callee after executing it's body should
return to the point where it left in the caller..
Is there any technique to make the callee to return to some other
point(within the current process) other than the callee by changing
the call stack in callee...
My code runs on 86 processor
(If this thread is irrelevent to this group please kindly igore the
same)
thanks in advance
 
D

Dave Vandervies

hi,

the grammer for any programming language says that when a function is
called by another function,the callee after executing it's body should
return to the point where it left in the caller..

The grammar says no such thing. The grammar only describes syntax;
what happens when it runs is a matter of semantics.
Is there any technique to make the callee to return to some other
point(within the current process) other than the callee by changing
the call stack in callee...

Use INTERCAL, which has a COME FROM statement for precisely this purpose.

Alternatively, use a functional programming language that lets you use
explicit continuations and invoke a continuation instead of returning.

Both of these can be done in (correct, portable) C if you try hard enough,
but You Don't Want To Do That. Either re-frame the problem to fit your
tools or choose your tools to fit the problem.


dave
 
T

Tak-Shing Chan

The grammar says no such thing. The grammar only describes syntax;
what happens when it runs is a matter of semantics.


Use INTERCAL, which has a COME FROM statement for precisely this purpose.

Alternatively, use a functional programming language that lets you use
explicit continuations and invoke a continuation instead of returning.

Both of these can be done in (correct, portable) C if you try hard enough,
but You Don't Want To Do That. Either re-frame the problem to fit your
tools or choose your tools to fit the problem.

I don't quite agree with this anti-goto mentality.

In some cases, setjmp and longjmp are actually better than
reframing the problem.

Tak-Shing
 
B

Barry

Dave Vandervies said:
I see no anti-goto mentality here.



There's not enough information to be certain, but the way the question
was stated is a pretty strong hint that the OP is looking for something
less restricted than setjmp/longjmp.


dave

But you commented that is can be done in correct, portable C.
Would you care to elaborate?
 
M

Martin Ambuhl

KIRAN said:
hi,

the grammer for any programming language says that when a function is
called by another function,the callee after executing it's body should
return to the point where it left in the caller..
Is there any technique to make the callee to return to some other
point(within the current process) other than the callee by changing
the call stack in callee...
My code runs on 86 processor
(If this thread is irrelevent to this group please kindly igore the
same)
thanks in advance

what you seem to want to do would, in some C-like language, look like
(in one of many variations):

LABEL caller_first_return, caller_second_return; /* ALGOL-like type */

void called(/* parameters */
{
int return_code;
/* some code */
return_to return_code == 0 ? caller_first_return : caller_second_return;
}

void caller(/* parameters */)
{
/* some code */
called(/* arguments */
caller_first_return:
/* block 1 */
caller_second_return:
/* blocl 2 */
}

Now, let's consider how this might be accomplished in C. Here is one of
many answers:


int called(/* parameters */
{
int return_code;
/* some code */
return return_code;
}

void caller(/* parameters */)
{
/* some code */
switch(called(/* arguments */) {
case 0:
/* block 1 */
case 1:
/* blocl 2 */
}
}

If the blocks are too large, then using function calls or goto
statements in the switch body can do the job.
Note that the C switch statement (unlike Pascal, for example) allows you
to drop through from case 0 to case 1, so the code you wanted to write
needs little modification other than that seen above.
 
D

Dave Vandervies

But you commented that is can be done in correct, portable C.
Would you care to elaborate?

Make the program use explicit continuations, then do it the same way
you'd do it if explicit continuations were built into the langauge.
(Doing this in C will require at least a partial CPS transform, since
any code that can cross a continuation capture or invocation boundary
needs to be able to return to the top-level trampoline loop and whatever
comes after that point needs to be accessible from the top level.)


So the program would run from a trampoline loop that looks not entirely
unlike:
--------
while(next_continuation)
{
next_continuation=invoke_continuation(next_continuation);
}
--------

Then a normal function call would look something like:
--------
/*cont.args needs to be populated; for simplicity I'll assume
it's a void function
*/
cont->nargs=1; /*only the return continuation, no "real" args*/
cont->args[0]=magic_conversion(what_happens_next,current_state);
cont->func=called_function;
return cont;
--------
The called function would need to expect a return continuation as one
of its arguments, and it would return to its caller by doing:
--------
/*ret_cont is the continuation we got as an argument*/
ret_cont->nargs=1;
ret_cont->args[0]=magic_conversion(return_value);
return ret_cont;
--------
(Note that this is exactly the same mechanism that we used to call a
function. In a language like Scheme, the code looks exactly the same,
and in fact doesn't even need to know at the point of the call whether
it's calling a continuation or an ordinary function.)


To allow a function to return to arbitrary points in the code, simply
create a continuation for each point it might need to return to (either
by capturing a normally-existing one or by creating one for that point)
and make all of those available to the function. Then it can decide
where it wants to return to and just return the continuation for that
return point as its "next continuation".


(Once you have this, you can implement setjmp and longjmp on top of it
fairly easily; setjmp will save its return continuation in the jmp_buf
before invoking it, and longjmp will just invoke it again. The hard
part will be making sure you don't leak any temporary storage allocated
in between, since you can't just reset the stack pointer like you could
with a more typical stack-in-contiguous-memory implementation of the
function call stack.)


This is a lot of work and you end up with ugly code that's going to
be hard to understand for anybody who hasn't been exposed to the idea
before. Far better to just write code that needs it in a language that
has built-in support for it.


dave
(The biggest strength of C is that you can create any high-level
abstraction you want to use yourself; the biggest weakness of C is that
you have to create any high-level abstraction you want to use yourself.)
 
B

Barry

Dave Vandervies said:
But you commented that is can be done in correct, portable C.
Would you care to elaborate?

Make the program use explicit continuations, then do it the same way
you'd do it if explicit continuations were built into the langauge.
(Doing this in C will require at least a partial CPS transform, since
any code that can cross a continuation capture or invocation boundary
needs to be able to return to the top-level trampoline loop and whatever
comes after that point needs to be accessible from the top level.)


So the program would run from a trampoline loop that looks not entirely
unlike:
--------
while(next_continuation)
{
next_continuation=invoke_continuation(next_continuation);
}
--------

Then a normal function call would look something like:
--------
/*cont.args needs to be populated; for simplicity I'll assume
it's a void function
*/
cont->nargs=1; /*only the return continuation, no "real" args*/
cont->args[0]=magic_conversion(what_happens_next,current_state);
cont->func=called_function;
return cont;
--------
The called function would need to expect a return continuation as one
of its arguments, and it would return to its caller by doing:
--------
/*ret_cont is the continuation we got as an argument*/
ret_cont->nargs=1;
ret_cont->args[0]=magic_conversion(return_value);
return ret_cont;
--------
(Note that this is exactly the same mechanism that we used to call a
function. In a language like Scheme, the code looks exactly the same,
and in fact doesn't even need to know at the point of the call whether
it's calling a continuation or an ordinary function.)


To allow a function to return to arbitrary points in the code, simply
create a continuation for each point it might need to return to (either
by capturing a normally-existing one or by creating one for that point)
and make all of those available to the function. Then it can decide
where it wants to return to and just return the continuation for that
return point as its "next continuation".


(Once you have this, you can implement setjmp and longjmp on top of it
fairly easily; setjmp will save its return continuation in the jmp_buf
before invoking it, and longjmp will just invoke it again. The hard
part will be making sure you don't leak any temporary storage allocated
in between, since you can't just reset the stack pointer like you could
with a more typical stack-in-contiguous-memory implementation of the
function call stack.)


This is a lot of work and you end up with ugly code that's going to
be hard to understand for anybody who hasn't been exposed to the idea
before. Far better to just write code that needs it in a language that
has built-in support for it.


dave
(The biggest strength of C is that you can create any high-level
abstraction you want to use yourself; the biggest weakness of C is that
you have to create any high-level abstraction you want to use yourself.)

--
Dave Vandervies (e-mail address removed)
Basically, there is no control structure you can imagine that
can't be implemented using call/cc. Even very silly ones.
--Bear in comp.lang.scheme

That wasn't what the OP was asking.
 
D

Dave Vandervies

Dave Vandervies said:
(snip details of how to implement explicit continuations in C)

That wasn't what the OP was asking.

The OP was asking how to make the called function return somewhere else.

If you have continuations, just write it in CPS and give it a continuation
for wherever you want it to return to.

You were the one who asked how to do it in C, which is what I gave you.


dave
 
B

Barry

Dave Vandervies said:
Dave Vandervies said:
(snip details of how to implement explicit continuations in C)



The OP was asking how to make the called function return somewhere else.

If you have continuations, just write it in CPS and give it a continuation
for wherever you want it to return to.

You were the one who asked how to do it in C, which is what I gave you.

No, the OP asked how to return to an arbitrary statement in the C code.
Or that is how I interpreted the question.
 
C

Chris Dollin

KIRAN said:
the grammer for any programming language says that when a function is
called by another function,the callee after executing it's body should
return to the point where it left in the caller..

That's not what the grammar (-AR, not -ER) says. That's what the
semantics says.What's more, that's not what the semantics says
for /all/ programming languages: any language with tail-call
optimisation (prototypically, Scheme) doesn't say that.
Is there any technique to make the callee to return to some other
point(within the current process) other than the callee by changing
the call stack in callee...
My code runs on 86 processor
(If this thread is irrelevent to this group please kindly igore the
same)
Shan't.

thanks in advance

What (C) /problem/ are you trying to solve?
 
K

KIRAN

That's not what the grammar (-AR, not -ER) says. That's what the
semantics says.What's more, that's not what the semantics says
for /all/ programming languages: any language with tail-call
optimisation (prototypically, Scheme) doesn't say that.


What (C) /problem/ are you trying to solve?

The kind of problem i am trying to solve is something like this.
My code contains N functions ,
void Task1(void)
{
void *pv_msg;


while(1)
{
pv_msg = QueuReceive(QUEUE1);


/* here QUEUE1 is a global data structue used implement queue for
Task1. If QUEUE1 is empty ,then scheduler should call the next highest
thread(here a function with 1 being highest priority) */

do_someoperation(msg); /* process the message */
}/* while(1) */

}

Note: All the N tasks are within the same process where each task
(function) is treated as a thread...at a time only one function can
execute..
 
C

Chris Dollin

KIRAN said:
(fx:snipped-own-signature-hint-hint)

The kind of problem i am trying to solve is something like this.
My code contains N functions ,
void Task1(void)
{
void *pv_msg;


while(1)
{
pv_msg = QueuReceive(QUEUE1);


/* here QUEUE1 is a global data structue used implement queue for
Task1. If QUEUE1 is empty ,then scheduler should call the next highest
thread(here a function with 1 being highest priority) */

do_someoperation(msg); /* process the message */
}/* while(1) */

}

Note: All the N tasks are within the same process where each task
(function) is treated as a thread...at a time only one function can
execute..

I can see at least three possibilities.

(a) Just run the functions one after another. (Queue them up, if
necessary). This assumes that latency isn't an issue.

Note that you'd probably have to arrange a single message
arrival queue.

(b) Break the functions up into smaller pieces, so each function
is short (quick) and schedules (queues) it's successor. May
be painful to do, of course.

(a) and (b) can be done in C with no extras, but (b) induces overhead
in maintenance since there's now a bunch of short functions tied
together by scheduling and internal logic: it's likely harder to
see what's going on.

(c) Use a non-Standard library to provide coroutines or threads.
This (may) mean that the overall structure becomes visible
again, but now you have to rely on this extra library (and
maintenance programmers being familiar with it). Portability
may be compromised. An example would be the Posix threads
library.

Note that these answers don't depend on the x86 architecture nor
are they much to do -- on the outside -- with making "the callee
to return to some other point(within the current process) other
than the callee by changing the call stack in callee": that may
be how they're /implemented/ but it's not what they're /for/.
 

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

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top