Groups | Search | Server Info | Login | Register


Groups > comp.lang.pascal.misc > #2791

More of my philosophy and precision about the link of the article and more..

From World-News2100 <m1@m1.com>
Newsgroups comp.lang.pascal.misc
Subject More of my philosophy and precision about the link of the article and more..
Date 2021-11-25 11:18 -0500
Organization A noiseless patient Spider
Message-ID <snod16$a30$1@dont-email.me> (permalink)

Show all headers | View raw


Hello,



More of my philosophy and precision about the link of the article and more..

And notice that the link below of the article that shows the problem
of implementing coroutines with just setjmp() and longjmp()
is from the last semester of the second year of the course
called  "CS4411 Operating Systems" from Michigan Technological 
University, but i think i am smart and those courses are easy
for me, so i invite you to read about this course that requires
both the course of "CS3331 Concurrent Computing" and "CS3421 Computer 
Organization", and here it is:

http://www.csl.mtu.edu/cs4411.ck/www/Home.html

More of my philosophy about coroutines and about setjmp() and longjmp()..

I think i am smart, and i will say that with setjmp() and longjmp()
you can implement a generator or the like, but you can not implement 
coroutines with just setjmp() and longjmp(), and so that to understand 
it, i invite you to read the following article that shows how when you 
yield from a first function with a longjmp() to the main body of a 
program and when you call another functions with longjmp(), it can make 
the stack frames not work correctly, and when you understand it you will 
not use setjmp() and longjmp() alone so that to implement coroutines, so 
read the following article so that to understand the problem with
the stack frames, and i am understanding it easily:

https://www.csl.mtu.edu/cs4411.ck/www/NOTES/non-local-goto/coroutine.html

So this is why i have also implemented my sophisticated stackful 
coroutines library so that to solve this problem, and here is my 
sophisticated coroutines library and read about it and download it from 
here:

https://sites.google.com/site/scalable68/object-oriented-stackful-coroutines-library-for-delphi-and-freepascal

More of my philosophy about setjmp() and longjmp() and generators and 
coroutines..

I have just quickly implemented setjmp() and longjmp() in x64 assembler,
and after that i have just implemented quickly a good example of a 
generator with my setjmp() and longjmp(), look at it below, and in 
computer science, a generator is a routine that can be used to control 
the iteration behaviour of a loop. All generators are also iterators. A 
generator is very similar to a function that returns an array, in that a 
generator has parameters, can be called, and generates a sequence of 
values. However, instead of building an array containing all the values 
and returning them all at once, a generator yields the values one at a 
time, which requires less memory and allows the caller to get started 
processing the first few values immediately. In short, a generator looks 
like a function but behaves like an iterator. So here is my 
implementations in freepascal and delphi and they are working perfectly:

Here is my first unit that implements longjmp() and setjmp() and notice
how i am saving the non-volatile registers and how i am coding it in
x64 assembler:

======


{ Volatile registers: The calling program assumes registers
RAX, RCX, RDX, and R8 through R11 are volatile.
The contents of registers RBX, RSI, RDI, RBP, RSP, and
R12 through R15 are considered non-volatile. Functions return
values in RAX. }



unit JmpLib64;

{$IFDEF FPC}
{$ASMMODE intel}
{$ENDIF}
interface

type
   jmp_buf = record
     RBX,
     RSI,
     RDI,
     RSP,
     RBP,
     RIP,
     R12,
     R13,
     R14,
     R15: UInt64;
  end;

{ setjmp captures the complete task state which can later be used to 
perform a non-local goto using longjmp. setjmp returns 0 when it is 
initially called,  and a non-zero value when it is returning from a call 
to longjmp. setjmp must be called before longjmp. }

function  setjmp(out jmpb: jmp_buf): UInt64;

{ longjmp restores the task state captured by setjmp (and passed in 
jmpb). It then returns in such a way that setjmp appears to have 
returned with the value retval. setjmp must be called before longjmp. }

procedure longjmp(const jmpb: jmp_buf; retval: UInt64);
implementation

function  setjmp(out jmpb: jmp_buf): UInt64; assembler;{$IFDEF FPC} 
nostackframe; {$ENDIF}register;
asm
{     ->  RCX     jmpb   }
{     <-  RAX     Result }
           MOV     RDX, [RSP]  // Fetch return address (RIP)
           // Save task state
           MOV     [RCX+jmp_buf.&RBX], RBX
           MOV     [RCX+jmp_buf.&RSI], RSI
           MOV     [RCX+jmp_buf.&RDI], RDI
           MOV     [RCX+jmp_buf.&RSP], RSP
           MOV     [RCX+jmp_buf.&RBP], RBP
           MOV     [RCX+jmp_buf.&RIP], RDX
           MOV     [RCX+jmp_buf.&R12], R12
           MOV     [RCX+jmp_buf.&R13], R13
           MOV     [RCX+jmp_buf.&R14], R14
           MOV     [RCX+jmp_buf.&R15], R15


           SUB     RAX, RAX
@@1:
end;

procedure longjmp(const jmpb: jmp_buf; retval: UInt64);assembler;{$IFDEF 
FPC} nostackframe; {$ENDIF}register;
asm
{     ->  RCX     jmpb   }
{         RDX     retval }
{     <-  RAX     Result }
           XCHG    RDX, RCX
           MOV     RAX,RCX
           MOV     RCX, [RDX+jmp_buf.&RIP]
           // Restore task state
           MOV     RBX, [RDX+jmp_buf.&RBX]
           MOV     RSI, [RDX+jmp_buf.&RSI]
           MOV     RDI, [RDX+jmp_buf.&RDI]
           MOV     RSP, [RDX+jmp_buf.&RSP]
           MOV     RBP, [RDX+jmp_buf.&RBP]
           MOV     R12, [RDX+jmp_buf.&R12]
           MOV     R13, [RDX+jmp_buf.&R13]
           MOV     R14, [RDX+jmp_buf.&R14]
           MOV     R15, [RDX+jmp_buf.&R15]
           MOV     [RSP], RCX  // Restore return address (RIP)

           TEST    RAX, RAX    // Ensure retval is <> 0
           JNZ     @@1
           MOV     RAX, 1
@@1:
end;

end.

================

And here is my example of a generator with my longjmp() and setjmp():


{ In computer science, a generator is a routine that can be used to 
control the iteration behaviour of a loop. All generators are also 
iterators. A generator is very similar to a function that returns an 
array, in that a generator has parameters, can be called, and generates 
a sequence of values. However, instead of building an array containing 
all the values and returning them all at once, a generator yields the 
values one at a time, which requires less memory and allows the caller 
to get started processing the first few values immediately. In short, a 
generator looks like a function but behaves like an iterator. }

program test_generator;

{$APPTYPE CONSOLE}

uses
    JmpLib64;

type PtrInt = ^Integer;

var
   childtask,maintask: jmp_buf;
   myarr1: array of integer;
   i,a:integer;
   Ptr1:PtrInt;

function generator(var myarr:array of integer):integer;

var i1:integer;
     val:integer;
     ptr:PtrInt;
begin


i1:=0;

val:= setjmp(childtask);

i1:=val-1;

if val=0 then
    begin
     new(ptr);
     ptr^:=myarr1[i1];
     longjmp(maintask,uint64(ptr));
    end;

if val=10
    then
     begin
	 writeln('Exiting child..');
	 exit;
	end;

  inc(i1);
  new(ptr);
  ptr^:=myarr1[i1];
  longjmp(maintask,uint64(ptr));
end;

begin

setlength(myarr1,10);

for i:=0 to 9
do myarr1[i]:=i;

uint64(ptr1):=setjmp(maintask);

if ptr1=nil then generator(myarr1);

a:=ptr1^;
dispose(ptr1);

if (a<=length(myarr1))
   then
     begin
       if a=length(myarr1)
	  then longjmp(childtask,a+1)
	  else
	    begin
               writeln('Value retuned by generator is: ',a);
	      longjmp(childtask,a+1);
          end;
	end;

setlength(myarr1,0);

end.

====


Thank you,
Amine Moulay Ramdane.

Back to comp.lang.pascal.misc | Previous | Next | Find similar


Thread

More of my philosophy and precision about the link of the article and more.. World-News2100 <m1@m1.com> - 2021-11-25 11:18 -0500

csiph-web