X-Received: by 2002:a05:620a:8d4:: with SMTP id z20mr23698766qkz.526.1637952853324; Fri, 26 Nov 2021 10:54:13 -0800 (PST) X-Received: by 2002:a05:6214:2341:: with SMTP id hu1mr14815964qvb.76.1637952853177; Fri, 26 Nov 2021 10:54:13 -0800 (PST) Path: csiph.com!weretis.net!feeder8.news.weretis.net!proxad.net!feeder1-2.proxad.net!209.85.160.216.MISMATCH!news-out.google.com!nntp.google.com!postnews.google.com!google-groups.googlegroups.com!not-for-mail Newsgroups: comp.programming Date: Fri, 26 Nov 2021 10:54:12 -0800 (PST) Injection-Info: google-groups.googlegroups.com; posting-host=173.178.84.155; posting-account=R-6XjwoAAACnHXTO3L-lyPW6wRsSmYW9 NNTP-Posting-Host: 173.178.84.155 User-Agent: G2/1.0 MIME-Version: 1.0 Message-ID: <3deefa22-e5df-4e4e-8cc1-a4c9516ed72dn@googlegroups.com> Subject: More of my philosophy about preemptive and non-preemptive timesharing and more.. From: Amine Moulay Ramdane Injection-Date: Fri, 26 Nov 2021 18:54:13 +0000 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Xref: csiph.com comp.programming:14262 Hello, More of my philosophy about preemptive and non-preemptive timesharing and m= ore.. I am a white arab from Morocco, and i think i am smart since i have also invented many scalable algorithms and algorithms.. I have just took a smart look at Modula-2 language(Modula-2 is a structured= , procedural programming language developed between 1977 and 1985 by Niklau= s Wirth at ETH Zurich, and he has also developed Pascal=20 language, read about Niklaus Wirth here: https://en.wikipedia.org/wiki/Nikl= aus_Wirth), and i think Modula-2 language was among the first languages tha= t has provided preemptive and non-preemptive timesharing with coroutines, b= ut the preemptive timesharing in Modula-2 uses Interrupt handling using IOT= RANSFER, but it is best reserved for programs that will run without operati= ng system support. Installing an interrupt handler on a multiuser system is= not feasi=C2=ADble because doing so would affect other users. (For this re= ason, IOTRANSFER is not a mandatory feature of Modula-2.) Even on single-us= er systems, IOTRANSFER can be difficult to use because installing an interr= upt handler causes the old interrupt handler (which most likely belongs to = the operating system) to be lost. So this is why i think that the best way = in modern operating systems is to use non-preemptive timesharing with corou= tines, so this is why i am providing you with my sophisticated implementati= on of stackful coroutines, read about it in my thoughts below: More of my philosophy about timesharing that is a Solution to Computer Bott= lenecks.. I invite you to look at the following very interesting video about timeshar= ing that is a Solution to Computer Bottlenecks: https://www.youtube.com/watch?v=3DQ07PhW5sCEk I think i am smart, and you have to understand one important thing=20 and it is: What is the difference between a software architect and=20 a software engineer?, i think there is an important difference and it=20 is also like abstracted in the following question: "How it is made?" So i think that software engineering works at a higher level than=20 a software architect, this is why you will notice that i am=20 quickly implementing a sophisticated stackful coroutines=20 Library and i am quickly implementing setjmp() and longjmp() with=20 x64 assembler or code machine, read my below thoughts about them, but you h= ave to know that my sophisticated stackful coroutines Library=20 does a kind of timesharing as in the above video, but i think that there i= s two kinds of timesharing: the preemptive one, and the non-preemptive one,= but the difference is that the preemptive one does interrupt with a timer = the coroutines from an external scheduler in=20 a form of function, but notice below that i am implementing the non-preempt= ive timesharing in my sophisticated coroutines Library, but you have to be = smart and notice that my way of doing is like the software architect way, s= ince i am implementing it from the lowest level with x64 assembler routines= that are part of the non-preemptive scheduler, but not only that, but you = have also to look at how i am also implementing a=20 sophisticated and much more rich interface in my stackful coroutines Librar= y, so it is like both software achitecting and software engineering, so her= e is all my below thoughts that shows how i am implementing it quickly, so = read it carefully since you have also to know what's the problem with the s= tack frames when architecturing and using the setjmp() and longjmp() so tha= t to implement coroutines: 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 Organ= ization", 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 corout= ines with just setjmp() and longjmp(), and so that to understand it, i invi= te you to read the following article that shows how when you yield from a f= irst function with a longjmp() to the main body of a program and when you c= all another functions with longjmp(), it can make the stack frames not work= correctly, and when you understand it you will not use setjmp() and longjm= p() 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 corout= ines library and read about it and download it from here: https://sites.google.com/site/scalable68/object-oriented-stackful-coroutine= s-library-for-delphi-and-freepascal More of my philosophy about setjmp() and longjmp() and generators and corou= tines.. I have just quickly implemented setjmp() and longjmp() in x64 assembler, and after that i have just implemented quickly a good example of a generato= r 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 behavi= our of a loop. All generators are also iterators. A generator is very simil= ar 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 bui= lding 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 a= llows 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 workin= g 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: =3D=3D=3D=3D=3D=3D { 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 =3D 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 perfor= m a non-local goto using longjmp. setjmp returns 0 when it is initially cal= led, and a non-zero value when it is returning from a call to longjmp. set= jmp 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} nostack= frame; {$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 FP= C} 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. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D 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 ge= nerator is very similar to a function that returns an array, in that a gene= rator has parameters, can be called, and generates a sequence of values. Ho= wever, 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 requi= res less memory and allows the caller to get started processing the first f= ew values immediately. In short, a generator looks like a function but beha= ves like an iterator. } program test_generator; {$APPTYPE CONSOLE} uses JmpLib64; type PtrInt =3D ^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:=3D0; val:=3D setjmp(childtask); i1:=3Dval-1; if val=3D0 then begin new(ptr); ptr^:=3Dmyarr1[i1]; longjmp(maintask,uint64(ptr)); end; if val=3D10 then begin writeln('Exiting child..'); exit; end; inc(i1); new(ptr); ptr^:=3Dmyarr1[i1]; longjmp(maintask,uint64(ptr)); end; begin setlength(myarr1,10); for i:=3D0 to 9 do myarr1[i]:=3Di; uint64(ptr1):=3Dsetjmp(maintask); if ptr1=3Dnil then generator(myarr1); a:=3Dptr1^; dispose(ptr1); if (a<=3Dlength(myarr1)) then begin if a=3Dlength(myarr1) then longjmp(childtask,a+1) else begin writeln('Value returned by generator is: ',a); longjmp(childtask,a+1); end; end; setlength(myarr1,0); end. =3D=3D=3D=3D Thank you, Amine Moulay Ramdane.