Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2015-03

Portable coroutines

7 messages · 4 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Mark Morgan Lloyd

Efficient implementation of coroutines requires CPU-specific code in the RTL and possibly the compiler. However
http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html suggests a way that coroutines can be implemented in a portable fashion in C, how can this be done in Object Pascal?

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

Marco van de Voort
to Mark Morgan Lloyd

In our previous episode, Mark Morgan Lloyd said:

Show quoted text 5 lines
Efficient implementation of coroutines requires CPU-specific code in the RTL and possibly the compiler. However http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html suggests a way that coroutines can be implemented in a portable fashion in C, how can this be done in Object Pascal?

Seems more an oddity than a system, but it relies heavily on preprocessor and fallthrough case.

The preprocessor part can be done, just use whatever preprocessor (maybe even cpp) and then haul the resulting code through fpc.

But there is no fallthrough case (and personally I think that is a good thing)

Reply by email

Unknown author
to Marco van de Voort

Maybe look at the coroutine implementation in Go (Golang).

Maybe a better refrence. Maybe an optional switch in compiler so you are not required to have all CPU architectures working on day 1.

Intel and ARM seem nice...

md

Marco van de Voort wrote 19 lines
In our previous episode, Mark Morgan Lloyd said: > Efficient implementation of coroutines requires CPU-specific code in the > RTL and possibly the compiler. However > http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html suggests a > way that coroutines can be implemented in a portable fashion in C, how > can this be done in Object Pascal? Seems more an oddity than a system, but it relies heavily on preprocessor and fallthrough case. The preprocessor part can be done, just use whatever preprocessor (maybe even cpp) and then haul the resulting code through fpc. But there is no fallthrough case (and personally I think that is a good thing) _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal

Reply by email

Mark Morgan Lloyd
to Unknown author
Show quoted text 6 lines
Maybe look at the coroutine implementation in Go (Golang). Maybe a better refrence. Maybe an optional switch in compiler so you are not required to have all CPU architectures working on day 1. Intel and ARM seem nice...

The issue isn't the syntax, it's that proper implementation of coroutines means switching stacks which is highly architecture-specific; adding something like that to the RTL is a non-starter.

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

Mark Morgan Lloyd
to Marco van de Voort: In our previous episode, Mark Morgan Lloyd said: Seems more an oddity than a system, but…
Marco van de Voort wrote 15 lines
In our previous episode, Mark Morgan Lloyd said: > Efficient implementation of coroutines requires CPU-specific code in the > RTL and possibly the compiler. However > http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html suggests a > way that coroutines can be implemented in a portable fashion in C, how > can this be done in Object Pascal? Seems more an oddity than a system, but it relies heavily on preprocessor and fallthrough case. The preprocessor part can be done, just use whatever preprocessor (maybe even cpp) and then haul the resulting code through fpc. But there is no fallthrough case (and personally I think that is a good thing)

Generally agreed. I'm not particularly bothered about the syntax, although obviously having it fairly compact would be an advantage. I don't think it's possible to use a case/goto arrangement since this wouldn't be happy jumping into repeat or while loops, but it does look as though it's possible to use LongJmp() (insomnia has its advantages):

program coroutines;
uses SysUtils;
type    TState= record
            env: jmp_buf;
            line: cardinal
         end;
var     state: TState;
         once: boolean= false;
         scratch: char;
   function getchar(): char;
   var   sanity: jmp_buf;
   begin
     // Check that we're not trying to jump into exception blocks etc.
     if state.line  0 then begin
       SetJmp(sanity);
       Assert(PtrUInt(state.env.sp) + PtrUInt(state.env.bp) =
                 PtrUInt(sanity.sp) + PtrUInt(sanity.bp),
                 'Bad SP or BP at xfer to line ' + IntToStr(state.line));
       LongJmp(state.env, 1)
     end;
     SetJmp(state.env);
     if state.line = 0 then begin
       state.line := StrToInt( (*$I %LINE% *) );
       exit('A')
     end else
       state.line := 0;

..

     repeat
       SetJmp(state.env);
       if state.line = 0 then begin
         state.line := StrToInt( (*$I %LINE% *) );
         exit(#$ff)
       end else
         state.line := 0;
       once := true
     until once
   end { getChar } ;
begin
   FillByte(state, SizeOf(state), 0);
   scratch := getChar();
   while scratch  #$ff do begin
     WriteLn(scratch);
     scratch := getChar()
   end
end.

The sanity check at the start is obviously processor-specific, but it doesn't use anything hidden and can at a pinch be omitted. It's obviously excessively verbose, but it is comparatively regular and does appear to handle at least some loop types properly.

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

Michael Schnell
to Mark Morgan Lloyd: Efficient implementation of coroutines requires CPU-specific code in the RTL and possibly…
Mark Morgan Lloyd wrote 6 lines
Efficient implementation of coroutines requires CPU-specific code in the RTL and possibly the compiler. However http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html suggests a way that coroutines can be implemented in a portable fashion in C, how can this be done in Object Pascal?

Lazarus seems to supports a similar concept by using events and "Application.ProcessMessages". it might not be especially efficient, though.

-Michael

Reply by email

Mark Morgan Lloyd
to Michael Schnell
Michael Schnell wrote 10 lines
On 03/20/2015 11:09 PM, Mark Morgan Lloyd wrote: > Efficient implementation of coroutines requires CPU-specific code in > the RTL and possibly the compiler. However > http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html suggests a > way that coroutines can be implemented in a portable fashion in C, how > can this be done in Object Pascal? > Lazarus seems to supports a similar concept by using events and "Application.ProcessMessages". it might not be especially efficient, though.

My tentative solution simplifies to the excerpt below, which I think is reasonably efficient.

..
     // Check that we're not trying to jump into exception blocks etc. Valid
     // line numbers are known to be > 0, the assertion is CPU-specific.
     if state.line > 0 then begin
       SetJmp(sanity);
       Assert(PtrUInt(state.env.sp) shr 1 xor PtrUInt(state.env.bp) =
                 PtrUInt(sanity.sp) shr 1 xor PtrUInt(sanity.bp),
                 'Bad stack frame at xfer to line ' +
IntToStr(state.line - 1));
       LongJmp(state.env, state.line)
     end;
     if SetJmp(state.env) = 0 then begin
       state.line := StrToInt( (*$I %LINE% *) );
       exit('A')
     end;
     if SetJmp(state.env) = 0 then begin
..

Pity about the StrToInt(), which in principle could be resolved at compilation time.

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email