alloca... (and setjmp/longjmp coroutines)
Dave Jones
djones at megatest.UUCP
Sat Jun 11 12:18:31 AEST 1988
>From article <11902 at mimsy.UUCP>, by chris at mimsy.UUCP (Chris Torek):
> In article <16126 at brl-adm.ARPA> ted%nmsu.csnet at relay.cs.net writes:
> [alloca + setjmp/longjmp for coroutines]
>
> longjmp is not suitable for coroutines because it is valid for longjmp
> to attempt to unwind the stack in order to find the corresponding
> setjmp, and it is therefore legal for longjmp to abort if it is
> attempting to jump the `wrong way' on the stack.
> --
> In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
> Domain: chris at mimsy.umd.edu Path: uunet!mimsy!chris
I'm no C wizard -- BSD4.2 and Sun3-OS are the only C's I've ever used --
but it seems to me that longjmp is the most suitable technique going,
by default.
What else is there? You could use [abuse?] sigvec and kill. But if you
use separate stacks of fixed sizes, they can overflow with disastrous
consequences. And -- correct me if I'm wrong -- more systems have
setjmp/longjmp/alloca than have sigvec and kill.
Or you could use a smattering of assembler. But, it will certainly run
on more kinds of machines if written in C than it would if written in
assembler.
And to answer your objection about unwinding the stack, you can see to
it that the stack is restored _before_ you do the longjmp, so the longjmp
can "unwind" as it pleases.
I recently wrote a little discrete-event-simulator using
setjmp/longjmp/alloca to do lightweight processes.
We hope to run it on both Sun3s and IBM PCs. Haven't tried it on the PCs
yet, so I don't know if it works there or not. Do I have a surprise in
store for me?
Here's what I did. The main simulator loop calls alloca(1) to find
the bottom of the part of the stack that lightweight processes will
be using. It squirrels that address away in the variable {stack_bottom}.
To start a process initially, it just calls the process's procedure.
Then the simulator and the process trade setjmp/longjmp cycles through
a couple of jmpbufs.
Well, you'll see.
Is there some gotcha that will break this code on some systems?
If so, is there a better [more machine independent] way?
/***********************************************************************
** Run the simulation, stopping after some number of ticks, unless
** all processes exit, or some process calls PSim_stop() first.
***********************************************************************/
unsigned long
PSim_run(obj, ticks)
Simulation* obj;
unsigned long ticks;
{
obj->stack_bottom = (char*)alloca(1);
obj->stop_time += ticks;
while(!obj->quit)
{
/* Get a busy process from the busy-queue */
obj->active = (Process*) PQ_pop(&obj->busy);
/* If all processes are finished, or are waiting on
** a semaphore, we are blocked, and must exit the simulation.
*/
if(obj->active==0)
goto end_simulation;
{ register Process *active = obj->active;
/* Update the time to the time of the active process */
obj->time = active->busy_until;
if( obj->time >= obj->stop_time)
goto end_simulation;
if(setjmp(active->suspend) == 0)
if(active->stack_save == 0)
/* Process has not yet started. Call its start-procedure. */
active->return_value =
(*(active->start))(obj);
else
{ /* Process has been suspended, and will now be restarted. */
/* allocate the restarting process's stack. */
alloca( active->stack_size );
/* restore it */
bcopy( active->stack_save, active->stack_real,
active->stack_size);
sfree(active->stack_save);
active->stack_save = 0;
/* restart the process */
longjmp(active->restart, 1);
}
}
}
end_simulation:
cleanup(obj);
return obj->time;
}
static
suspend_active_proc(obj)
register Simulation* obj;
{
char* stack_top = (char*)alloca(1);
long size = abs(obj->stack_bottom - stack_top);
register Process* active = obj->active;
active->stack_save = (char*)smalloc(size);
active->stack_real = min(stack_top, obj->stack_bottom);
active->stack_size = size;
if(setjmp(active->restart) == 0)
{
/* copy the stack and return to the simulator. */
bcopy( active->stack_real, active->stack_save, size);
longjmp(active->suspend, 1);
}
}
More information about the Comp.unix.wizards
mailing list