home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga MA Magazine 1998 #6
/
amigamamagazinepolishissue1998.iso
/
coders
/
jËzyki_programowania
/
oberon
/
system
/
coroutines.mod
(
.txt
)
< prev
next >
Wrap
Oberon Text
|
1977-12-31
|
5KB
|
100 lines
Syntax10.Scn.Fnt
Syntax10b.Scn.Fnt
Syntax10i.Scn.Fnt
MODULE Coroutines; (* jr/14jul94, updated cn/20jan96 *)
This module implements coroutines as known from Modula-2. Although it is machine
dependent, it was programed in a way, which should make it adaptable to
differen platforms by just a few changes in constant definitions. See the section marked CHANGE.
There is one restriction which procedures, that you use to create processe in NEWPROCESS,
have to obey. If they allocate space on the heap they must assure, that some global variable
points to this space during the entiere time this space is needed. If you don't follow this rule,
the garbage collector may reclaim the space, even though you still have some local
variables pointing to it.
On the Macintosh there is an additional restriction. The storage are used as stack for
a process has itself to be on the stack. Otherwise some check code will complain
about illegal stack pointer values.
This module was used on the different platforms at different stages of its development.
It showed some strange efects on the Oberon system, which we suspected as
a problem with garbage collection. I've fixed it now for the SGI Oberon. As I don't have
access to the other platforms, I don't really know if this module is still usable on them.
In theory, this is expected:
Macintosh:
The Mac Oberon does never perform garbage collection while outside of the
Oberon.Loop and therefore does not have to inspect the stack when deciding
which memory space is to be marked as in use. Thus the disabling of the garbage
collector is not needed, and the statements using Kernel.GCenabled can be
removed, maybe even have to be removed, as Kernel doesn't export GCenabled.
SGI,HP:
The garbage collector may be called when executing a command. It then scans
the stack to see, if there are pointer pointing to some heap ares, so it can mark
this area as in use. When executing a process, the stack pointer points to the
private stack of this process, and no more to the usual one. And if it points to the
wrong side of the stack, the garbage collector will not inspect the stack at all.
Therefore we disable the garbage collector when we are not in the main
execution thread, and reenable it, when we return to the main thread.
In case your command traps, while executing a coroutine, the garbage collector
remains disabled, and Coroutines continues to believe, that you are not in the
main thread. You should then use the Coroutines.Reset command to reenable the
garbage collector, and reset Coroutines.
Amiga:
The same as said for SGI and HP applies to the Amiga. But I don't know, if the
Amiga Kernel does export an GCenabled variable, as the Unix Kernel does.
If it doesn't, you have to wait for a future relase supporting it.
Later it was discovered, that the problem was cause by writing to the Log, while
executing code called from the handler in the SortBasic module.
Apart from the above mentioned problems, their might be others. So please be
carefull when using commands which use Coroutines. Don't do this, while you
have viewers with unsaved files open etc.
If you can identify problems with Coroutines, please send Mail to
claudio@dial.eunet.ch or joerg.straube@alcatel.ch
so we can improve this module.
The modifications for AXP were provided by
Guenter Dotzel <100023.2527@compuserve.com>
Thank you very much!
IMPORT SYSTEM,Kernel;
CONST (* CHANGE *)
(* Amiga/Mac: *) MP=14; SP=15; negativeGrow=TRUE; align=4;
(* HP: MP=30; SP=30; negativeGrow=FALSE; align=4; *)
(* SGI: MP=29; SP=29; negativeGrow=TRUE; align=4; *)
(* AXP: MP=29; SP=30; negativeGrow=TRUE; align=16; TYPE LONGINT=SYSTEM.SIGNED_64; *)
PROC*=PROCEDURE;
PROCESS*=RECORD
p:PROC;
stackForP:LONGINT;
MP:LONGINT
END;
mainMP:LONGINT;
proc:PROC;
PROCEDURE NEWPROCESS*(p:PROC; VAR stack:ARRAY OF SYSTEM.BYTE; VAR new:PROCESS);
BEGIN
new.p:=p;
IF negativeGrow THEN
new.stackForP:=((SYSTEM.ADR(stack)+LEN(stack)) DIV align)*align; (* respect alignment requirments *)
ELSE
new.stackForP:=((SYSTEM.ADR(stack)+3) DIV align)*align; (* long word align *)
END;
new.MP:=0;
END NEWPROCESS;
PROCEDURE TRANSFER*(VAR from,to:PROCESS);
BEGIN
SYSTEM.GETREG(MP,from.MP);
IF mainMP=0 THEN Kernel.GCenabled:=FALSE; mainMP:=from.MP; END;
IF to.MP#0 THEN
SYSTEM.PUTREG(MP,to.MP)
ELSE
proc:=to.p; (* copy into global variable needed when MP=SP *)
SYSTEM.PUTREG(SP,to.stackForP);
IF to.MP=mainMP THEN Kernel.GCenabled:=TRUE; mainMP:=0; END;
proc;
HALT(100);
END;
END TRANSFER;
PROCEDURE Reset*;
BEGIN
mainMP:=0;
Kernel.GCenabled:=TRUE;
END Reset;
BEGIN
Reset;
END Coroutines.