Date: Fri, 8 May 2020 21:32:25 -0400
On Fri, May 8, 2020 at 21:14 Brian Bi <bbi5291_at_[hidden]> wrote:
> On Fri, May 8, 2020 at 9:03 PM connor horman via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
>> Currently in the C++ language, it is undefined behaviour to have an
>> infinite loop without observable side effects.
>>
>
> Is that true? I thought the rule was that the compiler is allowed to
> assume that the loop will eventually terminate.
>
That would be the result of undefined behavior.
>
>
>> While this is nice on paper, it has a few issues. Any time you need to
>> loop forever, you basically need to insert a (potentially costly) side
>> effect. This applies any time you need are, say, running a game on a old
>> console, and just need to spin while waiting for interrupts to do stuff
>> (same with an os kernel). This results in requiring assembly to so this, or
>> maybe insert an instruction to wait for an interrupt in a loop (both llvm
>> and gcc allow the volatile specifier in an assembly declaration, which is
>> treated as observable, so x86_64 code could use hlt (in CPL=0), 65816 could
>> WAI). This, however, seems to violate one of C++'s core principles, that
>> there is no lower level language.
>> A further case would be an init process on linux, which cannot terminate
>> (doing so results in a kernel panic), nor can just call hlt in a loop, as
>> that's one way to get a #GP which probably translates to SIGILL. Once an
>> init process is done setting up, it could want to just spin forever, and do
>> so using as little system resources as possible. The logical idea would be
>> just for(;;) std::this_thread::yield();, but that would be UB as yield() is
>> not observable (correct me if I'm wrong).
>>
>> Having the ability to spin forever, without wasting time actually doing
>> stuff, seems like a reasonable thing to have in low-level code, so its very
>> curious (and in many cases, annoying) that you cannot actually do this in
>> real code that might have to.
>>
>
> Couldn't you just do: `volatile int x; x = 0;`? This is considered a side
> effect.
>
That wastes time, especially in the init process example, where I really
want to just spin forever. Time spent not yielding back to the kernel is
time not available for another process that's next in the task queue (and
there may not be a good alternative to spinning available, depending on os
configuration. futexs may exist, or they may be disabled).
That may also cause issues with limited stack space (going back to my
example with the 65816, I have 2k stack space, and interrupts doing
whatever), Ideally, when I start spinning, I'm in the bottom stack frame,
with no actual local variables allocated at the time, so it can just use
the entire thing.
As a side note, not necessarily dealing with the specifics of the proposal,
because of this "feature" llvm really likes to delete infinite loops that
don't do anything, which leads to problems in other languages (particularly
rust, where it is safe to use loop{}, an infinite loop, and rely on it
being infinite, and the ability to cause undefined behaviour in safe code
is a bug), and the same arguments apply there. Inserting a side effect has
many of the same problems I bring up here.
>
>
>> --
>> Std-Proposals mailing list
>> Std-Proposals_at_[hidden]
>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>
>
>
> --
> *Brian Bi*
>
> On Fri, May 8, 2020 at 9:03 PM connor horman via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
>> Currently in the C++ language, it is undefined behaviour to have an
>> infinite loop without observable side effects.
>>
>
> Is that true? I thought the rule was that the compiler is allowed to
> assume that the loop will eventually terminate.
>
That would be the result of undefined behavior.
>
>
>> While this is nice on paper, it has a few issues. Any time you need to
>> loop forever, you basically need to insert a (potentially costly) side
>> effect. This applies any time you need are, say, running a game on a old
>> console, and just need to spin while waiting for interrupts to do stuff
>> (same with an os kernel). This results in requiring assembly to so this, or
>> maybe insert an instruction to wait for an interrupt in a loop (both llvm
>> and gcc allow the volatile specifier in an assembly declaration, which is
>> treated as observable, so x86_64 code could use hlt (in CPL=0), 65816 could
>> WAI). This, however, seems to violate one of C++'s core principles, that
>> there is no lower level language.
>> A further case would be an init process on linux, which cannot terminate
>> (doing so results in a kernel panic), nor can just call hlt in a loop, as
>> that's one way to get a #GP which probably translates to SIGILL. Once an
>> init process is done setting up, it could want to just spin forever, and do
>> so using as little system resources as possible. The logical idea would be
>> just for(;;) std::this_thread::yield();, but that would be UB as yield() is
>> not observable (correct me if I'm wrong).
>>
>> Having the ability to spin forever, without wasting time actually doing
>> stuff, seems like a reasonable thing to have in low-level code, so its very
>> curious (and in many cases, annoying) that you cannot actually do this in
>> real code that might have to.
>>
>
> Couldn't you just do: `volatile int x; x = 0;`? This is considered a side
> effect.
>
That wastes time, especially in the init process example, where I really
want to just spin forever. Time spent not yielding back to the kernel is
time not available for another process that's next in the task queue (and
there may not be a good alternative to spinning available, depending on os
configuration. futexs may exist, or they may be disabled).
That may also cause issues with limited stack space (going back to my
example with the 65816, I have 2k stack space, and interrupts doing
whatever), Ideally, when I start spinning, I'm in the bottom stack frame,
with no actual local variables allocated at the time, so it can just use
the entire thing.
As a side note, not necessarily dealing with the specifics of the proposal,
because of this "feature" llvm really likes to delete infinite loops that
don't do anything, which leads to problems in other languages (particularly
rust, where it is safe to use loop{}, an infinite loop, and rely on it
being infinite, and the ability to cause undefined behaviour in safe code
is a bug), and the same arguments apply there. Inserting a side effect has
many of the same problems I bring up here.
>
>
>> --
>> Std-Proposals mailing list
>> Std-Proposals_at_[hidden]
>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>
>
>
> --
> *Brian Bi*
>
Received on 2020-05-08 20:35:39