POSIX used to have the functions getcontext and setcontext. Most Unices
still provide them.
They worked like setjmp / longjmp except that longjmp can only be called
from the function that called setjmp, while getcontext / setcontext has
no such restriction.
From an implementation side that means that setjmp / longjmp can be implemented much more efficiently, with a small jmp_buf, while
getcontext / setcontext handles a copy of the whole stack in their
jmp_buf equivalent.
On the other hand, the functionality provided by getcontext / setcontext
is available in virtually all hardware, has important use cases (as can
be seen by the various uses of call/cc in functional languages, with efficient translation of functional languages to C being another use
case) and is currently not exposed in C.
The only problem I see is that it cannot be implemented by
implementations that do not use a stack for local variables (but those
are already non-conforming by not allowing recursion), but since all
those I know of are freestanding, it could be worked around by only
requiring the etcontext / setcontext-like functionality for hosted implementations.
Philipp
POSIX used to have the functions getcontext and setcontext. Most Unices
still provide them.
They worked like setjmp / longjmp except that longjmp can only be called
from the function that called setjmp, while getcontext / setcontext has
no such restriction.
From an implementation side that means that setjmp / longjmp can be implemented much more efficiently, with a small jmp_buf, while
getcontext / setcontext handles a copy of the whole stack in their
jmp_buf equivalent.
On the other hand, the functionality provided by getcontext / setcontext
is available in virtually all hardware, has important use cases (as can
be seen by the various uses of call/cc in functional languages, with efficient translation of functional languages to C being another use
case) and is currently not exposed in C.
The only problem I see is that it cannot be implemented by
implementations that do not use a stack for local variables (but those
are already non-conforming by not allowing recursion), but since all
those I know of are freestanding, it could be worked around by only
requiring the etcontext / setcontext-like functionality for hosted implementations.
On 2/18/20 4:17 AM, Philipp Klaus Krause wrote:
POSIX used to have the functions getcontext and setcontext. Most Unices
still provide them.
They worked like setjmp / longjmp except that longjmp can only be called
from the function that called setjmp, while getcontext / setcontext has
no such restriction.
From an implementation side that means that setjmp / longjmp can be
implemented much more efficiently, with a small jmp_buf, while
getcontext / setcontext handles a copy of the whole stack in their
jmp_buf equivalent.
On the other hand, the functionality provided by getcontext / setcontext
is available in virtually all hardware, has important use cases (as can
be seen by the various uses of call/cc in functional languages, with
efficient translation of functional languages to C being another use
case) and is currently not exposed in C.
The only problem I see is that it cannot be implemented by
implementations that do not use a stack for local variables (but those
are already non-conforming by not allowing recursion), but since all
those I know of are freestanding, it could be worked around by only
requiring the etcontext / setcontext-like functionality for hosted
implementations.
On my desktop system, "man getcontext" displays a description that
includes a "CONFORMING TO" section which says:
"SUSv2, POSIX.1-2001. POSIX.1-2008 removes the specification of >getcontext(), citing portability issues, and recommending that
applications be rewritten to use POSIX threads instead."
I'd recommend following that recommendation.
On 2/18/20 4:17 AM, Philipp Klaus Krause wrote:
POSIX used to have the functions getcontext and setcontext. Most Unices
still provide them.
They worked like setjmp / longjmp except that longjmp can only be called
from the function that called setjmp, while getcontext / setcontext has
no such restriction.
From an implementation side that means that setjmp / longjmp can be
implemented much more efficiently, with a small jmp_buf, while
getcontext / setcontext handles a copy of the whole stack in their
jmp_buf equivalent.
On the other hand, the functionality provided by getcontext / setcontext
is available in virtually all hardware, has important use cases (as can
be seen by the various uses of call/cc in functional languages, with
efficient translation of functional languages to C being another use
case) and is currently not exposed in C.
The only problem I see is that it cannot be implemented by
implementations that do not use a stack for local variables (but those
are already non-conforming by not allowing recursion), but since all
those I know of are freestanding, it could be worked around by only
requiring the etcontext / setcontext-like functionality for hosted
implementations.
On my desktop system, "man getcontext" displays a description that
includes a "CONFORMING TO" section which says:
"SUSv2, POSIX.1-2001. POSIX.1-2008 removes the specification of getcontext(), citing portability issues, and recommending that
applications be rewritten to use POSIX threads instead."
I'd recommend following that recommendation.
On 2020-02-18 13:11, James Kuyper wrote:
On 2/18/20 4:17 AM, Philipp Klaus Krause wrote:
POSIX used to have the functions getcontext and setcontext. Most Unices
still provide them.
They worked like setjmp / longjmp except that longjmp can only be called >>> from the function that called setjmp, while getcontext / setcontext has
no such restriction.
From an implementation side that means that setjmp / longjmp can be
implemented much more efficiently, with a small jmp_buf, while
getcontext / setcontext handles a copy of the whole stack in their
jmp_buf equivalent.
On the other hand, the functionality provided by getcontext / setcontext >>> is available in virtually all hardware, has important use cases (as can
be seen by the various uses of call/cc in functional languages, with
efficient translation of functional languages to C being another use
case) and is currently not exposed in C.
The only problem I see is that it cannot be implemented by
implementations that do not use a stack for local variables (but those
are already non-conforming by not allowing recursion), but since all
those I know of are freestanding, it could be worked around by only
requiring the etcontext / setcontext-like functionality for hosted
implementations.
On my desktop system, "man getcontext" displays a description that
includes a "CONFORMING TO" section which says:
"SUSv2, POSIX.1-2001. POSIX.1-2008 removes the specification of
getcontext(), citing portability issues, and recommending that
applications be rewritten to use POSIX threads instead."
I'd recommend following that recommendation.
Perhaps the common use is CoRoutines (not threads).
POSIX used to have the functions getcontext and setcontext. Most Unices
still provide them.
They worked like setjmp / longjmp except that longjmp can only be called
from the function that called setjmp, while getcontext / setcontext has
no such restriction.
Philipp Klaus Krause <pkk@spth.de> writes:
POSIX used to have the functions getcontext and setcontext. Most Unices
still provide them.
They worked like setjmp / longjmp except that longjmp can only be called
from the function that called setjmp, while getcontext / setcontext has
no such restriction.
setjmp and longjmp also have no such restriction.
Here's an example from the standard, N1570 7.13.2.1p5. (The example is
about possibly squandering memory associated with a VLA.)
I was thinking about that too. (Or, roughly equivalently, cooperative multi-threading.) A quick search shows that the GNU Portable Threads library for implementing fibers uses getcontext, setcontext and
swapcontext.
I am not sure there would be much use in standardising something as
low-level as setcontext/getcontext. I think it would be better to standardise fiber or coroutine support, similar to the C11 thread
support, and let implementations worry about whether they want to use OS kernel support, setcontext/getcontext, assembly code, or whatever. But first it would make sense to see how C++20 coroutines play out in
practice - let C++ go first, and learn from what works or does not work.
What purpose would these functions serve? I haven't had any use for
these kinds of thing, so I could well be missing something.
Am 18.02.20 um 11:07 schrieb David Brown:
What purpose would these functions serve? I haven't had any use for
these kinds of thing, so I could well be missing something.
One important use case is to make translation of functional languages to
C easier.
E.g. a Scheme-to-C compiler is quite straightforward (both in
implementation and in how the generated C code looks), as long as
call/cc is not fully supported.
But once full support for call/cc is implemented, the compiler has to
emit nonstandard C or generate C code that looks nothing like what a c C programmer would write or what the original scheme looked like.
Supporting call/cc usign stadnard C usually also results in using the C
heap to emulate the Scheme stack, while without full call/cc one can use
the C stack (which is more intuitive and much faster).
Philipp
On 19/02/2020 11:03, Philipp Klaus Krause wrote:
Am 18.02.20 um 11:07 schrieb David Brown:
What purpose would these functions serve? I haven't had any use for
these kinds of thing, so I could well be missing something.
One important use case is to make translation of functional languages to
C easier.
E.g. a Scheme-to-C compiler is quite straightforward (both in
implementation and in how the generated C code looks), as long as
call/cc is not fully supported.
But once full support for call/cc is implemented, the compiler has to
emit nonstandard C or generate C code that looks nothing like what a c C
programmer would write or what the original scheme looked like.
Supporting call/cc usign stadnard C usually also results in using the C
heap to emulate the Scheme stack, while without full call/cc one can use
the C stack (which is more intuitive and much faster).
I am not familiar with Scheme, and while I have used functional
programming languages, I have never translated them to C. Are you
talking about something like lazy evaluation, implemented using
coroutines?
I would expect setcontext/getcontext to be very inefficient
for such purposes.
Efficient coroutine support is going to need serious compiler support.
David Brown <david.brown@hesbynett.no> writes:
On 19/02/2020 11:03, Philipp Klaus Krause wrote:
Am 18.02.20 um 11:07 schrieb David Brown:
What purpose would these functions serve? I haven't had any use for
these kinds of thing, so I could well be missing something.
One important use case is to make translation of functional languages to >>> C easier.
E.g. a Scheme-to-C compiler is quite straightforward (both in
implementation and in how the generated C code looks), as long as
call/cc is not fully supported.
This surprises me. Surely even something a simple as a full closure
value will give rise to strange-looking C.
But once full support for call/cc is implemented, the compiler has to
emit nonstandard C or generate C code that looks nothing like what a c C >>> programmer would write or what the original scheme looked like.
Supporting call/cc usign stadnard C usually also results in using the C
heap to emulate the Scheme stack, while without full call/cc one can use >>> the C stack (which is more intuitive and much faster).
I am not familiar with Scheme, and while I have used functional
programming languages, I have never translated them to C. Are you
talking about something like lazy evaluation, implemented using
coroutines?
No, Scheme is not lazy, but it has a built-in function call/cc (call
with current continuation) that, to cut a very long story short, calls a function with the possibility of immediately "coming back here" with a result. Combined with the other features of a functional language, this allows almost any computational pattern to be implemented.
I would expect setcontext/getcontext to be very inefficient
for such purposes.
I doubt that efficiency is the main concern here. I think keeping the C looking like normal C is the main concern. That said, given that setcontext/getcontext are not seen in normal C, and they behave in a way
that many C programmer would find unusual, I don't think they would
really acheiv`qe the desired result.
Efficient coroutine support is going to need serious compiler support.
On 19/02/2020 14:29, Ben Bacarisse wrote:
David Brown <david.brown@hesbynett.no> writes:
On 19/02/2020 11:03, Philipp Klaus Krause wrote:
Am 18.02.20 um 11:07 schrieb David Brown:
What purpose would these functions serve? I haven't had any use for >>>>> these kinds of thing, so I could well be missing something.
One important use case is to make translation of functional languages to >>>> C easier.
E.g. a Scheme-to-C compiler is quite straightforward (both in
implementation and in how the generated C code looks), as long as
call/cc is not fully supported.
This surprises me. Surely even something a simple as a full closure
value will give rise to strange-looking C.
But once full support for call/cc is implemented, the compiler has to
emit nonstandard C or generate C code that looks nothing like what a c C >>>> programmer would write or what the original scheme looked like.
Supporting call/cc usign stadnard C usually also results in using the C >>>> heap to emulate the Scheme stack, while without full call/cc one can use >>>> the C stack (which is more intuitive and much faster).
I am not familiar with Scheme, and while I have used functional
programming languages, I have never translated them to C. Are you
talking about something like lazy evaluation, implemented using
coroutines?
No, Scheme is not lazy, but it has a built-in function call/cc (call
with current continuation) that, to cut a very long story short, calls a
function with the possibility of immediately "coming back here" with a
result. Combined with the other features of a functional language, this
allows almost any computational pattern to be implemented.
I should probably read the Wikipedia article on Scheme - if you think
that would be more useful than writing a fuller reply, please do so.
But isn't it a feature of normal functions that they usually "come back
here with a result" ? Or do you mean they can return immediately with a "future" type whose real value will be filled in asynchronously from the calling code? (Or do you mean something else entirely?)
I would expect setcontext/getcontext to be very inefficient
for such purposes.
I doubt that efficiency is the main concern here. I think keeping the C
looking like normal C is the main concern. That said, given that
setcontext/getcontext are not seen in normal C, and they behave in a way
that many C programmer would find unusual, I don't think they would
really [acheive] the desired result.
Agreed. I think if you are willing to generate getcontext/setcontext,
you should be willing to generate just about anything! There is some
sense in generating C code that is easy to follow and matches the source language - it makes it simpler to find where things have gone wrong (for
the person writing the generator) and where things are unexpectedly inefficient.
POSIX used to have the functions getcontext and setcontext. Most Unices
still provide them.
They worked like setjmp / longjmp except that longjmp can only be called
from the function that called setjmp, while getcontext / setcontext has
no such restriction.
From an implementation side that means that setjmp / longjmp can be implemented much more efficiently, with a small jmp_buf, while
getcontext / setcontext handles a copy of the whole stack in their
jmp_buf equivalent.
On the other hand, the functionality provided by getcontext / setcontext
is available in virtually all hardware, has important use cases (as can
be seen by the various uses of call/cc in functional languages, with efficient translation of functional languages to C being another use
case) and is currently not exposed in C.
The only problem I see is that it cannot be implemented by
implementations that do not use a stack for local variables (but those
are already non-conforming by not allowing recursion), but since all
those I know of are freestanding, it could be worked around by only
requiring the etcontext / setcontext-like functionality for hosted implementations.
Philipp
Actually, I am not sure getcontext / setcontext really work the way I
thought (after discussion on comp.unix.programmer).
So C++ callcc() (https://www.boost.org/doc/libs/1_72_0/libs/context/doc/html/context/cc.html and http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0534r3.pdf) would probably be a better example than getcontext() for the
functionality I'd like to see in C.
David Brown <david.brown@hesbynett.no> writes:
On 19/02/2020 14:29, Ben Bacarisse wrote:
David Brown <david.brown@hesbynett.no> writes:
On 19/02/2020 11:03, Philipp Klaus Krause wrote:
Am 18.02.20 um 11:07 schrieb David Brown:
What purpose would these functions serve? I haven't had any use for >>>>>> these kinds of thing, so I could well be missing something.
One important use case is to make translation of functional languages to >>>>> C easier.
E.g. a Scheme-to-C compiler is quite straightforward (both in
implementation and in how the generated C code looks), as long as
call/cc is not fully supported.
This surprises me. Surely even something a simple as a full closure
value will give rise to strange-looking C.
But once full support for call/cc is implemented, the compiler has to >>>>> emit nonstandard C or generate C code that looks nothing like what a c C >>>>> programmer would write or what the original scheme looked like.
Supporting call/cc usign stadnard C usually also results in using the C >>>>> heap to emulate the Scheme stack, while without full call/cc one can use >>>>> the C stack (which is more intuitive and much faster).
I am not familiar with Scheme, and while I have used functional
programming languages, I have never translated them to C. Are you
talking about something like lazy evaluation, implemented using
coroutines?
No, Scheme is not lazy, but it has a built-in function call/cc (call
with current continuation) that, to cut a very long story short, calls a >>> function with the possibility of immediately "coming back here" with a
result. Combined with the other features of a functional language, this >>> allows almost any computational pattern to be implemented.
I should probably read the Wikipedia article on Scheme - if you think
that would be more useful than writing a fuller reply, please do so.
But isn't it a feature of normal functions that they usually "come back
here with a result" ? Or do you mean they can return immediately with a
"future" type whose real value will be filled in asynchronously from the
calling code? (Or do you mean something else entirely?)
Something else entirely. You can "come back here" even from a function called by the function that is called with the current continuation.
And code can end up with multiple continuations in scope and so can
decide where to "go back to".
POSIX used to have the functions getcontext and setcontext. Most Unices
still provide them.
I am not familiar with Scheme, and while I have used functional
programming languages, I have never translated them to C. Are you
talking about something like lazy evaluation, implemented using
coroutines? I would expect setcontext/getcontext to be very inefficient
for such purposes.
Efficient coroutine support is going to need serious compiler support.
* David Brown:
I am not familiar with Scheme, and while I have used functional
programming languages, I have never translated them to C. Are you
talking about something like lazy evaluation, implemented using
coroutines? I would expect setcontext/getcontext to be very inefficient
for such purposes.
Yes, setcontext/getcontext are basically used as a fallback if you
want to implement context switching without an existing assembler implementation. They were specified to save and restore the process
signal mask, which makes them quite slow. Perhaps slightly faster
than a signal through a condition variable, but probably not by much.
The trouble is anyone can write assembler code for coroutine
suspend/resume, but the tricky part is making sure that it's actually
correct in the presence of compiler optimizations. (We just went
through that with the context switching implementation in C++ for a
new architecture.) Using setcontext/getcontext is generally a safe
bet (if you always resume on the same thread), but it's really quite
slow.
Efficient coroutine support is going to need serious compiler support.
Yes, and there could be ABI implications for TLS if the goal is to
suspend with non-coroutine functions on the stack (as it is possible
with setcontext/getcontext, but not with C++ coroutines).
Am 20.02.20 um 09:20 schrieb Philipp Klaus Krause:
Actually, I am not sure getcontext / setcontext really work the way I thought (after discussion on comp.unix.programmer).
So C++ callcc() (https://www.boost.org/doc/libs/1_72_0/libs/context/doc/html/context/cc.html
and http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0534r3.pdf) would probably be a better example than getcontext() for the
functionality I'd like to see in C.
On second look, I am not sure C++ callcc() is good enough either. While
very close to Schem call/cc in syntax, it still seems less powerful.
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 349 |
Nodes: | 16 (0 / 16) |
Uptime: | 142:17:14 |
Calls: | 7,613 |
Calls today: | 1 |
Files: | 12,790 |
Messages: | 5,684,452 |