Article View: comp.sys.amiga.tech
Article #11926Re: CBM, Why did you make it so hard?
From: Glen Fullmer
Date: Wed, 22 Mar 1989 23:20
Date: Wed, 22 Mar 1989 23:20
174 lines
10388 bytes
10388 bytes
In article <3623@amiga.UUCP> jimm@cloyd.UUCP (Jim Mackraz) writes:
>)3. How does one restore the environment, for example, after an interrupt?
>
>I don't follow. Unless you are using interrupts as part of the package,
>the system will restore you without your ever knowing. All registers must
>...
>)4. Is making a package that must retain context both over the life of a
>) call and the life of the session different than "pure" residentable
>) code? If so, how are they different, and what are the coding
>) differences?
>
>Most system libraries don't have a notion of "session," that is, there is
>typically no preserved state. To do this, you would just introduce
>a "handle" that is returned by InitSession() and passed to every pertinent
>call (including EndSession()). I guess you could say the OpenWindow() is
>doing just that. Think also about the model of a RastPort: it isn't
>session-based, but it is a handle. It has an Init() (although no Create()),
>and no End().
>Jim Mackraz, I and I Computing "Like you said when we crawled down
>{cbmvax,well,oliveb}!amiga!jimm from the trees: We're in transition."
> - Gang of Four
I want to thank all those who responded to my original inquiry about
Amiga run-time libraries. It was very helpful and enlightening.
Howard Anderson, whose generic graphics system originally elicited the
questions, also appreciated the comments.
There was some misunderstanding concerning my reference to interrupts.
No, he is not using interrupts as part of the package. The essential
question was: How does one maintain session context (reentrancy) in an
Amiga run-time library when multiple sessions use a set of changing
globals? There was a couple of suggestions: (1) To require the user
to create a session context pointer (like Raster-Pointer in Intuition)
or (2) to maintain a session context table within the library. He had
some additional comments about his preference to (2) and questions
about methods to achieve it. Any other methods that I missed? As it
is more convenient for me to post news than he, I am including his
comments and questions:
OK, let's try a concrete example. I have a graphics system that
is a collection of library routines that can be called by the
user. The user must call "gstart" first. He must call "gend"
when finished using the library. There is a function called
"gdraw" that the user can call to draw a line. There is a
function called "gset" that allows one to change modes, such as
the drawing color, that will be used for subsequent "gdraw"
calls. There are of course a lot of other callable functions in
the library.
I don't want the user to have to bother with setting up a
graphics structure for the graphics system. I don't want the
user to have to bother with passing some structure pointer that
is irrelevant to doing graphics. Since the graphics system
library is the object that NEEDS the structure for saving mode
data, it should do its own allocation, pointer-finding, and
deallocation of its task-dependent global/persistent storage.
The purpose of putting a generic graphics system up on the Amiga
is to make it easier for the user to use.
So the problem on the Amiga is how to set up a library with
task-dependent global/persistent storage that, after a
time-share interrupt or other interrupt, remembers where its
particular task-dependent global/persistent storage area is when
it again receives control from the scheduler. I so far have
placed all of the global/persistent storage items in one
structure. I can use MemAlloc to allocate storage for the
area. The problem is how to preserve that pointer through a
time-share interrupt (or any other sort of asynchronous
interrupt that takes control away from me, runs something else,
then returns to me.)
During an interrupt, 70 bytes are pushed onto the stack
representing all of the data registers, address registers,
status register, and the program counter. When you find
yourself back in your code after an interrupt, those 70 bytes
are all you really know. (You wouldn't even know where the
stack was unless one of the registers was dedicated to holding a
pointer to it.) Clearly, the best way to save a pointer to a
task-dependent global/persistent storage area is to DEDICATE one
of the registers, say A3, to always holding the pointer to the
task-dependent global/persistent storage area. This is how
Multics achieved what I consider to be true reentrancy -
reentrancy with per process global/persistent data - and spoiled
me beyond words... (See page 68 of "Timesharing System Design
Concepts", Richard Watson, McGraw-Hill, 1970. The Multics
operating system, by convention, dedicates a hardware register
called a "link pointer" to the "linkage information", i.e., the
task-dependent storage. This is always restored after an
interrupt so the task ALWAYS knows where its own storage is.
All programs are shared. New storage for task-dependent data of
a called function is always allocated whenever that function is
first called by a new process. On Multics, the operating system
takes care of all reentrancy/data mechanics.)
If I had written the graphics system in assembly language, I
could have dedicated a register to point to the task-dependent
storage. This register would have to be reserved and untouched
in the user program that calls the library function of course.
There does not appear to be a way to do that if the calling
program is written in C.
My best guess at present is that to fake reentrancy with
per-process global/persistent data, for a program written in C,
where the shared code is responsible for allocating and
deallocating its own global/persistent storage automatically, is
to use FindTask with a null argument to get a pointer to the
current task, then use tc_UserData as a storage location for the
pointer to the task-dependent global/persistent storage area --
IF the Amiga designers meant for tc_UserData to be used by ME.
Did they? My documentation says "per task data" but doesn't say
WHOSE. (I see that it is NULL from within a CLI task.)
Now even if I have that, I don't exactly like it. My "gstart"
routine would have to call Forbid(), then FindTask so that the
pointer could be stored in tc_UserData. Then I would have to
store the pointer in a local automatic variable for further use
within "gstart" then I'd have to call Permit(). That would be
OK but EACH routine in the graphics library, subsequently called
by the user program, would have to call FindTask to locate
tc_UserData and store the pointer in a local automatic variable
so that graphics mode data could be referenced through that
structure pointer. What is the overhead for a FindTask?
Now assuming the Commodore/Amiga people really don't want me
mucking around with tc_UserData, I could define a 2xn vector in
static storage that would contain the address of the current
task block as determined by a FindTask call paired with the
address of the corresponding global/persistent storage area.
Then EACH routine in the graphics library would have to call
FindTask, to get the task block pointer, then search the vector
for that pointer which would yield the index of the
corresponding address of global/persistent storage so that it
could be placed in a local automatic variable. I don't like the
idea of having to search that vector even though I know some
great hash algorithms.
So I really don't like any of the alternatives very well. Am I
missing something?
I figured out how to link to a library and pass floating point
variables. I know how to DO reentrant code with per-process
global/persistent data. I'm just not sure if there is an
efficient way to do it in C on the Amiga. I definitely don't
like the idea of the user having to pass a pointer to each
routine he calls as is done with RPort.
All of this began of course with the fact that the Manx and
Lattice compilers cannot link each other's object segments. I
had originally intended to create a library of object segments
for linking in with the user program. Most of the larger
machines I've worked with such as the Philco 2000, IBM 360/85,
3094-Q, Honeywell 6080, Multics and even Sun and Apollo have
standard linkers on the system provided as part of the system.
(At least I've always thought they were provided as part of the
system.) On smaller machines I've worked on such as the Apple
II and C-64, the linkers appear to have been specified by
third-party software suppliers. The shared library method
however seems to be a better answer than a link library if I can
get it to work the way I want it to.
I like the Amiga a lot. Don't misconstrue any of this as
criticism of the design. Commodore/Amiga did a rather brilliant
job. I am just trying to understand the Amiga conventions while
attempting to implement some software whose interface I want to
conform to some of my conventions.
Is there an easier way to do what I want to do?
_____ _ "For a successful technology, reality must take precedence"
{____/ // "over public relations, for Nature cannot be fooled."
\ // _ __Richard P. Feynman, Appendix F of Shuttle Disaster Report
{____/ </_</_/ / <_ {sun!sunburn | cadillac} !dover!fullmer
--
Technical Details
Message-ID:
<933@dover.azsps.mot.com>Path:
arc1-ca.pugleaf.net!utzoo!attcan!uunet!lll-winken!ames!pasteur!ucbvax!tut.cis.ohio-state.edu!cs.utexas.edu!oakhill!dover!fullmerReferences:
<913@dover.uucp> <3623@amiga.UUCP>Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!attcan!uunet!lll-winken!ames!pasteur!ucbvax!tut.cis.ohio-state.edu!cs.utexas.edu!oakhill!dover!fullmer From: fullmer@dover.azsps.mot.com (Glen Fullmer) Newsgroups: comp.sys.amiga.tech Subject: Re: CBM, Why did you make it so hard? Keywords: Graphics Libraries, reentrancy Message-ID: <933@dover.azsps.mot.com> Date: 22 Mar 89 23:20:51 GMT References: <913@dover.uucp> <3623@amiga.UUCP> Reply-To: fullmer@dover.UUCP (Glen Fullmer) Organization: Motorola CAD, Mesa Lines: 178