From Modula to Oberon

J. Collier james at cantuar.UUCP
Tue Mar 29 07:16:56 AEST 1988


Expires:

Sender:

Followup-To:

Distribution:

Keywords:


Peter da Silva (peter at sugar.UUCP) writes:
>....
>I'd like to see the following functions become standard in 'C':
>....
>COROUTINE -- Build a jmp_buf for a coroutine.
>....
>This sets up the stack and jmp_buf so that a call to "longjmp(jmp_buf)"
>will appear to be a call to entry().
> [implementation outlines deleted]

   I seem to remember a minor war in the letters to 'Software Practice
and Experience' [I think] on this subject a couple of years back.
(Wasn't it peaceful in the days when it took a month or two to get the
next installment..)

   Correct me if I'm wrong, but I find that on some machines (well, on
BSD Vaxen anyway) setjmp()/longjmp() can't be used to implement
coroutines because longjmp() unwinds the stack destructively while
checking for botches. A small amount of in-line assembly language is
therefore necessary for transferring control.

   I agree with Peter's view that coroutines should be supported in the
C library. As he says, coroutine packages are quite easy to write and they
are indispensible for certain classes of application (I wanted one originally
for a window server/multiplexor).

   The current situation where everybody brews their own isn't really
acceptable. The programs aren't portable, and the semantics differ
sufficiently to make things confusing for the reader. The details will
have to be thrashed out before a standard is defined.

   Pre-empting threads which share a common data space are probably not
a good idea for most purposes - the synchronisation problems usually
outweigh any advantages. Leave true multitasking to the operating system
and keep to protected data spaces if possible, unless you enjoy wrapping
semaphore primitives around every second line of code. (OK, I've just spent
2 years doing this on the Mac, but that's different - no OS processes).

   Threads with explicit sleep() calls and round-robin transfer - as
suggested by Peter - are one way of organising things. I suppose it's
a matter of personal taste, but I prefer a system where the 'new_coroutine()'
call returns a pointer to a structure which contains at least the context
information and the stack base pointer, a reduced form of Peter's 'proc'
structure. This makes it easier to tailor your use of coroutines; sometimes
you want to transfer control explicitly rather than set up a threads system,
and you therefore need some way to identify coroutines throughout their
lifespan. The switch()/transfer()/resume() call keeps track of the
current coroutine through a static pointer, and hence needs no 'from'
parameter.

   There are other issues, such as how best to set up the routines so that
they exit cleanly, whether the original context should be set up as
a coroutine, and whether to support special transfers such as resume_caller()
or resume_<some default>(). Comments?

-------------------------
James Collier              Internet(ish):  james at cantuar.uucp
Computer Science Dept.,    UUCP:           {watmath,munnari,mcvax}!cantuar!james
University of Canterbury,  Spearnet/Janet: j.collier at nz.ac.canty
Christchurch, New Zealand. Office: +64 3 482 009 x8356  Home: +64 3 554 025



More information about the Comp.unix.wizards mailing list